Commit graph

5 commits

Author SHA1 Message Date
9f75f2160c fix(260721-n49): resolve per-company Mimecast tenant in gatherCampaignEvidence
- Thread company_id through reports query and CampaignReportSummary
- Mirror the route's Bug 2 (D-05) tenant-resolution block: query
  mimecast_tenants for an enabled row, build a tenant-scoped client via
  getMimecastClientForTenant, and pass { client, cacheScope } to
  getBlastRadius() when one exists
- Preserve global env fallback unchanged when no companyId or no
  enabled tenant row is present
2026-07-21 16:44:44 -04:00
204276c88a feat(quick-260717-a19): add 3 confirmed KnowBe4 domains to sim allowlist
- Extend knowbe4 vendor entry with customer-portal.info,
  cloud-service-care.com, bankonlinesupport.com (confirmed via shared
  URL fingerprint across Seubert tickets 699419/699421/699422/699433/
  699435/699456 on 2026-07-16/17)
- domainMatchesAllowlist and isKnownSimulationSender untouched
- Add tests for exact match, subdomain match, and suffix-spoof rejection
2026-07-17 07:19:18 -04:00
14ed8ca248 feat(23-01): add USER_AWARENESS verdict + acknowledge_user action mapping
- Add USER_AWARENESS to the Verdict union in campaign-classifier.ts
- mapVerdictToActions('USER_AWARENESS') returns ['acknowledge_user']; not added to DESTRUCTIVE_ACTIONS so requires_approval computes false
- classifyCampaign's simulation branch now assigns verdict = 'USER_AWARENESS' directly instead of falling through to evaluateSpamVsUnwanted
- deriveDefaultParams('acknowledge_user') returns {} (no operator-editable params)
- Widen TriageNoteEvidence.verdict to admit 'USER_AWARENESS' (pure type widen, no formatting change)
- Tests: classifier simulation fixtures now assert USER_AWARENESS/acknowledge_user/requiresApproval=false; new mapVerdictToActions/computeRequiresApproval/deriveDefaultParams cases
2026-07-16 19:36:53 -04:00
38c1ae4daf feat(19-01): implement classifyCampaign orchestrator + evidence gathering (GREEN)
- gatherCampaignEvidence: bulk-fetches reports (earliest-first, joined to
  contacts for requester email) -> messages (report_id = ANY) -> indicators
  (message_id = ANY), parses messages.headers JSONB into bounded
  ParsedMessage fields, and runs one getBlastRadius() lookup keyed off the
  earliest report's sender/subject/±24h window (research A6); synthesizes
  unavailable/not_configured with no Mimecast call when no report is linked
- evaluateThreatTier (D-03): blastRadius.status==='ok' AND
  (delivered>0 OR clicked>0) AND (hasHardAuthFail via effectiveAuthResults
  OR hasKnownBadIndicatorMatch — same attachment_hash/url value spanning
  >=2 distinct messages, cross-report correlation only, no external
  reputation lookup per research A4)
- evaluateSpamVsUnwanted (D-04): UNWANTED when any attachment/url indicator
  matches or delivery is contained to the reporter(s) only; SPAM otherwise
- classifyCampaign: D-06 simulation short-circuit -> D-03 -> D-04 ->
  computeConfidence -> mapVerdictToActions -> computeRequiresApproval ->
  append-only INSERT into classifications (D-02, no ON CONFLICT), wrapped
  in try/catch logging [CAMPAIGN-CLASSIFIER] + err.message and rethrowing
- isKnownSimulationSender relaxed to a narrower SenderIdentity shape so both
  the full NormalizedMessage fixtures and the bounded ParsedMessage type
  can share it
- All 39 tests green; tsc clean; full `npm test` suite green except 2
  pre-existing, unrelated itglue-search.test.ts failures (see
  deferred-items.md)
2026-07-16 08:20:58 -04:00
3ea6c95e38 feat(19-01): implement classifier pure rule functions (D-05/D-06/D-08)
- KNOWN_SIMULATION_SENDERS allowlist (it-support.care, breachsecurenow.com)
  with domainMatchesAllowlist (exact-or-proper-subdomain, no substring match
  — T-19-01) and isKnownSimulationSender (checks From + Return-Path domain
  — Pitfall 3)
- effectiveAuthResults (authResultsOriginal precedence — Pitfall 1) and
  hasHardAuthFail (spf/dkim/dmarc hard-fail only)
- computeConfidence: additive-from-1.0 with 0.4/0.3/0.2 named deductions,
  floors at 0.10 (D-05)
- mapVerdictToActions + DESTRUCTIVE_ACTIONS + computeRequiresApproval
  (OR'd across actions, D-08/CLASSIFY-02)
- All 30 pure-function tests green; tsc clean
2026-07-16 08:14:57 -04:00