Share secret traversal between resolution and validation
This commit is contained in:
67
internal/engine/secret_walk.go
Normal file
67
internal/engine/secret_walk.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"reflect"
|
||||
"slices"
|
||||
)
|
||||
|
||||
type secretSlotAccess uint8
|
||||
|
||||
const (
|
||||
secretSlotsReadOnly secretSlotAccess = iota
|
||||
secretSlotsWritable
|
||||
)
|
||||
|
||||
// walkSecretSlots visits schema-bound secret references. Writable traversal
|
||||
// copies map entries into addressable values and writes them back; read-only
|
||||
// traversal borrows them. The visitor owns the operation performed at each slot.
|
||||
func walkSecretSlots(root reflect.Value, descriptor *typeDescriptor, access secretSlotAccess, visit func(reflect.Value, Path, bool)) {
|
||||
var walk func(reflect.Value, *typeDescriptor, Path, bool)
|
||||
walk = func(value reflect.Value, descriptor *typeDescriptor, path Path, optional bool) {
|
||||
if descriptor.kind == descriptorPointer {
|
||||
if !value.IsNil() {
|
||||
walk(value.Elem(), descriptor.element, path, descriptor.element.kind == descriptorSecret)
|
||||
}
|
||||
return
|
||||
}
|
||||
switch descriptor.kind {
|
||||
case descriptorSecret:
|
||||
visit(value, path, optional)
|
||||
case descriptorStruct:
|
||||
for _, member := range descriptor.members {
|
||||
memberPath := path
|
||||
if !member.inline {
|
||||
memberPath = path.Key(member.name)
|
||||
}
|
||||
walk(value.Field(member.index), member.descriptor, memberPath, false)
|
||||
}
|
||||
case descriptorMap:
|
||||
if value.IsNil() {
|
||||
return
|
||||
}
|
||||
keys := value.MapKeys()
|
||||
slices.SortFunc(keys, func(left, right reflect.Value) int { return cmp.Compare(left.String(), right.String()) })
|
||||
for _, key := range keys {
|
||||
entry := value.MapIndex(key)
|
||||
if access == secretSlotsWritable {
|
||||
copy := reflect.New(value.Type().Elem()).Elem()
|
||||
copy.Set(entry)
|
||||
entry = copy
|
||||
}
|
||||
walk(entry, descriptor.element, path.Key(key.String()), false)
|
||||
if access == secretSlotsWritable {
|
||||
value.SetMapIndex(key, entry)
|
||||
}
|
||||
}
|
||||
case descriptorSlice, descriptorArray:
|
||||
if descriptor.kind == descriptorSlice && value.IsNil() {
|
||||
return
|
||||
}
|
||||
for index := 0; index < value.Len(); index++ {
|
||||
walk(value.Index(index), descriptor.element, path.Index(index), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(root, descriptor, Path{}, false)
|
||||
}
|
||||
Reference in New Issue
Block a user