Check source versions in direct underlays

This commit is contained in:
2026-10-15 15:40:11 +00:00
parent 813d6a38c9
commit 184f29c7af
6 changed files with 284 additions and 11 deletions

View File

@@ -2,6 +2,7 @@ package engine
import (
"errors"
"path/filepath"
"testing"
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
@@ -754,6 +755,225 @@ configkit:
})
}
func TestSourceVersionUnderlaysCheckDistinctMountedDeclarations(t *testing.T) {
t.Parallel()
var checked []string
definition := Definition[map[string]any]{Version: &VersionRule{
Path: Keys("meta", "version"),
Check: func(version Version, validation *Validation) error {
checked = append(checked, version.Text)
if version.Text == "peer-a" || version.Text == "peer-c" {
validation.Warning(Path{}, "accepted with advisory")
}
return nil
},
}}
main := Input{
Source: Bytes("main", []byte("meta: {version: main-v}\nservice: primary\n")),
Destination: Keys("service"),
}
first := Input{
Source: Bytes("peer-a", []byte("meta:\n version: peer-a\nvalues: {first: one}\n")),
Destination: Keys("defaults", "first"),
}
second := Input{
Source: Bytes("peer-b", []byte("meta:\n version: peer-b\nvalues: {second: two}\n")),
Destination: Keys("defaults", "second"),
}
third := Input{
Source: Bytes("peer-c", []byte("meta:\n version: peer-c\nvalues: {third: three}\n")),
Destination: Keys("defaults", "third"),
}
loaded, err := LoadLayered(main, testSecretBinding(), LayeredOptions[map[string]any]{
Definition: definition, SourceVersionMode: sourceVersionModeRequired,
Underlays: []Underlay{{Inputs: []Input{first, second}}, {Inputs: []Input{third}}},
})
if err != nil {
t.Fatalf("LoadLayered: %v", err)
}
if len(checked) != 4 {
t.Fatalf("checked declarations = %#v, want main and all underlays", checked)
}
for _, want := range []string{"main-v", "peer-a", "peer-b", "peer-c"} {
found := false
for _, got := range checked {
found = found || got == want
}
if !found {
t.Errorf("checked declarations %#v do not include %q", checked, want)
}
}
if len(loaded.Inspection.Diagnostics()) != 2 || loaded.Inspection.Diagnostics()[0].Code != CodeVersionWarning || loaded.Inspection.Diagnostics()[1].Code != CodeVersionWarning {
t.Fatalf("accepted underlay warning was not retained: %#v", loaded.Inspection.Diagnostics())
}
sources := loaded.Inspection.Sources()
if len(sources) != 4 || sources[1].Layer != LayerUnderlay || sources[1].UnderlayIndex != 1 || sources[2].Layer != LayerUnderlay || sources[2].UnderlayIndex != 1 || sources[3].Layer != LayerUnderlay || sources[3].UnderlayIndex != 2 {
t.Fatalf("underlay source records = %#v", sources)
}
defaults, ok := loaded.Config["defaults"].(map[string]any)
if !ok {
t.Fatalf("defaults = %#v", loaded.Config["defaults"])
}
firstValue, ok := defaults["first"].(map[string]any)
if !ok || firstValue["values"] == nil {
t.Fatalf("first mounted contribution = %#v", defaults["first"])
}
if meta, ok := firstValue["meta"].(map[string]any); !ok || len(meta) != 0 {
t.Fatalf("consumed nested declaration did not preserve its empty ancestor: %#v", firstValue["meta"])
}
}
func TestSourceVersionUnderlaysRejectDeclarationsHiddenByMain(t *testing.T) {
t.Parallel()
var checked []string
loaded, err := LoadLayered(Input{Source: Bytes("main", []byte("meta: {version: main-v}\nservice: primary\n"))}, testSecretBinding(), LayeredOptions[map[string]any]{
Definition: Definition[map[string]any]{Version: &VersionRule{
Path: Keys("meta", "version"),
Check: func(version Version, _ *Validation) error {
checked = append(checked, version.Text)
if version.Text == "rejected-peer" {
return errors.New("peer declaration is not accepted")
}
return nil
},
}},
SourceVersionMode: sourceVersionModeIfPresent,
Underlays: []Underlay{{Inputs: []Input{{Source: Bytes("underlay", []byte("meta: {version: rejected-peer}\nservice: shadowed\n"))}}}},
})
if err == nil || loaded != nil {
t.Fatalf("LoadLayered = %#v, %v, want hidden underlay rejection", loaded, err)
}
loadErr, ok := err.(*LoadError)
if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeVersionHookFailed {
t.Fatalf("underlay rejection diagnostics = %#v", err)
}
if len(checked) != 2 || checked[0] != "main-v" || checked[1] != "rejected-peer" {
t.Fatalf("checked declarations = %#v", checked)
}
}
func TestSourceVersionUnderlaysRequireActualHeadersButSkipAbsentSources(t *testing.T) {
t.Parallel()
newOptions := func(underlays []Underlay) LayeredOptions[map[string]any] {
return LayeredOptions[map[string]any]{
Definition: Definition[map[string]any]{Version: &VersionRule{
Path: Keys("meta", "version"),
Check: func(Version, *Validation) error { return nil },
}},
SourceVersionMode: sourceVersionModeRequired,
Underlays: underlays,
}
}
main := Input{Source: Bytes("main", []byte("meta: {version: main-v}\n"))}
t.Run("required absence", func(t *testing.T) {
loaded, err := LoadLayered(main, testSecretBinding(), newOptions([]Underlay{{Inputs: []Input{{Source: Bytes("missing", []byte("value: present\n"))}}}}))
if err == nil || loaded != nil {
t.Fatalf("LoadLayered = %#v, %v, want missing underlay declaration", loaded, err)
}
loadErr, ok := err.(*LoadError)
if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeVersionError {
t.Fatalf("missing underlay diagnostics = %#v", err)
}
})
t.Run("empty group and NoSource", func(t *testing.T) {
loaded, err := LoadLayered(main, testSecretBinding(), newOptions([]Underlay{{}, {Inputs: []Input{{Source: NoSource()}}}}))
if err != nil {
t.Fatalf("LoadLayered with absent contributions: %v", err)
}
if sources := loaded.Inspection.Sources(); len(sources) != 1 {
t.Fatalf("empty groups and NoSource created source records: %#v", sources)
}
})
}
func TestSourceVersionUnderlayImportsKeepLocalHeadersAndMountedDestinations(t *testing.T) {
t.Parallel()
directory := t.TempDir()
underlayPath := writeImportFile(t, directory, "underlay.yml", `meta: {version: peer-root}
configkit:
imports:
- path: nested.yml
destination: [nested]
root: retained
`)
writeImportFile(t, directory, "nested.yml", "meta: {version: peer-nested}\nname: nested\n")
var checked []string
loaded, err := LoadLayered(Input{
Source: Bytes("main", []byte("meta: {version: main-v}\n")), Destination: Keys("service"),
}, testSecretBinding(), LayeredOptions[map[string]any]{
Definition: Definition[map[string]any]{Version: &VersionRule{
Path: Keys("meta", "version"),
Check: func(version Version, _ *Validation) error {
checked = append(checked, version.Text)
return nil
},
}},
SourceVersionMode: sourceVersionModeRequired,
Underlays: []Underlay{{Inputs: []Input{{
Source: File(underlayPath), Imports: true, Destination: Keys("defaults"),
}}}},
})
if err != nil {
t.Fatalf("LoadLayered: %v", err)
}
if len(checked) != 3 {
t.Fatalf("checked source declarations = %#v", checked)
}
for _, want := range []string{"main-v", "peer-root", "peer-nested"} {
found := false
for _, got := range checked {
found = found || got == want
}
if !found {
t.Errorf("checked source declarations %#v do not include %q", checked, want)
}
}
sources := loaded.Inspection.Sources()
if len(sources) != 3 || sources[1].Path != filepath.Clean(underlayPath) || sources[2].Destination.String() != "/defaults/nested" {
t.Fatalf("underlay and nested import records = %#v", sources)
}
if sources[1].Layer != LayerUnderlay || sources[1].UnderlayIndex != 1 || sources[2].Layer != LayerUnderlay || sources[2].UnderlayIndex != 1 {
t.Fatalf("underlay and nested import tiers = %#v", sources)
}
defaults, ok := loaded.Config["defaults"].(map[string]any)
if !ok || defaults["root"] != "retained" {
t.Fatalf("mounted underlay root = %#v", loaded.Config["defaults"])
}
nested, ok := defaults["nested"].(map[string]any)
if !ok || nested["name"] != "nested" {
t.Fatalf("mounted nested import = %#v", defaults["nested"])
}
}
func TestSourceVersionUnderlaysProtectRemainingMountedPayload(t *testing.T) {
t.Parallel()
loaded, err := LoadLayered(Input{
Source: Bytes("main", []byte("meta: {version: main-v}\n")), Destination: Keys("service"),
}, testSecretBinding(), LayeredOptions[map[string]any]{
Definition: Definition[map[string]any]{Version: &VersionRule{
Path: Keys("meta", "version"), Check: func(Version, *Validation) error { return nil },
}},
SourceVersionMode: sourceVersionModeRequired,
Underlays: []Underlay{{Inputs: []Input{{Source: Bytes("underlay", []byte(
"meta: {version: accepted}\nservice: {meta: {version: payload}}\n",
))}}}},
})
if err == nil || loaded != nil {
t.Fatalf("LoadLayered = %#v, %v, want protected remaining payload rejection", loaded, err)
}
loadErr, ok := err.(*LoadError)
if !ok || len(loadErr.Diagnostics()) != 1 || loadErr.Diagnostics()[0].Code != CodeUnderlayVersion {
t.Fatalf("remaining payload diagnostics = %#v", err)
}
}
func TestSourceVersionImportAccountingIncludesConsumedHeaderNodes(t *testing.T) {
t.Parallel()