373 lines
12 KiB
Go
373 lines
12 KiB
Go
package engine
|
|
|
|
// Layer identifies the precedence layer responsible for a configuration value.
|
|
type Layer string
|
|
|
|
const (
|
|
LayerDefault Layer = "default"
|
|
LayerBase Layer = "base"
|
|
LayerUnderlay Layer = "underlay"
|
|
LayerOverlay Layer = "overlay"
|
|
LayerCLI Layer = "cli"
|
|
LayerResolution Layer = "resolution"
|
|
)
|
|
|
|
// SourceKind identifies source acquisition independently of precedence.
|
|
type SourceKind string
|
|
|
|
const (
|
|
SourceKindFile SourceKind = "file"
|
|
SourceKindFilesystem SourceKind = "filesystem"
|
|
SourceKindBytes SourceKind = "bytes"
|
|
SourceKindReader SourceKind = "reader"
|
|
SourceKindMapping SourceKind = "mapping"
|
|
SourceKindCLI SourceKind = "cli"
|
|
)
|
|
|
|
// ChangeKind identifies a recorded operation. The zero value is
|
|
// used for input and default origins.
|
|
type ChangeKind string
|
|
|
|
const (
|
|
// ChangeDecoding records the built-in transition to canonical typed values.
|
|
// It is inspection metadata, not an operation accepted by Resolution.Record.
|
|
ChangeDecoding ChangeKind = "decoding"
|
|
// ChangeInheritance records structural input expansion. It is inspection
|
|
// metadata, not an operation accepted by Resolution.Record.
|
|
ChangeInheritance ChangeKind = "inheritance"
|
|
ChangeDerivedDefault ChangeKind = "derived_default"
|
|
ChangeNormalization ChangeKind = "normalization"
|
|
)
|
|
|
|
// Severity classifies a diagnostic.
|
|
type Severity string
|
|
|
|
const (
|
|
SeverityError Severity = "error"
|
|
SeverityWarning Severity = "warning"
|
|
)
|
|
|
|
// Code is a stable, machine-readable diagnostic classification.
|
|
type Code string
|
|
|
|
const (
|
|
CodeSourceInvalid Code = "source.invalid"
|
|
CodeSourceMissing Code = "source.missing"
|
|
CodeSourcePermission Code = "source.permission"
|
|
CodeSourceRead Code = "source.read"
|
|
CodeSourceNotRegular Code = "source.not_regular"
|
|
CodeSourceLimitExceeded Code = "source.limit_exceeded"
|
|
CodeSourceReaderUsed Code = "source.reader_used"
|
|
|
|
CodeYAMLInvalid Code = "yaml.invalid"
|
|
CodeYAMLEmpty Code = "yaml.empty"
|
|
CodeYAMLMultipleDocuments Code = "yaml.multiple_documents"
|
|
CodeYAMLRootType Code = "yaml.root_type"
|
|
CodeYAMLDuplicateKey Code = "yaml.duplicate_key"
|
|
CodeYAMLTag Code = "yaml.tag"
|
|
CodeYAMLAnchor Code = "yaml.anchor"
|
|
CodeYAMLAlias Code = "yaml.alias"
|
|
CodeYAMLMergeKey Code = "yaml.merge_key"
|
|
CodeYAMLScalar Code = "yaml.scalar"
|
|
CodeYAMLDepthLimit Code = "yaml.depth_limit"
|
|
CodeYAMLNodeLimit Code = "yaml.node_limit"
|
|
|
|
CodeSchemaRoot Code = "schema.root"
|
|
CodeSchemaUnsupportedType Code = "schema.unsupported_type"
|
|
CodeSchemaAmbiguousField Code = "schema.ambiguous_field"
|
|
CodeSchemaTag Code = "schema.tag"
|
|
CodeSchemaTextCodec Code = "schema.text_codec"
|
|
CodeSchemaInline Code = "schema.inline"
|
|
CodeSchemaCycle Code = "schema.cycle"
|
|
CodeSchemaProjectionLimit Code = "schema.projection_limit"
|
|
CodeSchemaCodec Code = "schema.codec"
|
|
CodeSchemaNonFinite Code = "schema.non_finite"
|
|
CodeSchemaDynamicType Code = "schema.dynamic_type"
|
|
|
|
CodeDecodeType Code = "decode.type"
|
|
CodeDecodeNull Code = "decode.null"
|
|
CodeDecodeRange Code = "decode.range"
|
|
CodeDecodeDuration Code = "decode.duration"
|
|
CodeDecodeText Code = "decode.text"
|
|
CodeDecodeUnknownField Code = "decode.unknown_field"
|
|
CodeDecodeArrayLength Code = "decode.array_length"
|
|
|
|
CodeOptionsInvalid Code = "options.invalid"
|
|
CodeOptionsUnavailable Code = "options.unavailable"
|
|
|
|
CodeImportDisabled Code = "import.disabled"
|
|
CodeImportInvalid Code = "import.invalid"
|
|
CodeImportMissing Code = "import.missing"
|
|
CodeImportPermission Code = "import.permission"
|
|
CodeImportRead Code = "import.read"
|
|
CodeImportOutsideRoot Code = "import.outside_root"
|
|
CodeImportCycle Code = "import.cycle"
|
|
CodeImportRepeated Code = "import.repeated"
|
|
CodeImportLimitExceeded Code = "import.limit_exceeded"
|
|
CodeImportVersion Code = "import.version"
|
|
CodeUnderlayVersion Code = "underlay.version"
|
|
|
|
CodeOverlayInvalid Code = "overlay.invalid"
|
|
CodeOverlayMissing Code = "overlay.missing"
|
|
CodeOverlayOutsideRoot Code = "overlay.outside_root"
|
|
CodeOverlayRepeated Code = "overlay.repeated"
|
|
CodeOverlayDirective Code = "overlay.directive"
|
|
CodeOverlayVersion Code = "overlay.version"
|
|
CodeOverlayLimitExceeded Code = "overlay.limit_exceeded"
|
|
|
|
CodeComposeInvalid Code = "compose.invalid"
|
|
CodeComposeConflict Code = "compose.conflict"
|
|
|
|
CodeVersionType Code = "version.type"
|
|
CodeVersionError Code = "version.error"
|
|
CodeVersionWarning Code = "version.warning"
|
|
CodeVersionHookFailed Code = "version.hook_failed"
|
|
|
|
CodeResolveError Code = "resolve.error"
|
|
CodeResolveWarning Code = "resolve.warning"
|
|
CodeResolveHookFailed Code = "resolve.hook_failed"
|
|
CodeResolveInvalidPath Code = "resolve.invalid_path"
|
|
CodeResolveInvalidKind Code = "resolve.invalid_kind"
|
|
CodeResolveInvalidRecord Code = "resolve.invalid_record"
|
|
CodeResolveInvalidTarget Code = "resolve.invalid_target"
|
|
CodeResolveInvalidValue Code = "resolve.invalid_value"
|
|
CodeResolveUnrecordedChange Code = "resolve.unrecorded_change"
|
|
|
|
CodeValidateError Code = "validate.error"
|
|
CodeValidateWarning Code = "validate.warning"
|
|
CodeValidateInvalidPath Code = "validate.invalid_path"
|
|
CodeValidateMutation Code = "validate.mutation"
|
|
|
|
CodeSecretsInvalidPath Code = "secrets.invalid_path"
|
|
CodeSecretsMissing Code = "secrets.missing"
|
|
CodeSecretsPermission Code = "secrets.permission"
|
|
CodeSecretsRead Code = "secrets.read"
|
|
CodeSecretsNotRegular Code = "secrets.not_regular"
|
|
CodeSecretsInvalidName Code = "secrets.invalid_name"
|
|
CodeSecretsLimitExceeded Code = "secrets.limit_exceeded"
|
|
CodeSecretsInvalidValue Code = "secrets.invalid_value"
|
|
CodeSecretsApplyFailed Code = "secrets.apply_failed"
|
|
|
|
CodeSecretRequired Code = "secret.required"
|
|
CodeSecretInvalidName Code = "secret.invalid_name"
|
|
CodeSecretUnset Code = "secret.unset"
|
|
CodeSecretEmpty Code = "secret.empty"
|
|
|
|
CodeOverrideInvalidPath Code = "override.invalid_path"
|
|
CodeOverrideInvalidLabel Code = "override.invalid_label"
|
|
CodeOverrideInvalidValue Code = "override.invalid_value"
|
|
CodeOverrideDuplicate Code = "override.duplicate"
|
|
CodeOverrideOverlap Code = "override.overlap"
|
|
CodeOverrideDirective Code = "override.directive"
|
|
CodeOverrideVersion Code = "override.version"
|
|
CodeOverrideLimitExceeded Code = "override.limit_exceeded"
|
|
|
|
CodeExplainLimitExceeded Code = "explain.limit_exceeded"
|
|
|
|
CodeInheritanceInvalid Code = "inheritance.invalid"
|
|
CodeInheritanceMissing Code = "inheritance.missing"
|
|
CodeInheritanceCycle Code = "inheritance.cycle"
|
|
CodeInheritanceVersion Code = "inheritance.version"
|
|
)
|
|
|
|
// Location identifies a position in a configuration source. Zero line and column
|
|
// values mean that coordinates are unavailable or synthetic.
|
|
type Location struct {
|
|
SourceID string
|
|
Line int
|
|
Column int
|
|
}
|
|
|
|
// SourceInfo describes a source discovered during a load. Kind identifies
|
|
// acquisition independently of Layer. Path is a canonical host path or a
|
|
// namespace-relative filesystem path; synthetic sources have no Path.
|
|
// ImportedFrom identifies the declaration that included this source.
|
|
type SourceInfo struct {
|
|
ID string
|
|
Label string
|
|
Path string
|
|
Destination Path
|
|
Layer Layer
|
|
Kind SourceKind
|
|
UnderlayIndex int
|
|
ImportedFrom *Location
|
|
VersionCheck *SourceVersionCheck
|
|
namespace *namespaceToken
|
|
placementMode placementMode
|
|
destinationUnresolved bool
|
|
}
|
|
|
|
// SourceVersionCheck is a detached, public-safe record of a source-local
|
|
// version declaration observed during an enabled load.
|
|
type SourceVersionCheck struct {
|
|
Path Path
|
|
Version Version
|
|
Location *Location
|
|
Redacted bool
|
|
}
|
|
|
|
// Diagnostic is a safe structured problem report. Message and source labels must
|
|
// never contain configuration values or other secrets.
|
|
type Diagnostic struct {
|
|
Code Code
|
|
Severity Severity
|
|
Path Path
|
|
Message string
|
|
Primary *Location
|
|
Related []Location
|
|
}
|
|
|
|
// InheritanceStep identifies a concrete payload transfer controlled by a
|
|
// relationship directive. Locations belong to that directive, not its value.
|
|
type InheritanceStep struct {
|
|
From Path
|
|
To Path
|
|
Reference Path
|
|
Locations []Location
|
|
}
|
|
|
|
// Origin describes where an effective definition came from. Multiple locations
|
|
// represent a composite origin; resolution origins are synthetic and identify their
|
|
// operation instead of a file location. Inheritance is projected from private
|
|
// contributor traces at inspection boundaries.
|
|
type Origin struct {
|
|
Layer Layer
|
|
Locations []Location
|
|
Operation ChangeKind
|
|
Inheritance []InheritanceStep
|
|
contributors []inheritanceContributor
|
|
}
|
|
|
|
// FieldInfo describes an effective configuration path.
|
|
type FieldInfo struct {
|
|
Explicit bool
|
|
Null bool
|
|
Origin Origin
|
|
}
|
|
|
|
// Change describes a definition or application-resolution operation. Path can name
|
|
// an ancestor operation affecting the queried descendant. Historical values are
|
|
// intentionally not exposed by this record.
|
|
type Change struct {
|
|
Path Path
|
|
Origin Origin
|
|
Previous []Origin
|
|
Reasons []string
|
|
Dependencies []Path
|
|
}
|
|
|
|
func cloneLocation(location *Location) *Location {
|
|
if location == nil {
|
|
return nil
|
|
}
|
|
cloned := *location
|
|
return &cloned
|
|
}
|
|
|
|
func cloneLocations(locations []Location) []Location {
|
|
if locations == nil {
|
|
return nil
|
|
}
|
|
return append([]Location(nil), locations...)
|
|
}
|
|
|
|
func cloneSourceInfo(source SourceInfo) SourceInfo {
|
|
source.ImportedFrom = cloneLocation(source.ImportedFrom)
|
|
source.Destination = source.Destination.clone()
|
|
source.VersionCheck = cloneSourceVersionCheck(source.VersionCheck)
|
|
return source
|
|
}
|
|
|
|
func cloneSourceVersionCheck(value *SourceVersionCheck) *SourceVersionCheck {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
cloned := *value
|
|
cloned.Path = value.Path.clone()
|
|
cloned.Location = cloneLocation(value.Location)
|
|
return &cloned
|
|
}
|
|
|
|
func cloneSourceInfos(sources []SourceInfo) []SourceInfo {
|
|
if sources == nil {
|
|
return nil
|
|
}
|
|
cloned := make([]SourceInfo, len(sources))
|
|
for i, source := range sources {
|
|
cloned[i] = cloneSourceInfo(source)
|
|
}
|
|
return cloned
|
|
}
|
|
|
|
func cloneOrigin(origin Origin) Origin {
|
|
origin.Locations = cloneLocations(origin.Locations)
|
|
origin.Inheritance = cloneInheritanceSteps(origin.Inheritance)
|
|
if origin.contributors != nil {
|
|
contributors := make([]inheritanceContributor, len(origin.contributors))
|
|
for index, contributor := range origin.contributors {
|
|
contributors[index] = contributor
|
|
contributors[index].source = contributor.source.clone()
|
|
}
|
|
origin.contributors = contributors
|
|
}
|
|
return origin
|
|
}
|
|
|
|
func cloneInheritanceSteps(steps []InheritanceStep) []InheritanceStep {
|
|
if steps == nil {
|
|
return nil
|
|
}
|
|
cloned := make([]InheritanceStep, len(steps))
|
|
for index, step := range steps {
|
|
cloned[index] = InheritanceStep{
|
|
From: step.From.clone(), To: step.To.clone(), Reference: step.Reference.clone(),
|
|
Locations: cloneLocations(step.Locations),
|
|
}
|
|
}
|
|
return cloned
|
|
}
|
|
|
|
func cloneFieldInfo(info FieldInfo) FieldInfo {
|
|
info.Origin = cloneOrigin(info.Origin)
|
|
return info
|
|
}
|
|
|
|
func cloneChange(change Change) Change {
|
|
change.Path = change.Path.clone()
|
|
change.Origin = cloneOrigin(change.Origin)
|
|
if change.Previous != nil {
|
|
previous := make([]Origin, len(change.Previous))
|
|
for i, origin := range change.Previous {
|
|
previous[i] = cloneOrigin(origin)
|
|
}
|
|
change.Previous = previous
|
|
}
|
|
change.Reasons = append([]string(nil), change.Reasons...)
|
|
if change.Dependencies != nil {
|
|
dependencies := make([]Path, len(change.Dependencies))
|
|
for i, path := range change.Dependencies {
|
|
dependencies[i] = path.clone()
|
|
}
|
|
change.Dependencies = dependencies
|
|
}
|
|
return change
|
|
}
|
|
|
|
func cloneDiagnostic(diagnostic Diagnostic) Diagnostic {
|
|
diagnostic.Path = diagnostic.Path.clone()
|
|
diagnostic.Primary = cloneLocation(diagnostic.Primary)
|
|
diagnostic.Related = cloneLocations(diagnostic.Related)
|
|
return diagnostic
|
|
}
|
|
|
|
func cloneDiagnostics(diagnostics []Diagnostic) []Diagnostic {
|
|
if diagnostics == nil {
|
|
return nil
|
|
}
|
|
cloned := make([]Diagnostic, len(diagnostics))
|
|
for i, diagnostic := range diagnostics {
|
|
cloned[i] = cloneDiagnostic(diagnostic)
|
|
}
|
|
return cloned
|
|
}
|