Audit source version lifecycle agreement

This commit is contained in:
2026-10-15 16:17:21 +00:00
parent 43c994a32a
commit b0550af6a3
2 changed files with 135 additions and 2 deletions

View File

@@ -1,6 +1,6 @@
# Implement shared source version checks # Implement shared source version checks
Status: Stages 1–10 complete; public source evidence remains private. Status: Stages 1–12 complete; adoption examples and documentation reconciliation remain.
Audience: a Luna coding agent implementing one numbered stage per prompt, in Audience: a Luna coding agent implementing one numbered stage per prompt, in
order. The [feature roadmap](source-version-checks.md) owns target behavior and order. The [feature roadmap](source-version-checks.md) owns target behavior and
@@ -573,7 +573,7 @@ These checks passed with Go `go1.26.8 linux/amd64`:
No environmental limitation affected validation; checks ran on Linux/amd64. No environmental limitation affected validation; checks ran on Linux/amd64.
## Stage 12 — Audit lifecycle agreement and compatibility ## Stage 12 — Audit lifecycle agreement and compatibility — Done
1. Map tests to every roadmap participation row/edge decision; add only missing 1. Map tests to every roadmap participation row/edge decision; add only missing
cross-boundary regressions with one primary owner per behavior. cross-boundary regressions with one primary owner per behavior.
@@ -594,6 +594,27 @@ No environmental limitation affected validation; checks ran on Linux/amd64.
Done: all target behavior has public-boundary evidence and deterministic checks Done: all target behavior has public-boundary evidence and deterministic checks
pass, without extra contract restrictions or redundant coverage. pass, without extra contract restrictions or redundant coverage.
Completion evidence: mapped source-local lookup, malformed/overlapping headers,
consumption, roles, mounted protection, directives, and source participation to
the focused `source_version_test.go` suite; mapped classification and historical
propagation to `secret_classification_test.go`, `inheritance_secret_test.go`,
and the recorded-dependency regression; and retained existing destination,
accounting, resource-context, and default-mode suites as the owners for those
boundaries. Added a public-facade lifecycle regression that accepts distinct
main/underlay declarations while verifying exact large-integer decoding,
zero/false/null, defaults, one resolved configuration, secret lookup, validation,
evidence retention, and unchanged effective explanation/rendering/Diff. No
source-order promise or additional policy was introduced. These checks passed
with Go `go1.26.8 linux/amd64`:
- `GOTOOLCHAIN=local GOPROXY=off go test ./internal/engine -run 'SourceVersion|Version|Import|Underlay|Overlay|Destination|Secret|Sensitivity|History|Inheritance|Resolution' -count=1`
- `GOTOOLCHAIN=local GOPROXY=off go test . -run 'SourceVersion|Version|Layered|SourceInfo|Destination|Diff|PublicFacadeBoundary|DependencyImportBoundary' -count=1`
- `GOTOOLCHAIN=local ./scripts/check.sh`
- `GOTOOLCHAIN=local GOPROXY=off go test -race ./...`
- `git diff --check`
No environmental limitation affected validation; checks ran on Linux/amd64.
## Stage 13 — Add maintained adoption examples ## Stage 13 — Add maintained adoption examples
1. Add a small executable example showing if-present and required adoption with 1. Add a small executable example showing if-present and required adoption with

View File

@@ -1,6 +1,7 @@
package configkit_test package configkit_test
import ( import (
"bytes"
"errors" "errors"
"os" "os"
"path/filepath" "path/filepath"
@@ -418,3 +419,114 @@ func TestFacadeSourceVersionEvidencePreservesAbsenceAndNull(t *testing.T) {
t.Fatalf("null declaration evidence = %#v", null) t.Fatalf("null declaration evidence = %#v", null)
} }
} }
func TestFacadeSourceVersionLifecycleKeepsConsumedHeadersOutOfPayloadHistory(t *testing.T) {
type serviceConfig struct {
Version uint64 `yaml:"version"`
Count int `yaml:"count"`
Enabled bool `yaml:"enabled"`
Nullable *string `yaml:"nullable"`
Revision string `yaml:"revision"`
Defaulted string `yaml:"defaulted"`
Resolved string `yaml:"resolved"`
Credential configkit.Secret `yaml:"credential"`
}
type configuration struct {
Service serviceConfig `yaml:"service"`
}
t.Setenv("CONFIGKIT_LIFECYCLE_SECRET", "lifecycle-secret-value")
var checked []configkit.Version
var validationCalls int
definition := configkit.Definition[configuration]{
Defaults: func() configuration {
return configuration{Service: serviceConfig{Defaulted: "from defaults"}}
},
Version: &configkit.VersionRule{
Path: configkit.Keys("version"),
Check: func(version configkit.Version, _ *configkit.Validation) error {
checked = append(checked, version)
return nil
},
},
Resolve: func(current *configuration, resolution *configkit.Resolution) error {
current.Service.Resolved = "resolved once"
resolution.Record(configkit.Keys("service", "resolved"), configkit.ChangeNormalization, "derive resolved value")
return nil
},
Validate: func(current *configuration, validation *configkit.Validation) {
validationCalls++
if current.Service.Version != 9007199254740993 || current.Service.Count != 0 || current.Service.Enabled ||
current.Service.Nullable != nil || current.Service.Revision != "ordinary-payload" || current.Service.Defaulted != "from defaults" ||
current.Service.Resolved != "resolved once" || current.Service.Credential.Value() != "lifecycle-secret-value" {
validation.Error(configkit.Keys("service"), "assembled values did not survive source declaration processing")
}
},
}
load := func(header string) *configkit.Result[configuration] {
t.Helper()
result, err := configkit.LoadLayered(configkit.Input{
Source: configkit.Bytes("main", []byte("version: 9007199254740993\n")), Destination: configkit.Keys("service"),
}, configkit.LayeredOptions[configuration]{
Definition: definition, SourceVersionMode: configkit.SourceVersionModeIfPresent,
Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{
Source: configkit.Bytes("underlay", []byte("version: "+header+"\ncount: 0\nenabled: false\nnullable: null\nrevision: ordinary-payload\ncredential: CONFIGKIT_LIFECYCLE_SECRET\n")),
Destination: configkit.Keys("service"),
}}}},
})
if err != nil || result == nil {
var failure *configkit.LoadError
var diagnostics []configkit.Diagnostic
if errors.As(err, &failure) {
diagnostics = failure.Diagnostics()
}
t.Fatalf("LoadLayered(%q) = %#v, %v; diagnostics %#v", header, result, err, diagnostics)
}
return result
}
first := load("underlay-release-a")
second := load("underlay-release-b")
if len(checked) != 4 || checked[0].Text != "9007199254740993" || checked[1].Text != "underlay-release-a" ||
checked[2].Text != "9007199254740993" || checked[3].Text != "underlay-release-b" {
t.Fatalf("source declarations checked = %#v", checked)
}
if validationCalls != 2 || first.Config.Service != second.Config.Service {
t.Fatalf("final configs or validation count = %#v, %#v, %d", first.Config, second.Config, validationCalls)
}
if differences, err := configkit.Diff(first, second); err != nil || len(differences) != 0 {
t.Fatalf("different consumed declarations created effective differences: %#v, %v", differences, err)
}
var firstEffective, secondEffective bytes.Buffer
if err := first.WriteEffective(&firstEffective); err != nil {
t.Fatal(err)
}
if err := second.WriteEffective(&secondEffective); err != nil {
t.Fatal(err)
}
if firstEffective.String() != secondEffective.String() || strings.Contains(firstEffective.String(), "underlay-release") {
t.Fatalf("consumed declarations affected effective rendering:\n%s\n%s", firstEffective.String(), secondEffective.String())
}
sourcesA, sourcesB := first.Sources(), second.Sources()
if len(sourcesA) != 2 || len(sourcesB) != 2 || sourcesA[1].VersionCheck == nil || sourcesB[1].VersionCheck == nil ||
sourcesA[1].VersionCheck.Version.Text != "underlay-release-a" || sourcesB[1].VersionCheck.Version.Text != "underlay-release-b" {
t.Fatalf("sanitized evidence did not retain distinct accepted declarations: %#v / %#v", sourcesA, sourcesB)
}
versionExplanation, found := first.Explain(configkit.Keys("service", "version"))
if !found {
t.Fatal("retained main version missing from effective explanation")
}
underlayID := sourcesA[1].ID
for _, location := range versionExplanation.Origin.Locations {
if location.SourceID == underlayID {
t.Fatalf("consumed underlay declaration entered effective origin: %#v", versionExplanation.Origin)
}
}
for _, change := range versionExplanation.History {
for _, location := range change.Origin.Locations {
if location.SourceID == underlayID {
t.Fatalf("consumed underlay declaration entered effective history: %#v", versionExplanation.History)
}
}
}
}