Project history and sensitivity paths
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
||||
@@ -137,6 +139,89 @@ func TestHistoryMergeSupportsSemanticIndexedPrefixes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectedSequenceHistoryAgreesAcrossMetadataAndExplanation(t *testing.T) {
|
||||
policy := sequencePolicy{identityFields: map[string]string{"/records": "id"}}
|
||||
composed, diagnostics := composeDocumentsWithPolicy(policy,
|
||||
parseCompositionDocument(t, "first", "records: [{id: first, token: public}]"),
|
||||
parseCompositionDocument(t, "second", "records: [{id: second, token: private}]"),
|
||||
)
|
||||
if len(diagnostics) != 0 {
|
||||
t.Fatalf("compose diagnostics = %#v", diagnostics)
|
||||
}
|
||||
path := Keys("records").Index(1).Key("token")
|
||||
var metadata Metadata
|
||||
finalizeMetadataPaths(&metadata, composed.root, composed.applications)
|
||||
if !metadata.hasHistoricalPath(path) {
|
||||
t.Fatalf("projected metadata omitted shifted path %s: %#v", path, metadata.historicalPaths)
|
||||
}
|
||||
|
||||
inspection := &Inspection{
|
||||
metadata: metadata, baseline: &document.Node{Kind: document.Mapping},
|
||||
input: composed.root, final: composed.root, applications: composed.applications,
|
||||
}
|
||||
inspection.secrets = classifySecretPaths(nil, func(candidate Path) bool {
|
||||
return reflect.DeepEqual(candidate, path)
|
||||
}, metadata, composed.root, composed.applications)
|
||||
explanation, ok := inspection.Explain(path)
|
||||
if !ok || !explanation.Effective.Redacted {
|
||||
t.Fatalf("shifted explanation = %#v, %v", explanation, ok)
|
||||
}
|
||||
var foundSecondOrigin bool
|
||||
for _, change := range explanation.History {
|
||||
for _, location := range change.Origin.Locations {
|
||||
foundSecondOrigin = foundSecondOrigin || location.SourceID == "second"
|
||||
}
|
||||
}
|
||||
if !foundSecondOrigin {
|
||||
t.Fatalf("shifted history lost second source attribution: %#v", explanation.History)
|
||||
}
|
||||
var rendered bytes.Buffer
|
||||
if err := inspection.WriteExplanation(&rendered, path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(rendered.String(), `path: "/records/1/token"`) || strings.Contains(rendered.String(), "private") {
|
||||
t.Fatalf("shifted explanation rendering is incomplete or unsafe: %s", rendered.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplacedProjectedSensitiveRecordRemainsRedacted(t *testing.T) {
|
||||
policy := sequencePolicy{identityFields: map[string]string{"/records": "id"}}
|
||||
composed, diagnostics := composeDocumentsWithPolicy(policy,
|
||||
parseCompositionDocument(t, "first", "records: [{id: first, token: public}]"),
|
||||
parseCompositionDocument(t, "second", "records: [{id: second, token: PRIVATE-RECORD-CANARY}]"),
|
||||
)
|
||||
if len(diagnostics) != 0 {
|
||||
t.Fatalf("compose diagnostics = %#v", diagnostics)
|
||||
}
|
||||
applications := append([]historyApplication(nil), composed.applications...)
|
||||
applications = append(applications, historyApplication{
|
||||
layer: LayerOverlay,
|
||||
value: parseCompositionDocument(t, "replacement", "records: [{id: replacement, token: visible}]"),
|
||||
})
|
||||
final := applications[len(applications)-1].value
|
||||
path := Keys("records").Index(1).Key("token")
|
||||
var metadata Metadata
|
||||
finalizeMetadataPaths(&metadata, final, applications)
|
||||
inspection := &Inspection{
|
||||
metadata: metadata, baseline: &document.Node{Kind: document.Mapping},
|
||||
input: final, final: final, applications: applications,
|
||||
}
|
||||
inspection.secrets = classifySecretPaths(nil, func(candidate Path) bool {
|
||||
return reflect.DeepEqual(candidate, path)
|
||||
}, metadata, final, applications)
|
||||
explanation, ok := inspection.Explain(path)
|
||||
if !ok || explanation.Effective.Present {
|
||||
t.Fatalf("replaced shifted record explanation = %#v, %v", explanation, ok)
|
||||
}
|
||||
var rendered bytes.Buffer
|
||||
if err := inspection.WriteExplanation(&rendered, path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(rendered.String(), "PRIVATE-RECORD-CANARY") || !strings.Contains(rendered.String(), "[REDACTED]") {
|
||||
t.Fatalf("replaced sensitive history leaked or was not redacted: %s", rendered.String())
|
||||
}
|
||||
}
|
||||
|
||||
func mustParsePath(t *testing.T, value string) Path {
|
||||
t.Helper()
|
||||
path, err := ParsePath(value)
|
||||
|
||||
Reference in New Issue
Block a user