Add explicit secrets directory bootstrap

This commit is contained in:
2026-09-06 21:29:25 +00:00
parent 828fdd38eb
commit 16f4212770
7 changed files with 845 additions and 3 deletions

View File

@@ -144,6 +144,41 @@ 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.
## Explicit secrets-directory bootstrap
`LoadSecretsDir(directory)` is a separate, opt-in startup operation. It is never
called by `Load`, is not a YAML option, and does not participate in configuration
validation. Applications choose the native directory path and should invoke the
operation once before starting concurrent work. The selected path may itself be a
symlink; ConfigKit resolves it to an existing canonical directory before examining
its immediate entries.
The bootstrap enumerates at most 1,024 entries and sorts them by filename. Every
entry must have an ASCII environment-variable name and be a regular, nonsymlink
file. Metadata for all entries is validated before file content is read or process
state is changed. Existing environment variables win, including variables whose
value is empty; their files are not opened. Each eligible file is limited to 1 MiB,
and eligible content is limited to 8 MiB in total. ConfigKit removes exactly one
terminal LF or CRLF, preserves all other whitespace, accepts an empty value, and
rejects NUL bytes.
All eligible files are read successfully before application begins. Presence is
checked again immediately before each `os.Setenv`: a variable populated since
preflight is skipped. A write failure stops application without rollback, so prior
writes remain and later eligible entries are `not_applied`. This operation is not
atomic and does not provide compare-and-set semantics for concurrent environment
mutation.
`SecretsReport.Entries` returns detached, filename-ordered `SecretFileResult`
records with `loaded`, `skipped_existing`, `not_applied`, or `failed` status.
`ExistingEmpty` distinguishes an empty existing winner. `SecretsReport.WriteTo`
renders only quoted names, canonical paths, statuses, and that empty-state flag;
it never retains or renders file contents. Failures return the non-nil partial
report with a `*SecretsError` containing detached `secrets.*` diagnostics and no
raw filesystem or environment error chain. Applications should retain the report
alongside the later configuration result and explicitly present blocked and failed
files when appropriate; ConfigKit stores no implicit global report.
### Recorded application resolution
An optional `Definition.Resolve` callback runs after successful typed decoding. It