docs(21-01): complete triage-note sanitizer/formatter plan
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6RuWdiUiXrPK6FLBHjtpY
This commit is contained in:
parent
17ba0e880f
commit
03bb560874
1 changed files with 105 additions and 0 deletions
105
.planning/phases/21-autotask-triage-note/21-01-SUMMARY.md
Normal file
105
.planning/phases/21-autotask-triage-note/21-01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
---
|
||||||
|
phase: 21-autotask-triage-note
|
||||||
|
plan: 01
|
||||||
|
subsystem: api
|
||||||
|
tags: [phishing-triage, sanitization, autotask, vitest, pure-functions]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 17-mimecast-blast-radius-lookup
|
||||||
|
provides: BlastRadiusResult discriminated union imported as a type
|
||||||
|
- phase: 19-classification-engine
|
||||||
|
provides: Verdict type and classification shape (verdict/confidence/summary/reasons/recommended_actions) this formatter summarizes
|
||||||
|
- phase: 20-remediation-approval-audit-safety
|
||||||
|
provides: remediation_actions status lifecycle (proposed/approved/completed) this formatter renders
|
||||||
|
provides:
|
||||||
|
- "sanitizeUrl / sanitizeNoteText pure functions (lib/services/triage-note-sanitize.ts)"
|
||||||
|
- "formatTriageNote(evidence) pure function + TriageNoteEvidence contract (lib/services/triage-note-format.ts)"
|
||||||
|
affects: [21-02-triage-note-service-and-endpoint]
|
||||||
|
|
||||||
|
# Tech tracking
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "SECURITY-CRITICAL module-header convention mirrored from lib/services/analyzer/itglue-redact.ts (why-it-exists doc-comment + exported-pure-function-for-tests shape)"
|
||||||
|
- "Formatter routes all free text and URLs through a shared sanitizer before returning, so no source field can bypass redaction"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- lib/services/triage-note-sanitize.ts
|
||||||
|
- lib/services/triage-note-sanitize.test.ts
|
||||||
|
- lib/services/triage-note-format.ts
|
||||||
|
- lib/services/triage-note-format.test.ts
|
||||||
|
modified: []
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "sanitizeUrl always strips query+fragment wholesale (never selectively keeps benign params) per NOTE-01's 'full malicious URL query strings' requirement"
|
||||||
|
- "sanitizeNoteText intentionally does NOT redact bare emails or hex attachment hashes — those are evidence per 21-CONTEXT.md Claude's Discretion, not credentials"
|
||||||
|
- "formatTriageNote passes its entire assembled string through sanitizeNoteText (not just discrete fields) so a secret embedded anywhere in free text is caught regardless of source field"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Pure-function-first design for security-critical text transforms: no I/O, fully unit-testable, consumed later by a thin service layer (Plan 02)"
|
||||||
|
|
||||||
|
requirements-completed: [NOTE-01]
|
||||||
|
|
||||||
|
# Metrics
|
||||||
|
duration: 2min
|
||||||
|
completed: 2026-07-16
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 21 Plan 01: Triage Note Sanitizer + Formatter Summary
|
||||||
|
|
||||||
|
**Pure sanitizer (URL query/fragment stripping + Bearer/credential redaction) and pure formatter (`formatTriageNote`) turning classification + blast-radius + remediation-state evidence into human-readable, secret-free Autotask note text, both fully unit-tested with Vitest.**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** ~2 min
|
||||||
|
- **Started:** 2026-07-16T12:04:58-04:00
|
||||||
|
- **Completed:** 2026-07-16T12:06:31-04:00
|
||||||
|
- **Tasks:** 2 completed
|
||||||
|
- **Files modified:** 4 (all newly created)
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
- `sanitizeUrl` strips every URL down to scheme+host+path (query + fragment always removed), never throws on malformed input, falls back to truncating at `?`/`#`
|
||||||
|
- `sanitizeNoteText` redacts Bearer/Authorization tokens and credential-style query-param values (`token`, `access_token`, `password`, `api_key`, etc.) while explicitly preserving bare sender emails and attachment hashes as evidence
|
||||||
|
- `formatTriageNote` renders a `TriageNoteEvidence` object into labeled prose sections (header, Classification, Reasons, Blast Radius — both `ok`/`unavailable` branches, Recommended Actions, Current Remediation State, Indicator URLs), routing every URL through `sanitizeUrl` and the whole assembled string through `sanitizeNoteText`
|
||||||
|
- `TriageNoteEvidence` interface exported for Plan 02 to build its evidence-gathering service against
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task followed RED → GREEN (TDD):
|
||||||
|
|
||||||
|
1. **Task 1: Sanitizer** - `cc93707` (test: RED, 8 failing tests) → `226f300` (feat: GREEN, all 8 pass)
|
||||||
|
2. **Task 2: Note formatter + TriageNoteEvidence contract** - `b4e05eb` (test: RED, 9 failing tests) → `17ba0e8` (feat: GREEN, all 9 pass)
|
||||||
|
|
||||||
|
_TDD gate compliance: both tasks have a `test(...)` commit followed by a `feat(...)` commit; no refactor step was needed._
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
- `lib/services/triage-note-sanitize.ts` - `sanitizeUrl` + `sanitizeNoteText` pure functions with `REDACTED_MARKER` constant
|
||||||
|
- `lib/services/triage-note-sanitize.test.ts` - 8 Vitest cases covering query/fragment stripping, malformed-input safety, token/credential redaction, email/hash preservation
|
||||||
|
- `lib/services/triage-note-format.ts` - `TriageNoteEvidence` interface + `formatTriageNote(evidence)` pure function
|
||||||
|
- `lib/services/triage-note-format.test.ts` - 9 Vitest cases covering verdict/confidence rendering, both blast-radius branches, empty/populated remediation state, URL sanitization, whole-output secret redaction, null-verdict handling
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
- Query strings are stripped unconditionally in `sanitizeUrl` — no allowlist of "safe" params, since selectively keeping some params risks missing a novel credential-param name (matches NOTE-01's wording exactly: "full malicious URL query strings").
|
||||||
|
- `sanitizeNoteText` explicitly does not touch email addresses or hex hashes — confirmed as intentional in `21-CONTEXT.md` Claude's Discretion block (these are attacker-identity evidence, not secrets belonging to Pulse/its operators).
|
||||||
|
- `formatTriageNote` sanitizes the entire assembled output string (not just individual fields) as a defense-in-depth measure — if a future evidence field carries an embedded secret, it's still caught at the final sanitize pass regardless of which section it landed in.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - plan executed exactly as written. Both tasks' `<behavior>`, `<action>`, and `<acceptance_criteria>` blocks were implemented as specified; no architectural changes, no missing critical functionality found, no blocking issues encountered.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
None.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
None - no external service configuration required. Both modules are pure functions with no DB/network/Autotask dependency.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
- `TriageNoteEvidence` interface and `formatTriageNote()` are ready for Plan 02 to import and build its evidence-gathering service + `POST /api/phishing/campaigns/{id}/triage-note` endpoint against.
|
||||||
|
- `sanitizeUrl`/`sanitizeNoteText` are exported and stable for direct reuse if Plan 02 needs to sanitize any additional free text outside the formatter's own URL list.
|
||||||
|
- No blockers.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 21-autotask-triage-note*
|
||||||
|
*Completed: 2026-07-16*
|
||||||
Loading…
Add table
Add a link
Reference in a new issue