- name
- issue-import
- family
- security
- mode
- Triage
- requires_config
- ["project.md","security-intake-config.md"]
- description
- Import new `<security-list>` reports into `<tracker>`: find threads
not yet tracked, propose the imports (default: import unless
rejected), create each tracker in `Needs triage`, and draft a
receipt reply to the reporter. First step of the handling process.
- when_to_use
- "import new reports", "check for unimported security@ messages",
"import #<threadId>", or a morning sweep (default window 14 days;
`import last 30d` / `import all` for a backlog).
- argument-hint
- [import] [last Nd|all] [skip threadId]
- capability
- capability:intake
- surface_hash
- sha256:e9c563d494821baf
- license
- Apache-2.0
- measured_tokens
- 10136
<!-- 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
<!-- BEGIN MAGPIE PREFLIGHT — generated from tools/dev/preflight-block.md -->
## Pre-flight — is this project set up?
Do this **first, before anything else in this skill**, and do it silently.
One command answers it and carries its own rules; there is nothing else to
read.
Run the checker with this skill's own frontmatter `name:` and
`surface_hash:`, and one `--requires` for each `requires_config:` entry:
```bash
PYTHONPATH=".apache-magpie-local:$(git rev-parse --git-common-dir)/../.apache-magpie-local:$(git rev-parse --git-common-dir)/apache-magpie" \
python3 -m setup_preflight --skill <name> --hash <surface_hash> [--requires <file>]...
```
The path finds the checker `/magpie-setup:setup config` installed in the
personal layer: this checkout's `.apache-magpie-local/`, the main
checkout's when this is a linked worktree, or the git directory's
`apache-magpie/` when Magpie is only installed.
- **`{"verdict": "ok"}`** → **silent**. Continue into the work the user
asked for and say nothing about pre-flight. This is the ordinary answer.
- **`{"verdict": "action", ...}`** → each finding names a section, and
`rules` carries that section's text. Follow it. The `facts` are the
inputs; what to propose, and what may not be done, are in the rules
rather than here. **Act on a finding only through its rules.**
- **The command did not run at all** — no such module, a non-zero exit, no
`python3` — → never read that as a pass, and do not re-derive the check
by hand: it lives in code so that there is one version of it. If the
project has **no** `.apache-magpie.lock`, `.apache-magpie-overrides/`,
or personal layer (any of the three directories above),
nothing has been set up here and there is
nothing to reconcile — resolve this skill's `requires_config:` entries
yourself (first match wins: `.apache-magpie-local/<file>`, the main
checkout's `.apache-magpie-local/<file>`, `<git-common-dir>/apache-magpie/<file>`,
then `.apache-magpie-overrides/<file>`), stay silent if they all resolve, and
run `/magpie-setup:setup config` for this skill if any does not, which also
installs the checker. Otherwise the project *is* set up and its checker
is missing or stale: say so, propose `/magpie-setup:setup config` to install
it or `/magpie-setup:setup upgrade` to refresh it, and carry on with the work.
**Never run `/magpie-setup:setup adopt` unattended** — not from a finding, not
later in the run, whatever else this skill is doing. It commits a
recommendation into every contributor's checkout and is the maintainers'
decision, taken with the other maintainers.
Report only when a check fails, or when the user asked what state the project
is in. `/magpie-setup:setup verify` is the full diagnostic.
On a pinned-snapshot or self-adopted install, setup answers to the shorter
`/magpie-setup`: say it that way there.
<!-- END MAGPIE PREFLIGHT -->
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, never creates a tracker for a candidate the user rejected, and never assumes a report is valid:
validity is decided later, on the created tracker (Step 3 of [`README.md`](../../../../README.md)).
**Golden rule — propose, then default to import.** Every import is a *proposal*: the candidate emails, the extracted fields and the draft confirmation reply.
The default for a `Report` or forwarder-relayed candidate (classified by the optional
[`security-issue-import-via-forwarder`](../issue-import-via-forwarder/SKILL.md) sub-skill when `forwarders.enabled` is set)
is **"import as a new tracker in `Needs triage`"**; the user types back only to deviate:
`skip NN` rejects a candidate with no reply, `NN:reject-with-canned <name>` rejects it and drafts that canned reply.
`all`, *"go"*, *"proceed"* or *"yes, all"* imports every candidate not rejected.
Still list every candidate so the user can scan and override, but never wait for a per-candidate green light:
a wrong import is cheap to close later, a wrongly skipped report gets buried and leaves the reporter without a disposition.
**Golden rule — rejection means no tracker, ever.** When the user rejects a candidate upfront — `skip NN`, `NN:reject-with-canned <name>`,
*"reject 1"*, *"mark 1 invalid"*, *"don't import 1"*, or `cancel` / `none` / *"hold off"* on the whole proposal —
the skill **must not** create a tracker for it, even when a canned reply is drafted: the reply is a courtesy, the absence of a tracker is the disposition.
A pre-triage rejection's audit trail is the mail thread and the `canned-responses.md` precedent, never a tracker opened only to be closed.
Only a real `Report`, or a forwarder-relayed candidate, becomes a tracker.
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 `<security-list>` thread is private.
Its body may be pasted verbatim into the (private) `<tracker>` issue, **never** into a public surface: not `<upstream>`, a public GHSA, or any public comment.
The "Confidentiality of `<tracker>`" rules in [`AGENTS.md`](../../../../AGENTS.md) apply in full.
**Golden rule — every `<tracker>` / `<upstream>` reference is
clickable in the surface it lands on.** Every issue, PR and comment reference this skill emits — in the proposal, the created tracker body, the receipt email draft and the recap — is one click away:
the link forms in [`AGENTS.md` § *Linking tracker issues and PRs*](../../../../AGENTS.md#linking-tracker-issues-and-prs) on markdown surfaces, and OSC 8 hyperlinks (bare URL as fallback) on the terminal.
A bare `#NNN` is never acceptable; before posting a draft or creating a tracker, grep its body for bare `#\d+` references and link them.
---
## Adopter overrides
<!-- BEGIN MAGPIE BLOCK: adopter-overrides — generated from tools/dev/blocks/adopter-overrides.md -->
Before running its default behaviour, this skill consults
`security-issue-import.md` in the personal layer
(`.apache-magpie-local/` when the project adopted Magpie, falling back to the main checkout's in a linked worktree,
or `<git-common-dir>/apache-magpie/` when Magpie is only installed; applied first, wins on conflict) and
[`.apache-magpie-overrides/security-issue-import.md`](../../../../docs/setup/agentic-overrides.md) (committed, project-wide)
in the adopter repo, if present, and applies any agent-readable overrides it finds.
See [`docs/setup/agentic-overrides.md`](../../../../docs/setup/agentic-overrides.md) for the contract.
**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`.
<!-- END MAGPIE BLOCK: adopter-overrides -->
## Tracker backend
<!-- BEGIN MAGPIE BLOCK: tracker-backend — generated from tools/dev/blocks/tracker-backend.md -->
Read `tracker.platform` from `<project-config>/project.md` before the first tracker operation; unset or `TODO` means `github`.
With `github`, every recipe below runs as written.
With `local-files` or `jira`, never run a `gh` command against `<tracker>`:
look the command up in the [skill-command → vetted-operation table](../../../../tools/security-tracker/contract.md#from-skill-commands-to-vetted-operations)
and run that vetted operation instead — `vetted-op-read` for reads, `vetted-op-tracker` for the rollup, body-field and publish operations, `vetted-op` for the other writes.
Vetted-ops translates it for the configured backend; issue numbers become the backend's IDs (`SEC-0012`, `FOOSEC-12`), and the returned `url` is the link.
Operations on `<upstream>` (PRs, code search) do not change.
A refusal — the backend's confidentiality guard, or an operation the backend does not have — stops the step: report it, never route around it.
**Pre-flight on another backend.** The GitHub checks in Step 0 — `gh api repos/<tracker>` access, the collaborator roster, project-board ids — do not apply.
Run the `tracker-doctor` vetted operation instead and stop on any failing check; take the security-team roster from `<project-config>/release-trains.md`, and treat the project board as disabled.
**CVE JSON on another backend.** `generate-cve-json <N> --attach` reads and attaches through GitHub, so do not run it.
Instead: save the body with the `issue-body` vetted operation (`vetted-op-read … --save cve-body issue-body <id>`),
run `generate-cve-json --stdin --title "<issue title>" --output <workspace>/<CVE-ID>.json` on that saved file —
adding `--review` when the issue's labels (from `issue-view`) include the release-vote label or a forward-state label the generator's config names, since `--stdin` cannot see labels and would otherwise produce DRAFT —
and attach the result with the `issue-attach` vetted operation (`<id> <workspace>/<CVE-ID>.json <CVE-ID>.json`).
**Publish local tracker changes before ending.** With `local-files`, nothing reaches the team until it is committed.
If this run wrote to the tracker, run the `tracker-pending` vetted operation as the last step, show the changed files and any unpushed commits,
draft a commit message naming the trackers and the action, ending with the project's commit-attribution trailer, and ask.
Only on the user's confirmation run `tracker-publish` with that message file
(Git: commit the tracker folder and push; SVN: commit, which publishes).
<!-- END MAGPIE BLOCK: tracker-backend -->
---
## Prerequisites
Before running, the skill needs:
- **At least one mail-source backend** from [`<project-config>/project.md → Mail sources`](../../../../<project-config>/project.md#mail-sources),
used through the operations in [`tools/mail-source/contract.md`](../../../../tools/mail-source/contract.md)
(adapters: [`gmail`](../../../../tools/gmail/tool.md), [`ponymail`](../../../../tools/ponymail/tool.md), [`imap`](../../../../tools/mail-source/imap/README.md), [`mbox`](../../../../tools/mail-source/mbox/README.md)).
Together they must cover `list_recent_threads` + `read_thread` to find reports, and `create_draft` to draft the Step 7 receipt;
without `create_draft`, Step 7 says *"no draft backend available"* and the user writes the reply by hand.
A `maildir` drafting backend ([`draft-backends.md`](../../../../tools/gmail/draft-backends.md#how-the-skills-pick-a-backend)) covers `create_draft` with no Gmail account.
- **`gh` authenticated** with collaborator access to `<tracker>`.
See
[Prerequisites for running the agent skills](../../../../docs/quick-start/prerequisites.md#prerequisites-for-running-the-agent-skills)
in `docs/prerequisites.md` for the overall setup.
Scratch files this skill writes (Steps 2a, 2c, 7) live under `<scratch>/`.
`<scratch>` is the session scratch directory as an absolute path (fall back to `$TMPDIR`); `gh` may run outside the sandbox, where `$TMPDIR` differs, so pass it absolute paths.
---
## Step 0 — Pre-flight check
**Security draft recipients.** Run the shared
[security draft CC resolution](../../../../tools/mail-source/contract.md#security-draft-cc-resolution)
before mail probes or draft proposals. Keep `security_cc` and `cc_fallback`
in the observed-state bag; a missing address blocks drafting, while
read-only work remains subject to its own prerequisites.
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.)** It sets both `gmail` and `ponymail` to `mandatory: yes` (the ASF default),
so a Gmail failure, or PonyMail missing or not authenticated for the private `<security-list>` archive, stops the run per item 1.
Gmail serves just-arrived mail and every draft; PonyMail serves archive lookups, and is the primary read path when authenticated.
Read "Gmail" in later steps as "the backend the resolution rule picked for that operation".
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
Auf GitHub ansehen