Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
371 changes: 228 additions & 143 deletions .claude/skills/security-cve-allocate/SKILL.md

Large diffs are not rendered by default.

62 changes: 55 additions & 7 deletions .claude/skills/security-issue-deduplicate/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ license: Apache-2.0
(example: airflow-s/airflow-s for the Apache Airflow security team)
<upstream> → value of `upstream_repo:` in <project-config>/project.md
(example: apache/airflow)
<cve-tool> → CVE-tool adapter directory under `tools/` named by
`cve_authority.tool` in <project-config>/project.md
(example: cve-tool-vulnogram for the ASF default).
Before running any bash command below, substitute these with the
concrete values from the adopting project's <project-config>/project.md. -->

Expand Down Expand Up @@ -177,6 +180,18 @@ does **not** auto-pick. Practical guidance to offer when asked:
CVSS scoring, PoC code), merge *into* the one with the CVE but
keep all the rich content via the "Second independent report"
section described in Step 3 below.
- If **both** trackers carry an allocated CVE ID, prefer the one
whose record is further along the state machine — keep the
tracker whose record sits at `publish-ready` over one at
`review-ready`, and `review-ready` over `allocated`. Once the
kept side is chosen, the duplicate's CVE record is retracted
via `<cve-tool>`'s `retract(cve_id, reason)` per
[`tools/cve-tool/README.md`](../../../tools/cve-tool/README.md#retractcve_id-reason-to-ok)
as part of the Step 5 apply loop. **Refuse the merge** if
either CVE record is already `public` — once an advisory has
shipped, retroactively folding it into another tracker is an
errata announcement (Step 16 of the handling process), not a
dedupe.

---

Expand Down Expand Up @@ -350,8 +365,8 @@ original report, earliest first)
confirmed, or the placeholder form when unconfirmed; the merge
does not silently re-synthesize credits)

**Apply the [bot/AI credit policy](../../../tools/vulnogram/bot-credits-policy.md)
when consolidating.** If either tracker carries a credit line on
**Apply the [bot/AI credit policy](../../../tools/cve-tool-vulnogram/bot-credits-policy.md)
(at `tools/<cve-tool>/bot-credits-policy.md`) when consolidating.** If either tracker carries a credit line on
the **finder side** (*Reporter credited as*) that matches the bot
detection rule (`*[bot]` suffix, known-bot list,
`*-bot`/`*-ai`/`*-agent`/`*-gpt` / `*scanner*` / `*automat*`
Expand Down Expand Up @@ -539,12 +554,36 @@ After confirmation, apply **sequentially** (never in parallel):
(GitHub's `duplicate` close-reason is not exposed by `gh` on
all versions; `not planned` combined with the `duplicate` label
carries the same signal)
6. `uv run --project <framework>/tools/vulnogram/generate-cve-json generate-cve-json <keep> --attach`
6. `uv run --project <framework>/tools/<cve-tool>/generate-cve-json generate-cve-json <keep> --attach`
— the *Remediation developer* body field is the source of truth
for remediation-developer credits (populated by the
`security-issue-sync` skill from the linked PR's author); no CLI
flag needed
7. For each legacy bot comment folded in steps 2 / 3, delete the
flag needed. The regen output is the canonical JSON record for
the kept tracker; when the kept tracker already carries an
allocated CVE ID, the regenerated record is then fed into
`<cve-tool>`'s `push_update(cve_id, fields)` per the contract in
[`tools/cve-tool/README.md`](../../../tools/cve-tool/README.md#push_updatecve_id-fields-state_transitionnone-to-diff)
so the merged credits + references land on the CVE record itself
— the adapter does the storage (for the Vulnogram adapter that's
the OAuth-authenticated write to the `#source` tab URL —
`cve_authority.source_tab_url_template`). No state transition is
passed: dedup never moves the record across state verbs, it only
updates fields at whatever state the record is already in
(`allocated` / `review-ready` / `publish-ready`). If the kept
tracker has no CVE ID, the `push_update` step is skipped and
only the tracker-side JSON attachment is regenerated.
7. **Only when both trackers carried an allocated CVE ID** —
retract the dropped side's CVE record via `<cve-tool>`'s
`retract(cve_id, reason)` per
[`tools/cve-tool/README.md`](../../../tools/cve-tool/README.md#retractcve_id-reason-to-ok),
with `reason` set to a short string of the form *"merged into
<kept-CVE-ID> per <tracker>#<keep> on <YYYY-MM-DD>"*. This call
is governance-gated (the same `governance.cve_allocation_gate`
role that gated allocation); the skill surfaces the gate before
firing. The contract refuses retraction of any record already
at the `public` state — the Step 0 / Inputs pre-check above
should already have blocked the merge in that case.
8. For each legacy bot comment folded in steps 2 / 3, delete the
original with `gh api -X DELETE
repos/<tracker>/issues/comments/<id>` — only after the
matching rollup PATCH succeeded.
Expand Down Expand Up @@ -626,6 +665,15 @@ recap before presenting.
- [`security-issue-sync`](../security-issue-sync/SKILL.md) — runs
on the kept tracker after the merge to reconcile labels /
milestone / credit-preference drafts for both reporters.
- [`generate-cve-json`](../../../tools/vulnogram/generate-cve-json/SKILL.md) —
- [`generate-cve-json`](../../../tools/cve-tool-vulnogram/generate-cve-json/SKILL.md)
(at `tools/<cve-tool>/generate-cve-json/`) —
regenerates the kept tracker's CVE JSON attachment so both
finders land in `credits[]`.
finders land in `credits[]`. The regenerated record is fed
into `<cve-tool>`'s `push_update` so the merged credits also
land on the CVE record itself.
- [`tools/cve-tool/README.md`](../../../tools/cve-tool/README.md) —
the CVE-tool adapter contract that defines the
`push_update` and `retract` methods this skill invokes on the
kept and dropped sides respectively, plus the generic state
verbs (`allocated` / `review-ready` / `publish-ready` /
`public`) the skill speaks in.
2 changes: 1 addition & 1 deletion .claude/skills/security-issue-import-from-md/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ with the heading literals declared under `tracker.body_fields`):
| `**Repository:**` + `**Branch:**` | `Affected versions` | Literal text *"`<owner>/<repo>` @ `<branch>` — versions to be confirmed during triage."* The release-train mapping happens at allocation. |
| (auto) | `Security mailing list thread` (the concrete heading name comes from `tracker.body_fields.mailing_thread` in `<project-config>/project.md`) | `N/A — imported from markdown file <basename>; no <security-list> thread.` |
| (auto) | `Public advisory URL` | `_No response_`. |
| (auto) | `Reporter credited as` | `_No response_`. The credit decision happens at triage; if the file is AI-generated, there is typically no human finder to credit. If the markdown carries a `**Reporter:**` / `**Finder:**` / `**Discovered by:**` metadata line naming a specific handle, **apply the [bot/AI credit policy](../../../tools/vulnogram/bot-credits-policy.md)** before lifting it into the field — when the policy fires (e.g. the markdown was generated by an LLM scan and names the scanner itself), **include** the detected handle in the field (the CVE JSON generator will emit it with `type: "tool"` per the finder-side rule) and surface *"credited as tool: `<handle>` (matches bot policy — `<rule>`)"* in the per-finding proposal. The user can override per the policy doc. Since this skill imports from a file (no inbound reporter), the policy's email-clarification step is skipped — if a human researcher was behind the tool, the user adds them with an explicit override at triage time. |
| (auto) | `Reporter credited as` | `_No response_`. The credit decision happens at triage; if the file is AI-generated, there is typically no human finder to credit. If the markdown carries a `**Reporter:**` / `**Finder:**` / `**Discovered by:**` metadata line naming a specific handle, **apply the [bot/AI credit policy](../../../tools/cve-tool-vulnogram/bot-credits-policy.md)** before lifting it into the field — when the policy fires (e.g. the markdown was generated by an LLM scan and names the scanner itself), **include** the detected handle in the field (the CVE JSON generator will emit it with `type: "tool"` per the finder-side rule) and surface *"credited as tool: `<handle>` (matches bot policy — `<rule>`)"* in the per-finding proposal. The user can override per the policy doc. Since this skill imports from a file (no inbound reporter), the policy's email-clarification step is skipped — if a human researcher was behind the tool, the user adds them with an explicit override at triage time. |
| `## Location` URL (when it points at a `<upstream>` PR) | `PR with the fix` | The URL. Otherwise `_No response_` — the location commonly references a vulnerable file, not a fix. |
| (auto) | `Remediation developer` | `_No response_`. |
| `**Category:**` | `CWE` | Literal value (free text); the actual CWE assignment happens at triage / allocation. |
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/security-issue-import-from-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ has nine fields. Fill them as follows:
| **Public advisory URL** | `_No response_`. |
| **Reporter credited as** | `_No response_`. **The PR author is *not* credited as the CVE reporter for this kind of import.** A public PR is not a responsible disclosure — the contributor went straight to the public fix without giving the security team a chance to coordinate the announcement, so the security team neither owes a finder credit nor wants to incentivise the practice. The user can populate the field manually if there is a project-specific reason to credit a different individual (e.g. an internal reviewer who privately flagged the issue on the PR before it landed). See *[Reporter credit policy for public-PR imports](#reporter-credit-policy-for-public-pr-imports)* below. |
| **PR with the fix** | `pr.url` (e.g. `https://github.com/<upstream>/pull/65703`). |
| **Remediation developer** | `pr.author.name` (fall back to `pr.author.login`). One name per line. **Apply the [bot/AI credit policy](../../../tools/vulnogram/bot-credits-policy.md) before populating** — if the PR author handle matches the bot detection rule (`*[bot]` suffix, known-bot list, `*-bot`/`*-ai`/`*-agent`/`*-gpt` suffix patterns), leave the field at `_No response_` and surface the skip in Step 6's proposal with the matched rule (e.g. *"skipped credit: `dependabot[bot]` (matches bot policy — ends with `[bot]`)"*). The user can override per the policy doc. Since this is an `-from-pr` import (no inbound reporter), the policy's email-clarification step is skipped. |
| **Remediation developer** | `pr.author.name` (fall back to `pr.author.login`). One name per line. **Apply the [bot/AI credit policy](../../../tools/cve-tool-vulnogram/bot-credits-policy.md) before populating** — if the PR author handle matches the bot detection rule (`*[bot]` suffix, known-bot list, `*-bot`/`*-ai`/`*-agent`/`*-gpt` suffix patterns), leave the field at `_No response_` and surface the skip in Step 6's proposal with the matched rule (e.g. *"skipped credit: `dependabot[bot]` (matches bot policy — ends with `[bot]`)"*). The user can override per the policy doc. Since this is an `-from-pr` import (no inbound reporter), the policy's email-clarification step is skipped. |
| **CWE** | `_No response_` (the team assesses; not derivable). |
| **Severity** | `Unknown`. |
| **CVE tool link** | `_No response_` (filled by [`security-cve-allocate`](../security-cve-allocate/SKILL.md)). |
Expand Down Expand Up @@ -526,7 +526,7 @@ This tracker was deliberately opened by the security team for a public fix that
**Next:** Step 6 — allocate the CVE via the [`security-cve-allocate`](https://github.com/<tracker>/blob/<default-branch>/.claude/skills/security-cve-allocate/SKILL.md) skill.

Provenance: public PR <pr.url>, author `@<pr.author.login>`.
Extracted fields: scope=`<scope>`, *PR with the fix*=<pr.url>, *Remediation developer*=<pr.author.name> *(or `_No response_` + skip note when the PR author matches the [bot/AI credit policy](../../../tools/vulnogram/bot-credits-policy.md))*, *Affected versions*=`<per-scope shape>`, Severity=`Unknown`.
Extracted fields: scope=`<scope>`, *PR with the fix*=<pr.url>, *Remediation developer*=<pr.author.name> *(or `_No response_` + skip note when the PR author matches the [bot/AI credit policy](../../../tools/cve-tool-vulnogram/bot-credits-policy.md))*, *Affected versions*=`<per-scope shape>`, Severity=`Unknown`.

*Reporter credited as* intentionally left blank — public-PR imports do not credit the PR author as the CVE reporter (no responsible disclosure). See the [Reporter credit policy](https://github.com/<tracker>/blob/<tracker-default-branch>/.claude/skills/security-issue-import-from-pr/SKILL.md#reporter-credit-policy-for-public-pr-imports) section of the skill for the rationale.
```
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/security-issue-import-via-forwarder/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ The adapter returns either:

**When the adapter returns a credit** — apply the bot/AI credit
policy in
[`tools/vulnogram/bot-credits-policy.md`](../../../tools/vulnogram/bot-credits-policy.md)
[`tools/cve-tool-vulnogram/bot-credits-policy.md`](../../../tools/cve-tool-vulnogram/bot-credits-policy.md)
to the extracted `name`. The policy decides whether the credit
should be recorded with `type: "tool"` in the CVE record (when
the name matches `*-ai` / `*-bot` / `*-agent` / `*-gpt` / a
Expand Down Expand Up @@ -585,7 +585,7 @@ call against the tracker; there is no Gmail draft created.
a tracker, *which* milestones get relayed, and *what* falls
into the do-not-relay negative space. The adapter contract is
the mechanism; this doc is the policy that drives it.
- [`tools/vulnogram/bot-credits-policy.md`](../../../tools/vulnogram/bot-credits-policy.md)
- [`tools/cve-tool-vulnogram/bot-credits-policy.md`](../../../tools/cve-tool-vulnogram/bot-credits-policy.md)
— the bot / AI credit policy applied to the extracted credit
string at Step 2. Drives whether the CVE record lists the
credit as a tool vs an individual, and whether the parent
Expand Down
Loading
Loading