Skip to content

Built-in redaction ruleset and test corpus #18

Description

@Saber5656

Title

Built-in redaction ruleset and test corpus

Summary

Implement the eleven built-in redaction rules from DESIGN.md §8 with their
exact ids and patterns, plus the true-positive / false-positive regression
corpus that pins their behavior.

Context

The ruleset table in DESIGN §8 is the contract: rule ids are public API
(users reference them in allowlist docs), and the "commit hashes and
ordinary text are never masked" guarantee is what keeps reports readable.
This issue is deliberately separate from the engine (16) because the corpus
is large and the patterns need focused review.

Scope

  • internal/redact/builtin.go (func Builtin() []Rule),
    builtin_test.go, testdata/corpus.json — a JSON array of cases:
    {"name": "<unique>", "rule": "<rule-id or NONE>", "input": "<text>", "want": "<exact expected output>"}. JSON strings carry multiline inputs
    (PEM blocks) losslessly and want pins the exact masking result.

Detailed Requirements

  1. Implement exactly the rules of DESIGN §8's table, in that order, with
    those ids: private-key-block (Block rule), aws-access-key-id,
    github-token, slack-token, google-api-key, openai-anthropic-key,
    jwt, authorization-header (mask value group),
    env-assignment (mask value group, keep name), cli-secret-flag
    (mask value group), url-userinfo (mask password group).
  2. Pattern refinements (allowed to tighten, never loosen, relative to the
    table; document any deviation in code comments AND update DESIGN §8 in
    the same PR if a pattern must change):
    • env-assignment must handle export NAME=…, quoted values, and stop
      at whitespace for unquoted values.
    • cli-secret-flag must handle --token=x, --token x, -p=x forms
      listed in the pattern.
    • url-userinfo masks only the password span (user:****@host).
  3. Corpus — minimum content:
    • Positives (each rule ≥ 5 lines): realistic fakes (e.g.
      AKIA + 16 uppercase, ghp_ + 36 alnum, quoted/unquoted env
      assignments, curl -H "Authorization: Bearer …", a 3-line PEM block,
      JWT with three segments, https://user:pass@host/path,
      --api-key=sk-… which must double-mask under two rules without
      corruption).
    • Negatives (must NOT mask, ≥ 20 lines): 12/40-char git hashes; commit
      subject fix: rotate token handling; TOKEN_COUNT=5 (name not in the
      secret-name list — verify the pattern's name list is anchored);
      --tokenizer bert; URL without userinfo; skiing sk-lift schedule
      (no, sk-lift — 7 chars — must not match sk-[A-Za-z0-9_-]{20,});
      Japanese text; password: prose without assignment; base64 blob of 30
      chars in plain prose (entropy is v2 — must pass through).
  4. Corpus runner test: for every case, assert Redact(input) == want
    byte-for-byte. Derived assertions: cases with rule != "NONE" must have
    want containing [REDACTED:<rule>] and must differ from input
    (self-checking corpus — a want equal to input on a positive case
    fails the suite); cases with rule == "NONE" must have
    want == input (asserted at load time so corpus typos are caught).
  5. A doc.go table listing rule ids + one-line descriptions (renders in
    pkg docs; README links here in 31).

Acceptance Criteria

  • All 11 rules present, ids exactly as specified, order preserved.
  • Corpus passes (Redact(input) == want for all cases); negatives
    byte-identical; the multiline PEM positive is present as a JSON case
    and collapses to one [REDACTED:private-key-block] token.
  • Double-match line (--api-key=sk-…) yields a stable, parseable result
    (no nested/garbled tokens) — exact expected string in the test.
  • Engine idempotence test (16) re-run against the full builtin set still
    green ([REDACTED:…] tokens match no builtin rule).
  • Worst-case benchmark from 16 with full ruleset still < 1s.
  • Every pattern compiles as RE2 and contains no lookahead/backreference
    (compile-time guarantee via regexp.MustCompile — build fails
    otherwise).

Validation

go test -race -cover ./internal/redact/ in PR, plus paste 5 sample
positive→masked lines (fake secrets only) demonstrating output shape.

Dependencies

Non-goals

Entropy heuristics, cloud-provider-exhaustive token catalogs (the 11 rules
are v1 scope; additions are post-v1 issues driven by real misses),
locale-specific secrets.

Design References

  • docs/DESIGN.md §8 (normative rule table)
  • docs/decisions/ADR-004-redaction-default-on.md

Source of truth: docs/issues/17-redaction-ruleset.md (PR #1, branch docs/v1-design). If this issue and the repo docs disagree, the docs win. Execution order and dependencies: docs/ISSUE_PLAN.md (this is issue 17 of 33).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions