mailsec: full CLI and SDK coverage of the Email Security API - #344
Merged
Conversation
Adds `limacharlie mailsec ...` over all 22 `/mailsec/{oid}/*` gateway routes:
coverage, the message index and drawer, the justified raw-EML download,
similar-message pivots, per-message and campaign-wide actions, campaigns,
sender profiles, the action audit trail, standalone EML analysis, the
abuse-mailbox report queue, retro-hunts, custom-rule validation and backtest,
the connection preflight, and the served onboarding guide.
Structured as noun-verb groups (`message get`, `report resolve`, `rule
backtest`) matching the cloudsec surface, with an --explain entry per command.
Three contracts the wrapper had to preserve rather than smooth over, because
each is a place where being "helpful" would quietly change what the caller
asked for:
- BOOLEANS ARE TRI-STATE. Absent means unconstrained; it is NOT False. The
--user-reported / --no-user-reported pair resolves to None when neither is
given, so an unfiltered read stays unfiltered. Collapsing the two would
narrow every such read invisibly, because a smaller result set looks exactly
like a correct one.
- CURSORS ARE OPAQUE and are passed back verbatim. They encode which index the
walk is pinned to and are bound to the filter set that minted them.
- CONFIRM IS ABSENT, NOT EMPTY. Campaign sweeps and hunt remediation preview
by default; omitting --confirm must reach the server as an absence rather
than an empty string that could read as a confirmation.
The EML download refuses an empty justification client-side. The justification
is what makes the access auditable, and discovering that requirement as a
server error after the fact is a worse way to learn it.
Tests: 21 SDK tests including a route-coverage table that asserts all 22 routes
have a method with the right verb and URL — a route with no SDK method is a
capability the CLI silently lacks until someone needs it.
The three CLI inventory guards (command count, expected commands, module map)
are updated to include mailsec, which is what those guards exist for. Verified
against a stashed baseline: the suite's 111 pre-existing failures are unchanged
and this adds none.
Exercised against the live API on exp: report list (with paging), coverage,
filtered message list, and a rule backtest over the real 34-message window.
lcbill
previously approved these changes
Aug 28, 2026
`message eml --output FILE` collided with the global `--output <format>` option. A user or an agent writing `--output yaml` would have silently created a file named 'yaml' instead of formatting the response — a wrong outcome that looks like nothing happened. It is --out-file now, and the help says why so the next person does not reintroduce it.
lcbill
previously approved these changes
Aug 28, 2026
Found reviewing my own PR: cloudsec quotes user-controlled path segments with `_quote(value, safe="")` and this SDK escaped none. Most of these ids are server-minted UUIDs and are harmless either way. Two are not: the sender key is an address or domain a person types, and the connection record is a hive record name. An unescaped slash in either silently addresses a DIFFERENT route rather than failing, which turns a typo into a request nobody intended. Verified against the live API that ordinary keys still resolve — `sender get admin@elephantwhich.com` escapes the `@` and the server returns the profile.
lcbill
approved these changes
Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
limacharlie mailsec ...over all 22/mailsec/{oid}/*gateway routes: coverage, the message index and drawer, the justified raw-EML download, similar-message pivots, per-message and campaign-wide actions, campaigns, sender profiles, the action audit trail, standalone EML analysis, the abuse-mailbox report queue, retro-hunts, custom-rule validation and backtest, the connection preflight, and the served onboarding guide.Noun-verb groups (
message get,report resolve,rule backtest) matching the cloudsec surface, with an--explainentry per command.Three contracts the wrapper preserves rather than smooths over
Each is a place where being "helpful" would quietly change what the caller asked for:
False.--user-reported/--no-user-reportedresolves toNonewhen neither is given. Collapsing the two would narrow every unfiltered read invisibly, because a smaller result set looks exactly like a correct one.confirmis absent, not empty. Campaign sweeps and hunt remediation preview by default; omitting--confirmmust reach the server as an absence rather than an empty string that could read as a confirmation.The EML download refuses an empty justification client-side — the justification is what makes the access auditable, and discovering that requirement as a server error after the fact is a worse way to learn it.
Verification
report list(with paging),coverage, a filteredmessage list, and arule backtestover the real 34-message window.