sanitize
sanitize
¶
Wire-format string invariant: printable ASCII only, length-capped.
Every string field that crosses the reader → hub socket originates, directly or indirectly, in container-controlled bytes — a crafted DNS name, a forged hostname header, an OCI annotation copied verbatim from an untrusted runtime configuration. The hub fans those values out to multiple consumers (desktop notifier, Textual TUIs, future audit / forensic listeners), each with its own rendering quirks: Pango markup, ANSI terminal escapes, JSON log aggregators. Defining a single catch-everything rule on the receive side spares every consumer from re-implementing its own escape pass — and stops a third-party subscriber from inheriting whatever footgun a consumer-specific sanitiser missed.
The rule is deliberately the smallest one that holds the contract:
- Bytes inside
[\x20, \x7E](printable ASCII, including space) pass through verbatim. - Anything else — control chars,
\n,\t, NULs, every non-ASCII codepoint, RTLO/LRO bidi overrides, NBSP, the lot — is replaced with a single space. Position is preserved so adjacent printable characters stay readable. - Strings longer than
max_lenare truncated and end with a three-dot...marker.…(U+2026) is itself outside the printable-ASCII window, so it can't double as a truncation indicator under our own rule.
The ASCII restriction loses non-ASCII project / task / hostname
display fidelity (café becomes caf), but the wire-format
docs name that as a deliberate tradeoff: simpler invariant, smaller
attack surface, parser-robustness for free. Sinks that want
markup-specific escaping (& < > for Pango) layer it on top — the
chars are still printable ASCII at this stage so the layered escape
remains well-defined.
DEFAULT_MAX_LEN = 256
module-attribute
¶
sanitize(value, *, max_len=DEFAULT_MAX_LEN)
¶
Return value coerced to printable ASCII, capped at max_len.
Non-printable / non-ASCII bytes become a single space; the
resulting string is truncated to max_len characters with a
trailing ... if the cap actually fired. Empty input
round-trips unchanged. When max_len is itself shorter than the
truncation marker, the marker is clipped to fit so the post-
condition len(result) <= max_len always holds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
Raw string from a wire payload — assumed UTF-8 already decoded by the JSON parser, but otherwise of unknown provenance. |
required |
max_len
|
int
|
Hard ceiling on the returned length, including the
truncation marker when present. |
DEFAULT_MAX_LEN
|
Returns:
| Type | Description |
|---|---|
str
|
A string composed entirely of |
str
|
than |
Source code in src/terok_clearance/wire/sanitize.py
sanitize_mapping(mapping, *, max_len=DEFAULT_MAX_LEN)
¶
Apply sanitize to every value in mapping.
Keys flow through unchanged — they are internal contract identifiers
(project, task, name, …), not user-visible strings, so
a typo'd or attacker-injected key still surfaces somewhere a
debugging human can spot it rather than being silently rewritten.