Conversation
analyzeDmarc's p= if/else-if chain had no final else, so an unrecognized policy value (e.g. a typo like p=Quarntine) pushed no validation at all and the record could report overall "pass". Grading then fell into scoring.ts's "shouldn't normally reach here" fallback arm and credited the domain with quarantine-level (C tier) enforcement it does not have. The sp= branch had the same gap but worse: it pushed a "pass" for any non-empty value, so sp=Rejectt reported as correctly configured. Add an explicit fail branch to both the p= and sp= checks for values outside reject/quarantine/none (RFC 7489 §6.3). This makes analyzeDmarc return status "fail" for these records, which already routes them through scoring.ts's existing gatekeeper (dmarc.status === "fail" -> grade F) before the fallback arm is ever reached — no change to scoring.ts itself. Closes #738 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01THpUFWMdjGGDJinJx6GzHc
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
dmarcheck | f6c8efa | Sep 14 2026, 12:17 PM |
|
Auto-merge routine: escalating to human review. This PR modifies Separately, noting for transparency: the routine's configured review/scan tooling ( This PR needs a human code-owner review before merging. Generated by Claude Code |
Summary
analyzeDmarc'sp=if/else-if chain had no finalelse: an unrecognized value (e.g. the real-world typop=Quarntine) pushed no validation at all, so the record could report overall"pass"and grading fell intoscoring.ts's "shouldn't normally reach here" fallback arm, crediting the domain with quarantine-level (C tier) enforcement it does not have.sp=branch had the same gap but a worse failure mode: it pushed apass/"Subdomain policy explicitly set" for any non-empty value, sosp=Rejecttreported as correctly configured.failbranch to both thep=andsp=checks for any value outsidereject/quarantine/none(RFC 7489 §6.3), citing the unrecognized value in the message.Owner / zone steps
None — code-only change, no provisioning required.
Security notes
Not security-sensitive in the auth/injection/exfiltration sense, but this PR touches
src/analyzers/dmarc.ts, which is CODEOWNERS-gated (@schmug) as part of the analyzer/orchestration/scoring supply-chain surface. Auto-merge is intentionally NOT enabled on this PR — it needs human code-owner review per the CODEOWNERS path-scoping in the repo's operating rules.Testing
npm test— 1521/1521 passing in the coverage-gated node project (vitest run --project=node --coverage), no per-file coverage threshold regressions (dmarc.ts96.96% lines / 91.35% branches,scoring.tsunaffected). The one failure surfaced by the fullnpm testchain (test/integration/mta-sts-runtime.test.ts, a real-network fetch tomta-sts.dmarc.mx) is a pre-existing, network-dependent failure reproduced identically on unmodifiedmainin this sandbox (no outbound network to the live domain here) — unrelated to this change.npm run typecheck— clean.npm run lint— clean (191 files checked, no issues).test/dmarc.test.tsuse the issue's literal fixtures (p=Quarntine,sp=Rejectt) plus two tests confirmingp=REJECT(case-insensitive) andsp=nonestill behave exactly as before.test/scoring.test.tsconfirms aDmarcResultwithstatus: "fail"and an unparseablep=tag gradesFand never producestierReason: "Fallback — quarantine-level enforcement".Choices made
fail(notwarn) for the unrecognizedsp=case, matching thep=handling for consistency — the issue's Acceptance criteria permitted either, and Acceptance mandatedfailunconditionally forp=.src/shared/scoring.ts: makinganalyzeDmarcemitstatus: "fail"for these records is sufficient — it now hits the existing gatekeeper (dmarc.status === "fail"→ grade F) before the fallback arm at line 281 is ever reached, per the issue's constraint to "fix only the path this bug opens."learnAnchorto the new validations — no existing/learn/dmarcanchor covers "unrecognized policy value," and the issue's pointers only expected alearnAnchorforp=none, which already has one.Deferred
pct/rua/ruf/adkim/aspf), and the wider "is the fallback arm reachable at all" question inscoring.ts.Refs
Closes #738
🤖 Generated with Claude Code
https://claude.ai/code/session_01THpUFWMdjGGDJinJx6GzHc
Generated by Claude Code