Add redacted effective rendering
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# Configuration Input Contract
|
||||
|
||||
This document owns ConfigKit's currently implemented source-input, YAML syntax,
|
||||
schema, typed-decoding, loading, metadata, and ownership contracts. The parser,
|
||||
owned document representation, and decoder remain private behind the public loading
|
||||
lifecycle.
|
||||
schema, typed-decoding, loading, metadata, redaction, rendering, and ownership
|
||||
contracts. The parser, owned document representation, and decoder remain private
|
||||
behind the public loading lifecycle.
|
||||
|
||||
## Sources
|
||||
|
||||
@@ -42,7 +42,7 @@ The current lifecycle is:
|
||||
validate options → parse the selected source → traverse/compose enabled imports
|
||||
→ build schema → check the optional application version → apply a selected profile
|
||||
→ create and clone defaults → strictly decode → recorded application resolution
|
||||
→ semantic validation → snapshot configuration and metadata
|
||||
→ semantic validation → classify secrets → snapshot configuration and metadata
|
||||
```
|
||||
|
||||
`File`, `Bytes`, and `Reader` each contribute the first base source with deterministic
|
||||
@@ -53,17 +53,18 @@ missing file remains an error; it is never interpreted as no input.
|
||||
|
||||
The current `Options` boundary accepts a defaults factory, `VersionRule`, resolver,
|
||||
semantic validator, explicit path and glob imports, one selected profile, and
|
||||
filesystem context. Overrides and dynamic secret classification return
|
||||
`options.unavailable` because their lifecycle stages are not implemented. `NoSource`
|
||||
rejects imports, active profiles, and filesystem context as invalid combinations.
|
||||
Input containing a reserved `_configkit` mapping key is rejected while imports are
|
||||
disabled.
|
||||
filesystem context. It also accepts static secret tags and a dynamic path predicate.
|
||||
Overrides return `options.unavailable` because their lifecycle stage is not
|
||||
implemented. `NoSource` rejects imports, active profiles, and filesystem context as
|
||||
invalid combinations. Input containing a reserved `_configkit` mapping key is
|
||||
rejected while imports are disabled.
|
||||
|
||||
Every source, options, schema, version, defaults, decode, resolution, or validation
|
||||
failure returns a nil result and a `*LoadError`. Successful results contain caller-owned `Config`, detached
|
||||
`Metadata`, a defensive source list, and defensive nonfatal diagnostics. Mutating
|
||||
the returned configuration or inspection records cannot alter ConfigKit's private
|
||||
snapshot. ConfigKit performs no logging and exposes no effective writer yet.
|
||||
snapshot. ConfigKit performs no logging. `Result.WriteEffective` exposes only the
|
||||
frozen redacted projection.
|
||||
|
||||
### Application schema versions
|
||||
|
||||
@@ -88,8 +89,7 @@ available source coordinates are retained. `History` records the Go-zero or appl
|
||||
default baseline followed by exact base or profile definitions, including
|
||||
equal-valued input. Profile replacement removes displaced descendants from effective
|
||||
metadata while retaining their base definition and the parent replacement operation
|
||||
in history.
|
||||
All metadata queries and returned nested records are detached.
|
||||
in history. All metadata queries and returned nested records are detached.
|
||||
|
||||
History is chronological: a path can have a synthetic default record, its exact base
|
||||
definition, a profile replacement, and a recorded resolution operation. A descendant
|
||||
@@ -108,6 +108,42 @@ operation. Reasons and dependency paths retain first occurrence order with dupli
|
||||
removed. Source records remain ordered as selected source, depth-first imports, then
|
||||
the selected profile.
|
||||
|
||||
### Secret classification and effective rendering
|
||||
|
||||
Secret classification combines `configkit:"secret"` field tags with the optional
|
||||
pure `Definition.Secret(Path) bool` predicate. A tagged or predicate-classified
|
||||
container makes all descendants sensitive. ConfigKit evaluates final and historical
|
||||
paths, so replacing or deleting a definition does not erase its classification. The
|
||||
predicate can add sensitivity but cannot declassify a tagged path.
|
||||
|
||||
Recorded resolution dependencies propagate sensitivity to their derived target.
|
||||
Propagation reaches a fixed point, so record/map iteration order does not affect the
|
||||
result and dependency cycles terminate. A dependency on a classified descendant or
|
||||
on a container that contains one is treated conservatively as sensitive. Applications
|
||||
must classify secret-producing transformations whose dependencies are not recorded.
|
||||
|
||||
`Result.WriteEffective` writes the frozen resolved snapshot as deterministic redacted
|
||||
YAML. Mappings sort by decoded key string, sequences retain order, indentation is two
|
||||
spaces with noncompact sequence indentation, line endings are LF, the document has no
|
||||
start or end marker, and output ends with a newline. Nil pointers/maps/slices remain
|
||||
`null`; non-nil empty maps and sequences remain `{}` and `[]`. A secret root is
|
||||
replaced by the quoted string `'[REDACTED]'`. Redacted output is intended for
|
||||
inspection and is not promised to be reloadable.
|
||||
|
||||
Rendering uses only a safe adapter tree built from the already completed canonical
|
||||
typed projection. It does not invoke application YAML marshal hooks or text codecs;
|
||||
all text-codec projection has succeeded before `Load` returns. Caller mutation of
|
||||
`Result.Config` cannot change later output. Writer failures, including short writes,
|
||||
are returned and may leave partial redacted output; internal dumper failures are
|
||||
translated to a fixed safe error. There is no unredacted rendering option and
|
||||
ConfigKit performs no implicit logging.
|
||||
|
||||
`Result.Config` is the explicit trusted boundary and contains ordinary typed values,
|
||||
including secrets. Metadata, histories, diagnostics, and load errors contain no raw
|
||||
configuration values. Applications must still keep source labels, resolution
|
||||
reasons, and diagnostic messages value-free because ConfigKit cannot infer and
|
||||
sanitize secrets embedded in arbitrary application prose.
|
||||
|
||||
### Recorded application resolution
|
||||
|
||||
An optional `Definition.Resolve` callback runs after successful typed decoding. It
|
||||
@@ -356,7 +392,8 @@ or pointer-to-struct, or designates at most one string-keyed inline map for othe
|
||||
unmatched names. Ambiguous names, named inline fields, multiple inline maps, and
|
||||
unsupported or malformed tag options are schema errors. Embedded fields are ordinary
|
||||
named fields unless explicitly inlined. `configkit:"secret"` is the only current
|
||||
ConfigKit field tag and records sensitivity for later lifecycle work.
|
||||
ConfigKit field tag and marks its bound field or container for secret classification
|
||||
and redacted inspection.
|
||||
|
||||
Schema path traversal uses these same bindings. Explicit key segments address
|
||||
mappings, explicit index segments address sequences, and parsed numeric pointer
|
||||
|
||||
Reference in New Issue
Block a user