Skip to main content

magpie-security-issue-import

Scan <security-list> for reports that have not yet been copied into <tracker> as tracking issues, present the proposed imports to the user, and — defaulting to *import unless the user rejects upfront* — create the tracking issues with the `Needs triage` project-board status and draft a receipt-of- confirmation reply to each reporter. This is the first step of the handling process: the entry point that converts an inbound email thread into a tracker the rest of the skills (security-issue-sync, security-issue-fix, generate-cve-json) operate on.

Source facts

Repository
apache/airflow-steward
Last source activity
August 29, 2026 at 19:20
Detected SKILL.md language
English
Stars
87
Forks
85

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
magpie-security-issue-import
family
security
mode
Triage
description
Scan <security-list> for reports that have not yet been copied into <tracker> as tracking issues, present the proposed imports to the user, and — defaulting to *import unless the user rejects upfront* — create the tracking issues with the `Needs triage` project-board status and draft a receipt-of- confirmation reply to each reporter. This is the first step of the handling process: the entry point that converts an inbound email thread into a tracker the rest of the skills (security-issue-sync, security-issue-fix, generate-cve-json) operate on.
when_to_use
Invoke when a security team member says "import new reports", "check for unimported security@ messages", "import #<threadId>", or when they start a morning-triage sweep and want to see what has landed on security@ overnight. Also appropriate as a recurring check — the skill is cheap to run against the default 14-day Gmail window and a no-op when every recent thread is already tracked or already answered-and-closed on-thread. Use `import last 30d` / `import all` (= disclosure_governance.window_days, default 90d) for a wider backlog sweep when genuinely warranted.
argument-hint
[import] [last Nd|all] [skip threadId]
capability
capability:intake
license
Apache-2.0
<!-- Placeholder convention (see AGENTS.md#placeholder-convention-used-in-skill-files): <project-config> → adopting project's `.apache-magpie/` directory <tracker> → value of `tracker_repo:` in <project-config>/project.md <upstream> → value of `upstream_repo:` in <project-config>/project.md Before running any bash command below, substitute these with the concrete values from the adopting project's <project-config>/project.md. --> # security-issue-import This skill is the **on-ramp** of the security-issue handling process. It converts an inbound `<security-list>` email thread into an `<tracker>` tracking issue that follows the repo's issue template, then drafts the receipt-of-confirmation reply to the reporter. It never sends email. It never creates a tracker for a candidate the user has explicitly rejected. It never assumes a report is valid — the validity / invalid / CVE-worthy decision still happens later in the discussion on the created tracker (Step 3 of [`README.md`](../../README.md)). **Golden rule — propose, then default to import.** Every import this skill performs is a *proposal* that lists the candidate emails, the extracted fields, and the draft confirmation reply. The user's default disposition for any `Report` or forwarder-relayed candidate (the latter classified by the optional [`security-issue-import-via-forwarder`](../security-issue-import-via-forwarder/SKILL.md) sub-skill when `forwarders.enabled` is non-empty) is **"import as a new tracker landing in `Needs triage`"**; the user only has to type back when they want to *deviate* from that default — `skip NN` to reject a candidate upfront with no reply, or `NN:reject-with-canned <name>` to reject upfront *and* draft a specific canned negative-assessment / out-of-scope reply. A bare `all` (or no reply at all to the proposal — the user typing *"go"*, *"proceed"*, *"yes, all"*) means *"import every non-rejected candidate as proposed"*. The skill must still surface each candidate one-by-one in the proposal so the user can scan and override if needed; what the skill must *not* do is sit on a report waiting for an explicit per-candidate green light. The bias is toward landing trackers — a wrongly-imported report is cheap to close at Step 5 / 6 of the handling process; a wrongly-skipped one gets buried in the inbox and the reporter is left without a disposition. **Golden rule — rejection means no tracker, ever.** When the user rejects a candidate upfront — any of `skip NN`, `NN:reject-with-canned <name>`, an explicit *"reject 1"*, *"mark 1 invalid"*, *"don't import 1"*, or a `cancel` / `none` / *"hold off"* on the whole proposal — the skill **must not** create a tracker for that candidate. This holds even when the user also asks for a canned reply to be drafted: the draft is a courtesy to the reporter, the absence of a tracker is the disposition. There is no "create the tracker so the team can close it as invalid later" path; if the team has decided pre-triage that the report is invalid, the audit trail lives on the Gmail thread and on the `canned-responses.md` precedent, not in a tracker that exists only to be closed. A tracker is created **only** when the candidate is imported as a real `Report` (or a forwarder-relayed candidate classified by the [`security-issue-import-via-forwarder`](../security-issue-import-via-forwarder/SKILL.md) sub-skill) for triage. Non-import candidate classes (`automated-scanner`, `consolidated-multi-issue`, `media-request`, `spam`, `cross-thread-followup`, `cve-tool-bookkeeping`) keep the original "propose first, apply only on explicit confirm" rule — those never default to a tracker. **Golden rule — confidentiality.** The inbound thread on `<security-list>` is private. The skill may paste the email body verbatim into the created `<tracker>` tracking issue (that repo is also private). It must **never** paste the report content into a public surface — not into `<upstream>`, not into a public GHSA, not into any comment on a public repo. The same confidentiality rule documented in the "Confidentiality of `<tracker>`" section of [`AGENTS.md`](../../AGENTS.md) applies in full. **Golden rule — every `<tracker>` / `<upstream>` reference is clickable in the surface it lands on.** Whenever this skill emits a reference to a tracker issue, PR, or comment — the proposal shown to the user before import, the created tracker issue body (observed-state dump, sibling-tracker cross-links, prior-rejection cross-links, fix-already-public PR pointers), the receipt-of- confirmation draft email reply, the recap output — the reference must be one click away in whatever surface it lands on: - **On markdown surfaces** (the created tracker issue body, the draft email reply destined for the `<security-list>` thread, any markdown-rendered cross-link list): use the markdown link form per [`AGENTS.md` § *Linking tracker issues and PRs*](../../AGENTS.md#linking-tracker-issues-and-prs): - **Sibling `<tracker>` issue**: `[<tracker>#NNN](https://github.com/<tracker>/issues/NNN)` - **Public `<upstream>` PR** (e.g. fix-already-public match): `[<upstream>#NNN](https://github.com/<upstream>/pull/NNN)` - **Comment**: link to the `#issuecomment-<C>` anchor. - **On terminal surfaces** (the proposal shown to the user before import, the recap output): wrap the visible short form (`<tracker>#NNN`, `<upstream>#NNN`) in **OSC 8 hyperlink escape sequences** (`\e]8;;<URL>\e\\<short>\e]8;;\e\\`) so modern terminals (iTerm2, Kitty, GNOME Terminal, WezTerm, Windows Terminal, …) render the short text as clickable. Where OSC 8 is unsupported (CI logs, dumb terminals), fall back to printing the bare URL on the same line after the number. Bare `#NNN` with no link wrapper of any kind is never acceptable. The created tracker issue is read by the security team who drill into the cross-links to assess; the draft email reply lands on `<security-list>` where the reporter needs the references to be one click away. Both surfaces are private, but `<tracker>` URLs themselves are public-safe per the [Confidentiality of `<tracker>`](../../AGENTS.md#confidentiality-of-the-tracker-repository) rule — what stays private is the *contents* the link points at. **Self-check before posting any draft email or creating any tracker issue**: grep the body for bare `#\d+` / `<tracker>#\d+` tokens that aren't already inside a markdown link or an OSC 8 wrapper, and convert any match. --- ## Adopter overrides Before running the default behaviour documented below, this skill consults [`.apache-magpie-local/security-issue-import.md`](../../docs/setup/agentic-overrides.md) (personal, gitignored) and [`.apache-magpie-overrides/security-issue-import.md`](../../docs/setup/agentic-overrides.md) (committed, project-wide) in the adopter repo if it exists, and applies any agent-readable overrides it finds. See [`docs/setup/agentic-overrides.md`](../../docs/setup/agentic-overrides.md) for the contract — what overrides may contain, hard rules, the reconciliation flow on framework upgrade, upstreaming guidance. **Hard rule**: agents NEVER modify the snapshot under `<adopter-repo>/.apache-magpie/`. Local modifications go in the override file. Framework changes go via PR to `apache/magpie`. --- ## Snapshot drift Also at the top of every run, this skill compares the gitignored `.apache-magpie.local.lock` (per-machine fetch) against the committed `.apache-magpie.lock` (the project pin). On mismatch the skill surfaces the gap and proposes [`/magpie-setup upgrade`](../setup/upgrade.md). The proposal is non-blocking — the user may defer if they want to run with the local snapshot for now. See [`docs/setup/install-recipes.md` § Subsequent runs and drift detection](../../docs/setup/install-recipes.md#subsequent-runs-and-drift-detection) for the full flow. Drift severity: - **method or URL differ** → ✗ full re-install needed. - **ref differs** (project bumped tag, or `git-branch` local is behind upstream tip) → ⚠ sync needed. - **`svn-zip` SHA-512 mismatches the committed anchor** → ✗ security-flagged; investigate before upgrading. --- ## Prerequisites Before running, the skill needs: - **At least one configured mail-source backend** per [`<project-config>/project.md → Mail sources`](../../<project-config>/project.md#mail-sources). The skill treats every backend the same way — through the abstract operations defined in [`tools/mail-source/contract.md`](../../tools/mail-source/contract.md) (`list_recent_threads`, `read_thread`, `list_drafts`, `list_sent_since`, `create_draft`, `thread_url`). Reference adapters: [`gmail`](../../tools/gmail/tool.md) (full read+write), [`ponymail`](../../tools/ponymail/tool.md) (read-only ASF archive), [`imap`](../../tools/mail-source/imap/README.md) (stub), [`mbox`](../../tools/mail-source/mbox/README.md) (read-only offline archive — stub). To **discover new reports** the configured backends must collectively cover `list_recent_threads` + `read_thread`; to **draft the receipt-of-confirmation reply in Step 7** they must additionally cover `create_draft`. If no available backend covers `create_draft`, Step 7 surfaces a one-line *"no draft backend available"* note and the user composes the reply by hand. - **`gh` CLI authenticated** (`gh auth status` returns OK) with collaborator access to `<tracker>`. The skill calls `gh issue create` and `gh search issues` directly. See [Prerequisites for running the agent skills](../../docs/prerequisites.md#prerequisites-for-running-the-agent-skills) in `docs/prerequisites.md` for the overall setup. --- ## Step 0 — Pre-flight check Before touching any candidate thread, verify: 1. **Mail-source backends from `<project-config>/project.md → Mail sources` are available.** For each declared backend, run the backend's trivial health probe (per its adapter doc — Gmail: `mcp__claude_ai_Gmail__search_threads` with `pageSize: 1`; Ponymail: `mcp__ponymail__auth_status()`; IMAP: a `CAPABILITY` against the configured host; mbox: a `stat` on the archive path) and record the result in the skill's observed-state bag. Apply the [contract's resolution rule](../../tools/mail-source/contract.md#resolution-rule--which-backend-runs-an-operation) to figure out which backend serves which op for this run. * **`mandatory: yes` backend unavailable** → **stop immediately**. Surface *"mandatory mail-source backend `<name>` unavailable: `<reason>`; run aborted"*. The user fixes the auth / connection and re-invokes. * **`mandatory: no` backend unavailable** → continue with the remaining backends. If the resolution then leaves an operation with no provider (e.g. no available backend supports `create_draft`), the skill records *"no `<op>` backend available"* in the observed-state bag and the relevant downstream step omits that proposal with a clear hand-back to the user. * **Every declared backend healthy** → proceed; the observed-state bag records one provider per op so every dispatch later is unambiguous. 2. **`gh` is authenticated and has access.** Run `gh api repos/<tracker> --jq .name`; if it errors (401, 403, 404), stop and tell the user to log in with `gh auth login` or get added to `<tracker>`. 3. **(Reference-adopter guidance.)** The reference adopter lists `gmail` as primary `mandatory: yes` and — per the ASF default — `ponymail` as `mandatory: yes` too (`fallback` role for drafts, since PonyMail is read-only). So for the reference flow **both** backends are pre-flight prerequisites: a Gmail-MCP failure stops the run (drafts have no home), and a PonyMail-MCP miss — not registered, or registered but unauthenticated for the private `<security-list>` archive — stops it too, per item 1's `mandatory: yes` rule. Gmail handles reads of just-arrived inbound mail and all draft creation; PonyMail handles archive lookups (and is the primary read path when authenticated). Adopters whose `Mail sources` table sets `ponymail` to `mandatory: no` get the old degrade-quietly behaviour; the step-by-step references to "Gmail" below should be read as "the backend the resolution rule picked for the relevant op". 4. **Privacy-LLM contract.** This skill reads `<security-list>` bodies that may contain third-party PII the reporter discloses about other people. Run the gate-check first — non-zero exit is a hard stop: ```bash uv run --project <framework>/tools/privacy-llm/checker \ privacy-llm-check ``` The checker auto-locates `<project-config>/privacy-llm.md` (template at [`projects/_template/privacy-llm.md`](../../projects/_template/privacy-llm.md)) and verifies every entry in *Currently configured LLM stack* is approved per [`tools/privacy-llm/models.md`](../../tools/privacy-llm/models.md#the-pre-flight-check). In addition, verify: - `~/.config/apache-magpie/` is writable (the redactor's mapping file lives there); - the configured collaborator source is reachable via `gh api` (default: `<tracker>` from `project.md`); - the redaction-tuning knobs (collaborator exemption, enabled field types) are loaded into the skill's observed-state bag — they apply at filter-time below. Each subsequent body fetch in Steps 4 / 7 / 7g (template- field extraction, draft assembly, recap) follows the redact-after-fetch protocol in [`tools/privacy-llm/wiring.md`](../../tools/privacy-llm/wiring.md#redact-after-fetch-protocol); the receipt-of-confirmation draft assembly follows the [reveal-before-send protocol](../../tools/privacy-llm/wiring.md#reveal-before-send-protocol) when (and only when) the draft references a third-party identifier. 5. **Disclosure governance from `<project-config>/security-intake-config.md`.** If the file exists, read the `disclosure_governance` block and load these two keys into the observed-state bag for use in Step 7: - `reporter_acknowledgement_model` — `manual` | `auto` | `none`. Controls whether and how the receipt-of-confirmation reply is drafted (Step 7.4). - `window_days` — integer; the CVD window in calendar days, used as the disclosure deadline hint when composing the acknowledgement draft. If the file does not exist or the `disclosure_governance` block is absent, silently default to `reporter_acknowledgement_model: manual` and `window_days: 90`. A missing file is **not** a stop condition — adopters who have not yet created this config receive the same ASF defaults the skill has always applied. If a `mandatory: yes` mail-source backend or the `gh` check fails, do **not** proceed — the skill would fail mid-flow otherwise, leaving half-built state (a draft on the wrong thread, or a tracker with no receipt reply). Fail fast instead. `mandatory: no` backends degrade quietly per the contract's resolution rule. A privacy-llm pre-flight failure is also a hard stop — the redactor's mapping store and the collaborator-source lookup are both load-bearing for every subsequent body read. --- ## Inputs Before running, resolve the user's selector into a concrete set of candidate Gmail threads: | Selector | Resolves to | |---|---| | `import new` (default) | every security@ thread received in the last **14 days** that has not yet been imported as an <tracker> issue and has not already been answered-and-closed on-thread |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub