Skip to content

Read the alignment tags from DmarcRua's properties again - #209

Merged
michaelTBF merged 1 commit into
mainfrom
chore/retire-alignment-workaround
Sep 2, 2026
Merged

Read the alignment tags from DmarcRua's properties again#209
michaelTBF merged 1 commit into
mainfrom
chore/retire-alignment-workaround

Conversation

@michaelTBF

Copy link
Copy Markdown
Contributor

Follow-up to #204, which bumped DmarcRua to 2.1.0 and deliberately left the parser untouched. This retires the one workaround that upgrade made obsolete. No behaviour change.

Background

2.0.1 replaced PolicyPublishedType.Adkim/.Aspf with get-only properties computed from new AdkimRaw/AspfRaw strings, and the helper behind them called Regex.Replace on a value that can be null. Both tags are minOccurs="0", so a reporter that simply omits them made reading the property throw ArgumentNullException — after deserialization had already succeeded, so it surfaced in the parser rather than as a parse error. That is 1.5% of the reports vendored in the library's own test resources, Mail.Ru and Fastmail among them. MapAlignment read the raw strings instead, to keep 2.0.0's behaviour without waiting on an upstream fix.

2.1.0 null-guards the helper (danielsen/DmarcRua#11).

Why it is safe to remove now

The workaround's own comment set out what to check before going back to the properties. Both conditions hold, verified against the published package rather than inferred from the diff:

  • an absent tag returns null rather than throwingAdkim = null (AdkimRaw = null), no exception
  • the library has not changed what absent means — it still returns null and expresses no opinion; relaxed remains this project's reading

MapAlignment therefore takes the AlignmentType? directly and collapses from a nine-line character-scrubbing routine to one line. The library's own trimming and case folding is why <adkim> S </adkim> still reads as strict.

What deliberately did not change

Relaxed stays this project's decision, not the library's. DmarcRua returns null for absent, empty and unrecognised alike, and all three land on relaxed — an alignment we could not parse is not a reason to claim the stricter policy. Unlike sp, adkim/aspf have fixed RFC 7489 §6.3 defaults, so this still needs no HasSubdomainPolicyTag-style presence sniff.

Tests

Parse_DefaultsAlignmentWhenTagIsAbsentOrUnusable needed no change — all six cases pass against the properties exactly as they did against the raw strings:

input expected
both omitted relaxed, relaxed
<adkim>s</adkim>, aspf omitted strict, relaxed
adkim omitted, <aspf>s</aspf> relaxed, strict
<adkim></adkim>, <aspf/> relaxed, relaxed
<adkim> S </adkim>, <aspf>R</aspf> strict, relaxed
<adkim>strict</adkim>, <aspf>bogus</aspf> relaxed, relaxed

That the theory needed no change is the point of it. Every other parser test supplies both tags, so without these cases the suite goes green on exactly the kind of upgrade that broke 2.0.1 — which is what happened. Its comment is updated to say it now guards the library rather than a workaround around it.

846/846 unit tests pass, build clean with 0 warnings.

Still in place

The DMARCbis disposition machinery stays, for the reason recorded in #204: 2.1.0 retyped PolicyEvaluatedType.Disposition but never pointed rua.xsd at the new type, so a conformant pass report deserializes correctly and then fails schema validation. Being reported upstream separately.

🤖 Generated with Claude Code

2.0.1 replaced PolicyPublishedType.Adkim/.Aspf with get-only properties computed
from new AdkimRaw/AspfRaw strings, and the helper behind them called
Regex.Replace on a value that can be null. Both tags are minOccurs="0", so a
reporter that omits them made merely *reading* the property throw
ArgumentNullException — after deserialization had already succeeded, so it
surfaced in the parser rather than as a parse error. That is 1.5% of the reports
vendored in the library's own test resources, Mail.Ru and Fastmail among them.
MapAlignment read the raw strings instead to keep 2.0.0's behaviour.

2.1.0 null-guards the helper (danielsen/DmarcRua#11), so the properties are safe
again, and the comment on the workaround set out what to check before removing
it: that an absent tag returns null rather than throwing, and that the library
has not changed what absent *means*. Both hold — verified against the published
package rather than inferred from the diff — so MapAlignment takes the
AlignmentType? directly and collapses to one line.

Relaxed stays this project's reading, not the library's. DmarcRua returns null
for absent, empty and unrecognised alike, and all three land on relaxed: an
alignment we could not parse is not a reason to claim the stricter policy. The
existing theory covers all three cases and needed no change, which is the point
of it — every other parser test supplies both tags, so without those cases the
suite would go green on exactly the kind of upgrade that broke 2.0.1. Its
comment is updated to say it now guards the library rather than a workaround
around it.

No behaviour change: 846 unit tests pass, including the six alignment cases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Team

Run ID: 4ff990c8-3558-44c8-8976-c13ef8bc8fb9

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa4783 and 79881ac.

📒 Files selected for processing (3)
  • docs/planning/status.md
  • src/api.tests/DmarcRuaReportParserTests.cs
  • src/api/Application/Reports/DmarcRuaReportParser.cs

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The parser now uses DmarcRua’s typed nullable alignment properties. MapAlignment maps only Strict to "strict" and maps absent, invalid, or other values to "relaxed". Documentation and alignment test notes describe the DmarcRua 2.1.0 behavior.

Changes

DMARC alignment parsing

Layer / File(s) Summary
Typed alignment mapping
src/api/Application/Reports/DmarcRuaReportParser.cs, src/api.tests/DmarcRuaReportParserTests.cs, docs/planning/status.md
Parse passes typed Adkim and Aspf values to MapAlignment. The mapper handles nullable values and returns "relaxed" for absent or non-strict values. Tests and upgrade notes document the updated behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 79881

This localized parser cleanup preserves the documented alignment behavior, and no actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: reading DMARC alignment tags from DmarcRua properties instead of using the parsing workaround.
Description check ✅ Passed The description is directly related to the changeset. It explains the retired workaround, DmarcRua 2.1.0 behavior, preserved alignment mappings, tests, and unchanged DMARCbis handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/retire-alignment-workaround

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused change preserves documented behavior and is covered by existing alignment regression cases.

Pull request overview

Retires the obsolete DmarcRua 2.0.1 alignment workaround after the 2.1.0 null-handling fix, preserving existing parser behavior.

Changes:

  • Reads alignment through Adkim and Aspf properties.
  • Simplifies alignment mapping while retaining relaxed defaults.
  • Updates test commentary and implementation status documentation.
File summaries
File Description
src/api/Application/Reports/DmarcRuaReportParser.cs Uses nullable alignment enums directly.
src/api.tests/DmarcRuaReportParserTests.cs Documents regression coverage for optional and invalid tags.
docs/planning/status.md Records retirement of the workaround.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@michaelTBF
michaelTBF requested a balanced review from Copilot September 2, 2026 14:49
@michaelTBF
michaelTBF merged commit a629bdb into main Sep 2, 2026
7 checks passed
@michaelTBF
michaelTBF deleted the chore/retire-alignment-workaround branch September 2, 2026 14:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused change preserves established behavior and is adequately covered by existing tests.

Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants