feat: redact api keys/secrets/JWTs during session import (Privacy) #27
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem Statement
The session-search spec's "Security & Privacy" section (terraphim-agent-session-search-spec.md, lines 588-606) requires api key and secret redaction during session import:
Verification:
Today every imported
Session::messages[].contentis stored verbatim, including any inlined OpenAI/Anthropic/AWS keys, GitHub tokens, JWTs, and.envpaste-ins from coding sessions. This violates the privacy-first guarantee (Non-Goal 1: "privacy-first, local only") because:/sessions export --format markdownwill write them to disk in plaintext.We need a pluggable redaction stage at the connector boundary, applied uniformly across
NativeClaudeConnector,ClaClaudeConnector,ClaCursorConnector, and any future connector (#3, #13, plus OpenCode/Codex tracked separately).Acceptance Criteria
crates/terraphim_sessions/src/redaction.rsexportingRedactor,RedactionRule { name, pattern: regex::Regex, replacement },RedactionReport { rule_hits: BTreeMap<String,usize> }with methodswith_default_rules(),with_rules(...),redact(text) -> (String, RedactionReport),redact_session(&mut Session) -> RedactionReportsk-[A-Za-z0-9]{20,}->[REDACTED:openai-key]sk-ant-[A-Za-z0-9_-]{20,}->[REDACTED:anthropic-key]AKIA[0-9A-Z]{16}->[REDACTED:aws-access-key](?i)aws_secret_access_key\s*=\s*[A-Za-z0-9/+=]{30,}->[REDACTED:aws-secret]gh[pousr]_[A-Za-z0-9]{36,}->[REDACTED:github-pat](?i)Bearer\s+[A-Za-z0-9._-]{20,}->Bearer [REDACTED]eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+->[REDACTED:jwt]Sessionservice::import_with_optionsacceptsredactor: Option<Arc<Redactor>>; default =Some(Redactor::with_default_rules())-- OPT-OUT semanticsredactor.redact_session(&mut session)after building the Session and before cachingRedactionReportreturned fromimport()and surfaced in CLI:imported 42 sessions; redacted 3 OpenAI keys, 1 GitHub PATmeta.redaction_report: { rule_hits: {..}, total: N }<terraphim_data_dir>/redaction.toml([[rules]] name pattern replacement)--no-redactflag on/sessions import(writes warning to stderr when used)Message::contentANDCodeSnippet::content(code blocks are highest-leak surface)redact_sessionwalks all messages including code snippets; counter increments correctly; idempotent (second pass yields empty report)sk-test-...and assert cached body equals[REDACTED:openai-key]cargo test -p terraphim_sessions redactionpassescargo test -p terraphim_sessions --features cla-fullpasses (existing tests still green)cargo clippy -p terraphim_sessions -- -D warningspassesProposed Approach
crates/terraphim_sessions/src/redaction.rs(~200 LOC)regexdep; no new depsmessage.contentandCodeSnippet::content(highest-leak surface)BTreeMap<String, usize>for stable JSON orderingSessionservice::import_*callsites (~5 places); redactor staysOptionso tests can passNoneredaction: RedactionReportDependencies
None. Independent of #5 (Tantivy index), #3 (Cline), #13 (Generic MCP). Should land BEFORE #5 lands its writer so the index never sees raw secrets, but neither blocks the other.
Verification
Expected:
redaction_report.rule_hits["openai-key"] >= 1; cached session body equals[REDACTED:openai-key].Scope
Single PR, ~350-450 LOC: redactor ~200, wiring across 3 connectors ~60, CLI/robot surfacing ~50, TOML loader ~30, tests ~120. Public-api change limited to
ImportOptionsand the new opt-out flag.Upstream: terraphim-agent-session-search-spec.md "Security & Privacy" section (lines 588-606); privacy-first non-goal.
Duplicate of #26 (created accidentally on retry). Closing.