stormlog.scrub
Shared scrubbing primitives for what Stormlog records or sends elsewhere.
An exporter builds its output from allowlists of fields; these helpers are
the layers underneath, shared so that every surface redacts the same way.
Each exporter documents its own allowlists. See docs/scrubbing.md.
Functions
|
Whether a key's name says its value may be a credential. |
A URL as it may be recorded: no credentials and no query string. |
|
|
|
|
Free text with credentials removed, then cut to |
|
The longest prefix of |
|
The values in a URL that may be credentials, for |
Classes
|
The exact credentials Stormlog was given, redacted wherever they appear. |
- stormlog.scrub.redact_url(url: str, *, origin_only: bool = False) str[source]
- stormlog.scrub.redact_url(url: None, *, origin_only: bool = False) None
A URL as it may be recorded: no credentials and no query string.
Either can carry a token, so only the scheme, host, port and path are kept, and a removed query is marked.
origin_onlydrops the path too, for a destination whose path is not known to be safe: a token can sit in a path segment as easily as in a query.
- class stormlog.scrub.KnownSecrets(values=())[source]
Bases:
objectThe exact credentials Stormlog was given, redacted wherever they appear.
Allowlists decide which fields leave; this is the backstop behind them. Each value is matched in every spelling it most often travels in: as given; percent-encoded (inside a URL) in either case of hex digit, with any characters left plain, and with
+for a space; JSON-escaped (inside a JSON string), with or without unicode escapes in either case, surrogate pairs, an escaped/and the short escapes; and each character may be spelled differently from the next. Also base64, standard and URL-safe, padded or not, of the value on its own: an encoded token, or a Basic authorization header when theuser:passwordpair is registered.- Parameters:
values (Iterable[str | None])
- add(value)[source]
Register one value; empty and short values are skipped.
- Parameters:
value (str | None)
- Return type:
None
- redact(text)[source]
textwith every form of every registered value replaced.Every occurrence is found in the original text first, overlapping ones included, and the spans are merged before anything is replaced, so replacing one value can never uncover part of another.
- Parameters:
text (str)
- Return type:
str
- stormlog.scrub.replace_spans(text, spans, *, limit=None)[source]
textwith each span, overlapping or touching spans merged, redacted.With
limit, onlytext[:limit]is kept: a span that starts before it is redacted whole, and nothing after it is copied.- Parameters:
text (str)
spans (Iterable[tuple[int, int]])
limit (int | None)
- Return type:
str
- stormlog.scrub.url_secrets(url)[source]
The values in a URL that may be credentials, for
KnownSecrets.The user name, on its own whatever the password (it is often a token), the password, the
user:passwordpair a Basic header would encode, decoded and also as written in the URL for a client that did not decode it, and every query value. A fragment is never sent to a server, so it is not read.- Parameters:
url (str | None)
- Return type:
list[str]
- stormlog.scrub.truncate_utf8(text, max_bytes)[source]
The longest prefix of
textwhose UTF-8 encoding fitsmax_bytes.A character is never split. A lone surrogate, which UTF-8 cannot encode, becomes
?.- Parameters:
text (str)
max_bytes (int)
- Return type:
str
- stormlog.scrub.scrub_text(text, *, max_bytes=None, secrets=None)[source]
Free text with credentials removed, then cut to
max_bytes.For text an exporter has consent to send, such as an error message, and only as a layer under its allowlist: patterns catch the common shapes of a credential, not every secret. Every match, of the exact values in
secretsand of the patterns, is found in the same text before any is replaced; the cut comes last, so it never leaves part of a secret that a whole match would have removed.- Parameters:
text (str)
max_bytes (int | None)
secrets (KnownSecrets | None)
- Return type:
str
- stormlog.scrub.is_forbidden_key_name(name)[source]
Whether a key’s name says its value may be a credential.
An exporter refuses to admit such a key from any outside source (an environment variable or a flag), even one an operator names explicitly, because the value cannot be checked.
- Parameters:
name (str)
- Return type:
bool