symfonic.capabilities.governance.stages.credentials¶
credentials ¶
Credential hygiene: the first stage, and one of the two fail-closed ones.
The pattern set is a re-declaration of the legacy default rather than an import of it — this package imports nothing outside itself — and a contract test pins the two lists byte-for-byte in both directions, so a divergence is a failing test rather than a silent policy drift.
Shallow by design (the legacy invariant): nested dicts are not walked, because graph properties are persisted flat and value-scanning carries a false-positive tax that belongs to its own design track.
One scoped exception, added for #27. ToolCall.result is free text, and
the stage never read it — so a tool returning a credential in its output (an
API client echoing an auth header, a shell tool printing an env dump, a DB tool
returning a connection string) passed a fail-closed scrubber untouched. Keys
cannot be dropped from a string, so the result is redacted whole when the
pattern matches anywhere in it.
That is blunt, and deliberately so. Partial redaction of free text means
guessing where a value begins, and a guess inside a fail-closed stage is the
worst place for one. The cost is real — a result that merely discusses
authorization is redacted too — and it is pinned by a test rather than
discovered, so a deployment that finds it unacceptable narrows patterns
knowing exactly what it is trading.
CredentialHygieneStage ¶
Drop credential-shaped keys before any other stage observes them.
Source code in src/symfonic/capabilities/governance/stages/credentials.py
compile_credential_pattern ¶
None -> the default set; [] -> disabled; otherwise a replacement.
An invalid fragment raises re.error here, at construction, rather
than at scrub time: a misconfigured pattern list must fail while the
deployment is being built, not while a secret is passing through it.