package configkit_test import ( "fmt" "strings" "testing" "gitea.maximumdirect.net/eric/ConfigKit" ) func TestFinalSequenceIdentityTreatsLateExtendsFieldsAsPayload(t *testing.T) { for _, phase := range []string{"defaults", "resolution"} { for _, component := range []any{"application-data", nil} { for _, duplicate := range []bool{false, true} { t.Run(fmt.Sprintf("%s/%v/duplicate=%t", phase, component, duplicate), func(t *testing.T) { items := []any{map[string]any{"extends": component}} if duplicate { items = append(items, map[string]any{"extends": component}) } definition := configkit.Definition[map[string]any]{ SequenceIdentities: []configkit.SequenceIdentity{configkit.SequenceIdentityAt(configkit.Keys("items"), "extends")}, Defaults: func() map[string]any { if phase == "defaults" { return map[string]any{"items": items} } return map[string]any{} }, } if phase == "resolution" { definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error { (*value)["items"] = items resolution.Record(configkit.Keys("items"), configkit.ChangeNormalization, "supply application payload") return nil } } loaded, err := configkit.Load(configkit.NoSource(), configkit.Options[map[string]any]{Definition: definition}) if duplicate { loadErr := requireFacadeLoadError(t, err) diagnostics := loadErr.Diagnostics() if loaded != nil || len(diagnostics) != 1 || diagnostics[0].Code != configkit.CodeSequenceConflict || diagnostics[0].Path.String() != "/items" { t.Fatalf("duplicate effective payload diagnostics = %#v", diagnostics) } return } if err != nil || loaded == nil { t.Fatalf("ordinary effective identity was interpreted as a directive: %v", err) } value := loaded.Config["items"].([]any)[0].(map[string]any) if actual, present := value["extends"]; !present || actual != component { t.Fatalf("effective payload = %#v", value) } }) } } } } func TestFinalSequenceIdentityValidatesLateValues(t *testing.T) { identity := configkit.SequenceIdentityAt(configkit.Keys("items"), "id") for _, source := range []string{"defaults", "CLI", "resolution"} { for _, shape := range []string{"duplicate", "missing", "non-scalar"} { t.Run(source+"/"+shape, func(t *testing.T) { items := finalIdentityRecords(shape) definition := configkit.Definition[map[string]any]{ SequenceIdentities: []configkit.SequenceIdentity{identity}, Defaults: func() map[string]any { if source == "defaults" { return map[string]any{"items": items} } return map[string]any{} }, } options := configkit.Options[map[string]any]{Definition: definition} switch source { case "CLI": options.Overrides = []configkit.Override{{Path: configkit.Keys("items"), Value: items, Flag: "--items"}} case "resolution": options.Definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error { (*value)["items"] = items resolution.Record(configkit.Keys("items"), configkit.ChangeNormalization, "create effective records") return nil } } result, err := configkit.Load(configkit.NoSource(), options) if result != nil { t.Fatalf("invalid final identities returned a result: %#v", result.Config) } loadErr := requireFacadeLoadError(t, err) if len(loadErr.Diagnostics()) != 1 { t.Fatalf("diagnostics = %#v", loadErr.Diagnostics()) } diagnostic := loadErr.Diagnostics()[0] wantCode, wantPath := configkit.CodeSequenceInvalid, "/items/0/id" if shape == "duplicate" { wantCode, wantPath = configkit.CodeSequenceConflict, "/items" } if diagnostic.Code != wantCode || diagnostic.Path.String() != wantPath { t.Fatalf("diagnostic = %#v, want %s at %s", diagnostic, wantCode, wantPath) } if source == "CLI" && (diagnostic.Primary == nil || diagnostic.Primary.SourceID != "source-1") { t.Fatalf("CLI identity diagnostic lost its source: %#v", diagnostic) } }) } } } func TestFinalSequenceIdentityMatchesLateDynamicNamespaces(t *testing.T) { selector := configkit.SequenceSelector{ configkit.SequenceLiteralKey("collections"), configkit.SequenceAnyMappingKey(), configkit.SequenceLiteralKey("items"), } for _, source := range []string{"defaults", "CLI", "resolution"} { t.Run(source, func(t *testing.T) { name := map[string]string{"defaults": "team", "CLI": "cloud", "resolution": "orbit"}[source] path := configkit.Keys("collections", name, "items") items := finalIdentityRecords("duplicate") definition := configkit.Definition[map[string]any]{ SequenceIdentities: []configkit.SequenceIdentity{ configkit.SequenceIdentityMatching(selector, "id"), }, Defaults: func() map[string]any { if source == "defaults" { return map[string]any{"collections": map[string]any{name: map[string]any{"items": items}}} } return map[string]any{} }, } options := configkit.Options[map[string]any]{Definition: definition} switch source { case "CLI": options.Overrides = []configkit.Override{{Path: path, Value: items, Flag: "--items"}} case "resolution": options.Definition.Resolve = func(value *map[string]any, resolution *configkit.Resolution) error { (*value)["collections"] = map[string]any{name: map[string]any{"items": items}} resolution.Record(configkit.Keys("collections"), configkit.ChangeNormalization, "create namespaced records") return nil } } result, err := configkit.Load(configkit.NoSource(), options) if result != nil { t.Fatalf("invalid dynamic identity returned a result: %#v", result.Config) } loadErr := requireFacadeLoadError(t, err) if diagnostics := loadErr.Diagnostics(); len(diagnostics) != 1 || diagnostics[0].Code != configkit.CodeSequenceConflict || diagnostics[0].Path.String() != path.String() { t.Fatalf("dynamic identity diagnostics = %#v", diagnostics) } }) } } func TestFinalSequenceIdentityAppliesToLayeredLoads(t *testing.T) { definition := configkit.Definition[map[string]any]{ SequenceIdentities: []configkit.SequenceIdentity{configkit.SequenceIdentityAt(configkit.Keys("items"), "id")}, Defaults: func() map[string]any { return map[string]any{"items": finalIdentityRecords("duplicate")} }, } result, err := configkit.LoadLayered(configkit.Input{Source: configkit.NoSource()}, configkit.LayeredOptions[map[string]any]{Definition: definition}) if result != nil { t.Fatalf("invalid layered final identities returned a result: %#v", result.Config) } loadErr := requireFacadeLoadError(t, err) if diagnostics := loadErr.Diagnostics(); len(diagnostics) != 1 || diagnostics[0].Code != configkit.CodeSequenceConflict { t.Fatalf("layered identity diagnostics = %#v", diagnostics) } } func TestFinalSequenceIdentityUsesTypedNumbersAndIgnoresUnmatchedShapes(t *testing.T) { definition := configkit.Definition[map[string]any]{ SequenceIdentities: []configkit.SequenceIdentity{ configkit.SequenceIdentityAt(configkit.Keys("items"), "id"), configkit.SequenceIdentityAt(configkit.Keys("unmatched"), "id"), }, } _, err := configkit.Load(configkit.NoSource(), configkit.Options[map[string]any]{ Definition: configkit.Definition[map[string]any]{ SequenceIdentities: definition.SequenceIdentities, Defaults: func() map[string]any { return map[string]any{"items": []any{ map[string]any{"id": int64(1)}, map[string]any{"id": float64(1)}, }} }, }, }) loadErr := requireFacadeLoadError(t, err) if diagnostics := loadErr.Diagnostics(); len(diagnostics) != 1 || diagnostics[0].Code != configkit.CodeSequenceConflict { t.Fatalf("typed numeric identity diagnostics = %#v", diagnostics) } valid, err := configkit.Load(configkit.Mapping("valid", map[string]any{ "items": []any{ map[string]any{"id": nil}, map[string]any{"id": true}, map[string]any{"id": int64(1)}, map[string]any{"id": "one"}, }, "other": []any{map[string]any{"id": "same"}, map[string]any{"id": "same"}}, }), configkit.Options[map[string]any]{Definition: definition}) if err != nil || valid == nil { t.Fatalf("valid scalar identities and unmatched duplicate sequence = %#v, %v", valid, err) } if _, err := configkit.Load(configkit.Mapping("other-shapes", map[string]any{"items": nil}), configkit.Options[map[string]any]{Definition: definition}); err != nil { t.Fatalf("null at a registered path was validated as an identity sequence: %v", err) } } func TestFinalSequenceIdentityDiagnosticDoesNotRevealResolvedSecrets(t *testing.T) { const canary = "FINAL-IDENTITY-CREDENTIAL-CANARY" const secretName = "CONFIGKIT_FINAL_IDENTITY_SECRET" t.Setenv(secretName, canary) type item struct { ID string `yaml:"id"` Token configkit.Secret `yaml:"token"` } type config struct { Items []item `yaml:"items"` } definition := configkit.Definition[config]{ SequenceIdentities: []configkit.SequenceIdentity{configkit.SequenceIdentityAt(configkit.Keys("items"), "id")}, Defaults: func() config { return config{Items: []item{ {ID: "duplicate", Token: configkit.SecretEnv(secretName)}, {ID: "duplicate", Token: configkit.SecretEnv(secretName)}, }} }, } result, err := configkit.Load(configkit.NoSource(), configkit.Options[config]{Definition: definition}) if result != nil { t.Fatalf("duplicate identity returned a result: %#v", result.Config) } if err == nil || strings.Contains(err.Error(), canary) { t.Fatalf("identity diagnostic leaked a resolved secret: %v", err) } loadErr := requireFacadeLoadError(t, err) if diagnostics := loadErr.Diagnostics(); len(diagnostics) != 1 || diagnostics[0].Code != configkit.CodeSequenceConflict { t.Fatalf("secret-bearing identity diagnostics = %#v", diagnostics) } } func finalIdentityRecords(shape string) []any { switch shape { case "duplicate": return []any{map[string]any{"id": "same"}, map[string]any{"id": "same"}} case "missing": return []any{map[string]any{"other": "value"}} default: return []any{map[string]any{"id": map[string]any{"nested": "value"}}} } }