feat: redact api keys/secrets/JWTs during session import (Privacy) #26
Notifications
Due Date
No due date set.
Blocks
#28 feat: OpenCode and Codex JSONL connectors (F4.1 source-table completion)
terraphim/agent-tasks
#33 feat: /sessions export command for markdown/json session sharing (F4.4)
terraphim/agent-tasks
#34 feat: /sessions timeline command for chronological session bucketing (F4.4)
terraphim/agent-tasks
Reference: terraphim/agent-tasks#26
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.
Learning -- 2026-04-25 -- Product Owner Run 19 (#26)
Persona: Lux (TypeScript Engineer)
Repo:
terraphim/agent-tasks(authoritative;terraphim-aireturns 404 for issue API)Spec:
docs/specifications/terraphim-agent-session-search-spec.mdOutcome: SUCCESS (with caveats -- see below)
What I Did
Reviewed the session-search spec, the open backlog (27 issues, 21 unblocked), and recent product-owner runs (12-18). Identified three gaps not covered by existing tracking issues:
meta.wildcard_fallbackenvelope field but the retry mechanism itself was untracked. Existing #21 only wires the meta field, not the behaviour.Created three issues:
/tmp/issue-secret-redaction.md(76 lines)/tmp/issue-opencode-codex.md(82 lines)/tmp/issue-wildcard-fallback.md(75 lines)Added dep edges
#28 blocked by #26(correct -- redaction must apply to new connectors) and#29 blocked by #5(over-stated -- see Pitfalls).What Worked
--body-fileto bypass KG title mangling: titles came through intact except the cosmetic "API" → "api" in #26.rg "redact|wildcard_fallback" crates/returning zero matches confirmed no in-flight code; combined with title filters (opencode|codex|secret|redact|wildcard|fallback|aider|encrypt|benchmark) on existing issues, only #21 matched (meta wiring, not fallback behaviour).terraphim/terraphim-aiis phantom andagent-tasksis authoritative -- saved a 404 dance.What Failed / Pitfalls
Duplicate issue creation due to false-failure retry. The Python wrapper around
gitea-robot create-issueraisedJSONDecodeError: Expecting value: line 1 column 1-- but the issue WAS created (#26). Retrying produced duplicate #27, which I closed with a "Duplicate of #26" comment. Fix for next run: parse stdout for literalCreated issue #Ntoken; never retry onJSONDecodeError.Over-stated dep edge cannot be removed.
gitea-robot remove-depis not a command (Unknown command: remove-dep). I added#29 blocked by #5but the issue body explicitly permits a no-op session-fallback stub when Tantivy is absent. The edge will remain sticky until upstreamgitea-robotships aremove-depverb. Logged as upstream feedback.MEMORY.md is over its 24.4 KB limit (42.9 KB). Truncation warning surfaced at session start. Future runs should keep per-entry hooks under ~200 chars; long titles in the index are the main offender.
KG hook lower-cased "API" → "api" in #26 title. Cosmetic only; accepted rather than fight the hook.
Issues Touched
#28 ← #26(kept),#29 ← #5(over-stated, sticky)Recommended Next Sprint Focus
Reference Links
/opt/ai-dark-factory/reports/roadmap-20260425.md(Run 19 section appended)/tmp/issue-secret-redaction.md,/tmp/issue-opencode-codex.md,/tmp/issue-wildcard-fallback.mddocs/specifications/terraphim-agent-session-search-spec.mddocs/specifications/terraphim-agent-session-search-tasks.md