From b0550af6a32ddf7ffc665f8f488e81572a40e0b9 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Thu, 15 Oct 2026 16:17:21 +0000 Subject: [PATCH] Audit source version lifecycle agreement --- docs/roadmap/implementation.md | 25 ++++++- facade_source_version_mode_test.go | 112 +++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 2 deletions(-) diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index cb03bcf..1152557 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # 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 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. -## 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 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 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 1. Add a small executable example showing if-present and required adoption with diff --git a/facade_source_version_mode_test.go b/facade_source_version_mode_test.go index 2c203e1..3ed042f 100644 --- a/facade_source_version_mode_test.go +++ b/facade_source_version_mode_test.go @@ -1,6 +1,7 @@ package configkit_test import ( + "bytes" "errors" "os" "path/filepath" @@ -418,3 +419,114 @@ func TestFacadeSourceVersionEvidencePreservesAbsenceAndNull(t *testing.T) { 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) + } + } + } +}