package engine import ( "encoding/json" "fmt" "io" "reflect" "strconv" "testing" ) // Secret is a test-local facade secret. Production engine code must not depend // on this type; each test load supplies the binding below explicitly. type Secret struct { name string value string specified bool resolved bool } func SecretEnv(name string) Secret { return Secret{name: name, specified: true} } func (s Secret) EnvName() string { return s.name } func (s Secret) Value() string { if !s.resolved { return "" } return s.value } func (s Secret) IsResolved() bool { return s.resolved } func (s Secret) Format(state fmt.State, _ rune) { _, _ = io.WriteString(state, "configkit.SecretEnv("+strconv.Quote(s.name)+")") } func (s Secret) MarshalJSON() ([]byte, error) { return json.Marshal(s.name) } func testSecretBinding() SecretBinding { return SecretBinding{ Type: reflect.TypeFor[Secret](), Read: func(value reflect.Value) SecretState { secret := value.Interface().(Secret) return SecretState{Name: secret.name, Value: secret.value, Specified: secret.specified, Resolved: secret.resolved} }, Make: func(state SecretState) reflect.Value { return reflect.ValueOf(Secret{name: state.Name, value: state.Value, specified: state.Specified, resolved: state.Resolved}) }, } } func testLoad[T any](source Source, supplied ...Options[T]) (*testResult[T], error) { loaded, err := Load(source, testSecretBinding(), supplied...) return testLoaded(loaded), err } func testLoadWithSecretLookup[T any](source Source, lookup secretLookup, supplied ...Options[T]) (*testResult[T], error) { loaded, err := loadWithSecretLookup(source, testSecretBinding(), lookup, supplied...) return testLoaded(loaded), err } type testResult[T any] struct { Config T *Inspection } func testLoaded[T any](loaded *Loaded[T]) *testResult[T] { if loaded == nil { return nil } return &testResult[T]{Config: loaded.Config, Inspection: loaded.Inspection} } func (r *testResult[T]) Metadata() Metadata { if r == nil { return Metadata{} } return r.Inspection.Metadata() } func (r *testResult[T]) Sources() []SourceInfo { if r == nil { return nil } return r.Inspection.Sources() } func (r *testResult[T]) Diagnostics() []Diagnostic { if r == nil { return nil } return r.Inspection.Diagnostics() } func (r *testResult[T]) Explain(path Path) (Explanation, bool) { if r == nil { return Explanation{}, false } return r.Inspection.Explain(path) } func (r *testResult[T]) WriteEffective(output io.Writer) error { if r == nil { return errEffectiveUnavailable } return r.Inspection.WriteEffective(output) } func (r *testResult[T]) WriteExplanation(output io.Writer, path Path) error { if r == nil { return errExplanationUnknownPath } return r.Inspection.WriteExplanation(output, path) } func testBuildSchema(root reflect.Type) (*schemaDescriptor, *schemaIssue) { return buildSchema(root, testSecretBinding()) } func TestSecretBindingsRemainExactAndIndependent(t *testing.T) { t.Parallel() type otherSecret struct { name string } other := SecretBinding{ Type: reflect.TypeFor[otherSecret](), Read: func(value reflect.Value) SecretState { return SecretState{Name: value.Interface().(otherSecret).name} }, Make: func(state SecretState) reflect.Value { return reflect.ValueOf(otherSecret{name: state.Name}) }, } type config struct { First Secret `yaml:"first"` Second otherSecret `yaml:"second"` } firstSchema, firstIssue := buildSchema(reflect.TypeFor[config](), testSecretBinding()) if firstIssue != nil { t.Fatal(firstIssue) } secondSchema, secondIssue := buildSchema(reflect.TypeFor[config](), other) if secondIssue != nil { t.Fatal(secondIssue) } firstField := firstSchema.root.fields[firstSchema.root.fieldByName["first"]].descriptor firstOther := firstSchema.root.fields[firstSchema.root.fieldByName["second"]].descriptor secondField := secondSchema.root.fields[secondSchema.root.fieldByName["first"]].descriptor secondOther := secondSchema.root.fields[secondSchema.root.fieldByName["second"]].descriptor if firstField.kind != descriptorSecret || firstOther.kind == descriptorSecret || secondField.kind == descriptorSecret || secondOther.kind != descriptorSecret { t.Fatalf("secret descriptor kinds = %v, %v, %v, %v", firstField.kind, firstOther.kind, secondField.kind, secondOther.kind) } }