symfonic.agent.hygiene¶
hygiene ¶
Memory-hygiene utilities.
v6.2 T01: promotes the v6.1.9 credential-key scrubber to a public module
and exposes the pattern list as a tunable FrameworkConfig.credential_patterns
knob.
Design constraints (strictly additive against v6.1.9):
- The built-in default pattern set is byte-for-byte identical to the
inline regex that shipped in v6.1.9 (
engine.pyL110-113). Callers that do not touchFrameworkConfig.credential_patternskeep the exact v6.1.9 behaviour. credential_patterns=None(the default) uses the built-in list.credential_patterns=[](empty list) disables scrubbing. This is explicit opt-out, not a silent no-op — customers must knowingly ship a scrubber-less deployment.credential_patterns=[...]with one or more strings REPLACES the built-in list. This is the simpler contract vs. extend-mode: if we ever ship an extend knob it can be added additively later without changing this semantic.
The regex engine compiles once per compiled-pattern object. Callers that
scrub repeatedly should cache the compiled object via
:func:compile_credential_pattern rather than re-building it per call.
compile_credential_pattern ¶
compile_credential_pattern(
patterns: list[str] | tuple[str, ...] | None,
) -> re.Pattern[str] | None
Build a single alternation regex from a list of pattern fragments.
None-> return :data:DEFAULT_CREDENTIAL_KEY_PATTERN(v6.1.9).- Empty list/tuple -> return
None(explicit opt-out of scrubbing). - Non-empty list -> compile each fragment as a sub-alternation and OR them together into one case-insensitive regex.
Invalid regex fragments raise :class:re.error at compile time, not
silently at scrub time — a misconfigured pattern list should fail fast
during config construction, not leak secrets at runtime.
Source code in src/symfonic/agent/hygiene.py
scrub_credential_keys ¶
Drop dict keys whose names match the credential-key pattern.
Public v6.2 API. Byte-for-byte compatible with the private v6.1.9
_scrub_credential_keys when called with the default pattern.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
properties
|
Any
|
Candidate mapping. Non-dict / empty inputs are returned unchanged (idempotent). |
required |
pattern
|
Pattern[str] | None | object
|
Compiled credential-key pattern. When omitted the
v6.1.9 built-in :data: |
_UNSET
|
Returns:
| Type | Description |
|---|---|
Any
|
A new dict with the offending keys removed, or the original |
Any
|
input when no scrub applies. |
Scope note (v6.1.9 invariant, preserved): Shallow scrub only — nested dicts inside a value are NOT walked, because graph properties are persisted flat. Value scanning (regex over free-form strings) is a separate design track that carries a false-positive tax and is intentionally out of scope.
Emits a DEBUG log record listing every key removed. Values are never logged.