136 lines
5.4 KiB
Go
136 lines
5.4 KiB
Go
package configkit
|
|
|
|
import (
|
|
"errors"
|
|
"io/fs"
|
|
"path"
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
)
|
|
|
|
func TestDiscoveredItemHelpersPreserveNestedInheritedResourceEvidence(t *testing.T) {
|
|
const canary = "PRIVATE-CONSUMED-HEADER-CANARY"
|
|
filesystem := NewFilesystem("bundle", fstest.MapFS{
|
|
"bundle/config/main.yml": {Data: []byte(`configkit:
|
|
imports:
|
|
- dir: records
|
|
pattern: '*-item.yml'
|
|
destination: [services, records]
|
|
placement: sequence-item
|
|
services:
|
|
records:
|
|
- id: authored
|
|
version: authored
|
|
`)},
|
|
"bundle/config/records/a-item.yml": {Data: []byte(`configkit:
|
|
imports:
|
|
- path: helper.yml
|
|
version: ` + canary + `
|
|
entries:
|
|
parent:
|
|
resource: icon.txt
|
|
child:
|
|
extends: parent
|
|
`)},
|
|
"bundle/config/records/helper.yml": {Data: []byte("id: helper-supplied\n")},
|
|
"bundle/config/records/icon.txt": {Data: []byte("icon payload")},
|
|
})
|
|
result, err := Load(filesystem.File("bundle/config/main.yml"), Options[map[string]any]{
|
|
Imports: true,
|
|
Filesystem: &FilesystemContext{Root: "bundle", FS: &filesystem},
|
|
Definition: Definition[map[string]any]{
|
|
Version: &VersionRule{Path: Keys("version"), Check: func(Version, *Validation) error { return nil }},
|
|
SequenceIdentities: []SequenceIdentity{SequenceIdentityAt(Keys("services", "records"), "id")},
|
|
Secret: func(candidate Path) bool {
|
|
return candidate.String() == "/services/records/0/version"
|
|
},
|
|
},
|
|
SourceVersionMode: SourceVersionModeIfPresent,
|
|
})
|
|
if err != nil {
|
|
var loadError *LoadError
|
|
if errors.As(err, &loadError) {
|
|
t.Fatalf("load discovered item: %v; diagnostics: %#v", err, loadError.Diagnostics())
|
|
}
|
|
t.Fatalf("load discovered item: %v", err)
|
|
}
|
|
services := result.Config["services"].(map[string]any)
|
|
records := services["records"].([]any)
|
|
if len(records) != 2 || records[0].(map[string]any)["id"] != "helper-supplied" || records[0].(map[string]any)["version"] != nil || records[1].(map[string]any)["version"] != "authored" {
|
|
t.Fatalf("nested records = %#v", records)
|
|
}
|
|
childPath := Keys("services", "records").Index(0).Key("entries").Key("child").Key("resource")
|
|
child := records[0].(map[string]any)["entries"].(map[string]any)["child"].(map[string]any)
|
|
if child["resource"] != "icon.txt" {
|
|
t.Fatalf("inherited relative resource = %#v", child)
|
|
}
|
|
|
|
sources := result.Sources()
|
|
filesByID := make(map[string]string, len(sources))
|
|
for _, source := range sources {
|
|
filesByID[source.ID] = source.Path
|
|
}
|
|
var itemSource SourceInfo
|
|
for _, source := range sources {
|
|
if source.Path == "bundle/config/records/a-item.yml" {
|
|
itemSource = source
|
|
}
|
|
}
|
|
if itemSource.VersionCheck == nil || !itemSource.VersionCheck.Version.Present || !itemSource.VersionCheck.Redacted || itemSource.VersionCheck.Version.Text != "" {
|
|
t.Fatalf("consumed header inspection = %#v", itemSource.VersionCheck)
|
|
}
|
|
idInfo, ok := result.Metadata().Lookup(Keys("services", "records").Index(0).Key("id"))
|
|
if !ok || len(idInfo.Origin.Locations) != 1 || filesByID[idInfo.Origin.Locations[0].SourceID] != "bundle/config/records/helper.yml" {
|
|
t.Fatalf("assigned helper ID origin = %#v", idInfo)
|
|
}
|
|
resourceInfo, ok := result.Metadata().Lookup(childPath)
|
|
if !ok || len(resourceInfo.Origin.Locations) != 1 || filesByID[resourceInfo.Origin.Locations[0].SourceID] != "bundle/config/records/a-item.yml" {
|
|
t.Fatalf("inherited resource metadata = %#v", resourceInfo)
|
|
}
|
|
explanation, ok := result.Explain(childPath)
|
|
if !ok || explanation.Effective.YAML != "icon.txt\n" || len(explanation.Origin.Locations) != 1 || explanation.Origin.Locations[0].SourceID != resourceInfo.Origin.Locations[0].SourceID {
|
|
t.Fatalf("inherited resource explanation = %#v", explanation)
|
|
}
|
|
context, ok := result.SourceContext(resourceInfo.Origin.Locations[0].SourceID)
|
|
if !ok || context.FS == nil || context.BaseDir != "config/records" {
|
|
t.Fatalf("inherited resource context = %#v, %v", context, ok)
|
|
}
|
|
contents, err := fs.ReadFile(context.FS, path.Join(context.BaseDir, child["resource"].(string)))
|
|
if err != nil || string(contents) != "icon payload" {
|
|
t.Fatalf("inherited resource read = %q, %v", contents, err)
|
|
}
|
|
|
|
_, err = Load(filesystem.File("bundle/config/main.yml"), Options[map[string]any]{
|
|
Imports: true,
|
|
Filesystem: &FilesystemContext{Root: "bundle", FS: &filesystem},
|
|
Definition: Definition[map[string]any]{
|
|
Version: &VersionRule{Path: Keys("version"), Check: func(Version, *Validation) error { return nil }},
|
|
SequenceIdentities: []SequenceIdentity{SequenceIdentityAt(Keys("services", "records"), "version")},
|
|
Secret: func(candidate Path) bool {
|
|
return candidate.String() == "/services/records/0/version"
|
|
},
|
|
},
|
|
SourceVersionMode: SourceVersionModeIfPresent,
|
|
})
|
|
loadError, ok := err.(*LoadError)
|
|
if !ok || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != CodeComposeInvalid {
|
|
t.Fatalf("consumed header supplied an identity: %v", err)
|
|
}
|
|
if strings.Contains(err.Error(), canary) {
|
|
t.Fatalf("diagnostic exposed the consumed secret header: %v", err)
|
|
}
|
|
var failedItemSource SourceInfo
|
|
foundFailedItem := false
|
|
for _, source := range loadError.Sources() {
|
|
if source.Path == "bundle/config/records/a-item.yml" {
|
|
failedItemSource = source
|
|
foundFailedItem = true
|
|
break
|
|
}
|
|
}
|
|
if !foundFailedItem || failedItemSource.VersionCheck == nil || failedItemSource.VersionCheck.Version.Text != "" || !failedItemSource.VersionCheck.Redacted {
|
|
t.Fatalf("failed-load source inspection exposed or omitted header evidence: %#v", failedItemSource)
|
|
}
|
|
}
|