Move facade to the root package

This commit is contained in:
2026-09-12 16:21:17 +00:00
parent 550f92d7c6
commit 7f46c947dd
84 changed files with 176 additions and 14739 deletions

179
secret.go
View File

@@ -1,153 +1,52 @@
package configkit
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
import (
"encoding/json"
"fmt"
"io"
"reflect"
"strconv"
type secretDependency struct {
target Path
dependency Path
"gitea.maximumdirect.net/eric/ConfigKit/internal/engine"
)
// Secret is an opaque reference to an environment variable. Its name is public
// configuration; its resolved value is available only through Value.
type Secret struct {
name, value string
specified, resolved bool
}
func classifySecretPaths(schema *schemaDescriptor, predicate func(Path) bool, metadata Metadata, final *document.Node, applications []historyApplication, projections ...*document.Node) map[string]bool {
paths := make(map[string]Path)
finalPaths := make(map[string]*document.Node)
indexDocument(final, Path{}, finalPaths)
for pointer := range finalPaths {
addSecretPath(paths, pointer)
}
for _, application := range applications {
applicationPaths := make(map[string]*document.Node)
indexDocument(application.value, application.path, applicationPaths)
for pointer := range applicationPaths {
addSecretPath(paths, pointer)
}
}
var dependencies []secretDependency
for pointer, history := range metadata.history {
addSecretPath(paths, pointer)
for _, change := range history {
paths[change.Path.String()] = change.Path.clone()
for _, dependency := range change.Dependencies {
paths[dependency.String()] = dependency.clone()
dependencies = append(dependencies, secretDependency{
target: change.Path.clone(), dependency: dependency.clone(),
})
}
}
}
// SecretEnv constructs an unresolved environment-backed secret reference.
func SecretEnv(name string) Secret { return Secret{name: name, specified: true} }
secret := make(map[string]bool)
for _, tree := range append(projections, final) {
projected := make(map[string]*document.Node)
indexDocument(tree, Path{}, projected)
for pointer, node := range projected {
addSecretPath(paths, pointer)
if node.Sensitive {
secret[pointer] = true
}
}
}
for pointer, path := range paths {
if root, ok := schemaSecretRoot(schema, path); ok {
secret[root.String()] = true
}
if predicate != nil && predicate(path.clone()) {
secret[pointer] = true
}
}
for {
changed := false
for _, dependency := range dependencies {
if secretIntersectsPath(paths, secret, dependency.dependency) && !secret[dependency.target.String()] {
secret[dependency.target.String()] = true
changed = true
}
}
if !changed {
return secret
}
// EnvName returns the public environment-variable name.
func (s Secret) EnvName() string { return s.name }
// Value returns the resolved credential, or an empty string when unresolved.
func (s Secret) Value() string {
if !s.resolved {
return ""
}
return s.value
}
func addSecretPath(paths map[string]Path, pointer string) {
if path, err := ParsePath(pointer); err == nil {
paths[pointer] = path
}
// IsResolved reports whether this reference resolved to a nonempty value during its configuration load.
func (s Secret) IsResolved() bool { return s.resolved }
// Format renders only the public reference name for every formatting verb.
func (s Secret) Format(state fmt.State, _ rune) {
_, _ = io.WriteString(state, "configkit.SecretEnv("+strconv.Quote(s.name)+")")
}
func secretIntersectsPath(paths map[string]Path, secret map[string]bool, candidate Path) bool {
for pointer := range secret {
classified, ok := paths[pointer]
if !ok {
continue
}
if pathContains(classified, candidate) || pathContains(candidate, classified) {
return true
}
}
return false
}
// MarshalJSON emits only the public environment-variable name.
func (s Secret) MarshalJSON() ([]byte, error) { return json.Marshal(s.name) }
func schemaSecretRoot(schema *schemaDescriptor, path Path) (Path, bool) {
if schema == nil || schema.root == nil || !path.valid() {
return Path{}, false
}
current := schema.root
walked := Path{}
for _, segment := range path.segments {
walked.segments = append(walked.segments, segment)
for current.kind == descriptorPointer {
current = current.element
}
switch current.kind {
case descriptorStruct:
if segment.kind == pathSegmentIndex {
return Path{}, false
}
position, ok := current.fieldByName[segment.key]
var field *fieldDescriptor
if ok {
field = &current.fields[position]
} else {
field = current.inlineMap
}
if field == nil {
return Path{}, false
}
if field.secret {
return walked.clone(), true
}
if field.inlineMap {
current = field.descriptor.element
} else {
current = field.descriptor
}
case descriptorMap:
if segment.kind == pathSegmentIndex {
return Path{}, false
}
current = current.element
case descriptorSlice, descriptorArray:
if _, ok := schemaIndex(segment); !ok {
return Path{}, false
}
current = current.element
case descriptorDynamic:
return Path{}, false
default:
return Path{}, false
}
}
return Path{}, false
}
// Dynamic type replacement can change classification even when projected text
// is equal. Validators must preserve this inspection metadata as well as values.
func projectedSensitivity(root *document.Node) map[string]Path {
result := make(map[string]Path)
walkDocument(root, Path{}, func(path Path, node *document.Node) {
if node.Sensitive {
result[path.String()] = path.clone()
}
})
return result
func secretBinding() engine.SecretBinding {
return engine.SecretBinding{Type: reflect.TypeFor[Secret](), Read: func(value reflect.Value) engine.SecretState {
secret := value.Interface().(Secret)
return engine.SecretState{Name: secret.name, Value: secret.value, Specified: secret.specified, Resolved: secret.resolved}
}, Make: func(state engine.SecretState) reflect.Value {
return reflect.ValueOf(Secret{name: state.Name, value: state.Value, specified: state.Specified, resolved: state.Resolved})
}}
}