docs(quick-260717-v6c): Add Mark as accidental report action to phishing Action Area
This commit is contained in:
parent
565a0c1ee2
commit
4a77b0544c
2 changed files with 116 additions and 1 deletions
|
|
@ -28,7 +28,7 @@ See: .planning/PROJECT.md (updated 2026-07-14)
|
|||
Phase: Milestone v3.0 complete
|
||||
Plan: —
|
||||
Status: Awaiting next milestone
|
||||
Last activity: 2026-07-17 — Completed quick task 260717-a19: phishing allowlist/timing/idempotency fixes
|
||||
Last activity: 2026-07-18 — Completed quick task 260717-v6c: Mark as accidental report action
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
|
|
@ -127,6 +127,7 @@ None yet.
|
|||
| 260716-n46 | Fix Mimecast blast-radius future-end-date swallow bug + multi-tenant gap (per-company tenant resolution) | 2026-07-16 | 9951e53 | [260716-n46-fix-mimecast-blast-radius-date-window-fu](./quick/260716-n46-fix-mimecast-blast-radius-date-window-fu/) |
|
||||
| 260716-pgr | Fix confidence display bug (0-1 scale rendered as raw percent, e.g. "1%" instead of "100%") | 2026-07-16 | 3f16268 | [260716-pgr-fix-confidence-display-bug-in-classifica](./quick/260716-pgr-fix-confidence-display-bug-in-classifica/) |
|
||||
| 260717-a19 | Fix phishing simulation-vendor allowlist gaps (3 missing KnowBe4 domains), auto-parse timing race (retry on ticket.update), and parseAndStoreMessage idempotency; reclassified 6 stale Seubert campaigns (all flipped UNWANTED → USER_AWARENESS) | 2026-07-17 | cf04f07 | [260717-a19-fix-phishing-simulation-vendor-allowlist](./quick/260717-a19-fix-phishing-simulation-vendor-allowlist/) |
|
||||
| 260717-v6c | Add "Mark as accidental report" action to the phishing Action Area — closes out a campaign and posts a fixed customer-facing note to the reporter (distinct from the silent "Mark as false positive" action) | 2026-07-18 | 565a0c1 | [260717-v6c-add-a-mark-as-accidental-report-action-t](./quick/260717-v6c-add-a-mark-as-accidental-report-action-t/) |
|
||||
|
||||
## Deferred Items
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
phase: quick-260717-v6c
|
||||
plan: 01
|
||||
subsystem: api
|
||||
tags: [phishing, remediation, autotask, nextjs, react]
|
||||
|
||||
requires:
|
||||
- phase: 20-remediation-approval-audit-safety
|
||||
provides: markCampaignFalsePositive template, D-04 guard pattern, RemediationConflictError/RemediationValidationError
|
||||
- phase: 21-autotask-triage-note
|
||||
provides: generateAndPostAcknowledgment template, TriageNoteResult/TriageNotePostResult shapes
|
||||
provides:
|
||||
- markCampaignAccidentalReport service function (status flip + audit + post-commit customer note)
|
||||
- generateAndPostAccidentalReportNote service function (fixed-template customer note)
|
||||
- POST /api/phishing/campaigns/[id]/mark-accidental-report route
|
||||
- Mark as accidental report button + confirm dialog in ActionAreaCard
|
||||
- campaign_marked_accidental_report timeline entry
|
||||
affects: [phishing-campaign-review, remediation-service, triage-note-service]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Mirrored existing false-positive/acknowledgment templates verbatim, changing only status value/event type/note copy"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- "app/api/phishing/campaigns/[id]/mark-accidental-report/route.ts"
|
||||
modified:
|
||||
- "lib/services/remediation-service.ts"
|
||||
- "lib/services/triage-note-service.ts"
|
||||
- "components/phishing/action-area-card.tsx"
|
||||
- "components/phishing/timeline-card.tsx"
|
||||
- "lib/services/remediation-service.test.ts"
|
||||
- "lib/services/triage-note-service.test.ts"
|
||||
|
||||
key-decisions:
|
||||
- "campaigns.status is unconstrained TEXT (migration 097) — 'accidental_report' needed no schema migration"
|
||||
- "Note-post failure never propagates past markCampaignAccidentalReport — the committed status change is always returned, with notePosted/noteError reflecting the note outcome (mirrors the acknowledge_user post-commit pattern)"
|
||||
|
||||
patterns-established: []
|
||||
|
||||
requirements-completed: []
|
||||
|
||||
duration: 25min
|
||||
completed: 2026-07-18
|
||||
---
|
||||
|
||||
# Phase quick-260717-v6c: Add "Mark as accidental report" action Summary
|
||||
|
||||
Added a parallel-to-false-positive campaign resolution path that both closes out a phishing campaign and posts a fixed-template customer-visible Autotask note thanking the reporting employee and confirming no action is needed — mirroring the existing `markCampaignFalsePositive`/`generateAndPostAcknowledgment` templates verbatim except for the status value, event type, and note copy.
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~25 min
|
||||
- **Started:** 2026-07-18T02:10:00Z (approx, base commit 2b48dc0)
|
||||
- **Completed:** 2026-07-18T02:35:20Z
|
||||
- **Tasks:** 4/4 completed
|
||||
- **Files modified:** 6 modified, 1 created
|
||||
|
||||
## Accomplishments
|
||||
- `markCampaignAccidentalReport` (lib/services/remediation-service.ts) — D-04 guard against approved/completed remediation, flips `campaigns.status` to `'accidental_report'`, writes a `campaign_marked_accidental_report` audit event, and posts the customer note after the transaction commits (never inside the FOR UPDATE lock), returning `{ campaignId, status, auditEventId, notePosted, noteError? }` even when the note post fails.
|
||||
- `generateAndPostAccidentalReportNote` (lib/services/triage-note-service.ts) — fixed two-paragraph customer-visible template (`noteType: 18`, `publish: 1`), zero evidence/URL/classification interpolation (T-23-01 invariant), per-ticket try/catch isolation.
|
||||
- New route `POST /api/phishing/campaigns/[id]/mark-accidental-report`, gated by `requirePermission('phishing', 'approve')`, mirroring the mark-false-positive route's UUID validation, optional-reason body parsing, campaign-existence check, and 409/400/500 error mapping.
|
||||
- `ActionAreaCard` — new "Mark as accidental report" button + confirm `AlertDialog` with an optional reason `Textarea`; `resolved`/tooltip logic now also treats `campaignStatus === 'accidental_report'` as resolved; success/partial-failure toasts distinguish a fully-successful mark (note posted) from a status-change-only outcome (note failed, surfaces `noteError`).
|
||||
- `TimelineCard` — new `campaign_marked_accidental_report` case using the existing blue/`CheckCircle2` tint (matching `remediation_approved`), visually distinct from the slate/`XCircle` false-positive entry and from THREAT-toned entries.
|
||||
- Mirrored test coverage in both service test files: D-04 guard rejection, successful status flip + audit event, note-post-failure-still-commits path, `noteType`/`publish` assertions, and per-ticket isolation.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Add backend service functions (status flip + customer note)** - `aea4fd2` (feat)
|
||||
2. **Task 2: Add the mark-accidental-report API route** - `97804f2` (feat)
|
||||
3. **Task 3: Add frontend button, dialog, and timeline case** - `74e43e2` (feat)
|
||||
4. **Task 4: Mirror test coverage** - `0d6cd25` (test)
|
||||
|
||||
_Note: No TDD RED/GREEN split was applied — tasks 1 and 4 mirror existing verbatim templates from already-tested code paths (markCampaignFalsePositive/generateAndPostAcknowledgment), so implementation and its test coverage were written together per task rather than test-first, consistent with how the plan's `<action>` blocks were scoped._
|
||||
|
||||
## Files Created/Modified
|
||||
- `lib/services/remediation-service.ts` - Added `markCampaignAccidentalReport` + `MarkAccidentalReportResult` interface, imports `generateAndPostAccidentalReportNote`
|
||||
- `lib/services/triage-note-service.ts` - Added `generateAndPostAccidentalReportNote`
|
||||
- `app/api/phishing/campaigns/[id]/mark-accidental-report/route.ts` - New POST route
|
||||
- `components/phishing/action-area-card.tsx` - New button, dialog, state, handler, disabled-reason logic
|
||||
- `components/phishing/timeline-card.tsx` - New `campaign_marked_accidental_report` timeline case
|
||||
- `lib/services/remediation-service.test.ts` - New `describe('markCampaignAccidentalReport', ...)` block + mock wiring
|
||||
- `lib/services/triage-note-service.test.ts` - New `describe('generateAndPostAccidentalReportNote', ...)` block + import
|
||||
|
||||
## Decisions Made
|
||||
- No new migration needed — `campaigns.status` is unconstrained TEXT (migration 097), so the new `'accidental_report'` value required no schema change.
|
||||
- Kept the same post-commit-note-never-throws contract as `remediateApprovedActions`/`autoPostAcknowledgment`: a note-post failure is caught, logged with a distinct `[MARK-ACCIDENTAL-REPORT]` prefix, and surfaced to the caller via `notePosted: false` / `noteError` rather than aborting the already-committed status change.
|
||||
- Used `variant="outline"` (not `destructive`) for the new button, since — unlike false-positive — this action posts a warm, appreciative note rather than a silent closure; visually distinct from the destructive false-positive button per the plan's UI-tint guidance.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None - plan executed exactly as written. All interface templates (markCampaignFalsePositive, generateAndPostAcknowledgment, the mark-false-positive route, the false-positive button/dialog, the campaign_marked_false_positive timeline case) were mirrored per the plan's embedded exact templates.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npx tsc --noEmit --pretty` — clean, no errors.
|
||||
- `npx vitest run lib/services/remediation-service.test.ts lib/services/triage-note-service.test.ts` — 36/36 tests passing across both files.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- FOUND: `lib/services/remediation-service.ts` (markCampaignAccidentalReport present)
|
||||
- FOUND: `lib/services/triage-note-service.ts` (generateAndPostAccidentalReportNote present)
|
||||
- FOUND: `app/api/phishing/campaigns/[id]/mark-accidental-report/route.ts`
|
||||
- FOUND: `components/phishing/action-area-card.tsx` (accidental-report button/dialog present)
|
||||
- FOUND: `components/phishing/timeline-card.tsx` (campaign_marked_accidental_report case present)
|
||||
- FOUND: `lib/services/remediation-service.test.ts` (markCampaignAccidentalReport describe block present)
|
||||
- FOUND: `lib/services/triage-note-service.test.ts` (generateAndPostAccidentalReportNote describe block present)
|
||||
- FOUND commit `aea4fd2`
|
||||
- FOUND commit `97804f2`
|
||||
- FOUND commit `74e43e2`
|
||||
- FOUND commit `0d6cd25`
|
||||
Loading…
Add table
Add a link
Reference in a new issue