An unrecognised rspamd action is coerced to a pass instead of failing closed

Open Beginner friendly
#234 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
1/5
Estimated time
Under an hour
Newbie friendliness
85/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
backend

Research direction

Start by reading services/email/spam/client.py around line 42, especially SpamResult.from_response and the symbols check at L60. Confirm that an unrecognised rspamd action raises rather than becoming NO_ACTION, and verify that the existing spam-scan behavior still passes its tests.

Written by the indexing model from the issue text.

Description

Found by testJoe and tagged by lazyJoe during the ClamAV work on #184 (codingjoe-turbo-spoon). Pre-existing on main, not introduced by that PR.

lazyJoe defer line: defer: delete the \except ValueError` fallback in `SpamResult.from_response`; rspamd 4.1 under relay's pinned config emits only the six enumerated actions, so mapping an unknown action to `NO_ACTION` records a new scanner state as a pass instead of failing closed like the `symbols` check at L60. [services/email/spam/client.py:42]`

What

try:
    action = SpamAction(data.get("action", "no action"))
except ValueError:
    action = SpamAction.NO_ACTION

Under the pinned rspamd/rspamd:4.1 with the mounted local.d config, the six members of SpamAction are the entire vocabulary. So the fallback cannot fire today.

The problem is the direction it fails in. If rspamd ever grows an action — discard, quarantine, or a custom action — this coerces it to NO_ACTION, which the scan tasks read as a pass. A verdict that should suppress the message is delivered instead.

Why removal is the fix

Deleting the try/except leaves action = SpamAction(data.get("action", "no action")), three lines shorter. An unknown action then raises, the scan task retries, and the message fails closed. When rspamd really does grow an action, the fix is to add the enum member; message/models.py already absorbs extra values through spam_badge_variant and the model choices.

Failing closed is the same contract check_message re-established by keying its retry on the CLAM_VIRUS_FAIL symbol rather than on the soft reject action.

Note

Related but separate: SpamAction has no member for discard or quarantine, and force_actions could set either. Whoever picks this up should decide whether the enum grows or the client keeps failing closed on the unknown.

Dominant language
Python
Stars
4
Forks
0
Avg merge
7h 28m
Merged PRs (30d)
135

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from codingjoe/relay

All issues in codingjoe/relay

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.