feat: anti-triggers and governance docs for email security vendor plugins - #165
Merged
Conversation
Collaborator
Author
|
Base-branch note: this branch was cut from This PR's own commit is |
Applies the repo-wide connector-quality standard to the four near-substitute email security vendor plugins: abnormal, ironscales, mimecast, spamtitan. Anti-triggers (11 of 15 skills; all four api-patterns skills skipped as boilerplate-only per the checklist). These four vendors share almost all their vocabulary — "quarantine", "phishing", "release", "threat", "policy" match every one of them equally, plus the email-security bundle and the cipp/m365 tenant plugins. Each section states what the vendor uniquely owns and routes the neighbouring case elsewhere. GOVERNANCE.md per plugin, from _templates/governance-template.md. Tool names derived from each plugin's skills and cross-checked against the shipped MCP servers in /Users/asachs/mcp/<vendor>-mcp/src. Tiers follow blast radius, not HTTP verb: releasing a held message delivers possible malware to an inbox, purging mail destroys evidence, and a filter-list change silently drops a customer's legitimate mail — all destructive tier regardless of the verb. Additive only. No triggers: frontmatter (#158). No generated files.
asachs01
force-pushed
the
feat/quality-email-security-vendors
branch
from
August 4, 2026 18:47
52b324c to
5d87cbb
Compare
asachs01
marked this pull request as ready for review
August 4, 2026 18:47
The marketplace bump gate requires any plugin whose files changed to bump its own plugin.json version.
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.
Applies the repo-wide connector-quality standard to the four near-substitute email security vendor plugins. Branched from
feat/skill-anti-triggers-governance, which carries the standard.What each of these four uniquely owns
The whole value of this batch is cross-vendor disambiguation. These plugins are near-substitutes — "quarantine", "phishing", "release message", "threat", and "policy" match all of them equally, plus the
email-securitybundle and thecipp/m365tenant plugins. So each anti-trigger section leads with the boundary:Task A —
## Anti-triggers11 added / 4 skipped.
threats,cases,messages,account-takeover,vendorsapi-patternsincidentsapi-patternsmessage-tracking,queue-management,threat-intelligenceapi-patternsquarantine,listsapi-patternsWhy the four
api-patternsskills were skipped: any bullet there would only negatewhen_to_use("don't use for non-Mimecast questions"), which the checklist calls filler. This also matches the exemplar — Huntress has 7 skills and only 3 carry the section;api-patterns,billing,escalations, andorganizationswere all deliberately left alone.Every bullet names the skill to load instead, using each skill's frontmatter
name(the Huntress convention).Judgement calls
abnormal-messagesgets one pointing atMimecast Message Trackingbecause "trace this email / check these headers" pulls it wrongly; Mimecast doesn't get the mirror bullet, because nobody reaches for a delivery-pipeline skill when they want Abnormal.caseIdcollision is real and gets bullets on both sides.Abnormal Security CasesandAbnormal Security Account Takeoverboth call their identifiercaseIdand both are reached by the word "case". That is a genuine two-way mistake, so both carry it.FORCE_PASSWORD_RESET/REVOKE_SESSIONS/REMOVE_RULESas remediation actions, but no tool in the shipped MCP server performs them — those arecipp-usersandMicrosoft 365 Mailboxes. Same for Ironscales: remediation removes mail and blocks senders, it cannot reset a harvested credential.abnormal-vendorsgot a section for a vocabulary reason, not a sibling one. In MSP-land "vendor risk" overwhelmingly means a distributor. VendorBase means the opposite — an external party that emails your customer. That bullet routes toPax8 Products, mirroring the exemplar's "agent means a sensor, not a Claude subagent".spamtitan-quarantine,mimecast-message-tracking,abnormal-threats) because it is the single highest-traffic routing error in this batch, and the message IDs do not federate between vendors.Task B —
GOVERNANCE.mdOne per plugin, from
_templates/governance-template.md, with Conduit-gateway framing kept intact (centralised auth, no local secrets, per-operator audit identity).Tool names were derived from each plugin's own
skills/*/SKILL.mdand then cross-checked against the shipped MCP servers (abnormal-mcp,ironscales-mcp,mimecast-mcp,spamtitan-mcp). No tool name is invented.Tiers by blast radius, not HTTP verb
abnormal_remediation_manageironscales_remediation_act,ironscales_allowlist_managemimecast_hold_messagemimecast_release_messagespamtitan_release_message,spamtitan_delete_message,spamtitan_manage_allowlist,spamtitan_manage_blocklistThree of the four have an empty Write tier, and that is stated plainly rather than padded. These are mail-flow products: there is no reversible bookkeeping middle ground between reading a queue and moving a customer's mail.
The sharp edges the brief called out are all reflected: release delivers possible malware and cannot be recalled (
mimecast_release_message,spamtitan_release_message); purge destroys the only copy of the evidence (spamtitan_delete_message); a filter-policy change silently drops legitimate mail with no bounce and no alert (spamtitan_manage_blocklist). Each carries a written justification in the style of the exemplar'sincidents_bulk_approvenote.Disputable destructive-tier calls
Flagged in the docs themselves so a reviewer can argue them:
spamtitan_manage_allowlist→ destructive. The server does not annotate itdestructiveHint(unlike its blocklist sibling). But allowlisting bypasses spam scoring entirely, and spoofed mail claiming to be the allowlisted sender inherits the exemption. It is a durable hole in the customer's filtering with no visible symptom until it is used. Most likely to be argued down to Write.ironscales_allowlist_manage→ destructive, same reasoning: a permanent, company-wide, silent exemption from phishing detection.abnormal_remediation_manage→ destructive as a whole tool. Itsactionenum straddles read (status), destructive-removal (remediate), and destructive-delivery (unremediate). The gateway tiers by tool name, not by argument, so the tool takes the highest tier its arguments can reach. Same pattern noted for SpamTitan'smanage_*tools, whoselistaction is read-only but lives inside a destructive-tier tool.mimecast_hold_message→ Write, not destructive. Deliberate asymmetry with release: hold is undone by release, reaches one message, and its cost is a delayed email. Release is one-way.Data handling
Every tool returning message bodies, headers, or recipient PII is flagged. Two are worth a reviewer's attention:
mimecast_get_ttp_logsreturns every URL a named user clicked. That is a browsing-history-shaped dataset about identified employees and may attract employee-monitoring obligations independent of its security purpose.ironscales_email_classifyis the inverse flow — the operator supplies raw headers, bodies, and URLs outbound to Ironscales. It changes no state so it is tiered Read, but it exports customer email content.For abnormal and spamtitan the honest summary is recorded as-is: there is no PII-free read tier.
Drift found along the way (documented, not fixed)
Cross-checking against the shipped servers surfaced skill-vs-server tool-name drift. Fixing it is out of scope for an additive PR, so each
GOVERNANCE.mdrecords the real names under Known sharp edges — an operator tiering tools at the gateway needs names that exist:abnormal_ato_*,abnormal_vendors_*,abnormal_threats_remediate,abnormal_cases_action,abnormal_messages_headers. The server exposes 10 tools; none of those are among them.ironscales_list_incidents/ironscales_classify_email; server exposesironscales_incidents_list/ironscales_email_classify.mimecast_get_queue; server exposesmimecast_get_queue_status.spamtitan_list_allowlist/spamtitan_list_blocklist/spamtitan_get_domain_stats; the server covers those via thelistaction and adomainargument instead.spamtitan_get_queuehas nodomainparameter in the shipped server, though the skill documents one. In a multi-tenant appliance the quarantine listing is not scoped by customer, and the release/delete that follows is scoped only by the API key. Called out prominently; probably worth its own issue.Constraints observed
msp-claude-plugins/{abnormal,ironscales,mimecast,spamtitan}/. Diff is +614 / -0 — purely additive._standards/,_templates/,.claude-plugin/marketplace.json, ordocs/src/data/plugins.ts.npm run generate. Notriggers:frontmatter (refactor(skills): restructure all 341 skills per Claude 5 context-engineering guidance #158).Verification
node scripts/check-marketplace-drift.mjs→✔ marketplace drift check passed (76 entries)claude plugin validate→✔ Validation passedfor all four plugins