Skip to content

mailsec: add verdict-revision and report-reopen CLI/SDK surfaces - #350

Merged
maximelb merged 1 commit into
masterfrom
feat/mailsec-revision-cli
Sep 1, 2026
Merged

mailsec: add verdict-revision and report-reopen CLI/SDK surfaces#350
maximelb merged 1 commit into
masterfrom
feat/mailsec-revision-cli

Conversation

@maximelb

@maximelb maximelb commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

What

Wires the P3 verdict-revision and report-reopen mailsec gateway routes (now live on exp) into the limacharlie mailsec CLI and its SDK, building on the existing coverage/message/campaign/report/action/analyze/connection/onboarding group.

New verbs (matching the group's existing noun-verb grammar)

  • mailsec message revise MSG_UUID --verdict <malicious|suspicious|graymail|benign|unknown> --rationale <text> [--rationale ...] [--score N]
    POST /mailsec/{oid}/messages/{msg_uuid}/verdict (perm mailsec.act). Records an analyst verdict. --rationale is repeatable and required (1..10 lines, each ≤280 chars). mode is fixed to analyst because the CLI operator is a human — an autonomous agent revises with its own key and mode: ai through the API, not this command. applied:false is rendered as an honest no-op (already the current verdict), not an error.
  • mailsec message revisions MSG_UUID
    GET /mailsec/{oid}/messages/{msg_uuid}/revisions (perm mailsec.get). Oldest-first revision history (seq/mode/actor/verdict/decided_at/rationale), rendered via the standard --output json/table path.
  • mailsec report reopen REPORT_ID
    POST /mailsec/{oid}/reports/{report_id}/reopen (perm mailsec.set). The inverse of the existing report resolve; added beside it without duplicating resolve.

Conventions followed

  • Positional id argument (like message get/eml/similar/action, report get/resolve), Client.request wrapper via the Mailsec SDK, gateway stamps the actor (nothing stamped client-side), generic format_output rendering, register_explain AI-help entries, and the same explain/help text style.
  • Rationale bounds are enforced client-side (clear ValueError → clean non-zero CLI exit) so a caller learns the limit locally rather than from a 400.

Tests

Extends the established mock-the-transport pattern (no live API calls): asserts URL/method/body for each verb, the analyst mode default, rationale bounds (empty/blank/too-many/too-long, plus at-limit accepted), and that applied:false exits 0. The SDK route-coverage test is updated 22→25. Full unit + microbenchmark suite green (4003 passed, 5 pre-existing skips).

🤖 Generated with Claude Code

Wire the P3 verdict-revision and report-reopen gateway routes into the
mailsec CLI and SDK:

- message revise: POST messages/{uuid}/verdict — set an analyst verdict
  with a required, audited rationale (1..10 lines, <=280 chars each) and
  an optional score. mode is fixed to analyst since the CLI operator is a
  person; an agent revises with its own key and mode ai via the API.
  applied:false is rendered as an honest no-op, not an error.
- message revisions: GET messages/{uuid}/revisions — oldest-first history.
- report reopen: POST reports/{report_id}/reopen — the inverse of resolve.

Rationale bounds are enforced client-side with clear ValueErrors that the
CLI surfaces as clean non-zero exits. Matches the existing group grammar
(positional id argument, gateway stamps the actor, generic --output
rendering). Unit tests cover URL/method/body construction, the analyst
mode default, rationale bounds, and applied:false as a non-error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@maximelb
maximelb merged commit 8836620 into master Sep 1, 2026
6 checks passed
@maximelb
maximelb deleted the feat/mailsec-revision-cli branch September 1, 2026 20:18
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