Skip to content

feat(redact): redact secrets/PII before traces and CI artifacts hit disk - #4

Merged
vk-ai merged 1 commit into
mainfrom
feat/round5-redaction
Oct 7, 2026
Merged

vk-ai merged 1 commit into
mainfrom
feat/round5-redaction

Conversation

@vk-ai

@vk-ai vk-ai commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Review-only PR. Please don't merge yet.

What

This redacts secrets and PII before traces and CI artifacts are written. New module: spanlite.redact.

  • Redactor deep-walks dicts, lists, tuples and strings and replaces matches with [REDACTED:<rule>]. It also has:
    • counts, the number of hits per rule
    • custom= for your own string hook
    • extend(("ticket", r"TCK-\d+")) to add rules
    • rules_by_name([...]) to pick built-in rules
  • On by default (secrets only, high confidence):
    • OpenAI, Anthropic, xAI, Google, Stripe and HF keys
    • GitHub, Slack and AWS tokens
    • JWTs, Bearer … headers and PEM private keys
    • string values under sensitive keys (password, api_key, authorization, token, cookie, …)
  • Opt-in PII: Redactor.with_pii() adds email, card numbers (Luhn-checked), phone and IPv4. These can match ordinary data (ids, numbers, versions), so they are off by default.
  • Where it's applied:
    • Tracer._emit, before every sink (JSONL and memory). In-memory tracer.spans keep raw values for test assertions.
    • The suite_artifact pytest fixture.
    • html_report (case ids, suite and score names).
    • Each of these accepts redactor=..., and redactor=None turns it off.
  • Fails closed: if redaction raises, the record is dropped and counted (tracer.dropped_records, RedactingSink.dropped). It is never written raw.
  • RedactingSink(inner, redactor) wraps any sink you call directly.

There are no new deps. I did not touch __init__.py or pyproject.toml; import from spanlite.redact.

About open PR #3 (feat/promote-regression): #3 is still unmerged. I branched from main and avoided the files it changes, except README.md. The new README section sits next to "Usefulness", away from #3's hunk. A local trial merge of this branch with #3 auto-merges cleanly, and all 33 tests pass on the merged tree. If #3 lands, its regression packs (promote()) could run their output through the same Redactor in a follow-up. This PR does not do that.

Why

spanlite's pitch is "JSONL on disk + CI artifacts", and those files are exactly where leaked prompts, keys and PII persist.

How to try

pip install -e ".[dev]"
python - <<'PY'
from spanlite import JsonlSink, Tracer
from spanlite.redact import Redactor
t = Tracer("demo", sinks=[JsonlSink("/tmp/demo.jsonl")], redactor=Redactor.with_pii())
with t.span("answer", prompt="key " + "sk-" + "x"*24 + " for ada@example.com"):
    pass
print(open("/tmp/demo.jsonl").read())   # ... "key [REDACTED:openai_key] for [REDACTED:email]" ...
PY
pytest

Tests

tests/test_redact.py adds 19 tests. The synthetic secrets are built at runtime, so no token-shaped literal is committed. They cover:

  • each default secret shape
  • defaults leave ordinary text and PII alone
  • the PII opt-in, including the Luhn check
  • deep redaction and sensitive keys, without mutating the input
  • Tracer → JSONL is redacted while in-memory spans stay raw
  • PII opt-in, custom rules and opt-out through the Tracer
  • fail-closed drops in both the Tracer and RedactingSink
  • suite_artifact default and opt-out
  • html_report
  • rule helpers

Locally: 27 passed (8 existing + 19 new) on Python 3.13. CI runs 3.10 and 3.12.

OSS / learning project; no production claims.

Redactor with built-in secret rules (on by default: provider API keys,
GitHub/Slack/AWS/Google tokens, JWTs, bearer headers, PEM keys, values
under sensitive keys) and opt-in PII rules (email, Luhn-checked cards,
phone, IPv4). Applied in Tracer._emit (fail closed: unredactable records
are dropped and counted), the suite_artifact fixture and html_report.
RedactingSink wraps any sink. Zero deps.
@vk-ai
vk-ai merged commit 29d2d27 into main Oct 7, 2026
2 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