Index secret failure locations lazily

This commit is contained in:
2026-10-25 23:21:29 +00:00
parent f132cd6468
commit b4af900c10
3 changed files with 121 additions and 18 deletions

View File

@@ -21,6 +21,22 @@ type secretResolutionResult struct {
diagnostics []Diagnostic
}
type secretReferenceLocationResolver struct {
input *document.Node
lookup *documentLookup
}
func (resolver *secretReferenceLocationResolver) diagnostic(code Code, path Path, message string) Diagnostic {
if resolver.lookup == nil {
resolver.lookup = buildDocumentLookup(resolver.input)
}
diagnostic := Diagnostic{Code: code, Severity: SeverityError, Path: path.clone(), Message: message}
if location, ok := nearestDocumentLocationWithLookup(resolver.input, path, resolver.lookup); ok {
diagnostic.Primary = documentLocationPointer(location)
}
return diagnostic
}
func resolveSecretReferences(root reflect.Value, schema *schemaDescriptor, input *document.Node, lookup secretLookup) secretResolutionResult {
result := secretResolutionResult{
lookups: make(map[string]secretLookupResult), references: make(map[string]string),
@@ -32,17 +48,18 @@ func resolveSecretReferences(root reflect.Value, schema *schemaDescriptor, input
if lookup == nil {
lookup = func(string) (string, bool) { return "", false }
}
resolveSecretValue(root, schema.root, schema.secrets, Path{}, false, input, lookup, &result)
locations := &secretReferenceLocationResolver{input: input}
resolveSecretValue(root, schema.root, schema.secrets, Path{}, false, locations, lookup, &result)
result.diagnostics = canonicalDiagnostics(result.diagnostics)
return result
}
func resolveSecretValue(value reflect.Value, descriptor *typeDescriptor, secrets SecretBinding, path Path, optional bool, input *document.Node, lookup secretLookup, result *secretResolutionResult) {
func resolveSecretValue(value reflect.Value, descriptor *typeDescriptor, secrets SecretBinding, path Path, optional bool, locations *secretReferenceLocationResolver, lookup secretLookup, result *secretResolutionResult) {
if descriptor.kind == descriptorPointer {
if value.IsNil() {
return
}
resolveSecretValue(value.Elem(), descriptor.element, secrets, path, descriptor.element.kind == descriptorSecret, input, lookup, result)
resolveSecretValue(value.Elem(), descriptor.element, secrets, path, descriptor.element.kind == descriptorSecret, locations, lookup, result)
return
}
@@ -57,11 +74,11 @@ func resolveSecretValue(value reflect.Value, descriptor *typeDescriptor, secrets
code = CodeSecretInvalidName
message = "secret environment name is empty"
}
result.diagnostics = append(result.diagnostics, secretDiagnostic(code, path, message, input))
result.diagnostics = append(result.diagnostics, locations.diagnostic(code, path, message))
return
}
if !validEnvironmentName(name) {
result.diagnostics = append(result.diagnostics, secretDiagnostic(CodeSecretInvalidName, path, "secret environment name is invalid", input))
result.diagnostics = append(result.diagnostics, locations.diagnostic(CodeSecretInvalidName, path, "secret environment name is invalid"))
return
}
found, exists := result.lookups[name]
@@ -70,11 +87,11 @@ func resolveSecretValue(value reflect.Value, descriptor *typeDescriptor, secrets
result.lookups[name] = found
}
if !found.present {
result.diagnostics = append(result.diagnostics, secretDiagnostic(CodeSecretUnset, path, "secret environment variable is not set", input))
result.diagnostics = append(result.diagnostics, locations.diagnostic(CodeSecretUnset, path, "secret environment variable is not set"))
return
}
if found.value == "" {
result.diagnostics = append(result.diagnostics, secretDiagnostic(CodeSecretEmpty, path, "secret environment variable is empty", input))
result.diagnostics = append(result.diagnostics, locations.diagnostic(CodeSecretEmpty, path, "secret environment variable is empty"))
return
}
value.Set(secrets.Make(SecretState{Name: name, Value: found.value, Specified: true, Resolved: true}))
@@ -85,7 +102,7 @@ func resolveSecretValue(value reflect.Value, descriptor *typeDescriptor, secrets
if !member.inline {
memberPath = path.Key(member.name)
}
resolveSecretValue(value.Field(member.index), member.descriptor, secrets, memberPath, false, input, lookup, result)
resolveSecretValue(value.Field(member.index), member.descriptor, secrets, memberPath, false, locations, lookup, result)
}
case descriptorMap:
if value.IsNil() {
@@ -96,7 +113,7 @@ func resolveSecretValue(value reflect.Value, descriptor *typeDescriptor, secrets
for _, key := range keys {
entry := reflect.New(value.Type().Elem()).Elem()
entry.Set(value.MapIndex(key))
resolveSecretValue(entry, descriptor.element, secrets, path.Key(key.String()), false, input, lookup, result)
resolveSecretValue(entry, descriptor.element, secrets, path.Key(key.String()), false, locations, lookup, result)
value.SetMapIndex(key, entry)
}
case descriptorSlice, descriptorArray:
@@ -104,19 +121,11 @@ func resolveSecretValue(value reflect.Value, descriptor *typeDescriptor, secrets
return
}
for index := 0; index < value.Len(); index++ {
resolveSecretValue(value.Index(index), descriptor.element, secrets, path.Index(index), false, input, lookup, result)
resolveSecretValue(value.Index(index), descriptor.element, secrets, path.Index(index), false, locations, lookup, result)
}
}
}
func secretDiagnostic(code Code, path Path, message string, input *document.Node) Diagnostic {
diagnostic := Diagnostic{Code: code, Severity: SeverityError, Path: path.clone(), Message: message}
if location, ok := nearestDocumentLocation(input, path); ok {
diagnostic.Primary = documentLocationPointer(location)
}
return diagnostic
}
func changedSecretStates(root reflect.Value, schema *schemaDescriptor, lookups map[string]secretLookupResult) []Path {
var changed []Path
if schema == nil || schema.root == nil {