Skip to content

Optional value capture with default-on sensitive-key redaction - #10

Merged
mahmoud merged 2 commits into
masterfrom
optional-value-capture
Aug 12, 2026
Merged

Optional value capture with default-on sensitive-key redaction#10
mahmoud merged 2 commits into
masterfrom
optional-value-capture

Conversation

@mahmoud

@mahmoud mahmoud commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

optional value capture with default-on sensitive-key redaction

dump_graph/spawn_dump grow values='none'|'builtins'|'repr' (default 'none':
behavior and dump format unchanged, one falsy check per object), plus
value_limit=128 and redact=True. Captured reprs land in a new object_repr
table (object PK, repr, truncated, redacted); meta gains a capture_values
column so dumps are self-describing.

  • tier 'builtins': exact str/bytes/int/float/complex/bool only; C-level
    repr, never runs user code. str/bytes slice before repr; int guarded
    against 3.11+ int_max_str_digits; stored text hard-bounded at value_limit.
  • tier 'repr': everything else via a bounded reprlib.Repr; user repr
    runs mid-dump (accepted risk, fork isolation via spawn_dump), exceptions
    skip the row.
  • redaction post-pass (default on when capturing): any object referenced
    under a sensitive-looking edge label (key/secret/password/token/auth/...,
    attr and dict-key edges alike) has its repr replaced by a length-bucketed
    placeholder '<redacted len<=N>' (buckets 100, 500, 1000, 5000, ...) built
    from object.len; keys themselves stay readable, one sensitive inbound
    edge wins for aliased objects. Redaction is dump-time: the artifact never
    contains the secret text.
  • Reader.obj_repr (feature-detected via _table_names, old dumps fine),
    repr in object_summary, display-capped repr snippets in both
    Reader.object_label and Console._obj_label, Repr row in the web object
    panel.

Known hole inherited from traversal: CPython untracks atomic-only dicts,
so their key edges never materialize (values still captured, un-redacted
under tier 'repr' container reprs). Tests keep the fixture dict tracked.

dump_graph/spawn_dump grow values='none'|'builtins'|'repr' (default 'none':
behavior and dump format unchanged, one falsy check per object), plus
value_limit=128 and redact=True. Captured reprs land in a new object_repr
table (object PK, repr, truncated, redacted); meta gains a capture_values
column so dumps are self-describing.

- tier 'builtins': exact str/bytes/int/float/complex/bool only; C-level
  repr, never runs user code. str/bytes slice before repr; int guarded
  against 3.11+ int_max_str_digits; stored text hard-bounded at value_limit.
- tier 'repr': everything else via a bounded reprlib.Repr; user __repr__
  runs mid-dump (accepted risk, fork isolation via spawn_dump), exceptions
  skip the row.
- redaction post-pass (default on when capturing): any object referenced
  under a sensitive-looking edge label (key/secret/password/token/auth/...,
  attr and dict-key edges alike) has its repr replaced by a length-bucketed
  placeholder '<redacted len<=N>' (buckets 100, 500, 1000, 5000, ...) built
  from object.len; keys themselves stay readable, one sensitive inbound
  edge wins for aliased objects. Redaction is dump-time: the artifact never
  contains the secret text.
- Reader.obj_repr (feature-detected via _table_names, old dumps fine),
  repr in object_summary, display-capped repr snippets in both
  Reader.object_label and Console._obj_label, Repr row in the web object
  panel.

Known hole inherited from traversal: CPython untracks atomic-only dicts,
so their key edges never materialize (values still captured, un-redacted
under tier 'repr' container reprs). Tests keep the fixture dict tracked.
…as values

CPython 3.14 introduced internal dicts that map interned identifier
strings to themselves. The redaction pass saw 'api_token' as a value
under a key whose repr contains 'token' (sensitive pattern), and
replaced the key string's repr with a redacted placeholder. This broke
the design invariant: key labels must stay readable so the dump shows
*what* was redacted.

Fix: after collecting sensitive destinations from dict-key edges,
subtract any object ids that are themselves sensitive-pattern keys.
These are label strings (like 'password', 'api_token'), never actual
secrets. The test now filters to redacted-only rows when checking
placeholder format, tolerating the unredacted self-referencing entries.
@mahmoud
mahmoud merged commit a7feb66 into master Aug 12, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant