Files
resolutionflow/docs/archive/2026-01-13-report-phase-c-pt1.md
chihlasm 350c977eda feat: add procedural flows with intake forms, navigation, and seed templates
Adds a new "procedural" tree type for linear step-by-step project workflows
(domain controller setup, M365 onboarding, VPN config, etc). Includes intake
form builder, two-panel step navigation, variable resolution, procedural
exports, 3 seed templates, and UI rename from "Trees" to "Flows".

Also archives 19 implemented plan docs and creates deferred features backlog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 04:13:52 -05:00

4.7 KiB

Phase C: Sensitive Data Redaction — Design Document

Status: Approved — ready for implementation planning Spec: docs/plans/2026-02-13-EXPORT-IMPROVEMENTS-SPEC.md section C1 UI Decision: Simple toggle (Option 1) Branch: feat/export-phase-c

Overview

Server-side regex redaction with a simple checkbox toggle in the export preview modal. No rich editor — keeps the existing textarea. User sees a summary of what was masked and can manually edit the result.


Backend

New File: backend/app/services/redaction_service.py

apply_redaction(session) -> tuple[Session, RedactionSummary]

  • Deep-copies the session (original ORM object never mutated)
  • Walks decisions list and custom_steps, applies regex replacements to all string fields: answer, notes, command_output, content, action_performed
  • Also redacts top-level session fields: scratchpad, outcome_notes, next_steps
  • Returns the sanitized copy and a summary of what was found

RedactionSummary dataclass:

@dataclass
class RedactionSummary:
    ips: int = 0
    emails: int = 0
    tokens: int = 0
    unc_paths: int = 0

Regex Patterns (conservative — false positives > false negatives)

Pattern Regex Replacement
IPv4 \b(?:\d{1,3}\.){3}\d{1,3}\b [IP REDACTED]
IPv6 \b(?:[0-9a-fA-F]{1,4}:){2,7}[0-9a-fA-F]{1,4}\b [IP REDACTED]
Email \b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b [EMAIL REDACTED]
Bearer tokens Bearer\s+[A-Za-z0-9._-]+ [TOKEN REDACTED]
API key patterns Long hex/base64 strings (32+ chars) [TOKEN REDACTED]
UNC paths \\\\[\w.-]+\\[\w$.-]+ [UNC PATH REDACTED]

Hostname redaction is not included — MSP tickets legitimately reference hostnames.

Schema Change: backend/app/schemas/session.py

Add to SessionExport:

redaction_mode: Literal["none", "mask"] = "none"

Integration Point: backend/app/api/endpoints/sessions.py

Insert at ~line 297 (after session fetch, before format branching):

redaction_summary = None
if export_options.redaction_mode == "mask":
    session, redaction_summary = apply_redaction(session)

Export generators receive redaction_summary and append a footer when present:

--- Redacted: 3 IPs, 2 emails, 1 token ---

Response

The redaction summary is returned via an X-Redaction-Summary response header (JSON-encoded) to avoid changing the existing content-based response body.

No Migration Needed

All changes are runtime — no database schema changes.


Frontend

ExportPreviewModal.tsx

New props:

  • redactionEnabled?: boolean
  • onToggleRedaction?: (enabled: boolean) => void
  • redactionSummary?: { ips: number; emails: number; tokens: number; unc_paths: number } | null

Add a "Mask Sensitive Data" checkbox next to the existing "Include Summary" checkbox, using the same visual pattern:

<label className="flex items-center gap-2 text-sm text-white/60 cursor-pointer">
  <input type="checkbox" checked={redactionEnabled} onChange={...} />
  Mask Sensitive Data
</label>

When redactionSummary has matches, show an info line below the toggles in text-blue-400:

Masked: 3 IPs, 2 emails, 1 token

If redaction is on but nothing was found: "No sensitive data detected" in text-white/40.

SessionDetailPage.tsx

  • Add redactionMode state ('none' | 'mask')
  • Wire into export options object
  • Pass toggle callback to ExportPreviewModal
  • Same pattern as existing includeSummary state

types/session.ts

Add to SessionExport type:

redaction_mode?: 'none' | 'mask'

Testing

Backend: backend/tests/test_psa_export.pyTestPhaseC class

  • Test redaction of each pattern type individually (IP, email, bearer token, API key, UNC path)
  • Test redaction_mode="none" leaves content untouched
  • Test original session object is not mutated (deep copy verification)
  • Test redaction summary counts are accurate
  • Test redaction across all text fields (notes, command_output, answer, scratchpad, outcome_notes, next_steps)
  • Test edge cases: empty strings, no matches, overlapping patterns

Frontend

npm run build validates types. No new component tests needed for a checkbox toggle.


Files to Create/Modify

Action File
Create backend/app/services/redaction_service.py
Modify backend/app/schemas/session.py
Modify backend/app/api/endpoints/sessions.py
Modify frontend/src/types/session.ts
Modify frontend/src/components/session/ExportPreviewModal.tsx
Modify frontend/src/pages/SessionDetailPage.tsx
Extend backend/tests/test_psa_export.py