Skip to content

✨(inbound) ARC relay-trust: inbound_auth "arc" + arc_verdict rule#763

Merged
sylvinus merged 4 commits into
mainfrom
feat/inbound-arc-trust
Jul 23, 2026
Merged

✨(inbound) ARC relay-trust: inbound_auth "arc" + arc_verdict rule#763
sylvinus merged 4 commits into
mainfrom
feat/inbound-arc-trust

Conversation

@sylvinus

@sylvinus sylvinus commented Jul 22, 2026

Copy link
Copy Markdown
Member

Local branch from #756

Summary by CodeRabbit

  • New Features

    • Added ARC-based inbound authentication using trusted ARC relay sealers, with fail-closed behavior when trust can’t be established.
    • Added support for arc mode in spam filtering via arc_verdict conditions (trusted, untrusted, DNS-indeterminate), including drop actions.
    • Introduced retry/deferral behavior when DNS verification for trusted ARC sealers fails within the allowed window.
  • Documentation

    • Updated spam/sender-auth configuration guidance for ARC mode, trusted sealers, verdict semantics, and rule/action options.
  • Tests

    • Added extensive ARC verification, inbound auth, pipeline integration, and spam rule coverage.

@coderabbitai

coderabbitai Bot commented Jul 22, 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: ASSERTIVE

Plan: Pro Plus

Run ID: 2cff75af-16e7-46fd-97d9-e70aa0164150

📥 Commits

Reviewing files that changed from the base of the PR and between 2c68aac and 76ad8d6.

📒 Files selected for processing (2)
  • docs/spam.md
  • src/backend/messages/settings.py

📝 Walkthrough

Walkthrough

Changes

The inbound mail pipeline now verifies trusted ARC chains, caches ARC verdicts, supports ARC-based DKIM/DMARC authentication, and evaluates arc_verdict spam rules with normalized spam, ham, and drop outcomes. Configuration documentation and comprehensive ARC, authentication, pipeline, and spam tests were added or updated.

ARC relay trust

Layer / File(s) Summary
ARC verification and authentication
src/backend/core/mda/arc.py, src/backend/core/mda/inbound_auth.py, src/backend/core/tests/mda/test_arc.py, src/backend/core/tests/mda/test_inbound_auth.py
ARC chains are parsed and verified only for allowlisted sealers, DNS failures are classified separately, and trusted sealed authentication results drive the new arc authentication mode.
ARC pipeline and spam rules
src/backend/core/mda/inbound_pipeline.py, src/backend/core/mda/spam.py, src/backend/core/tests/mda/test_inbound_auth.py, src/backend/core/tests/mda/test_spam_processing.py
The pipeline caches ARC results, retries eligible DNS failures, skips ARC for widget submissions, and passes ARC verdicts into hardcoded rules supporting normalized spam, ham, and drop actions.
ARC configuration documentation
docs/spam.md, src/backend/messages/settings.py
Configuration, authentication modes, trusted sealer behavior, ARC verdict rules, actions, retry handling, and examples are documented.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Message
  participant InboundPipeline
  participant ARCVerifier
  participant SpamRules
  participant InboundAuth
  Message->>InboundPipeline: enter inbound processing
  InboundPipeline->>ARCVerifier: verify configured ARC sealer
  ARCVerifier-->>InboundPipeline: cached ARC verdict
  InboundPipeline->>SpamRules: evaluate arc_verdict conditions
  InboundPipeline->>InboundAuth: evaluate ARC-based authentication
  InboundAuth-->>Message: authentication verdict
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main ARC relay-trust addition, including inbound_auth "arc" and arc_verdict rules.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

mosa-riel and others added 3 commits July 23, 2026 10:28
New "arc" inbound_auth mode derives dkim/dmarc only from an ARC-sealed
ARC-Authentication-Results whose outermost sealer is in
SPAM_CONFIG["trusted_arc_sealers"] (empty = any valid seal); plaintext
headers are never trusted.

New SPAM_CONFIG["arc_gate"] (off|spam|drop) marks or drops inbound mail
lacking a valid trusted seal, so a publicly-reachable mta-in effectively
accepts only mail sealed by a trusted relay. The chain is verified with
dkimpy; a verification/DNS failure never spams or drops.

core/mda/arc.py holds the shared verifier. Config reference in
docs/spam-config.md.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@sylvinus
sylvinus force-pushed the feat/inbound-arc-trust branch from a2ffa20 to 2c68aac Compare July 23, 2026 10:42
@sylvinus sylvinus changed the title ✨(inbound) ARC relay-trust: inbound_auth "arc" + arc_gate ✨(inbound) ARC relay-trust: inbound_auth "arc" + arc_verdict rule Jul 23, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/spam.md`:
- Around line 233-235: Update the “Fail closed” statement in the
trusted_arc_sealers documentation to say that an arc_verdict: "untrusted" rule
matches every non-widget message when the allowlist is empty, preserving the
preceding widget exemption.

In `@src/backend/messages/settings.py`:
- Around line 555-569: Update the SPAM_CONFIG documentation comment to describe
ARC conditions using the implemented arc_verdict key, include the accepted
reject and no-action aliases alongside spam, ham, and drop, and document that
unresolved DNS verification is treated as untrusted after
MESSAGES_INBOUND_DEFERRAL_MAX_AGE.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0cb9aaee-e1a3-4bb4-92f7-880dbaefb241

📥 Commits

Reviewing files that changed from the base of the PR and between 3214cfb and 2c68aac.

📒 Files selected for processing (9)
  • docs/spam.md
  • src/backend/core/mda/arc.py
  • src/backend/core/mda/inbound_auth.py
  • src/backend/core/mda/inbound_pipeline.py
  • src/backend/core/mda/spam.py
  • src/backend/core/tests/mda/test_arc.py
  • src/backend/core/tests/mda/test_inbound_auth.py
  • src/backend/core/tests/mda/test_spam_processing.py
  • src/backend/messages/settings.py

Comment thread docs/spam.md Outdated
Comment thread src/backend/messages/settings.py Outdated
Comment on lines +555 to +569
# rules : list of spam rules; each is a header_match /
# header_match_regex OR an "arc_verdict" trust
# condition — "trusted" / "untrusted" — e.g.
# {"arc_verdict": "untrusted", "action": "drop"},
# with action spam / ham / drop.
# inbound_auth : sender authentication backend — one of
# "native", "rspamd", "authentication-results",
# or None/absent to disable. See
# core.mda.inbound_auth for semantics.
# "native", "rspamd", "arc",
# "authentication-results", or None to disable.
# See core.mda.inbound_auth for semantics.
# trusted_arc_sealers : list of trusted ARC sealer d= domains
# (empty = trust nothing). Used by inbound_auth
# "arc" and by "arc" spam rules. When non-empty,
# a DNS failure verifying a claimed-trusted
# sealer holds the message for retry rather than
# failing open or closed.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Keep the SPAM_CONFIG comment aligned with the implemented rule contract.

This comment names the condition family as "arc" instead of arc_verdict, omits the accepted reject/no action aliases, and does not mention that an unresolved DNS result becomes untrusted after MESSAGES_INBOUND_DEFERRAL_MAX_AGE.

Proposed wording
-    #                              condition — "trusted" / "untrusted" — e.g.
+    #                              condition — "trusted" / "untrusted" — e.g.
     #                              {"arc_verdict": "untrusted", "action": "drop"},
-    #                              with action spam / ham / drop.
+    #                              with action spam / reject, ham / no action,
+    #                              or drop.
...
-    #                              "arc" spam rules. When non-empty,
+    #                              "arc_verdict" spam rules. When non-empty,
     #                              a DNS failure verifying a claimed-trusted
-    #                              sealer holds the message for retry rather than
-    #                              failing open or closed.
+    #                              sealer holds the message for retry until
+    #                              MESSAGES_INBOUND_DEFERRAL_MAX_AGE, then treats
+    #                              it as untrusted.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# rules : list of spam rules; each is a header_match /
# header_match_regex OR an "arc_verdict" trust
# condition — "trusted" / "untrusted" — e.g.
# {"arc_verdict": "untrusted", "action": "drop"},
# with action spam / ham / drop.
# inbound_auth : sender authentication backend — one of
# "native", "rspamd", "authentication-results",
# or None/absent to disable. See
# core.mda.inbound_auth for semantics.
# "native", "rspamd", "arc",
# "authentication-results", or None to disable.
# See core.mda.inbound_auth for semantics.
# trusted_arc_sealers : list of trusted ARC sealer d= domains
# (empty = trust nothing). Used by inbound_auth
# "arc" and by "arc" spam rules. When non-empty,
# a DNS failure verifying a claimed-trusted
# sealer holds the message for retry rather than
# failing open or closed.
# rules : list of spam rules; each is a header_match /
# header_match_regex OR an "arc_verdict" trust
# condition — "trusted" / "untrusted" — e.g.
# {"arc_verdict": "untrusted", "action": "drop"},
# with action spam / reject, ham / no action,
# or drop.
# inbound_auth : sender authentication backend — one of
# "native", "rspamd", "arc",
# "authentication-results", or None to disable.
# See core.mda.inbound_auth for semantics.
# trusted_arc_sealers : list of trusted ARC sealer d= domains
# (empty = trust nothing). Used by inbound_auth
# "arc" and by "arc_verdict" spam rules. When non-empty,
# a DNS failure verifying a claimed-trusted
# sealer holds the message for retry until
# MESSAGES_INBOUND_DEFERRAL_MAX_AGE, then treats
# it as untrusted.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/messages/settings.py` around lines 555 - 569, Update the
SPAM_CONFIG documentation comment to describe ARC conditions using the
implemented arc_verdict key, include the accepted reject and no-action aliases
alongside spam, ham, and drop, and document that unresolved DNS verification is
treated as untrusted after MESSAGES_INBOUND_DEFERRAL_MAX_AGE.

@sylvinus
sylvinus merged commit cf0b70e into main Jul 23, 2026
17 checks passed
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