Retain inherited configuration inspection provenance

This commit is contained in:
2026-10-03 18:03:40 +00:00
parent f4779fede9
commit 1d1434b118
3 changed files with 186 additions and 2 deletions

View File

@@ -1,9 +1,11 @@
package config
import (
"bytes"
"errors"
"os"
"path/filepath"
"strings"
"testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
@@ -433,3 +435,175 @@ configkit:
t.Errorf("overlaid inherited step reference path = %q, want %q", got, want)
}
}
func TestInheritedInspectionRetainsOriginsRedactionAndOwnership(t *testing.T) {
t.Parallel()
root := t.TempDir()
parentDirectory := filepath.Join(root, "parents")
childDirectory := filepath.Join(root, "children")
overlayDirectory := filepath.Join(root, "overlays")
for _, directory := range []string{parentDirectory, childDirectory, overlayDirectory} {
if err := os.MkdirAll(directory, 0o700); err != nil {
t.Fatal(err)
}
}
parentFile := filepath.Join(parentDirectory, "pipelines.yml")
if err := os.WriteFile(parentFile, []byte(`pipelines:
parent:
input: {module: input}
structured_output_repair_attempts: 2
references:
source: {path: ./shared.txt}
artifacts:
summary:
extract:
module: extract
options:
nested: {value: original}
credentials: {api_key: fake-parent-secret}
`), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(parentDirectory, "shared.txt"), []byte("source\n"), 0o600); err != nil {
t.Fatal(err)
}
childFile := filepath.Join(childDirectory, "pipelines.yml")
if err := os.WriteFile(childFile, []byte(`pipelines:
child:
extends: parent
structured_output_repair_attempts: 0
`), 0o600); err != nil {
t.Fatal(err)
}
main := filepath.Join(root, "notarius.yml")
if err := os.WriteFile(main, []byte(`version: 5
configkit:
imports:
- path: parents/pipelines.yml
- path: children/pipelines.yml
`), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(overlayDirectory, "development.yml"), []byte(`pipelines:
parent:
artifacts:
summary:
extract:
options:
credentials: {api_key: fake-overlay-secret}
`), 0o600); err != nil {
t.Fatal(err)
}
loaded, err := Load(main, LoadOptions{Overlay: "development"})
if err != nil {
t.Fatalf("Load() error = %v", err)
}
child := loaded.Config.Pipelines["child"]
wantPath := filepath.Join(parentDirectory, "shared.txt")
if got := child.References["source"].Path; got != wantPath {
t.Fatalf("runtime inherited path = %q, want %q", got, wantPath)
}
if child.StructuredOutputRepairAttempts == nil || *child.StructuredOutputRepairAttempts != 0 {
t.Fatalf("runtime inherited repair setting = %#v", child.StructuredOutputRepairAttempts)
}
var effective bytes.Buffer
if err := loaded.WriteEffective(&effective); err != nil {
t.Fatalf("WriteEffective() error = %v", err)
}
if !strings.Contains(effective.String(), wantPath) || strings.Contains(effective.String(), "extends:") ||
!strings.Contains(effective.String(), "structured_output_repair_attempts: 0") {
t.Fatalf("effective configuration is inconsistent with runtime conversion: %s", effective.String())
}
for _, secret := range []string{"fake-parent-secret", "fake-overlay-secret"} {
if strings.Contains(effective.String(), secret) {
t.Fatalf("effective configuration exposed %q", secret)
}
}
for _, test := range []struct {
name string
path configkit.Path
}{
{name: "repair setting", path: configkit.Keys("pipelines", "child", "structured_output_repair_attempts")},
{name: "normalized reference", path: configkit.Keys("pipelines", "child", "references", "source", "path")},
} {
t.Run(test.name, func(t *testing.T) {
explanation, ok := loaded.result.Explain(test.path)
if !ok || len(explanation.History) == 0 {
t.Fatalf("inherited explanation = %#v, found=%v", explanation, ok)
}
inheritanceFromParent := false
for _, change := range explanation.History {
if len(change.Origin.Inheritance) == 0 {
continue
}
for _, location := range change.Origin.Locations {
for _, source := range loaded.result.Sources() {
if source.ID == location.SourceID && source.Path == parentFile {
inheritanceFromParent = true
}
}
}
}
if !inheritanceFromParent {
t.Fatalf("inheritance history lacks parent source evidence: %#v", explanation.History)
}
var rendered bytes.Buffer
if err := loaded.WriteExplanation(&rendered, test.path.String()); err != nil {
t.Fatalf("WriteExplanation() error = %v", err)
}
if !strings.Contains(rendered.String(), filepath.ToSlash(filepath.Join("parents", "pipelines.yml"))) {
t.Fatalf("explanation lacks parent source evidence: %s", rendered.String())
}
if test.name == "normalized reference" {
foundNormalization := false
for _, change := range explanation.History {
if change.Origin.Operation == configkit.ChangeNormalization {
foundNormalization = true
}
}
if !foundNormalization || !strings.Contains(rendered.String(), wantPath) {
t.Fatalf("normalized path evidence = %#v; rendered %s", explanation.History, rendered.String())
}
}
})
}
secretPath := configkit.Keys("pipelines", "child", "artifacts", "summary", "extract", "options", "credentials", "api_key")
secretExplanation, ok := loaded.result.Explain(secretPath)
if !ok || !secretExplanation.Effective.Redacted {
t.Fatalf("inherited secret explanation = %#v, found=%v", secretExplanation, ok)
}
redactedHistory := false
for _, change := range secretExplanation.History {
redactedHistory = redactedHistory || change.Before.Redacted || change.After.Redacted
}
if !redactedHistory {
t.Fatalf("secret history was not redacted: %#v", secretExplanation.History)
}
var secretOutput bytes.Buffer
if err := loaded.WriteExplanation(&secretOutput, secretPath.String()); err != nil {
t.Fatalf("WriteExplanation(secret) error = %v", err)
}
if strings.Contains(secretOutput.String(), "fake-parent-secret") || strings.Contains(secretOutput.String(), "fake-overlay-secret") ||
!strings.Contains(secretOutput.String(), "[REDACTED]") {
t.Fatalf("secret explanation did not redact values and history: %s", secretOutput.String())
}
childOptions := loaded.Config.Pipelines["child"].Artifacts["summary"].Extract.Options
childOptions["nested"].(map[string]any)["value"] = "changed"
parentValue := loaded.Config.Pipelines["parent"].Artifacts["summary"].Extract.Options["nested"].(map[string]any)["value"]
if parentValue != "original" {
t.Fatalf("child runtime mutation changed parent value: %#v", parentValue)
}
var frozen bytes.Buffer
if err := loaded.WriteEffective(&frozen); err != nil {
t.Fatalf("WriteEffective() after runtime mutation error = %v", err)
}
if !strings.Contains(frozen.String(), "original") || strings.Contains(frozen.String(), "changed") {
t.Fatalf("runtime mutation changed frozen inspection: %s", frozen.String())
}
}