[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-apache-generate-cve-json":3,"mdc-i2vjmc-key":39,"related-repo-apache-generate-cve-json":3442,"related-org-apache-generate-cve-json":3538},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":22,"repoUrl":23,"updatedAt":24,"license":25,"forks":26,"topics":27,"repo":34,"sourceUrl":37,"mdContent":38},"generate-cve-json","generate CVE JSON documents","Generate a CVE 5.x JSON document from an \u003Ctracker> tracking\nissue, ready to paste into the Vulnogram `#source` tab of the ASF CVE tool\nat https:\u002F\u002Fcveprocess.apache.org\u002Fcve5\u002F\u003CCVE-ID>#source. The conversion is\ndeterministic: same issue in, same JSON bytes out. Handles multiple\ncredits (one per line) and multiple references (URLs extracted from the\nissue's \"Public advisory URL\" and \"PR with the fix\" fields; the\n\"Security mailing list thread\" field is treated as internal-only and\nnever exported).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"apache","Apache Software Foundation","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fapache.png",[12,16,19],{"name":13,"slug":14,"type":15},"Security","security","tag",{"name":17,"slug":18,"type":15},"Compliance","compliance",{"name":20,"slug":21,"type":15},"Technical Writing","technical-writing",61,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie","2026-07-12T08:35:41.218722",null,42,[28,8,29,30,31,14,32,33],"agent-skills","automation","claude-code","cve","vulnerability-disclosure","vulnerability-management",{"repoUrl":23,"stars":22,"forks":26,"topics":35,"description":36},[28,8,29,30,31,14,32,33],"Agent-assisted maintainership and development framework for Apache projects — Triage, Mentoring, Drafting (agent-authored fixes with human review), and Pairing (developer-side dev-cycle) skills shipping; Agentic Autonomous (auto-merge) on the roadmap.","https:\u002F\u002Fgithub.com\u002Fapache\u002Fmagpie\u002Ftree\u002FHEAD\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json","---\n# SPDX-License-Identifier: Apache-2.0\n# https:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0\nname: generate-cve-json\ndescription: |\n  Generate a CVE 5.x JSON document from an \u003Ctracker> tracking\n  issue, ready to paste into the Vulnogram `#source` tab of the ASF CVE tool\n  at https:\u002F\u002Fcveprocess.apache.org\u002Fcve5\u002F\u003CCVE-ID>#source. The conversion is\n  deterministic: same issue in, same JSON bytes out. Handles multiple\n  credits (one per line) and multiple references (URLs extracted from the\n  issue's \"Public advisory URL\" and \"PR with the fix\" fields; the\n  \"Security mailing list thread\" field is treated as internal-only and\n  never exported).\nwhen_to_use: |\n  Invoke when a security team member says \"generate CVE JSON for NNN\",\n  \"update the CVE tool entry for NNN\", \"paste-ready CVE for NNN\", or is\n  about to publish the advisory for a tracking issue and wants the CVE\n  record filled in from the issue body in one paste-and-save step. Not\n  appropriate before the CVE has been allocated (the script needs a CVE\n  ID either from the issue body's `CVE tool link` field or from a\n  `--cve-id` override).\n---\n\n# generate-cve-json\n\nThis skill produces a CVE 5.x JSON document from a tracking issue in\n[`\u003Ctracker>`](https:\u002F\u002Fgithub.com\u002F\u003Ctracker>), ready to\npaste into the Vulnogram **\"#source\"** tab of the ASF CVE tool. The goal is\nto eliminate the manual \"copy each field from the issue into the right\nVulnogram form input\" step when you are preparing to publish an advisory.\n\n> **Project-agnostic by design.** All project-specific values\n> (vendor, top-level product \u002F package name, project display map,\n> CNA org id, generator tag, …) are loaded from a TOML config the\n> adopting project ships at `\u003Cproject-config>\u002Ftools\u002Fcve-tool-vulnogram\u002Fcve-json-config.toml`.\n> Concrete `apache-foo-project-*` strings appearing in this\n> document are **illustrative examples** of how a project with a\n> project-style package layout would configure things; replace\n> them mentally with the adopter's own package taxonomy. The\n> schema is documented in the package [README](README.md).\n\n**Golden rule:** the script generates a *proposal* JSON document. It\nparses a handful of structured fields from the issue body, but it cannot\nread the security team member's mind. Always review the generated JSON\nbefore pasting, and always do the final review inside Vulnogram before\nmoving the CVE from DRAFT → REVIEW → READY → PUBLIC.\n\n**Release-vote gating (opt-in, recommended for ASF projects).** The\nemitted `CNA_private.state` follows a tri-state state machine:\n\n- `DRAFT` — the CNA is incomplete *or* the project has opted into\n  release-vote gating and no vote is in progress yet.\n- `REVIEW` — the CNA is review-ready (CVE ID + title + description +\n  affected versions + CWE + severity + ≥ 1 credit + ≥ 1 reference)\n  *and* either the project hasn't opted into gating (legacy: ready ⇒\n  REVIEW) or an RC vote is in progress (signalled by the configured\n  tracker label or a `--review` CLI flag).\n- `PUBLIC` — the CNA is review-ready *and* the public advisory has\n  shipped (a `vendor-advisory` reference is present).\n\nProjects opt into gating by setting `[workflow].release_vote_gating\n= true` in their `cve-json-config.toml` and choosing the label name\nvia `[workflow].rc_voting_label` (default `\"rc voting\"`). The sync\nskill is responsible for detecting [VOTE] threads on the project's\ndev list (e.g. `dev@\u003Cproject>.apache.org`) and proposing the label\nadd\u002Fremove; the generator only reads the label on the tracker. Non-\nASF adopters who publish advisories without a separate release-vote\nstep typically leave gating off — the legacy \"ready ⇒ REVIEW\"\nbehaviour is the right default for that workflow.\n\n**Determinism:** the same input issue body produces exactly the same JSON\nbytes on every run. The script uses only the Python standard library, has\nno timestamps or machine-dependent values in its output, sorts JSON keys,\nand sorts references alphabetically. This lets you paste the result into\nVulnogram, tweak fields in the tool, re-run the script later, and cleanly\ndiff the two to see what the tool has added \u002F what you changed by hand.\n\n---\n\n## Inputs\n\n- **Issue number** (required) — e.g. `232`.\n- Optional CLI overrides:\n  - `--cve-id CVE-YYYY-NNNN+` — override the CVE ID if the issue body's\n    `CVE tool link` field has not yet been filled in, or retarget the\n    JSON to a different CVE ID.\n  - `--title \"\u003Cvendor>: \u003Cproduct>: …\"` — override the CVE title.\n    Default is the GitHub issue title with the project's\n    `\u003Cvendor>: \u003Cproduct>:` prefix (sourced from the TOML config) when\n    it does not already start with that phrase.\n  - `--version-start X.Y.Z` — override the start of the affected version\n    range (the `affected[].versions[].version` field). Default is the\n    lower bound parsed from the Affected versions field when it uses\n    `>= X, \u003C Y` syntax, otherwise `\"0\"`.\n  - `--remediation-developer \"Name\"` — append a `type: \"remediation\n    developer\"` credit on top of whatever the body's *Remediation\n    developer* field already lists (auto-populated by the\n    `security-issue-sync` skill from the linked PR's author). Repeat\n    the flag to add multiple developers; duplicates between the\n    body field and CLI flags are dropped silently. The reporter\n    credit(s) from the *Reporter credited as* field are always\n    emitted with `type: \"finder\"`.\n  - `--vendor` \u002F `--product` \u002F `--package-name` \u002F `--collection-url` —\n    override the product identity fields. The defaults come from the\n    project's TOML config (`product.vendor`, `product.default_product`,\n    `product.default_package_name`, `product.default_collection_url`).\n    They are used as the identity for *Affected versions* lines that\n    don't start with a recognisable per-package directory name\n    (see the multi-product note below).\n  - `--product-for PACKAGE=PRODUCT` — override the CVE product display\n    name for a specific `packageName`. Repeat to override multiple\n    packages. Useful when a package is not in the project's\n    `project_display_map` config, or when an acronym needs different\n    casing from the title-cased fallback. Example:\n    `--product-for apache-foo-project-baz='Apache Foo Project Baz'`.\n  - `--org-id \u003Cuuid>` — override the CNA assigner org id (defaults to\n    the ASF org id).\n  - `--discovery \u003Cword>` — override `source.discovery` (default\n    `\"UNKNOWN\"`; valid CVE 5.x values include `UNKNOWN`, `INTERNAL`,\n    `EXTERNAL`, `USER`).\n  - `--no-envelope` — emit only the inner `cna` container instead of\n    the full CVE 5.x record (envelope is the default).\n  - `--review` \u002F `--draft` (mutually exclusive) — force the emitted\n    `CNA_private.state` to `REVIEW` or `DRAFT` regardless of the\n    tracker's labels. Useful in two cases:\n    - `--review` lets a release manager nudge a record forward by\n      hand when the `rc voting` label is not yet set on the tracker.\n    - `--draft` walks a record back when an RC vote was cancelled or\n      failed and the label is still around.\n    Both flags only matter when release-vote gating is enabled in\n    the project's TOML config (see below); otherwise the state is\n    derived from the CNA's readiness alone and these flags have no\n    effect beyond what the legacy logic produces.\n  - `--attach` — after generating the JSON, embed it at the end of\n    the tracking issue's **body** (after the *CVE tool link* field),\n    wrapped in a collapsible `\u003Cdetails>` block. The block is bracketed\n    by HTML-comment markers\n    (``\u003C!-- generate-cve-json: cve=CVE-YYYY-NNNN+ version=v1 -->`` …\n    ``\u003C!-- generate-cve-json:end cve=CVE-YYYY-NNNN+ version=v1 -->``)\n    that the script uses on later runs to find the existing block and\n    **replace it in place**, so re-runs update the embedded attachment\n    instead of duplicating it or breaking other body fields. The\n    attachment lives in the body — not as a comment — so it stays\n    above every status-change comment in the timeline (effectively\n    \"pinned\" without needing any pin mechanism). Requires the\n    positional issue argument; incompatible with `--stdin`.\n\n---\n\n## Prerequisites on the tracking issue\n\nFor the generated JSON to be useful, the issue body should already be\nfilled in through a prior `security-issue-sync` run. In particular:\n\n- **Short public summary for publish** — becomes the CVE description.\n- **Affected versions** — becomes the CVE `affected[]` list. The script\n  understands the common version-expression shapes (`\u003C 3.2.2`,\n  `>= 2.0.0, \u003C 3.2.2`, `\u003C= 3.2.1`, a bare version like `3.1.5`, and a\n  bare lower bound like `>= 2.0.0`).\n  **Multi-product CVEs are supported** — put one package per line,\n  prefixing each with the package directory name as it appears in\n  the adopter's repo, and the script emits one `affected[]` entry\n  per line with the right `product` \u002F `packageName`. Example\n  (illustrative — using a hypothetical `apache-foo` project's\n  sub-project layout):\n\n      apache-foo-project-alpha \u003C=6.5.0\n      apache-foo-project-beta \u003C=1.9.0\n\n  Known package directory names are resolved to the vendor-preferred\n  display casing via the project's `packages.project_display_map`\n  config table; unknown packages fall back to title-cased dash-split\n  and can be overridden with `--product-for`. A line without a\n  package prefix (or a single-line field) falls back to the\n  `--product` \u002F `--package-name` defaults, which preserves the\n  single-product behaviour.\n\n  **`\u003C NEXT VERSION` placeholder** — multi-package trackers don't\n  know which package version will ship the fix until the wave's\n  release manager picks it during a release cut. Until then, the\n  *Affected versions* lines use the literal token `NEXT VERSION` as\n  the upper bound, e.g.:\n\n      apache-foo-project-alpha \u003C NEXT VERSION\n      apache-foo-project-beta \u003C NEXT VERSION\n\n  The generator strips `\u003C NEXT VERSION` before parsing each line and\n  emits a `versions[]` entry without `lessThan` (open-ended upper\n  bound — *\"affected from \\\u003Clow\\> onwards, no fix released yet\"*).\n  When the wave ships and the version is known, the\n  `security-issue-sync` skill replaces each `NEXT VERSION` with the\n  actual `\u003C X.Y.Z` and the next regen produces a fully-bounded entry.\n  Case-insensitive; combines with a lower bound (e.g.\n  `>= 2.0.0, \u003C NEXT VERSION` becomes `{version: \"2.0.0\", status: \"affected\"}`).\n- **Security mailing list thread** — internal navigation reference\n  only; the script **does not** export URLs from this field into\n  `references[]`. Keep whatever the reporter or triager put there.\n- **Public advisory URL** — each URL in this field is extracted and\n  added to `references[]` with `tags: [\"vendor-advisory\"]`. Populated\n  by the release manager (or the `security-issue-sync` skill) once\n  the advisory is archived on `\u003Cusers-list>`. The\n  `--advisory-url` CLI flag still exists for ad-hoc overrides.\n- **PR with the fix** — each URL in this field becomes a reference URL.\n  **Multiple URLs are supported**: paste them on separate lines, as a\n  bullet list, or comma-separated — the script extracts every\n  `https?:\u002F\u002F…` token it finds.\n- **Reporter credited as** — each line becomes one CVE credit entry\n  with `type: \"finder\"`. **Multiple credits are supported**: put each\n  person on their own line. `Full Name, Affiliation` on a single line\n  is treated as **one** credit, not two, so the common\n  `Jed Cunningham, Astronomer` pattern works as expected. Bullets\n  (`- `, `* `, `1. `) are stripped. Blank lines are ignored. If you\n  need to credit many people::\n\n      Jed Cunningham\n      Saurabh Banawar\n      selen (Huntr bounty 3e88d364-5047-4768-a52c-6568f21ef35b)\n\n- **Remediation developer** — each line becomes one CVE credit entry\n  with `type: \"remediation developer\"`. Same parsing rules as\n  *Reporter credited as* (newline-separated, `Full Name, Affiliation`\n  is one credit, bullets stripped). Auto-populated by the\n  `security-issue-sync` skill from the linked PR's author the first\n  time *PR with the fix* is set; manual edits survive subsequent\n  syncs (the skill only proposes appending names that aren't already\n  there). The `--remediation-developer` CLI flag adds further names\n  on top of whatever the body already lists.\n\n> **Bot \u002F AI credit policy.** This generator is intentionally\n> neutral on credit content: whatever a tracker's *Reporter credited\n> as* or *Remediation developer* field carries is what lands in\n> `credits[]`. The filtering of obvious bot \u002F AI accounts (e.g.\n> `dependabot[bot]`, `*-scanner`, `automated-*`) happens **upstream\n> in the skills** at extraction time — see\n> [`bot-credits-policy.md`](..\u002Fbot-credits-policy.md) for the\n> detection rule and the per-skill enforcement sites. Keeping the\n> filter upstream means an intentional human override (typed\n> directly into the field) survives every JSON regeneration without\n> needing a special bypass flag here.\n\n- **CWE** — `CWE-285: Improper Authorization` style works; so does a bare\n  `CWE-285` or a plain sentence. The script extracts the `CWE-\\d+` token\n  for the `cweId` field and uses the rest as the human-readable\n  description.\n- **Severity** — `None`, `Low`, `Medium`, `High`, `Critical`\n  (case-insensitive) are emitted as the text content of a `metrics[].other`\n  block. Vulnogram lets you replace this with a CVSS vector in its form if\n  you want a numeric score.\n- **CVE tool link** — the ASF CVE tool URL, e.g.\n  `https:\u002F\u002Fcveprocess.apache.org\u002Fcve5\u002FCVE-2026-40913`. The script extracts\n  the `CVE-YYYY-NNNN+` token from this field. If the field is still\n  `_No response_`, pass the CVE ID with `--cve-id`.\n\nIf one of these fields is missing, the JSON still generates, but the\nreviewer will need to fill the gap in Vulnogram. The skill surfaces any\nempty field in the proposal so nothing is silently skipped.\n\n---\n\n## Prerequisites\n\n- **`gh` CLI authenticated** with collaborator access to\n  `\u003Ctracker>` — the script reads the tracker via `gh`.\n- **`uv` installed** — the script is a small `uv`-managed Python\n  project and is invoked as `uv run --project\n  tools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json \u003CN>`.\n\nSee\n[Prerequisites for running the agent skills](..\u002F..\u002F..\u002Fdocs\u002Fprerequisites.md#prerequisites-for-running-the-agent-skills)\nin `README.md`.\n\n---\n\n## Step 0 — Pre-flight check\n\nBefore reading the tracker:\n\n1. `gh api repos\u002F\u003Ctracker> --jq .name` returns the adopter's\n   tracker repo name (per `\u003Cproject-config>\u002Fproject.md`), **and**\n2. `uv --version` returns.\n\nIf either fails, stop and tell the user what to install or log\nin to.\n\n---\n\n## Step 1 — Verify the issue has the required fields\n\nFetch the issue body and check every template field the script reads. If\na field is missing or still `_No response_`, either run\n[`security-issue-sync`](..\u002F..\u002F..\u002Fskills\u002Fsecurity-issue-sync\u002FSKILL.md) first to fill it\nin, or override it on the command line.\n\n```bash\ngh issue view \u003CN> --repo \u003Ctracker> --json body --jq .body \\\n  | grep -E '^###|^_No response_'\n```\n\nAsk the user whether to proceed if any critical field is empty\n(description, affected versions, CVE tool link, credits). Do not silently\ngenerate a JSON with placeholder values.\n\n---\n\n## Step 2 — Run the generator\n\nRun the project's console script through `uv run --project`, which\nprepares the (cached) virtualenv on first use and reuses it on later\nruns:\n\n```bash\nuv run --project \u003Cframework>\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json \u003CN> \\\n  --output \u002Ftmp\u002F\u003CCVE-ID>.json \\\n  --version-start \u003Cearliest-affected-version>\n```\n\n`--version-start` is the one flag the tracking issue body almost never\ncontains and that Vulnogram expects filled in (the body field usually\nencodes only the upper bound). The remediation developer credit comes\nfrom the body's *Remediation developer* field, populated by the\n`security-issue-sync` skill from the linked PR's author — no CLI flag\nneeded in the normal flow. For a fix that landed in `3.2.2` and was\nfirst introduced in `3.0.0`, for example:\n\n```bash\nuv run --project \u003Cframework>\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json 232 \\\n  --output \u002Ftmp\u002FCVE-2026-40913.json \\\n  --version-start 3.0.0\n```\n\nPass `--remediation-developer \"Name\"` only when you need to add a\ndeveloper credit on top of (or in place of) what the body already\ncontains — for example a co-author who didn't end up as the PR's\nGitHub author.\n\nAdditional flags, all optional:\n\n- `--cve-id CVE-YYYY-NNNN+` — override the CVE ID if the *CVE tool link*\n  field is empty.\n- `--title \"\u003Cvendor>: \u003Cproduct>: …\"` — override the title.\n- `--vendor` \u002F `--product` \u002F `--package-name` \u002F `--collection-url` —\n  override product identity (defaults sourced from the project's TOML\n  config under `[product]`).\n- `--org-id \u003Cuuid>` — override the CNA assigner org id (defaults to the\n  ASF org id).\n- `--discovery UNKNOWN|INTERNAL|EXTERNAL|USER` — override\n  `source.discovery`.\n- `--no-envelope` — emit only the `cna` container (no `cveMetadata`,\n  no `dataType`\u002F`dataVersion` wrapper). Use this if Vulnogram's `#source`\n  tab is in \"inner block only\" mode.\n- `--stdin` — read the issue body from stdin instead of calling `gh`.\n  Useful for offline iteration and for drafting by hand.\n\nThe script is deterministic — re-running it with the same flags and the\nsame tracking-issue body produces the same JSON bytes.\n\n### Output shape (in brief)\n\nThe generated record matches what Vulnogram exports after a save,\nminus editor cruft. Notable fields:\n\n- `containers.cna.affected[]` — `vendor`, `product`, `collectionURL`,\n  `packageName` and a `versions[]` entry with `version`, `lessThan`,\n  `status: \"affected\"`, `versionType: \"semver\"`.\n- `containers.cna.descriptions[]` — both a plain `value` and an HTML\n  `supportingMedia` alternative (Vulnogram's WYSIWYG mode needs both).\n- `containers.cna.problemTypes[].descriptions[]` — `cweId`,\n  human-readable `description`, `type: \"CWE\"`.\n- `containers.cna.metrics[].other` — `type: \"Textual description of\n  severity\"` and `content.text` = the severity word.\n- `containers.cna.credits[]` — one entry per *Reporter credited as*\n  line (type `\"finder\"`), plus one entry per *Remediation developer*\n  body line and per `--remediation-developer` CLI override (type\n  `\"remediation developer\"`); duplicates between the body field and\n  CLI flags are dropped silently.\n- `containers.cna.references[]` — URLs with auto-tagged `tags`:\n  - GitHub `pull\u002F` or `commit\u002F` URLs → `[\"patch\"]`;\n  - `lists.apache.org` \u002F `security.apache.org` → `[\"vendor-advisory\"]`;\n  - everything else → no tag.\n- `containers.cna.source.discovery` — `\"UNKNOWN\"` by default.\n- `containers.cna.providerMetadata.orgId` — ASF assigner org id.\n- `cveMetadata` — `assignerOrgId`, `cveId`, `serial`, `state: \"PUBLISHED\"`.\n\n---\n\n## Step 3 — Surface the output to the user\n\nAfter the script finishes, print these three things in order:\n\n1. **The output file path**, with a one-line `cat` suggestion so the user\n   can review the JSON in the terminal:\n\n       ```\n       Wrote \u002Ftmp\u002Fcve-CVE-2026-40913.json\n       cat \u002Ftmp\u002Fcve-CVE-2026-40913.json\n       ```\n\n2. **A clipboard-copy command** appropriate to the user's platform. On\n   Linux with `xclip` installed:\n\n       ```\n       xclip -selection clipboard \u003C \u002Ftmp\u002Fcve-CVE-2026-40913.json\n       ```\n\n   On Wayland: `wl-copy \u003C \u002Ftmp\u002Fcve-...json`. On macOS: `pbcopy \u003C …`. If\n   `xclip` \u002F `wl-copy` \u002F `pbcopy` is not on PATH, skip the clipboard\n   command and tell the user to copy manually.\n\n3. **The Vulnogram `#source` paste URL**, as a clickable link rendered per\n   the \"Linking CVEs\" rule in [`AGENTS.md`](..\u002F..\u002F..\u002FAGENTS.md):\n\n       ```\n       Paste the JSON into the Vulnogram #source tab:\n         [CVE-2026-40913](https:\u002F\u002Fcveprocess.apache.org\u002Fcve5\u002FCVE-2026-40913#source)\n       ```\n\nThe #source tab on the ASF CVE tool is the direct \"paste raw JSON\" view of\nthe Vulnogram form. The page loads the current record, you paste the\nscript output over the top, click Save, and the form view reflects the\nnew values.\n\n### Optional: `--attach` to embed (or refresh) the JSON in the issue body\n\nIf the user also wants the JSON *attached* to the tracking issue itself\n(so it is discoverable from the issue without needing the local file),\nadd `--attach` to the invocation:\n\n```bash\nuv run --project \u003Cframework>\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json 232 \\\n  --output \u002Ftmp\u002FCVE-2026-40913.json \\\n  --version-start 3.0.0 \\\n  --attach\n```\n\nWhat `--attach` does:\n\n- After generating the JSON (exactly the same bytes as without `--attach`),\n  edits the tracking **issue's body** to embed the full JSON inside a\n  four-backtick fenced code block, collapsed behind a `\u003Cdetails>`\n  disclosure so long records don't bloat the issue view. The block is\n  appended *after* the existing template fields, right after the\n  *CVE tool link* field, so it lives at the end of the body.\n- Brackets the attachment with a pair of hidden HTML-comment markers\n  (``\u003C!-- generate-cve-json: cve=CVE-YYYY-NNNN+ version=v1 -->`` …\n  ``\u003C!-- generate-cve-json:end cve=CVE-YYYY-NNNN+ version=v1 -->``) so\n  subsequent runs can find the existing embedded block and **replace it\n  in place**, without spawning duplicates and without touching any\n  other text in the body.\n- Re-running with `--attach` is safe and idempotent: same issue body →\n  same JSON → the script patches the body, leaving you with one and only\n  one embedded attachment per CVE id. If the current body already\n  matches what the script would write, the PATCH is skipped entirely\n  (no no-op timestamp on the issue).\n- The script prints `Embedded CVE JSON in issue body on\n  \u003Ctracker>#NNN` on first run and `Replaced CVE JSON in\n  issue body on \u003Ctracker>#NNN` on subsequent runs, followed\n  by a URL that deep-links to the `## CVE JSON — paste-ready for …`\n  heading anchor inside the body.\n\n**Why embedded in the body and not as a comment?** Two reasons:\n\n1. **Natural \"pinning\" without an API for it.** GitHub has no\n   pin-comment API. A separate comment ends up buried below every\n   status-change comment — so a newcomer looking at the issue sees a\n   long comment timeline with no obvious way to find the CVE JSON.\n   The issue body always renders *above* the entire comment timeline,\n   so anything embedded in the body is effectively pinned.\n2. **One place to read the tracker.** The reporter-template fields,\n   the CVE metadata, and the paste-ready JSON are all in one place —\n   no hunting through the timeline to reconstruct the current state.\n\n(GitHub also does not expose its `user-attachments` file-upload\npipeline to the REST API — only the web UI drag-and-drop uses it — so\na real file attachment isn't available to automation anyway. Embedding\nas body text is the closest automatable equivalent and is directly\nvisible without a download round-trip.)\n\n**Confidentiality.** The embedded block lives inside the private repo,\nso it inherits the repo-wide confidentiality rules. Linking CVE\nreferences inside the block follows the \"Linking CVEs\" rule in\n[`AGENTS.md`](..\u002F..\u002F..\u002FAGENTS.md): before publication the block links\nthe ASF CVE tool; after publication, re-running the script includes a\n`cve.org` link as well.\n\n---\n\n## Step 4 — Propose an issue comment recording the update\n\nPer the \"Keeping the reporter informed\" rule in\n[`README.md`](..\u002F..\u002F..\u002FREADME.md), any status change on an issue must be\nrecorded in an issue comment. Pasting a new version of the CVE record is\na status change. Propose (and, on confirmation, post) a short comment\nlike:\n\n> **CVE entry regenerated from the tracking issue** — generated paste-ready\n> JSON for [`CVE-2026-40913`](https:\u002F\u002Fcveprocess.apache.org\u002Fcve5\u002FCVE-2026-40913)\n> from the current body fields (description, affected versions `\u003C 3.2.2`,\n> CWE-285, Low severity, N credits, M references). Pasted into the\n> Vulnogram `#source` tab; the record is now in sync with the tracking\n> issue.\n\nInclude a count of credits and references so a later reviewer can\nsanity-check that nothing was dropped.\n\n---\n\n## Step 5 — Never edit the JSON in place after pasting\n\nOnce the JSON has been pasted into Vulnogram and saved, **do not** edit\nthe local JSON file to match tool-side changes. Re-run the script instead\n(it is deterministic — you will get a clean baseline), diff the new\noutput against the current Vulnogram state, and paste the merged JSON\nback. This keeps the tracking issue as the single source of truth: if\nVulnogram shows something different from the generated JSON, either the\nissue body is out of date and needs a `security-issue-sync` run, or the\ntool-side difference is intentional and the reviewer will keep it.\n\n---\n\n## Guardrails\n\n- **Confidentiality.** The script deliberately **drops** any URL that\n  points at `cveprocess.apache.org` or the project's `\u003Ctracker>` repo\n  from the references list before serialising. Those URLs are private\n  ASF-internal links and should not appear in a published CVE record.\n  See the \"Confidentiality of `\u003Ctracker>`\" section of\n  [`AGENTS.md`](..\u002F..\u002F..\u002FAGENTS.md).\n- **CVE IDs are always linked** per the \"Linking CVEs\" rule in\n  [`AGENTS.md`](..\u002F..\u002F..\u002FAGENTS.md). When the skill mentions the CVE in\n  proposals, recaps or comments on the `\u003Ctracker>` issue, it must\n  render the ID as a markdown link — before publication to the ASF\n  CVE tool, and additionally to `cve.org` after publication.\n- **`\u003Ctracker>` references are always linked** per the \"Linking\n  `\u003Ctracker>` issues and PRs\" rule in\n  [`AGENTS.md`](..\u002F..\u002F..\u002FAGENTS.md). When the skill mentions the\n  tracking issue in its own comments, render it as a markdown link.\n- **Deterministic output is a feature.** Do not introduce timestamps,\n  random UUIDs, ordering dependencies on dict iteration, or other sources\n  of non-determinism into the script. If you need to add a new field,\n  make sure the output still hashes the same across runs on the same\n  input.\n- **Multi-entry fields.** Credits are split on **newlines only** to\n  preserve the `Full Name, Affiliation` pattern. References are extracted\n  from URL tokens in the field value. Do not reintroduce comma-splitting\n  on credits.\n- **No envelope means no metadata.** `--no-envelope` drops the\n  `cveMetadata` block which includes the CVE ID; the JSON is pure CNA\n  content. Make sure the user knows they will have to set the CVE ID by\n  hand in Vulnogram in that mode.\n\n---\n\n## References\n\n- [`AGENTS.md`](..\u002F..\u002F..\u002FAGENTS.md) — repo-wide conventions (confidentiality,\n  Linking CVEs, Linking `\u003Ctracker>` issues and PRs, release-branch\n  defaults).\n- [`README.md`](..\u002F..\u002F..\u002FREADME.md) — handling process, in particular\n  step 13 (fill in CVE tool fields and send advisory from the tool)\n  and step 15 (paste the attached JSON into Vulnogram's #source tab,\n  move the CVE to PUBLIC, close the issue).\n- [`security-issue-sync`](..\u002F..\u002F..\u002Fskills\u002Fsecurity-issue-sync\u002FSKILL.md) — the sibling\n  skill that populates the tracking issue fields this skill consumes.\n- [`security-issue-fix`](..\u002F..\u002F..\u002Fskills\u002Fsecurity-issue-fix\u002FSKILL.md) — the other\n  sibling skill that opens a public PR and updates the tracking issue\n  with the fix URL.\n",{"data":40,"body":42},{"name":4,"description":6,"when_to_use":41},"Invoke when a security team member says \"generate CVE JSON for NNN\",\n\"update the CVE tool entry for NNN\", \"paste-ready CVE for NNN\", or is\nabout to publish the advisory for a tracking issue and wants the CVE\nrecord filled in from the issue body in one paste-and-save step. Not\nappropriate before the CVE has been allocated (the script needs a CVE\nID either from the issue body's `CVE tool link` field or from a\n`--cve-id` override).\n",{"type":43,"children":44},"root",[45,52,82,127,145,163,237,290,300,304,311,781,784,790,802,1289,1363,1501,1506,1509,1515,1577,1596,1599,1605,1610,1648,1653,1656,1662,1685,1814,1819,1822,1828,1841,1978,2018,2102,2114,2119,2276,2281,2288,2293,2642,2645,2651,2656,2751,2756,2769,2788,2882,2894,3002,3012,3042,3055,3083,3086,3092,3108,3147,3152,3155,3161,3180,3183,3189,3363,3366,3372,3436],{"type":46,"tag":47,"props":48,"children":49},"element","h1",{"id":4},[50],{"type":51,"value":4},"text",{"type":46,"tag":53,"props":54,"children":55},"p",{},[56,58,72,74,80],{"type":51,"value":57},"This skill produces a CVE 5.x JSON document from a tracking issue in\n",{"type":46,"tag":59,"props":60,"children":64},"a",{"href":61,"rel":62},"https:\u002F\u002Fgithub.com\u002F%3Ctracker%3E",[63],"nofollow",[65],{"type":46,"tag":66,"props":67,"children":69},"code",{"className":68},[],[70],{"type":51,"value":71},"\u003Ctracker>",{"type":51,"value":73},", ready to\npaste into the Vulnogram ",{"type":46,"tag":75,"props":76,"children":77},"strong",{},[78],{"type":51,"value":79},"\"#source\"",{"type":51,"value":81}," tab of the ASF CVE tool. The goal is\nto eliminate the manual \"copy each field from the issue into the right\nVulnogram form input\" step when you are preparing to publish an advisory.",{"type":46,"tag":83,"props":84,"children":85},"blockquote",{},[86],{"type":46,"tag":53,"props":87,"children":88},{},[89,94,96,102,104,110,112,117,119,125],{"type":46,"tag":75,"props":90,"children":91},{},[92],{"type":51,"value":93},"Project-agnostic by design.",{"type":51,"value":95}," All project-specific values\n(vendor, top-level product \u002F package name, project display map,\nCNA org id, generator tag, …) are loaded from a TOML config the\nadopting project ships at ",{"type":46,"tag":66,"props":97,"children":99},{"className":98},[],[100],{"type":51,"value":101},"\u003Cproject-config>\u002Ftools\u002Fcve-tool-vulnogram\u002Fcve-json-config.toml",{"type":51,"value":103},".\nConcrete ",{"type":46,"tag":66,"props":105,"children":107},{"className":106},[],[108],{"type":51,"value":109},"apache-foo-project-*",{"type":51,"value":111}," strings appearing in this\ndocument are ",{"type":46,"tag":75,"props":113,"children":114},{},[115],{"type":51,"value":116},"illustrative examples",{"type":51,"value":118}," of how a project with a\nproject-style package layout would configure things; replace\nthem mentally with the adopter's own package taxonomy. The\nschema is documented in the package ",{"type":46,"tag":59,"props":120,"children":122},{"href":121},"README.md",[123],{"type":51,"value":124},"README",{"type":51,"value":126},".",{"type":46,"tag":53,"props":128,"children":129},{},[130,135,137,143],{"type":46,"tag":75,"props":131,"children":132},{},[133],{"type":51,"value":134},"Golden rule:",{"type":51,"value":136}," the script generates a ",{"type":46,"tag":138,"props":139,"children":140},"em",{},[141],{"type":51,"value":142},"proposal",{"type":51,"value":144}," JSON document. It\nparses a handful of structured fields from the issue body, but it cannot\nread the security team member's mind. Always review the generated JSON\nbefore pasting, and always do the final review inside Vulnogram before\nmoving the CVE from DRAFT → REVIEW → READY → PUBLIC.",{"type":46,"tag":53,"props":146,"children":147},{},[148,153,155,161],{"type":46,"tag":75,"props":149,"children":150},{},[151],{"type":51,"value":152},"Release-vote gating (opt-in, recommended for ASF projects).",{"type":51,"value":154}," The\nemitted ",{"type":46,"tag":66,"props":156,"children":158},{"className":157},[],[159],{"type":51,"value":160},"CNA_private.state",{"type":51,"value":162}," follows a tri-state state machine:",{"type":46,"tag":164,"props":165,"children":166},"ul",{},[167,186,212],{"type":46,"tag":168,"props":169,"children":170},"li",{},[171,177,179,184],{"type":46,"tag":66,"props":172,"children":174},{"className":173},[],[175],{"type":51,"value":176},"DRAFT",{"type":51,"value":178}," — the CNA is incomplete ",{"type":46,"tag":138,"props":180,"children":181},{},[182],{"type":51,"value":183},"or",{"type":51,"value":185}," the project has opted into\nrelease-vote gating and no vote is in progress yet.",{"type":46,"tag":168,"props":187,"children":188},{},[189,195,197,202,204,210],{"type":46,"tag":66,"props":190,"children":192},{"className":191},[],[193],{"type":51,"value":194},"REVIEW",{"type":51,"value":196}," — the CNA is review-ready (CVE ID + title + description +\naffected versions + CWE + severity + ≥ 1 credit + ≥ 1 reference)\n",{"type":46,"tag":138,"props":198,"children":199},{},[200],{"type":51,"value":201},"and",{"type":51,"value":203}," either the project hasn't opted into gating (legacy: ready ⇒\nREVIEW) or an RC vote is in progress (signalled by the configured\ntracker label or a ",{"type":46,"tag":66,"props":205,"children":207},{"className":206},[],[208],{"type":51,"value":209},"--review",{"type":51,"value":211}," CLI flag).",{"type":46,"tag":168,"props":213,"children":214},{},[215,221,223,227,229,235],{"type":46,"tag":66,"props":216,"children":218},{"className":217},[],[219],{"type":51,"value":220},"PUBLIC",{"type":51,"value":222}," — the CNA is review-ready ",{"type":46,"tag":138,"props":224,"children":225},{},[226],{"type":51,"value":201},{"type":51,"value":228}," the public advisory has\nshipped (a ",{"type":46,"tag":66,"props":230,"children":232},{"className":231},[],[233],{"type":51,"value":234},"vendor-advisory",{"type":51,"value":236}," reference is present).",{"type":46,"tag":53,"props":238,"children":239},{},[240,242,248,250,256,258,264,266,272,274,280,282,288],{"type":51,"value":241},"Projects opt into gating by setting ",{"type":46,"tag":66,"props":243,"children":245},{"className":244},[],[246],{"type":51,"value":247},"[workflow].release_vote_gating = true",{"type":51,"value":249}," in their ",{"type":46,"tag":66,"props":251,"children":253},{"className":252},[],[254],{"type":51,"value":255},"cve-json-config.toml",{"type":51,"value":257}," and choosing the label name\nvia ",{"type":46,"tag":66,"props":259,"children":261},{"className":260},[],[262],{"type":51,"value":263},"[workflow].rc_voting_label",{"type":51,"value":265}," (default ",{"type":46,"tag":66,"props":267,"children":269},{"className":268},[],[270],{"type":51,"value":271},"\"rc voting\"",{"type":51,"value":273},"). The sync\nskill is responsible for detecting ",{"type":46,"tag":275,"props":276,"children":277},"span",{},[278],{"type":51,"value":279},"VOTE",{"type":51,"value":281}," threads on the project's\ndev list (e.g. ",{"type":46,"tag":66,"props":283,"children":285},{"className":284},[],[286],{"type":51,"value":287},"dev@\u003Cproject>.apache.org",{"type":51,"value":289},") and proposing the label\nadd\u002Fremove; the generator only reads the label on the tracker. Non-\nASF adopters who publish advisories without a separate release-vote\nstep typically leave gating off — the legacy \"ready ⇒ REVIEW\"\nbehaviour is the right default for that workflow.",{"type":46,"tag":53,"props":291,"children":292},{},[293,298],{"type":46,"tag":75,"props":294,"children":295},{},[296],{"type":51,"value":297},"Determinism:",{"type":51,"value":299}," the same input issue body produces exactly the same JSON\nbytes on every run. The script uses only the Python standard library, has\nno timestamps or machine-dependent values in its output, sorts JSON keys,\nand sorts references alphabetically. This lets you paste the result into\nVulnogram, tweak fields in the tool, re-run the script later, and cleanly\ndiff the two to see what the tool has added \u002F what you changed by hand.",{"type":46,"tag":301,"props":302,"children":303},"hr",{},[],{"type":46,"tag":305,"props":306,"children":308},"h2",{"id":307},"inputs",[309],{"type":51,"value":310},"Inputs",{"type":46,"tag":164,"props":312,"children":313},{},[314,331],{"type":46,"tag":168,"props":315,"children":316},{},[317,322,324,330],{"type":46,"tag":75,"props":318,"children":319},{},[320],{"type":51,"value":321},"Issue number",{"type":51,"value":323}," (required) — e.g. ",{"type":46,"tag":66,"props":325,"children":327},{"className":326},[],[328],{"type":51,"value":329},"232",{"type":51,"value":126},{"type":46,"tag":168,"props":332,"children":333},{},[334,336],{"type":51,"value":335},"Optional CLI overrides:\n",{"type":46,"tag":164,"props":337,"children":338},{},[339,358,377,411,459,530,564,575,631,650,719],{"type":46,"tag":168,"props":340,"children":341},{},[342,348,350,356],{"type":46,"tag":66,"props":343,"children":345},{"className":344},[],[346],{"type":51,"value":347},"--cve-id CVE-YYYY-NNNN+",{"type":51,"value":349}," — override the CVE ID if the issue body's\n",{"type":46,"tag":66,"props":351,"children":353},{"className":352},[],[354],{"type":51,"value":355},"CVE tool link",{"type":51,"value":357}," field has not yet been filled in, or retarget the\nJSON to a different CVE ID.",{"type":46,"tag":168,"props":359,"children":360},{},[361,367,369,375],{"type":46,"tag":66,"props":362,"children":364},{"className":363},[],[365],{"type":51,"value":366},"--title \"\u003Cvendor>: \u003Cproduct>: …\"",{"type":51,"value":368}," — override the CVE title.\nDefault is the GitHub issue title with the project's\n",{"type":46,"tag":66,"props":370,"children":372},{"className":371},[],[373],{"type":51,"value":374},"\u003Cvendor>: \u003Cproduct>:",{"type":51,"value":376}," prefix (sourced from the TOML config) when\nit does not already start with that phrase.",{"type":46,"tag":168,"props":378,"children":379},{},[380,386,388,394,396,402,404,410],{"type":46,"tag":66,"props":381,"children":383},{"className":382},[],[384],{"type":51,"value":385},"--version-start X.Y.Z",{"type":51,"value":387}," — override the start of the affected version\nrange (the ",{"type":46,"tag":66,"props":389,"children":391},{"className":390},[],[392],{"type":51,"value":393},"affected[].versions[].version",{"type":51,"value":395}," field). Default is the\nlower bound parsed from the Affected versions field when it uses\n",{"type":46,"tag":66,"props":397,"children":399},{"className":398},[],[400],{"type":51,"value":401},">= X, \u003C Y",{"type":51,"value":403}," syntax, otherwise ",{"type":46,"tag":66,"props":405,"children":407},{"className":406},[],[408],{"type":51,"value":409},"\"0\"",{"type":51,"value":126},{"type":46,"tag":168,"props":412,"children":413},{},[414,420,422,428,430,435,437,443,445,450,452,458],{"type":46,"tag":66,"props":415,"children":417},{"className":416},[],[418],{"type":51,"value":419},"--remediation-developer \"Name\"",{"type":51,"value":421}," — append a ",{"type":46,"tag":66,"props":423,"children":425},{"className":424},[],[426],{"type":51,"value":427},"type: \"remediation developer\"",{"type":51,"value":429}," credit on top of whatever the body's ",{"type":46,"tag":138,"props":431,"children":432},{},[433],{"type":51,"value":434},"Remediation\ndeveloper",{"type":51,"value":436}," field already lists (auto-populated by the\n",{"type":46,"tag":66,"props":438,"children":440},{"className":439},[],[441],{"type":51,"value":442},"security-issue-sync",{"type":51,"value":444}," skill from the linked PR's author). Repeat\nthe flag to add multiple developers; duplicates between the\nbody field and CLI flags are dropped silently. The reporter\ncredit(s) from the ",{"type":46,"tag":138,"props":446,"children":447},{},[448],{"type":51,"value":449},"Reporter credited as",{"type":51,"value":451}," field are always\nemitted with ",{"type":46,"tag":66,"props":453,"children":455},{"className":454},[],[456],{"type":51,"value":457},"type: \"finder\"",{"type":51,"value":126},{"type":46,"tag":168,"props":460,"children":461},{},[462,468,470,476,477,483,484,490,492,498,500,506,508,514,515,521,523,528],{"type":46,"tag":66,"props":463,"children":465},{"className":464},[],[466],{"type":51,"value":467},"--vendor",{"type":51,"value":469}," \u002F ",{"type":46,"tag":66,"props":471,"children":473},{"className":472},[],[474],{"type":51,"value":475},"--product",{"type":51,"value":469},{"type":46,"tag":66,"props":478,"children":480},{"className":479},[],[481],{"type":51,"value":482},"--package-name",{"type":51,"value":469},{"type":46,"tag":66,"props":485,"children":487},{"className":486},[],[488],{"type":51,"value":489},"--collection-url",{"type":51,"value":491}," —\noverride the product identity fields. The defaults come from the\nproject's TOML config (",{"type":46,"tag":66,"props":493,"children":495},{"className":494},[],[496],{"type":51,"value":497},"product.vendor",{"type":51,"value":499},", ",{"type":46,"tag":66,"props":501,"children":503},{"className":502},[],[504],{"type":51,"value":505},"product.default_product",{"type":51,"value":507},",\n",{"type":46,"tag":66,"props":509,"children":511},{"className":510},[],[512],{"type":51,"value":513},"product.default_package_name",{"type":51,"value":499},{"type":46,"tag":66,"props":516,"children":518},{"className":517},[],[519],{"type":51,"value":520},"product.default_collection_url",{"type":51,"value":522},").\nThey are used as the identity for ",{"type":46,"tag":138,"props":524,"children":525},{},[526],{"type":51,"value":527},"Affected versions",{"type":51,"value":529}," lines that\ndon't start with a recognisable per-package directory name\n(see the multi-product note below).",{"type":46,"tag":168,"props":531,"children":532},{},[533,539,541,547,549,555,557,563],{"type":46,"tag":66,"props":534,"children":536},{"className":535},[],[537],{"type":51,"value":538},"--product-for PACKAGE=PRODUCT",{"type":51,"value":540}," — override the CVE product display\nname for a specific ",{"type":46,"tag":66,"props":542,"children":544},{"className":543},[],[545],{"type":51,"value":546},"packageName",{"type":51,"value":548},". Repeat to override multiple\npackages. Useful when a package is not in the project's\n",{"type":46,"tag":66,"props":550,"children":552},{"className":551},[],[553],{"type":51,"value":554},"project_display_map",{"type":51,"value":556}," config, or when an acronym needs different\ncasing from the title-cased fallback. Example:\n",{"type":46,"tag":66,"props":558,"children":560},{"className":559},[],[561],{"type":51,"value":562},"--product-for apache-foo-project-baz='Apache Foo Project Baz'",{"type":51,"value":126},{"type":46,"tag":168,"props":565,"children":566},{},[567,573],{"type":46,"tag":66,"props":568,"children":570},{"className":569},[],[571],{"type":51,"value":572},"--org-id \u003Cuuid>",{"type":51,"value":574}," — override the CNA assigner org id (defaults to\nthe ASF org id).",{"type":46,"tag":168,"props":576,"children":577},{},[578,584,586,592,594,600,602,608,609,615,616,622,623,629],{"type":46,"tag":66,"props":579,"children":581},{"className":580},[],[582],{"type":51,"value":583},"--discovery \u003Cword>",{"type":51,"value":585}," — override ",{"type":46,"tag":66,"props":587,"children":589},{"className":588},[],[590],{"type":51,"value":591},"source.discovery",{"type":51,"value":593}," (default\n",{"type":46,"tag":66,"props":595,"children":597},{"className":596},[],[598],{"type":51,"value":599},"\"UNKNOWN\"",{"type":51,"value":601},"; valid CVE 5.x values include ",{"type":46,"tag":66,"props":603,"children":605},{"className":604},[],[606],{"type":51,"value":607},"UNKNOWN",{"type":51,"value":499},{"type":46,"tag":66,"props":610,"children":612},{"className":611},[],[613],{"type":51,"value":614},"INTERNAL",{"type":51,"value":507},{"type":46,"tag":66,"props":617,"children":619},{"className":618},[],[620],{"type":51,"value":621},"EXTERNAL",{"type":51,"value":499},{"type":46,"tag":66,"props":624,"children":626},{"className":625},[],[627],{"type":51,"value":628},"USER",{"type":51,"value":630},").",{"type":46,"tag":168,"props":632,"children":633},{},[634,640,642,648],{"type":46,"tag":66,"props":635,"children":637},{"className":636},[],[638],{"type":51,"value":639},"--no-envelope",{"type":51,"value":641}," — emit only the inner ",{"type":46,"tag":66,"props":643,"children":645},{"className":644},[],[646],{"type":51,"value":647},"cna",{"type":51,"value":649}," container instead of\nthe full CVE 5.x record (envelope is the default).",{"type":46,"tag":168,"props":651,"children":652},{},[653,658,659,665,667,672,674,679,681,686,688],{"type":46,"tag":66,"props":654,"children":656},{"className":655},[],[657],{"type":51,"value":209},{"type":51,"value":469},{"type":46,"tag":66,"props":660,"children":662},{"className":661},[],[663],{"type":51,"value":664},"--draft",{"type":51,"value":666}," (mutually exclusive) — force the emitted\n",{"type":46,"tag":66,"props":668,"children":670},{"className":669},[],[671],{"type":51,"value":160},{"type":51,"value":673}," to ",{"type":46,"tag":66,"props":675,"children":677},{"className":676},[],[678],{"type":51,"value":194},{"type":51,"value":680}," or ",{"type":46,"tag":66,"props":682,"children":684},{"className":683},[],[685],{"type":51,"value":176},{"type":51,"value":687}," regardless of the\ntracker's labels. Useful in two cases:\n",{"type":46,"tag":164,"props":689,"children":690},{},[691,709],{"type":46,"tag":168,"props":692,"children":693},{},[694,699,701,707],{"type":46,"tag":66,"props":695,"children":697},{"className":696},[],[698],{"type":51,"value":209},{"type":51,"value":700}," lets a release manager nudge a record forward by\nhand when the ",{"type":46,"tag":66,"props":702,"children":704},{"className":703},[],[705],{"type":51,"value":706},"rc voting",{"type":51,"value":708}," label is not yet set on the tracker.",{"type":46,"tag":168,"props":710,"children":711},{},[712,717],{"type":46,"tag":66,"props":713,"children":715},{"className":714},[],[716],{"type":51,"value":664},{"type":51,"value":718}," walks a record back when an RC vote was cancelled or\nfailed and the label is still around.\nBoth flags only matter when release-vote gating is enabled in\nthe project's TOML config (see below); otherwise the state is\nderived from the CNA's readiness alone and these flags have no\neffect beyond what the legacy logic produces.",{"type":46,"tag":168,"props":720,"children":721},{},[722,728,730,735,737,741,743,749,751,757,759,765,767,772,774,780],{"type":46,"tag":66,"props":723,"children":725},{"className":724},[],[726],{"type":51,"value":727},"--attach",{"type":51,"value":729}," — after generating the JSON, embed it at the end of\nthe tracking issue's ",{"type":46,"tag":75,"props":731,"children":732},{},[733],{"type":51,"value":734},"body",{"type":51,"value":736}," (after the ",{"type":46,"tag":138,"props":738,"children":739},{},[740],{"type":51,"value":355},{"type":51,"value":742}," field),\nwrapped in a collapsible ",{"type":46,"tag":66,"props":744,"children":746},{"className":745},[],[747],{"type":51,"value":748},"\u003Cdetails>",{"type":51,"value":750}," block. The block is bracketed\nby HTML-comment markers\n(",{"type":46,"tag":66,"props":752,"children":754},{"className":753},[],[755],{"type":51,"value":756},"\u003C!-- generate-cve-json: cve=CVE-YYYY-NNNN+ version=v1 -->",{"type":51,"value":758}," …\n",{"type":46,"tag":66,"props":760,"children":762},{"className":761},[],[763],{"type":51,"value":764},"\u003C!-- generate-cve-json:end cve=CVE-YYYY-NNNN+ version=v1 -->",{"type":51,"value":766},")\nthat the script uses on later runs to find the existing block and\n",{"type":46,"tag":75,"props":768,"children":769},{},[770],{"type":51,"value":771},"replace it in place",{"type":51,"value":773},", so re-runs update the embedded attachment\ninstead of duplicating it or breaking other body fields. The\nattachment lives in the body — not as a comment — so it stays\nabove every status-change comment in the timeline (effectively\n\"pinned\" without needing any pin mechanism). Requires the\npositional issue argument; incompatible with ",{"type":46,"tag":66,"props":775,"children":777},{"className":776},[],[778],{"type":51,"value":779},"--stdin",{"type":51,"value":126},{"type":46,"tag":301,"props":782,"children":783},{},[],{"type":46,"tag":305,"props":785,"children":787},{"id":786},"prerequisites-on-the-tracking-issue",[788],{"type":51,"value":789},"Prerequisites on the tracking issue",{"type":46,"tag":53,"props":791,"children":792},{},[793,795,800],{"type":51,"value":794},"For the generated JSON to be useful, the issue body should already be\nfilled in through a prior ",{"type":46,"tag":66,"props":796,"children":798},{"className":797},[],[799],{"type":51,"value":442},{"type":51,"value":801}," run. In particular:",{"type":46,"tag":164,"props":803,"children":804},{},[805,815,1064,1089,1137,1162,1239],{"type":46,"tag":168,"props":806,"children":807},{},[808,813],{"type":46,"tag":75,"props":809,"children":810},{},[811],{"type":51,"value":812},"Short public summary for publish",{"type":51,"value":814}," — becomes the CVE description.",{"type":46,"tag":168,"props":816,"children":817},{},[818,822,824,830,832,838,839,845,846,852,854,860,862,868,870,875,877,882,884,890,891,896,898,904,906,918,922,924,930,932,938,940,945,946,951,953,956,967,969,973,975,981,983,992,995,997,1002,1004,1010,1012,1018,1020,1025,1027,1032,1034,1039,1041,1047,1049,1055,1057,1063],{"type":46,"tag":75,"props":819,"children":820},{},[821],{"type":51,"value":527},{"type":51,"value":823}," — becomes the CVE ",{"type":46,"tag":66,"props":825,"children":827},{"className":826},[],[828],{"type":51,"value":829},"affected[]",{"type":51,"value":831}," list. The script\nunderstands the common version-expression shapes (",{"type":46,"tag":66,"props":833,"children":835},{"className":834},[],[836],{"type":51,"value":837},"\u003C 3.2.2",{"type":51,"value":507},{"type":46,"tag":66,"props":840,"children":842},{"className":841},[],[843],{"type":51,"value":844},">= 2.0.0, \u003C 3.2.2",{"type":51,"value":499},{"type":46,"tag":66,"props":847,"children":849},{"className":848},[],[850],{"type":51,"value":851},"\u003C= 3.2.1",{"type":51,"value":853},", a bare version like ",{"type":46,"tag":66,"props":855,"children":857},{"className":856},[],[858],{"type":51,"value":859},"3.1.5",{"type":51,"value":861},", and a\nbare lower bound like ",{"type":46,"tag":66,"props":863,"children":865},{"className":864},[],[866],{"type":51,"value":867},">= 2.0.0",{"type":51,"value":869},").\n",{"type":46,"tag":75,"props":871,"children":872},{},[873],{"type":51,"value":874},"Multi-product CVEs are supported",{"type":51,"value":876}," — put one package per line,\nprefixing each with the package directory name as it appears in\nthe adopter's repo, and the script emits one ",{"type":46,"tag":66,"props":878,"children":880},{"className":879},[],[881],{"type":51,"value":829},{"type":51,"value":883}," entry\nper line with the right ",{"type":46,"tag":66,"props":885,"children":887},{"className":886},[],[888],{"type":51,"value":889},"product",{"type":51,"value":469},{"type":46,"tag":66,"props":892,"children":894},{"className":893},[],[895],{"type":51,"value":546},{"type":51,"value":897},". Example\n(illustrative — using a hypothetical ",{"type":46,"tag":66,"props":899,"children":901},{"className":900},[],[902],{"type":51,"value":903},"apache-foo",{"type":51,"value":905}," project's\nsub-project layout):",{"type":46,"tag":907,"props":908,"children":912},"pre",{"className":909,"code":911,"language":51},[910],"language-text","apache-foo-project-alpha \u003C=6.5.0\napache-foo-project-beta \u003C=1.9.0\n",[913],{"type":46,"tag":66,"props":914,"children":916},{"__ignoreMap":915},"",[917],{"type":51,"value":911},{"type":46,"tag":919,"props":920,"children":921},"br",{},[],{"type":51,"value":923},"Known package directory names are resolved to the vendor-preferred\ndisplay casing via the project's ",{"type":46,"tag":66,"props":925,"children":927},{"className":926},[],[928],{"type":51,"value":929},"packages.project_display_map",{"type":51,"value":931},"\nconfig table; unknown packages fall back to title-cased dash-split\nand can be overridden with ",{"type":46,"tag":66,"props":933,"children":935},{"className":934},[],[936],{"type":51,"value":937},"--product-for",{"type":51,"value":939},". A line without a\npackage prefix (or a single-line field) falls back to the\n",{"type":46,"tag":66,"props":941,"children":943},{"className":942},[],[944],{"type":51,"value":475},{"type":51,"value":469},{"type":46,"tag":66,"props":947,"children":949},{"className":948},[],[950],{"type":51,"value":482},{"type":51,"value":952}," defaults, which preserves the\nsingle-product behaviour.",{"type":46,"tag":919,"props":954,"children":955},{},[],{"type":46,"tag":75,"props":957,"children":958},{},[959,965],{"type":46,"tag":66,"props":960,"children":962},{"className":961},[],[963],{"type":51,"value":964},"\u003C NEXT VERSION",{"type":51,"value":966}," placeholder",{"type":51,"value":968}," — multi-package trackers don't\nknow which package version will ship the fix until the wave's\nrelease manager picks it during a release cut. Until then, the\n",{"type":46,"tag":138,"props":970,"children":971},{},[972],{"type":51,"value":527},{"type":51,"value":974}," lines use the literal token ",{"type":46,"tag":66,"props":976,"children":978},{"className":977},[],[979],{"type":51,"value":980},"NEXT VERSION",{"type":51,"value":982}," as\nthe upper bound, e.g.:",{"type":46,"tag":907,"props":984,"children":987},{"className":985,"code":986,"language":51},[910],"apache-foo-project-alpha \u003C NEXT VERSION\napache-foo-project-beta \u003C NEXT VERSION\n",[988],{"type":46,"tag":66,"props":989,"children":990},{"__ignoreMap":915},[991],{"type":51,"value":986},{"type":46,"tag":919,"props":993,"children":994},{},[],{"type":51,"value":996},"The generator strips ",{"type":46,"tag":66,"props":998,"children":1000},{"className":999},[],[1001],{"type":51,"value":964},{"type":51,"value":1003}," before parsing each line and\nemits a ",{"type":46,"tag":66,"props":1005,"children":1007},{"className":1006},[],[1008],{"type":51,"value":1009},"versions[]",{"type":51,"value":1011}," entry without ",{"type":46,"tag":66,"props":1013,"children":1015},{"className":1014},[],[1016],{"type":51,"value":1017},"lessThan",{"type":51,"value":1019}," (open-ended upper\nbound — ",{"type":46,"tag":138,"props":1021,"children":1022},{},[1023],{"type":51,"value":1024},"\"affected from \u003Clow> onwards, no fix released yet\"",{"type":51,"value":1026},").\nWhen the wave ships and the version is known, the\n",{"type":46,"tag":66,"props":1028,"children":1030},{"className":1029},[],[1031],{"type":51,"value":442},{"type":51,"value":1033}," skill replaces each ",{"type":46,"tag":66,"props":1035,"children":1037},{"className":1036},[],[1038],{"type":51,"value":980},{"type":51,"value":1040}," with the\nactual ",{"type":46,"tag":66,"props":1042,"children":1044},{"className":1043},[],[1045],{"type":51,"value":1046},"\u003C X.Y.Z",{"type":51,"value":1048}," and the next regen produces a fully-bounded entry.\nCase-insensitive; combines with a lower bound (e.g.\n",{"type":46,"tag":66,"props":1050,"children":1052},{"className":1051},[],[1053],{"type":51,"value":1054},">= 2.0.0, \u003C NEXT VERSION",{"type":51,"value":1056}," becomes ",{"type":46,"tag":66,"props":1058,"children":1060},{"className":1059},[],[1061],{"type":51,"value":1062},"{version: \"2.0.0\", status: \"affected\"}",{"type":51,"value":630},{"type":46,"tag":168,"props":1065,"children":1066},{},[1067,1072,1074,1079,1081,1087],{"type":46,"tag":75,"props":1068,"children":1069},{},[1070],{"type":51,"value":1071},"Security mailing list thread",{"type":51,"value":1073}," — internal navigation reference\nonly; the script ",{"type":46,"tag":75,"props":1075,"children":1076},{},[1077],{"type":51,"value":1078},"does not",{"type":51,"value":1080}," export URLs from this field into\n",{"type":46,"tag":66,"props":1082,"children":1084},{"className":1083},[],[1085],{"type":51,"value":1086},"references[]",{"type":51,"value":1088},". Keep whatever the reporter or triager put there.",{"type":46,"tag":168,"props":1090,"children":1091},{},[1092,1097,1099,1104,1106,1112,1114,1119,1121,1127,1129,1135],{"type":46,"tag":75,"props":1093,"children":1094},{},[1095],{"type":51,"value":1096},"Public advisory URL",{"type":51,"value":1098}," — each URL in this field is extracted and\nadded to ",{"type":46,"tag":66,"props":1100,"children":1102},{"className":1101},[],[1103],{"type":51,"value":1086},{"type":51,"value":1105}," with ",{"type":46,"tag":66,"props":1107,"children":1109},{"className":1108},[],[1110],{"type":51,"value":1111},"tags: [\"vendor-advisory\"]",{"type":51,"value":1113},". Populated\nby the release manager (or the ",{"type":46,"tag":66,"props":1115,"children":1117},{"className":1116},[],[1118],{"type":51,"value":442},{"type":51,"value":1120}," skill) once\nthe advisory is archived on ",{"type":46,"tag":66,"props":1122,"children":1124},{"className":1123},[],[1125],{"type":51,"value":1126},"\u003Cusers-list>",{"type":51,"value":1128},". The\n",{"type":46,"tag":66,"props":1130,"children":1132},{"className":1131},[],[1133],{"type":51,"value":1134},"--advisory-url",{"type":51,"value":1136}," CLI flag still exists for ad-hoc overrides.",{"type":46,"tag":168,"props":1138,"children":1139},{},[1140,1145,1147,1152,1154,1160],{"type":46,"tag":75,"props":1141,"children":1142},{},[1143],{"type":51,"value":1144},"PR with the fix",{"type":51,"value":1146}," — each URL in this field becomes a reference URL.\n",{"type":46,"tag":75,"props":1148,"children":1149},{},[1150],{"type":51,"value":1151},"Multiple URLs are supported",{"type":51,"value":1153},": paste them on separate lines, as a\nbullet list, or comma-separated — the script extracts every\n",{"type":46,"tag":66,"props":1155,"children":1157},{"className":1156},[],[1158],{"type":51,"value":1159},"https?:\u002F\u002F…",{"type":51,"value":1161}," token it finds.",{"type":46,"tag":168,"props":1163,"children":1164},{},[1165,1169,1171,1176,1178,1183,1185,1191,1193,1198,1200,1206,1208,1214,1215,1221,1222,1228,1230],{"type":46,"tag":75,"props":1166,"children":1167},{},[1168],{"type":51,"value":449},{"type":51,"value":1170}," — each line becomes one CVE credit entry\nwith ",{"type":46,"tag":66,"props":1172,"children":1174},{"className":1173},[],[1175],{"type":51,"value":457},{"type":51,"value":1177},". ",{"type":46,"tag":75,"props":1179,"children":1180},{},[1181],{"type":51,"value":1182},"Multiple credits are supported",{"type":51,"value":1184},": put each\nperson on their own line. ",{"type":46,"tag":66,"props":1186,"children":1188},{"className":1187},[],[1189],{"type":51,"value":1190},"Full Name, Affiliation",{"type":51,"value":1192}," on a single line\nis treated as ",{"type":46,"tag":75,"props":1194,"children":1195},{},[1196],{"type":51,"value":1197},"one",{"type":51,"value":1199}," credit, not two, so the common\n",{"type":46,"tag":66,"props":1201,"children":1203},{"className":1202},[],[1204],{"type":51,"value":1205},"Jed Cunningham, Astronomer",{"type":51,"value":1207}," pattern works as expected. Bullets\n(",{"type":46,"tag":66,"props":1209,"children":1211},{"className":1210},[],[1212],{"type":51,"value":1213},"- ",{"type":51,"value":499},{"type":46,"tag":66,"props":1216,"children":1218},{"className":1217},[],[1219],{"type":51,"value":1220},"* ",{"type":51,"value":499},{"type":46,"tag":66,"props":1223,"children":1225},{"className":1224},[],[1226],{"type":51,"value":1227},"1. ",{"type":51,"value":1229},") are stripped. Blank lines are ignored. If you\nneed to credit many people::",{"type":46,"tag":907,"props":1231,"children":1234},{"className":1232,"code":1233,"language":51},[910],"Jed Cunningham\nSaurabh Banawar\nselen (Huntr bounty 3e88d364-5047-4768-a52c-6568f21ef35b)\n",[1235],{"type":46,"tag":66,"props":1236,"children":1237},{"__ignoreMap":915},[1238],{"type":51,"value":1233},{"type":46,"tag":168,"props":1240,"children":1241},{},[1242,1247,1248,1253,1255,1259,1261,1266,1268,1273,1275,1279,1281,1287],{"type":46,"tag":75,"props":1243,"children":1244},{},[1245],{"type":51,"value":1246},"Remediation developer",{"type":51,"value":1170},{"type":46,"tag":66,"props":1249,"children":1251},{"className":1250},[],[1252],{"type":51,"value":427},{"type":51,"value":1254},". Same parsing rules as\n",{"type":46,"tag":138,"props":1256,"children":1257},{},[1258],{"type":51,"value":449},{"type":51,"value":1260}," (newline-separated, ",{"type":46,"tag":66,"props":1262,"children":1264},{"className":1263},[],[1265],{"type":51,"value":1190},{"type":51,"value":1267},"\nis one credit, bullets stripped). Auto-populated by the\n",{"type":46,"tag":66,"props":1269,"children":1271},{"className":1270},[],[1272],{"type":51,"value":442},{"type":51,"value":1274}," skill from the linked PR's author the first\ntime ",{"type":46,"tag":138,"props":1276,"children":1277},{},[1278],{"type":51,"value":1144},{"type":51,"value":1280}," is set; manual edits survive subsequent\nsyncs (the skill only proposes appending names that aren't already\nthere). The ",{"type":46,"tag":66,"props":1282,"children":1284},{"className":1283},[],[1285],{"type":51,"value":1286},"--remediation-developer",{"type":51,"value":1288}," CLI flag adds further names\non top of whatever the body already lists.",{"type":46,"tag":83,"props":1290,"children":1291},{},[1292],{"type":46,"tag":53,"props":1293,"children":1294},{},[1295,1300,1302,1307,1308,1312,1314,1320,1322,1328,1329,1335,1336,1342,1344,1349,1351,1361],{"type":46,"tag":75,"props":1296,"children":1297},{},[1298],{"type":51,"value":1299},"Bot \u002F AI credit policy.",{"type":51,"value":1301}," This generator is intentionally\nneutral on credit content: whatever a tracker's ",{"type":46,"tag":138,"props":1303,"children":1304},{},[1305],{"type":51,"value":1306},"Reporter credited\nas",{"type":51,"value":680},{"type":46,"tag":138,"props":1309,"children":1310},{},[1311],{"type":51,"value":1246},{"type":51,"value":1313}," field carries is what lands in\n",{"type":46,"tag":66,"props":1315,"children":1317},{"className":1316},[],[1318],{"type":51,"value":1319},"credits[]",{"type":51,"value":1321},". The filtering of obvious bot \u002F AI accounts (e.g.\n",{"type":46,"tag":66,"props":1323,"children":1325},{"className":1324},[],[1326],{"type":51,"value":1327},"dependabot[bot]",{"type":51,"value":499},{"type":46,"tag":66,"props":1330,"children":1332},{"className":1331},[],[1333],{"type":51,"value":1334},"*-scanner",{"type":51,"value":499},{"type":46,"tag":66,"props":1337,"children":1339},{"className":1338},[],[1340],{"type":51,"value":1341},"automated-*",{"type":51,"value":1343},") happens ",{"type":46,"tag":75,"props":1345,"children":1346},{},[1347],{"type":51,"value":1348},"upstream\nin the skills",{"type":51,"value":1350}," at extraction time — see\n",{"type":46,"tag":59,"props":1352,"children":1354},{"href":1353},"..\u002Fbot-credits-policy.md",[1355],{"type":46,"tag":66,"props":1356,"children":1358},{"className":1357},[],[1359],{"type":51,"value":1360},"bot-credits-policy.md",{"type":51,"value":1362}," for the\ndetection rule and the per-skill enforcement sites. Keeping the\nfilter upstream means an intentional human override (typed\ndirectly into the field) survives every JSON regeneration without\nneeding a special bypass flag here.",{"type":46,"tag":164,"props":1364,"children":1365},{},[1366,1408,1461],{"type":46,"tag":168,"props":1367,"children":1368},{},[1369,1374,1376,1382,1384,1390,1392,1398,1400,1406],{"type":46,"tag":75,"props":1370,"children":1371},{},[1372],{"type":51,"value":1373},"CWE",{"type":51,"value":1375}," — ",{"type":46,"tag":66,"props":1377,"children":1379},{"className":1378},[],[1380],{"type":51,"value":1381},"CWE-285: Improper Authorization",{"type":51,"value":1383}," style works; so does a bare\n",{"type":46,"tag":66,"props":1385,"children":1387},{"className":1386},[],[1388],{"type":51,"value":1389},"CWE-285",{"type":51,"value":1391}," or a plain sentence. The script extracts the ",{"type":46,"tag":66,"props":1393,"children":1395},{"className":1394},[],[1396],{"type":51,"value":1397},"CWE-\\d+",{"type":51,"value":1399}," token\nfor the ",{"type":46,"tag":66,"props":1401,"children":1403},{"className":1402},[],[1404],{"type":51,"value":1405},"cweId",{"type":51,"value":1407}," field and uses the rest as the human-readable\ndescription.",{"type":46,"tag":168,"props":1409,"children":1410},{},[1411,1416,1417,1423,1424,1430,1431,1437,1438,1444,1445,1451,1453,1459],{"type":46,"tag":75,"props":1412,"children":1413},{},[1414],{"type":51,"value":1415},"Severity",{"type":51,"value":1375},{"type":46,"tag":66,"props":1418,"children":1420},{"className":1419},[],[1421],{"type":51,"value":1422},"None",{"type":51,"value":499},{"type":46,"tag":66,"props":1425,"children":1427},{"className":1426},[],[1428],{"type":51,"value":1429},"Low",{"type":51,"value":499},{"type":46,"tag":66,"props":1432,"children":1434},{"className":1433},[],[1435],{"type":51,"value":1436},"Medium",{"type":51,"value":499},{"type":46,"tag":66,"props":1439,"children":1441},{"className":1440},[],[1442],{"type":51,"value":1443},"High",{"type":51,"value":499},{"type":46,"tag":66,"props":1446,"children":1448},{"className":1447},[],[1449],{"type":51,"value":1450},"Critical",{"type":51,"value":1452},"\n(case-insensitive) are emitted as the text content of a ",{"type":46,"tag":66,"props":1454,"children":1456},{"className":1455},[],[1457],{"type":51,"value":1458},"metrics[].other",{"type":51,"value":1460},"\nblock. Vulnogram lets you replace this with a CVSS vector in its form if\nyou want a numeric score.",{"type":46,"tag":168,"props":1462,"children":1463},{},[1464,1468,1470,1476,1478,1484,1486,1492,1494,1500],{"type":46,"tag":75,"props":1465,"children":1466},{},[1467],{"type":51,"value":355},{"type":51,"value":1469}," — the ASF CVE tool URL, e.g.\n",{"type":46,"tag":66,"props":1471,"children":1473},{"className":1472},[],[1474],{"type":51,"value":1475},"https:\u002F\u002Fcveprocess.apache.org\u002Fcve5\u002FCVE-2026-40913",{"type":51,"value":1477},". The script extracts\nthe ",{"type":46,"tag":66,"props":1479,"children":1481},{"className":1480},[],[1482],{"type":51,"value":1483},"CVE-YYYY-NNNN+",{"type":51,"value":1485}," token from this field. If the field is still\n",{"type":46,"tag":66,"props":1487,"children":1489},{"className":1488},[],[1490],{"type":51,"value":1491},"_No response_",{"type":51,"value":1493},", pass the CVE ID with ",{"type":46,"tag":66,"props":1495,"children":1497},{"className":1496},[],[1498],{"type":51,"value":1499},"--cve-id",{"type":51,"value":126},{"type":46,"tag":53,"props":1502,"children":1503},{},[1504],{"type":51,"value":1505},"If one of these fields is missing, the JSON still generates, but the\nreviewer will need to fill the gap in Vulnogram. The skill surfaces any\nempty field in the proposal so nothing is silently skipped.",{"type":46,"tag":301,"props":1507,"children":1508},{},[],{"type":46,"tag":305,"props":1510,"children":1512},{"id":1511},"prerequisites",[1513],{"type":51,"value":1514},"Prerequisites",{"type":46,"tag":164,"props":1516,"children":1517},{},[1518,1547],{"type":46,"tag":168,"props":1519,"children":1520},{},[1521,1532,1534,1539,1541,1546],{"type":46,"tag":75,"props":1522,"children":1523},{},[1524,1530],{"type":46,"tag":66,"props":1525,"children":1527},{"className":1526},[],[1528],{"type":51,"value":1529},"gh",{"type":51,"value":1531}," CLI authenticated",{"type":51,"value":1533}," with collaborator access to\n",{"type":46,"tag":66,"props":1535,"children":1537},{"className":1536},[],[1538],{"type":51,"value":71},{"type":51,"value":1540}," — the script reads the tracker via ",{"type":46,"tag":66,"props":1542,"children":1544},{"className":1543},[],[1545],{"type":51,"value":1529},{"type":51,"value":126},{"type":46,"tag":168,"props":1548,"children":1549},{},[1550,1561,1563,1568,1570,1576],{"type":46,"tag":75,"props":1551,"children":1552},{},[1553,1559],{"type":46,"tag":66,"props":1554,"children":1556},{"className":1555},[],[1557],{"type":51,"value":1558},"uv",{"type":51,"value":1560}," installed",{"type":51,"value":1562}," — the script is a small ",{"type":46,"tag":66,"props":1564,"children":1566},{"className":1565},[],[1567],{"type":51,"value":1558},{"type":51,"value":1569},"-managed Python\nproject and is invoked as ",{"type":46,"tag":66,"props":1571,"children":1573},{"className":1572},[],[1574],{"type":51,"value":1575},"uv run --project tools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json \u003CN>",{"type":51,"value":126},{"type":46,"tag":53,"props":1578,"children":1579},{},[1580,1582,1588,1590,1595],{"type":51,"value":1581},"See\n",{"type":46,"tag":59,"props":1583,"children":1585},{"href":1584},"..\u002F..\u002F..\u002Fdocs\u002Fprerequisites.md#prerequisites-for-running-the-agent-skills",[1586],{"type":51,"value":1587},"Prerequisites for running the agent skills",{"type":51,"value":1589},"\nin ",{"type":46,"tag":66,"props":1591,"children":1593},{"className":1592},[],[1594],{"type":51,"value":121},{"type":51,"value":126},{"type":46,"tag":301,"props":1597,"children":1598},{},[],{"type":46,"tag":305,"props":1600,"children":1602},{"id":1601},"step-0-pre-flight-check",[1603],{"type":51,"value":1604},"Step 0 — Pre-flight check",{"type":46,"tag":53,"props":1606,"children":1607},{},[1608],{"type":51,"value":1609},"Before reading the tracker:",{"type":46,"tag":1611,"props":1612,"children":1613},"ol",{},[1614,1637],{"type":46,"tag":168,"props":1615,"children":1616},{},[1617,1623,1625,1631,1633],{"type":46,"tag":66,"props":1618,"children":1620},{"className":1619},[],[1621],{"type":51,"value":1622},"gh api repos\u002F\u003Ctracker> --jq .name",{"type":51,"value":1624}," returns the adopter's\ntracker repo name (per ",{"type":46,"tag":66,"props":1626,"children":1628},{"className":1627},[],[1629],{"type":51,"value":1630},"\u003Cproject-config>\u002Fproject.md",{"type":51,"value":1632},"), ",{"type":46,"tag":75,"props":1634,"children":1635},{},[1636],{"type":51,"value":201},{"type":46,"tag":168,"props":1638,"children":1639},{},[1640,1646],{"type":46,"tag":66,"props":1641,"children":1643},{"className":1642},[],[1644],{"type":51,"value":1645},"uv --version",{"type":51,"value":1647}," returns.",{"type":46,"tag":53,"props":1649,"children":1650},{},[1651],{"type":51,"value":1652},"If either fails, stop and tell the user what to install or log\nin to.",{"type":46,"tag":301,"props":1654,"children":1655},{},[],{"type":46,"tag":305,"props":1657,"children":1659},{"id":1658},"step-1-verify-the-issue-has-the-required-fields",[1660],{"type":51,"value":1661},"Step 1 — Verify the issue has the required fields",{"type":46,"tag":53,"props":1663,"children":1664},{},[1665,1667,1672,1674,1683],{"type":51,"value":1666},"Fetch the issue body and check every template field the script reads. If\na field is missing or still ",{"type":46,"tag":66,"props":1668,"children":1670},{"className":1669},[],[1671],{"type":51,"value":1491},{"type":51,"value":1673},", either run\n",{"type":46,"tag":59,"props":1675,"children":1677},{"href":1676},"..\u002F..\u002F..\u002Fskills\u002Fsecurity-issue-sync\u002FSKILL.md",[1678],{"type":46,"tag":66,"props":1679,"children":1681},{"className":1680},[],[1682],{"type":51,"value":442},{"type":51,"value":1684}," first to fill it\nin, or override it on the command line.",{"type":46,"tag":907,"props":1686,"children":1690},{"className":1687,"code":1688,"language":1689,"meta":915,"style":915},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","gh issue view \u003CN> --repo \u003Ctracker> --json body --jq .body \\\n  | grep -E '^###|^_No response_'\n","bash",[1691],{"type":46,"tag":66,"props":1692,"children":1693},{"__ignoreMap":915},[1694,1780],{"type":46,"tag":275,"props":1695,"children":1698},{"class":1696,"line":1697},"line",1,[1699,1704,1710,1715,1721,1727,1732,1737,1741,1746,1751,1755,1760,1765,1770,1775],{"type":46,"tag":275,"props":1700,"children":1702},{"style":1701},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[1703],{"type":51,"value":1529},{"type":46,"tag":275,"props":1705,"children":1707},{"style":1706},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[1708],{"type":51,"value":1709}," issue",{"type":46,"tag":275,"props":1711,"children":1712},{"style":1706},[1713],{"type":51,"value":1714}," view",{"type":46,"tag":275,"props":1716,"children":1718},{"style":1717},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[1719],{"type":51,"value":1720}," \u003C",{"type":46,"tag":275,"props":1722,"children":1724},{"style":1723},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[1725],{"type":51,"value":1726},"N",{"type":46,"tag":275,"props":1728,"children":1729},{"style":1717},[1730],{"type":51,"value":1731},">",{"type":46,"tag":275,"props":1733,"children":1734},{"style":1706},[1735],{"type":51,"value":1736}," --repo",{"type":46,"tag":275,"props":1738,"children":1739},{"style":1717},[1740],{"type":51,"value":1720},{"type":46,"tag":275,"props":1742,"children":1743},{"style":1706},[1744],{"type":51,"value":1745},"tracke",{"type":46,"tag":275,"props":1747,"children":1748},{"style":1723},[1749],{"type":51,"value":1750},"r",{"type":46,"tag":275,"props":1752,"children":1753},{"style":1717},[1754],{"type":51,"value":1731},{"type":46,"tag":275,"props":1756,"children":1757},{"style":1706},[1758],{"type":51,"value":1759}," --json",{"type":46,"tag":275,"props":1761,"children":1762},{"style":1706},[1763],{"type":51,"value":1764}," body",{"type":46,"tag":275,"props":1766,"children":1767},{"style":1706},[1768],{"type":51,"value":1769}," --jq",{"type":46,"tag":275,"props":1771,"children":1772},{"style":1706},[1773],{"type":51,"value":1774}," .body",{"type":46,"tag":275,"props":1776,"children":1777},{"style":1723},[1778],{"type":51,"value":1779}," \\\n",{"type":46,"tag":275,"props":1781,"children":1783},{"class":1696,"line":1782},2,[1784,1789,1794,1799,1804,1809],{"type":46,"tag":275,"props":1785,"children":1786},{"style":1717},[1787],{"type":51,"value":1788},"  |",{"type":46,"tag":275,"props":1790,"children":1791},{"style":1701},[1792],{"type":51,"value":1793}," grep",{"type":46,"tag":275,"props":1795,"children":1796},{"style":1706},[1797],{"type":51,"value":1798}," -E",{"type":46,"tag":275,"props":1800,"children":1801},{"style":1717},[1802],{"type":51,"value":1803}," '",{"type":46,"tag":275,"props":1805,"children":1806},{"style":1706},[1807],{"type":51,"value":1808},"^###|^_No response_",{"type":46,"tag":275,"props":1810,"children":1811},{"style":1717},[1812],{"type":51,"value":1813},"'\n",{"type":46,"tag":53,"props":1815,"children":1816},{},[1817],{"type":51,"value":1818},"Ask the user whether to proceed if any critical field is empty\n(description, affected versions, CVE tool link, credits). Do not silently\ngenerate a JSON with placeholder values.",{"type":46,"tag":301,"props":1820,"children":1821},{},[],{"type":46,"tag":305,"props":1823,"children":1825},{"id":1824},"step-2-run-the-generator",[1826],{"type":51,"value":1827},"Step 2 — Run the generator",{"type":46,"tag":53,"props":1829,"children":1830},{},[1831,1833,1839],{"type":51,"value":1832},"Run the project's console script through ",{"type":46,"tag":66,"props":1834,"children":1836},{"className":1835},[],[1837],{"type":51,"value":1838},"uv run --project",{"type":51,"value":1840},", which\nprepares the (cached) virtualenv on first use and reuses it on later\nruns:",{"type":46,"tag":907,"props":1842,"children":1844},{"className":1687,"code":1843,"language":1689,"meta":915,"style":915},"uv run --project \u003Cframework>\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json \u003CN> \\\n  --output \u002Ftmp\u002F\u003CCVE-ID>.json \\\n  --version-start \u003Cearliest-affected-version>\n",[1845],{"type":46,"tag":66,"props":1846,"children":1847},{"__ignoreMap":915},[1848,1909,1950],{"type":46,"tag":275,"props":1849,"children":1850},{"class":1696,"line":1697},[1851,1855,1860,1865,1869,1874,1879,1883,1888,1893,1897,1901,1905],{"type":46,"tag":275,"props":1852,"children":1853},{"style":1701},[1854],{"type":51,"value":1558},{"type":46,"tag":275,"props":1856,"children":1857},{"style":1706},[1858],{"type":51,"value":1859}," run",{"type":46,"tag":275,"props":1861,"children":1862},{"style":1706},[1863],{"type":51,"value":1864}," --project",{"type":46,"tag":275,"props":1866,"children":1867},{"style":1717},[1868],{"type":51,"value":1720},{"type":46,"tag":275,"props":1870,"children":1871},{"style":1706},[1872],{"type":51,"value":1873},"framewor",{"type":46,"tag":275,"props":1875,"children":1876},{"style":1723},[1877],{"type":51,"value":1878},"k",{"type":46,"tag":275,"props":1880,"children":1881},{"style":1717},[1882],{"type":51,"value":1731},{"type":46,"tag":275,"props":1884,"children":1885},{"style":1706},[1886],{"type":51,"value":1887},"\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json",{"type":46,"tag":275,"props":1889,"children":1890},{"style":1706},[1891],{"type":51,"value":1892}," generate-cve-json",{"type":46,"tag":275,"props":1894,"children":1895},{"style":1717},[1896],{"type":51,"value":1720},{"type":46,"tag":275,"props":1898,"children":1899},{"style":1723},[1900],{"type":51,"value":1726},{"type":46,"tag":275,"props":1902,"children":1903},{"style":1717},[1904],{"type":51,"value":1731},{"type":46,"tag":275,"props":1906,"children":1907},{"style":1723},[1908],{"type":51,"value":1779},{"type":46,"tag":275,"props":1910,"children":1911},{"class":1696,"line":1782},[1912,1917,1922,1927,1932,1937,1941,1946],{"type":46,"tag":275,"props":1913,"children":1914},{"style":1706},[1915],{"type":51,"value":1916},"  --output",{"type":46,"tag":275,"props":1918,"children":1919},{"style":1706},[1920],{"type":51,"value":1921}," \u002Ftmp\u002F",{"type":46,"tag":275,"props":1923,"children":1924},{"style":1717},[1925],{"type":51,"value":1926},"\u003C",{"type":46,"tag":275,"props":1928,"children":1929},{"style":1706},[1930],{"type":51,"value":1931},"CVE-I",{"type":46,"tag":275,"props":1933,"children":1934},{"style":1723},[1935],{"type":51,"value":1936},"D",{"type":46,"tag":275,"props":1938,"children":1939},{"style":1717},[1940],{"type":51,"value":1731},{"type":46,"tag":275,"props":1942,"children":1943},{"style":1706},[1944],{"type":51,"value":1945},".json",{"type":46,"tag":275,"props":1947,"children":1948},{"style":1723},[1949],{"type":51,"value":1779},{"type":46,"tag":275,"props":1951,"children":1953},{"class":1696,"line":1952},3,[1954,1959,1963,1968,1973],{"type":46,"tag":275,"props":1955,"children":1956},{"style":1706},[1957],{"type":51,"value":1958},"  --version-start",{"type":46,"tag":275,"props":1960,"children":1961},{"style":1717},[1962],{"type":51,"value":1720},{"type":46,"tag":275,"props":1964,"children":1965},{"style":1706},[1966],{"type":51,"value":1967},"earliest-affected-versio",{"type":46,"tag":275,"props":1969,"children":1970},{"style":1723},[1971],{"type":51,"value":1972},"n",{"type":46,"tag":275,"props":1974,"children":1975},{"style":1717},[1976],{"type":51,"value":1977},">\n",{"type":46,"tag":53,"props":1979,"children":1980},{},[1981,1987,1989,1993,1995,2000,2002,2008,2010,2016],{"type":46,"tag":66,"props":1982,"children":1984},{"className":1983},[],[1985],{"type":51,"value":1986},"--version-start",{"type":51,"value":1988}," is the one flag the tracking issue body almost never\ncontains and that Vulnogram expects filled in (the body field usually\nencodes only the upper bound). The remediation developer credit comes\nfrom the body's ",{"type":46,"tag":138,"props":1990,"children":1991},{},[1992],{"type":51,"value":1246},{"type":51,"value":1994}," field, populated by the\n",{"type":46,"tag":66,"props":1996,"children":1998},{"className":1997},[],[1999],{"type":51,"value":442},{"type":51,"value":2001}," skill from the linked PR's author — no CLI flag\nneeded in the normal flow. For a fix that landed in ",{"type":46,"tag":66,"props":2003,"children":2005},{"className":2004},[],[2006],{"type":51,"value":2007},"3.2.2",{"type":51,"value":2009}," and was\nfirst introduced in ",{"type":46,"tag":66,"props":2011,"children":2013},{"className":2012},[],[2014],{"type":51,"value":2015},"3.0.0",{"type":51,"value":2017},", for example:",{"type":46,"tag":907,"props":2019,"children":2021},{"className":1687,"code":2020,"language":1689,"meta":915,"style":915},"uv run --project \u003Cframework>\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json 232 \\\n  --output \u002Ftmp\u002FCVE-2026-40913.json \\\n  --version-start 3.0.0\n",[2022],{"type":46,"tag":66,"props":2023,"children":2024},{"__ignoreMap":915},[2025,2074,2090],{"type":46,"tag":275,"props":2026,"children":2027},{"class":1696,"line":1697},[2028,2032,2036,2040,2044,2048,2052,2056,2060,2064,2070],{"type":46,"tag":275,"props":2029,"children":2030},{"style":1701},[2031],{"type":51,"value":1558},{"type":46,"tag":275,"props":2033,"children":2034},{"style":1706},[2035],{"type":51,"value":1859},{"type":46,"tag":275,"props":2037,"children":2038},{"style":1706},[2039],{"type":51,"value":1864},{"type":46,"tag":275,"props":2041,"children":2042},{"style":1717},[2043],{"type":51,"value":1720},{"type":46,"tag":275,"props":2045,"children":2046},{"style":1706},[2047],{"type":51,"value":1873},{"type":46,"tag":275,"props":2049,"children":2050},{"style":1723},[2051],{"type":51,"value":1878},{"type":46,"tag":275,"props":2053,"children":2054},{"style":1717},[2055],{"type":51,"value":1731},{"type":46,"tag":275,"props":2057,"children":2058},{"style":1706},[2059],{"type":51,"value":1887},{"type":46,"tag":275,"props":2061,"children":2062},{"style":1706},[2063],{"type":51,"value":1892},{"type":46,"tag":275,"props":2065,"children":2067},{"style":2066},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[2068],{"type":51,"value":2069}," 232",{"type":46,"tag":275,"props":2071,"children":2072},{"style":1723},[2073],{"type":51,"value":1779},{"type":46,"tag":275,"props":2075,"children":2076},{"class":1696,"line":1782},[2077,2081,2086],{"type":46,"tag":275,"props":2078,"children":2079},{"style":1706},[2080],{"type":51,"value":1916},{"type":46,"tag":275,"props":2082,"children":2083},{"style":1706},[2084],{"type":51,"value":2085}," \u002Ftmp\u002FCVE-2026-40913.json",{"type":46,"tag":275,"props":2087,"children":2088},{"style":1723},[2089],{"type":51,"value":1779},{"type":46,"tag":275,"props":2091,"children":2092},{"class":1696,"line":1952},[2093,2097],{"type":46,"tag":275,"props":2094,"children":2095},{"style":1706},[2096],{"type":51,"value":1958},{"type":46,"tag":275,"props":2098,"children":2099},{"style":2066},[2100],{"type":51,"value":2101}," 3.0.0\n",{"type":46,"tag":53,"props":2103,"children":2104},{},[2105,2107,2112],{"type":51,"value":2106},"Pass ",{"type":46,"tag":66,"props":2108,"children":2110},{"className":2109},[],[2111],{"type":51,"value":419},{"type":51,"value":2113}," only when you need to add a\ndeveloper credit on top of (or in place of) what the body already\ncontains — for example a co-author who didn't end up as the PR's\nGitHub author.",{"type":46,"tag":53,"props":2115,"children":2116},{},[2117],{"type":51,"value":2118},"Additional flags, all optional:",{"type":46,"tag":164,"props":2120,"children":2121},{},[2122,2138,2148,2183,2193,2210,2259],{"type":46,"tag":168,"props":2123,"children":2124},{},[2125,2130,2132,2136],{"type":46,"tag":66,"props":2126,"children":2128},{"className":2127},[],[2129],{"type":51,"value":347},{"type":51,"value":2131}," — override the CVE ID if the ",{"type":46,"tag":138,"props":2133,"children":2134},{},[2135],{"type":51,"value":355},{"type":51,"value":2137},"\nfield is empty.",{"type":46,"tag":168,"props":2139,"children":2140},{},[2141,2146],{"type":46,"tag":66,"props":2142,"children":2144},{"className":2143},[],[2145],{"type":51,"value":366},{"type":51,"value":2147}," — override the title.",{"type":46,"tag":168,"props":2149,"children":2150},{},[2151,2156,2157,2162,2163,2168,2169,2174,2176,2182],{"type":46,"tag":66,"props":2152,"children":2154},{"className":2153},[],[2155],{"type":51,"value":467},{"type":51,"value":469},{"type":46,"tag":66,"props":2158,"children":2160},{"className":2159},[],[2161],{"type":51,"value":475},{"type":51,"value":469},{"type":46,"tag":66,"props":2164,"children":2166},{"className":2165},[],[2167],{"type":51,"value":482},{"type":51,"value":469},{"type":46,"tag":66,"props":2170,"children":2172},{"className":2171},[],[2173],{"type":51,"value":489},{"type":51,"value":2175}," —\noverride product identity (defaults sourced from the project's TOML\nconfig under ",{"type":46,"tag":66,"props":2177,"children":2179},{"className":2178},[],[2180],{"type":51,"value":2181},"[product]",{"type":51,"value":630},{"type":46,"tag":168,"props":2184,"children":2185},{},[2186,2191],{"type":46,"tag":66,"props":2187,"children":2189},{"className":2188},[],[2190],{"type":51,"value":572},{"type":51,"value":2192}," — override the CNA assigner org id (defaults to the\nASF org id).",{"type":46,"tag":168,"props":2194,"children":2195},{},[2196,2202,2204,2209],{"type":46,"tag":66,"props":2197,"children":2199},{"className":2198},[],[2200],{"type":51,"value":2201},"--discovery UNKNOWN|INTERNAL|EXTERNAL|USER",{"type":51,"value":2203}," — override\n",{"type":46,"tag":66,"props":2205,"children":2207},{"className":2206},[],[2208],{"type":51,"value":591},{"type":51,"value":126},{"type":46,"tag":168,"props":2211,"children":2212},{},[2213,2218,2220,2225,2227,2233,2235,2241,2243,2249,2251,2257],{"type":46,"tag":66,"props":2214,"children":2216},{"className":2215},[],[2217],{"type":51,"value":639},{"type":51,"value":2219}," — emit only the ",{"type":46,"tag":66,"props":2221,"children":2223},{"className":2222},[],[2224],{"type":51,"value":647},{"type":51,"value":2226}," container (no ",{"type":46,"tag":66,"props":2228,"children":2230},{"className":2229},[],[2231],{"type":51,"value":2232},"cveMetadata",{"type":51,"value":2234},",\nno ",{"type":46,"tag":66,"props":2236,"children":2238},{"className":2237},[],[2239],{"type":51,"value":2240},"dataType",{"type":51,"value":2242},"\u002F",{"type":46,"tag":66,"props":2244,"children":2246},{"className":2245},[],[2247],{"type":51,"value":2248},"dataVersion",{"type":51,"value":2250}," wrapper). Use this if Vulnogram's ",{"type":46,"tag":66,"props":2252,"children":2254},{"className":2253},[],[2255],{"type":51,"value":2256},"#source",{"type":51,"value":2258},"\ntab is in \"inner block only\" mode.",{"type":46,"tag":168,"props":2260,"children":2261},{},[2262,2267,2269,2274],{"type":46,"tag":66,"props":2263,"children":2265},{"className":2264},[],[2266],{"type":51,"value":779},{"type":51,"value":2268}," — read the issue body from stdin instead of calling ",{"type":46,"tag":66,"props":2270,"children":2272},{"className":2271},[],[2273],{"type":51,"value":1529},{"type":51,"value":2275},".\nUseful for offline iteration and for drafting by hand.",{"type":46,"tag":53,"props":2277,"children":2278},{},[2279],{"type":51,"value":2280},"The script is deterministic — re-running it with the same flags and the\nsame tracking-issue body produces the same JSON bytes.",{"type":46,"tag":2282,"props":2283,"children":2285},"h3",{"id":2284},"output-shape-in-brief",[2286],{"type":51,"value":2287},"Output shape (in brief)",{"type":46,"tag":53,"props":2289,"children":2290},{},[2291],{"type":51,"value":2292},"The generated record matches what Vulnogram exports after a save,\nminus editor cruft. Notable fields:",{"type":46,"tag":164,"props":2294,"children":2295},{},[2296,2367,2394,2425,2451,2497,2577,2594,2605],{"type":46,"tag":168,"props":2297,"children":2298},{},[2299,2305,2306,2312,2313,2318,2319,2325,2326,2331,2333,2338,2340,2346,2347,2352,2353,2359,2360,2366],{"type":46,"tag":66,"props":2300,"children":2302},{"className":2301},[],[2303],{"type":51,"value":2304},"containers.cna.affected[]",{"type":51,"value":1375},{"type":46,"tag":66,"props":2307,"children":2309},{"className":2308},[],[2310],{"type":51,"value":2311},"vendor",{"type":51,"value":499},{"type":46,"tag":66,"props":2314,"children":2316},{"className":2315},[],[2317],{"type":51,"value":889},{"type":51,"value":499},{"type":46,"tag":66,"props":2320,"children":2322},{"className":2321},[],[2323],{"type":51,"value":2324},"collectionURL",{"type":51,"value":507},{"type":46,"tag":66,"props":2327,"children":2329},{"className":2328},[],[2330],{"type":51,"value":546},{"type":51,"value":2332}," and a ",{"type":46,"tag":66,"props":2334,"children":2336},{"className":2335},[],[2337],{"type":51,"value":1009},{"type":51,"value":2339}," entry with ",{"type":46,"tag":66,"props":2341,"children":2343},{"className":2342},[],[2344],{"type":51,"value":2345},"version",{"type":51,"value":499},{"type":46,"tag":66,"props":2348,"children":2350},{"className":2349},[],[2351],{"type":51,"value":1017},{"type":51,"value":507},{"type":46,"tag":66,"props":2354,"children":2356},{"className":2355},[],[2357],{"type":51,"value":2358},"status: \"affected\"",{"type":51,"value":499},{"type":46,"tag":66,"props":2361,"children":2363},{"className":2362},[],[2364],{"type":51,"value":2365},"versionType: \"semver\"",{"type":51,"value":126},{"type":46,"tag":168,"props":2368,"children":2369},{},[2370,2376,2378,2384,2386,2392],{"type":46,"tag":66,"props":2371,"children":2373},{"className":2372},[],[2374],{"type":51,"value":2375},"containers.cna.descriptions[]",{"type":51,"value":2377}," — both a plain ",{"type":46,"tag":66,"props":2379,"children":2381},{"className":2380},[],[2382],{"type":51,"value":2383},"value",{"type":51,"value":2385}," and an HTML\n",{"type":46,"tag":66,"props":2387,"children":2389},{"className":2388},[],[2390],{"type":51,"value":2391},"supportingMedia",{"type":51,"value":2393}," alternative (Vulnogram's WYSIWYG mode needs both).",{"type":46,"tag":168,"props":2395,"children":2396},{},[2397,2403,2404,2409,2411,2417,2418,2424],{"type":46,"tag":66,"props":2398,"children":2400},{"className":2399},[],[2401],{"type":51,"value":2402},"containers.cna.problemTypes[].descriptions[]",{"type":51,"value":1375},{"type":46,"tag":66,"props":2405,"children":2407},{"className":2406},[],[2408],{"type":51,"value":1405},{"type":51,"value":2410},",\nhuman-readable ",{"type":46,"tag":66,"props":2412,"children":2414},{"className":2413},[],[2415],{"type":51,"value":2416},"description",{"type":51,"value":499},{"type":46,"tag":66,"props":2419,"children":2421},{"className":2420},[],[2422],{"type":51,"value":2423},"type: \"CWE\"",{"type":51,"value":126},{"type":46,"tag":168,"props":2426,"children":2427},{},[2428,2434,2435,2441,2443,2449],{"type":46,"tag":66,"props":2429,"children":2431},{"className":2430},[],[2432],{"type":51,"value":2433},"containers.cna.metrics[].other",{"type":51,"value":1375},{"type":46,"tag":66,"props":2436,"children":2438},{"className":2437},[],[2439],{"type":51,"value":2440},"type: \"Textual description of severity\"",{"type":51,"value":2442}," and ",{"type":46,"tag":66,"props":2444,"children":2446},{"className":2445},[],[2447],{"type":51,"value":2448},"content.text",{"type":51,"value":2450}," = the severity word.",{"type":46,"tag":168,"props":2452,"children":2453},{},[2454,2460,2462,2466,2468,2474,2476,2480,2482,2487,2489,2495],{"type":46,"tag":66,"props":2455,"children":2457},{"className":2456},[],[2458],{"type":51,"value":2459},"containers.cna.credits[]",{"type":51,"value":2461}," — one entry per ",{"type":46,"tag":138,"props":2463,"children":2464},{},[2465],{"type":51,"value":449},{"type":51,"value":2467},"\nline (type ",{"type":46,"tag":66,"props":2469,"children":2471},{"className":2470},[],[2472],{"type":51,"value":2473},"\"finder\"",{"type":51,"value":2475},"), plus one entry per ",{"type":46,"tag":138,"props":2477,"children":2478},{},[2479],{"type":51,"value":1246},{"type":51,"value":2481},"\nbody line and per ",{"type":46,"tag":66,"props":2483,"children":2485},{"className":2484},[],[2486],{"type":51,"value":1286},{"type":51,"value":2488}," CLI override (type\n",{"type":46,"tag":66,"props":2490,"children":2492},{"className":2491},[],[2493],{"type":51,"value":2494},"\"remediation developer\"",{"type":51,"value":2496},"); duplicates between the body field and\nCLI flags are dropped silently.",{"type":46,"tag":168,"props":2498,"children":2499},{},[2500,2506,2508,2514,2516],{"type":46,"tag":66,"props":2501,"children":2503},{"className":2502},[],[2504],{"type":51,"value":2505},"containers.cna.references[]",{"type":51,"value":2507}," — URLs with auto-tagged ",{"type":46,"tag":66,"props":2509,"children":2511},{"className":2510},[],[2512],{"type":51,"value":2513},"tags",{"type":51,"value":2515},":\n",{"type":46,"tag":164,"props":2517,"children":2518},{},[2519,2547,2572],{"type":46,"tag":168,"props":2520,"children":2521},{},[2522,2524,2530,2531,2537,2539,2545],{"type":51,"value":2523},"GitHub ",{"type":46,"tag":66,"props":2525,"children":2527},{"className":2526},[],[2528],{"type":51,"value":2529},"pull\u002F",{"type":51,"value":680},{"type":46,"tag":66,"props":2532,"children":2534},{"className":2533},[],[2535],{"type":51,"value":2536},"commit\u002F",{"type":51,"value":2538}," URLs → ",{"type":46,"tag":66,"props":2540,"children":2542},{"className":2541},[],[2543],{"type":51,"value":2544},"[\"patch\"]",{"type":51,"value":2546},";",{"type":46,"tag":168,"props":2548,"children":2549},{},[2550,2556,2557,2563,2565,2571],{"type":46,"tag":66,"props":2551,"children":2553},{"className":2552},[],[2554],{"type":51,"value":2555},"lists.apache.org",{"type":51,"value":469},{"type":46,"tag":66,"props":2558,"children":2560},{"className":2559},[],[2561],{"type":51,"value":2562},"security.apache.org",{"type":51,"value":2564}," → ",{"type":46,"tag":66,"props":2566,"children":2568},{"className":2567},[],[2569],{"type":51,"value":2570},"[\"vendor-advisory\"]",{"type":51,"value":2546},{"type":46,"tag":168,"props":2573,"children":2574},{},[2575],{"type":51,"value":2576},"everything else → no tag.",{"type":46,"tag":168,"props":2578,"children":2579},{},[2580,2586,2587,2592],{"type":46,"tag":66,"props":2581,"children":2583},{"className":2582},[],[2584],{"type":51,"value":2585},"containers.cna.source.discovery",{"type":51,"value":1375},{"type":46,"tag":66,"props":2588,"children":2590},{"className":2589},[],[2591],{"type":51,"value":599},{"type":51,"value":2593}," by default.",{"type":46,"tag":168,"props":2595,"children":2596},{},[2597,2603],{"type":46,"tag":66,"props":2598,"children":2600},{"className":2599},[],[2601],{"type":51,"value":2602},"containers.cna.providerMetadata.orgId",{"type":51,"value":2604}," — ASF assigner org id.",{"type":46,"tag":168,"props":2606,"children":2607},{},[2608,2613,2614,2620,2621,2627,2628,2634,2635,2641],{"type":46,"tag":66,"props":2609,"children":2611},{"className":2610},[],[2612],{"type":51,"value":2232},{"type":51,"value":1375},{"type":46,"tag":66,"props":2615,"children":2617},{"className":2616},[],[2618],{"type":51,"value":2619},"assignerOrgId",{"type":51,"value":499},{"type":46,"tag":66,"props":2622,"children":2624},{"className":2623},[],[2625],{"type":51,"value":2626},"cveId",{"type":51,"value":499},{"type":46,"tag":66,"props":2629,"children":2631},{"className":2630},[],[2632],{"type":51,"value":2633},"serial",{"type":51,"value":499},{"type":46,"tag":66,"props":2636,"children":2638},{"className":2637},[],[2639],{"type":51,"value":2640},"state: \"PUBLISHED\"",{"type":51,"value":126},{"type":46,"tag":301,"props":2643,"children":2644},{},[],{"type":46,"tag":305,"props":2646,"children":2648},{"id":2647},"step-3-surface-the-output-to-the-user",[2649],{"type":51,"value":2650},"Step 3 — Surface the output to the user",{"type":46,"tag":53,"props":2652,"children":2653},{},[2654],{"type":51,"value":2655},"After the script finishes, print these three things in order:",{"type":46,"tag":1611,"props":2657,"children":2658},{},[2659,2686,2713],{"type":46,"tag":168,"props":2660,"children":2661},{},[2662,2667,2669,2675,2677],{"type":46,"tag":75,"props":2663,"children":2664},{},[2665],{"type":51,"value":2666},"The output file path",{"type":51,"value":2668},", with a one-line ",{"type":46,"tag":66,"props":2670,"children":2672},{"className":2671},[],[2673],{"type":51,"value":2674},"cat",{"type":51,"value":2676}," suggestion so the user\ncan review the JSON in the terminal:",{"type":46,"tag":907,"props":2678,"children":2681},{"className":2679,"code":2680,"language":51},[910],"Wrote \u002Ftmp\u002Fcve-CVE-2026-40913.json\ncat \u002Ftmp\u002Fcve-CVE-2026-40913.json\n```\n\n",[2682],{"type":46,"tag":66,"props":2683,"children":2684},{"__ignoreMap":915},[2685],{"type":51,"value":2680},{"type":46,"tag":168,"props":2687,"children":2688},{},[2689,2694,2696,2702,2704],{"type":46,"tag":75,"props":2690,"children":2691},{},[2692],{"type":51,"value":2693},"A clipboard-copy command",{"type":51,"value":2695}," appropriate to the user's platform. On\nLinux with ",{"type":46,"tag":66,"props":2697,"children":2699},{"className":2698},[],[2700],{"type":51,"value":2701},"xclip",{"type":51,"value":2703}," installed:",{"type":46,"tag":907,"props":2705,"children":2708},{"className":2706,"code":2707,"language":51},[910],"xclip -selection clipboard \u003C \u002Ftmp\u002Fcve-CVE-2026-40913.json\n```\n\nOn Wayland: `wl-copy \u003C \u002Ftmp\u002Fcve-...json`. On macOS: `pbcopy \u003C …`. If\n`xclip` \u002F `wl-copy` \u002F `pbcopy` is not on PATH, skip the clipboard\ncommand and tell the user to copy manually.\n\n",[2709],{"type":46,"tag":66,"props":2710,"children":2711},{"__ignoreMap":915},[2712],{"type":51,"value":2707},{"type":46,"tag":168,"props":2714,"children":2715},{},[2716,2728,2730,2740,2742],{"type":46,"tag":75,"props":2717,"children":2718},{},[2719,2721,2726],{"type":51,"value":2720},"The Vulnogram ",{"type":46,"tag":66,"props":2722,"children":2724},{"className":2723},[],[2725],{"type":51,"value":2256},{"type":51,"value":2727}," paste URL",{"type":51,"value":2729},", as a clickable link rendered per\nthe \"Linking CVEs\" rule in ",{"type":46,"tag":59,"props":2731,"children":2733},{"href":2732},"..\u002F..\u002F..\u002FAGENTS.md",[2734],{"type":46,"tag":66,"props":2735,"children":2737},{"className":2736},[],[2738],{"type":51,"value":2739},"AGENTS.md",{"type":51,"value":2741},":",{"type":46,"tag":907,"props":2743,"children":2746},{"className":2744,"code":2745,"language":51},[910],"Paste the JSON into the Vulnogram #source tab:\n  [CVE-2026-40913](https:\u002F\u002Fcveprocess.apache.org\u002Fcve5\u002FCVE-2026-40913#source)\n```\n",[2747],{"type":46,"tag":66,"props":2748,"children":2749},{"__ignoreMap":915},[2750],{"type":51,"value":2745},{"type":46,"tag":53,"props":2752,"children":2753},{},[2754],{"type":51,"value":2755},"The #source tab on the ASF CVE tool is the direct \"paste raw JSON\" view of\nthe Vulnogram form. The page loads the current record, you paste the\nscript output over the top, click Save, and the form view reflects the\nnew values.",{"type":46,"tag":2282,"props":2757,"children":2759},{"id":2758},"optional-attach-to-embed-or-refresh-the-json-in-the-issue-body",[2760,2762,2767],{"type":51,"value":2761},"Optional: ",{"type":46,"tag":66,"props":2763,"children":2765},{"className":2764},[],[2766],{"type":51,"value":727},{"type":51,"value":2768}," to embed (or refresh) the JSON in the issue body",{"type":46,"tag":53,"props":2770,"children":2771},{},[2772,2774,2779,2781,2786],{"type":51,"value":2773},"If the user also wants the JSON ",{"type":46,"tag":138,"props":2775,"children":2776},{},[2777],{"type":51,"value":2778},"attached",{"type":51,"value":2780}," to the tracking issue itself\n(so it is discoverable from the issue without needing the local file),\nadd ",{"type":46,"tag":66,"props":2782,"children":2784},{"className":2783},[],[2785],{"type":51,"value":727},{"type":51,"value":2787}," to the invocation:",{"type":46,"tag":907,"props":2789,"children":2791},{"className":1687,"code":2790,"language":1689,"meta":915,"style":915},"uv run --project \u003Cframework>\u002Ftools\u002Fcve-tool-vulnogram\u002Fgenerate-cve-json generate-cve-json 232 \\\n  --output \u002Ftmp\u002FCVE-2026-40913.json \\\n  --version-start 3.0.0 \\\n  --attach\n",[2792],{"type":46,"tag":66,"props":2793,"children":2794},{"__ignoreMap":915},[2795,2842,2857,2873],{"type":46,"tag":275,"props":2796,"children":2797},{"class":1696,"line":1697},[2798,2802,2806,2810,2814,2818,2822,2826,2830,2834,2838],{"type":46,"tag":275,"props":2799,"children":2800},{"style":1701},[2801],{"type":51,"value":1558},{"type":46,"tag":275,"props":2803,"children":2804},{"style":1706},[2805],{"type":51,"value":1859},{"type":46,"tag":275,"props":2807,"children":2808},{"style":1706},[2809],{"type":51,"value":1864},{"type":46,"tag":275,"props":2811,"children":2812},{"style":1717},[2813],{"type":51,"value":1720},{"type":46,"tag":275,"props":2815,"children":2816},{"style":1706},[2817],{"type":51,"value":1873},{"type":46,"tag":275,"props":2819,"children":2820},{"style":1723},[2821],{"type":51,"value":1878},{"type":46,"tag":275,"props":2823,"children":2824},{"style":1717},[2825],{"type":51,"value":1731},{"type":46,"tag":275,"props":2827,"children":2828},{"style":1706},[2829],{"type":51,"value":1887},{"type":46,"tag":275,"props":2831,"children":2832},{"style":1706},[2833],{"type":51,"value":1892},{"type":46,"tag":275,"props":2835,"children":2836},{"style":2066},[2837],{"type":51,"value":2069},{"type":46,"tag":275,"props":2839,"children":2840},{"style":1723},[2841],{"type":51,"value":1779},{"type":46,"tag":275,"props":2843,"children":2844},{"class":1696,"line":1782},[2845,2849,2853],{"type":46,"tag":275,"props":2846,"children":2847},{"style":1706},[2848],{"type":51,"value":1916},{"type":46,"tag":275,"props":2850,"children":2851},{"style":1706},[2852],{"type":51,"value":2085},{"type":46,"tag":275,"props":2854,"children":2855},{"style":1723},[2856],{"type":51,"value":1779},{"type":46,"tag":275,"props":2858,"children":2859},{"class":1696,"line":1952},[2860,2864,2869],{"type":46,"tag":275,"props":2861,"children":2862},{"style":1706},[2863],{"type":51,"value":1958},{"type":46,"tag":275,"props":2865,"children":2866},{"style":2066},[2867],{"type":51,"value":2868}," 3.0.0",{"type":46,"tag":275,"props":2870,"children":2871},{"style":1723},[2872],{"type":51,"value":1779},{"type":46,"tag":275,"props":2874,"children":2876},{"class":1696,"line":2875},4,[2877],{"type":46,"tag":275,"props":2878,"children":2879},{"style":1706},[2880],{"type":51,"value":2881},"  --attach\n",{"type":46,"tag":53,"props":2883,"children":2884},{},[2885,2887,2892],{"type":51,"value":2886},"What ",{"type":46,"tag":66,"props":2888,"children":2890},{"className":2889},[],[2891],{"type":51,"value":727},{"type":51,"value":2893}," does:",{"type":46,"tag":164,"props":2895,"children":2896},{},[2897,2936,2961,2973],{"type":46,"tag":168,"props":2898,"children":2899},{},[2900,2902,2907,2909,2914,2916,2921,2923,2928,2930,2934],{"type":51,"value":2901},"After generating the JSON (exactly the same bytes as without ",{"type":46,"tag":66,"props":2903,"children":2905},{"className":2904},[],[2906],{"type":51,"value":727},{"type":51,"value":2908},"),\nedits the tracking ",{"type":46,"tag":75,"props":2910,"children":2911},{},[2912],{"type":51,"value":2913},"issue's body",{"type":51,"value":2915}," to embed the full JSON inside a\nfour-backtick fenced code block, collapsed behind a ",{"type":46,"tag":66,"props":2917,"children":2919},{"className":2918},[],[2920],{"type":51,"value":748},{"type":51,"value":2922},"\ndisclosure so long records don't bloat the issue view. The block is\nappended ",{"type":46,"tag":138,"props":2924,"children":2925},{},[2926],{"type":51,"value":2927},"after",{"type":51,"value":2929}," the existing template fields, right after the\n",{"type":46,"tag":138,"props":2931,"children":2932},{},[2933],{"type":51,"value":355},{"type":51,"value":2935}," field, so it lives at the end of the body.",{"type":46,"tag":168,"props":2937,"children":2938},{},[2939,2941,2946,2947,2952,2954,2959],{"type":51,"value":2940},"Brackets the attachment with a pair of hidden HTML-comment markers\n(",{"type":46,"tag":66,"props":2942,"children":2944},{"className":2943},[],[2945],{"type":51,"value":756},{"type":51,"value":758},{"type":46,"tag":66,"props":2948,"children":2950},{"className":2949},[],[2951],{"type":51,"value":764},{"type":51,"value":2953},") so\nsubsequent runs can find the existing embedded block and ",{"type":46,"tag":75,"props":2955,"children":2956},{},[2957],{"type":51,"value":2958},"replace it\nin place",{"type":51,"value":2960},", without spawning duplicates and without touching any\nother text in the body.",{"type":46,"tag":168,"props":2962,"children":2963},{},[2964,2966,2971],{"type":51,"value":2965},"Re-running with ",{"type":46,"tag":66,"props":2967,"children":2969},{"className":2968},[],[2970],{"type":51,"value":727},{"type":51,"value":2972}," is safe and idempotent: same issue body →\nsame JSON → the script patches the body, leaving you with one and only\none embedded attachment per CVE id. If the current body already\nmatches what the script would write, the PATCH is skipped entirely\n(no no-op timestamp on the issue).",{"type":46,"tag":168,"props":2974,"children":2975},{},[2976,2978,2984,2986,2992,2994,3000],{"type":51,"value":2977},"The script prints ",{"type":46,"tag":66,"props":2979,"children":2981},{"className":2980},[],[2982],{"type":51,"value":2983},"Embedded CVE JSON in issue body on \u003Ctracker>#NNN",{"type":51,"value":2985}," on first run and ",{"type":46,"tag":66,"props":2987,"children":2989},{"className":2988},[],[2990],{"type":51,"value":2991},"Replaced CVE JSON in issue body on \u003Ctracker>#NNN",{"type":51,"value":2993}," on subsequent runs, followed\nby a URL that deep-links to the ",{"type":46,"tag":66,"props":2995,"children":2997},{"className":2996},[],[2998],{"type":51,"value":2999},"## CVE JSON — paste-ready for …",{"type":51,"value":3001},"\nheading anchor inside the body.",{"type":46,"tag":53,"props":3003,"children":3004},{},[3005,3010],{"type":46,"tag":75,"props":3006,"children":3007},{},[3008],{"type":51,"value":3009},"Why embedded in the body and not as a comment?",{"type":51,"value":3011}," Two reasons:",{"type":46,"tag":1611,"props":3013,"children":3014},{},[3015,3032],{"type":46,"tag":168,"props":3016,"children":3017},{},[3018,3023,3025,3030],{"type":46,"tag":75,"props":3019,"children":3020},{},[3021],{"type":51,"value":3022},"Natural \"pinning\" without an API for it.",{"type":51,"value":3024}," GitHub has no\npin-comment API. A separate comment ends up buried below every\nstatus-change comment — so a newcomer looking at the issue sees a\nlong comment timeline with no obvious way to find the CVE JSON.\nThe issue body always renders ",{"type":46,"tag":138,"props":3026,"children":3027},{},[3028],{"type":51,"value":3029},"above",{"type":51,"value":3031}," the entire comment timeline,\nso anything embedded in the body is effectively pinned.",{"type":46,"tag":168,"props":3033,"children":3034},{},[3035,3040],{"type":46,"tag":75,"props":3036,"children":3037},{},[3038],{"type":51,"value":3039},"One place to read the tracker.",{"type":51,"value":3041}," The reporter-template fields,\nthe CVE metadata, and the paste-ready JSON are all in one place —\nno hunting through the timeline to reconstruct the current state.",{"type":46,"tag":53,"props":3043,"children":3044},{},[3045,3047,3053],{"type":51,"value":3046},"(GitHub also does not expose its ",{"type":46,"tag":66,"props":3048,"children":3050},{"className":3049},[],[3051],{"type":51,"value":3052},"user-attachments",{"type":51,"value":3054}," file-upload\npipeline to the REST API — only the web UI drag-and-drop uses it — so\na real file attachment isn't available to automation anyway. Embedding\nas body text is the closest automatable equivalent and is directly\nvisible without a download round-trip.)",{"type":46,"tag":53,"props":3056,"children":3057},{},[3058,3063,3065,3073,3075,3081],{"type":46,"tag":75,"props":3059,"children":3060},{},[3061],{"type":51,"value":3062},"Confidentiality.",{"type":51,"value":3064}," The embedded block lives inside the private repo,\nso it inherits the repo-wide confidentiality rules. Linking CVE\nreferences inside the block follows the \"Linking CVEs\" rule in\n",{"type":46,"tag":59,"props":3066,"children":3067},{"href":2732},[3068],{"type":46,"tag":66,"props":3069,"children":3071},{"className":3070},[],[3072],{"type":51,"value":2739},{"type":51,"value":3074},": before publication the block links\nthe ASF CVE tool; after publication, re-running the script includes a\n",{"type":46,"tag":66,"props":3076,"children":3078},{"className":3077},[],[3079],{"type":51,"value":3080},"cve.org",{"type":51,"value":3082}," link as well.",{"type":46,"tag":301,"props":3084,"children":3085},{},[],{"type":46,"tag":305,"props":3087,"children":3089},{"id":3088},"step-4-propose-an-issue-comment-recording-the-update",[3090],{"type":51,"value":3091},"Step 4 — Propose an issue comment recording the update",{"type":46,"tag":53,"props":3093,"children":3094},{},[3095,3097,3106],{"type":51,"value":3096},"Per the \"Keeping the reporter informed\" rule in\n",{"type":46,"tag":59,"props":3098,"children":3100},{"href":3099},"..\u002F..\u002F..\u002FREADME.md",[3101],{"type":46,"tag":66,"props":3102,"children":3104},{"className":3103},[],[3105],{"type":51,"value":121},{"type":51,"value":3107},", any status change on an issue must be\nrecorded in an issue comment. Pasting a new version of the CVE record is\na status change. Propose (and, on confirmation, post) a short comment\nlike:",{"type":46,"tag":83,"props":3109,"children":3110},{},[3111],{"type":46,"tag":53,"props":3112,"children":3113},{},[3114,3119,3121,3131,3133,3138,3140,3145],{"type":46,"tag":75,"props":3115,"children":3116},{},[3117],{"type":51,"value":3118},"CVE entry regenerated from the tracking issue",{"type":51,"value":3120}," — generated paste-ready\nJSON for ",{"type":46,"tag":59,"props":3122,"children":3124},{"href":1475,"rel":3123},[63],[3125],{"type":46,"tag":66,"props":3126,"children":3128},{"className":3127},[],[3129],{"type":51,"value":3130},"CVE-2026-40913",{"type":51,"value":3132},"\nfrom the current body fields (description, affected versions ",{"type":46,"tag":66,"props":3134,"children":3136},{"className":3135},[],[3137],{"type":51,"value":837},{"type":51,"value":3139},",\nCWE-285, Low severity, N credits, M references). Pasted into the\nVulnogram ",{"type":46,"tag":66,"props":3141,"children":3143},{"className":3142},[],[3144],{"type":51,"value":2256},{"type":51,"value":3146}," tab; the record is now in sync with the tracking\nissue.",{"type":46,"tag":53,"props":3148,"children":3149},{},[3150],{"type":51,"value":3151},"Include a count of credits and references so a later reviewer can\nsanity-check that nothing was dropped.",{"type":46,"tag":301,"props":3153,"children":3154},{},[],{"type":46,"tag":305,"props":3156,"children":3158},{"id":3157},"step-5-never-edit-the-json-in-place-after-pasting",[3159],{"type":51,"value":3160},"Step 5 — Never edit the JSON in place after pasting",{"type":46,"tag":53,"props":3162,"children":3163},{},[3164,3166,3171,3173,3178],{"type":51,"value":3165},"Once the JSON has been pasted into Vulnogram and saved, ",{"type":46,"tag":75,"props":3167,"children":3168},{},[3169],{"type":51,"value":3170},"do not",{"type":51,"value":3172}," edit\nthe local JSON file to match tool-side changes. Re-run the script instead\n(it is deterministic — you will get a clean baseline), diff the new\noutput against the current Vulnogram state, and paste the merged JSON\nback. This keeps the tracking issue as the single source of truth: if\nVulnogram shows something different from the generated JSON, either the\nissue body is out of date and needs a ",{"type":46,"tag":66,"props":3174,"children":3176},{"className":3175},[],[3177],{"type":51,"value":442},{"type":51,"value":3179}," run, or the\ntool-side difference is intentional and the reviewer will keep it.",{"type":46,"tag":301,"props":3181,"children":3182},{},[],{"type":46,"tag":305,"props":3184,"children":3186},{"id":3185},"guardrails",[3187],{"type":51,"value":3188},"Guardrails",{"type":46,"tag":164,"props":3190,"children":3191},{},[3192,3239,3273,3305,3315,3339],{"type":46,"tag":168,"props":3193,"children":3194},{},[3195,3199,3201,3206,3208,3214,3216,3221,3223,3228,3230,3238],{"type":46,"tag":75,"props":3196,"children":3197},{},[3198],{"type":51,"value":3062},{"type":51,"value":3200}," The script deliberately ",{"type":46,"tag":75,"props":3202,"children":3203},{},[3204],{"type":51,"value":3205},"drops",{"type":51,"value":3207}," any URL that\npoints at ",{"type":46,"tag":66,"props":3209,"children":3211},{"className":3210},[],[3212],{"type":51,"value":3213},"cveprocess.apache.org",{"type":51,"value":3215}," or the project's ",{"type":46,"tag":66,"props":3217,"children":3219},{"className":3218},[],[3220],{"type":51,"value":71},{"type":51,"value":3222}," repo\nfrom the references list before serialising. Those URLs are private\nASF-internal links and should not appear in a published CVE record.\nSee the \"Confidentiality of ",{"type":46,"tag":66,"props":3224,"children":3226},{"className":3225},[],[3227],{"type":51,"value":71},{"type":51,"value":3229},"\" section of\n",{"type":46,"tag":59,"props":3231,"children":3232},{"href":2732},[3233],{"type":46,"tag":66,"props":3234,"children":3236},{"className":3235},[],[3237],{"type":51,"value":2739},{"type":51,"value":126},{"type":46,"tag":168,"props":3240,"children":3241},{},[3242,3247,3249,3257,3259,3264,3266,3271],{"type":46,"tag":75,"props":3243,"children":3244},{},[3245],{"type":51,"value":3246},"CVE IDs are always linked",{"type":51,"value":3248}," per the \"Linking CVEs\" rule in\n",{"type":46,"tag":59,"props":3250,"children":3251},{"href":2732},[3252],{"type":46,"tag":66,"props":3253,"children":3255},{"className":3254},[],[3256],{"type":51,"value":2739},{"type":51,"value":3258},". When the skill mentions the CVE in\nproposals, recaps or comments on the ",{"type":46,"tag":66,"props":3260,"children":3262},{"className":3261},[],[3263],{"type":51,"value":71},{"type":51,"value":3265}," issue, it must\nrender the ID as a markdown link — before publication to the ASF\nCVE tool, and additionally to ",{"type":46,"tag":66,"props":3267,"children":3269},{"className":3268},[],[3270],{"type":51,"value":3080},{"type":51,"value":3272}," after publication.",{"type":46,"tag":168,"props":3274,"children":3275},{},[3276,3286,3288,3293,3295,3303],{"type":46,"tag":75,"props":3277,"children":3278},{},[3279,3284],{"type":46,"tag":66,"props":3280,"children":3282},{"className":3281},[],[3283],{"type":51,"value":71},{"type":51,"value":3285}," references are always linked",{"type":51,"value":3287}," per the \"Linking\n",{"type":46,"tag":66,"props":3289,"children":3291},{"className":3290},[],[3292],{"type":51,"value":71},{"type":51,"value":3294}," issues and PRs\" rule in\n",{"type":46,"tag":59,"props":3296,"children":3297},{"href":2732},[3298],{"type":46,"tag":66,"props":3299,"children":3301},{"className":3300},[],[3302],{"type":51,"value":2739},{"type":51,"value":3304},". When the skill mentions the\ntracking issue in its own comments, render it as a markdown link.",{"type":46,"tag":168,"props":3306,"children":3307},{},[3308,3313],{"type":46,"tag":75,"props":3309,"children":3310},{},[3311],{"type":51,"value":3312},"Deterministic output is a feature.",{"type":51,"value":3314}," Do not introduce timestamps,\nrandom UUIDs, ordering dependencies on dict iteration, or other sources\nof non-determinism into the script. If you need to add a new field,\nmake sure the output still hashes the same across runs on the same\ninput.",{"type":46,"tag":168,"props":3316,"children":3317},{},[3318,3323,3325,3330,3332,3337],{"type":46,"tag":75,"props":3319,"children":3320},{},[3321],{"type":51,"value":3322},"Multi-entry fields.",{"type":51,"value":3324}," Credits are split on ",{"type":46,"tag":75,"props":3326,"children":3327},{},[3328],{"type":51,"value":3329},"newlines only",{"type":51,"value":3331}," to\npreserve the ",{"type":46,"tag":66,"props":3333,"children":3335},{"className":3334},[],[3336],{"type":51,"value":1190},{"type":51,"value":3338}," pattern. References are extracted\nfrom URL tokens in the field value. Do not reintroduce comma-splitting\non credits.",{"type":46,"tag":168,"props":3340,"children":3341},{},[3342,3347,3349,3354,3356,3361],{"type":46,"tag":75,"props":3343,"children":3344},{},[3345],{"type":51,"value":3346},"No envelope means no metadata.",{"type":51,"value":3348}," ",{"type":46,"tag":66,"props":3350,"children":3352},{"className":3351},[],[3353],{"type":51,"value":639},{"type":51,"value":3355}," drops the\n",{"type":46,"tag":66,"props":3357,"children":3359},{"className":3358},[],[3360],{"type":51,"value":2232},{"type":51,"value":3362}," block which includes the CVE ID; the JSON is pure CNA\ncontent. Make sure the user knows they will have to set the CVE ID by\nhand in Vulnogram in that mode.",{"type":46,"tag":301,"props":3364,"children":3365},{},[],{"type":46,"tag":305,"props":3367,"children":3369},{"id":3368},"references",[3370],{"type":51,"value":3371},"References",{"type":46,"tag":164,"props":3373,"children":3374},{},[3375,3395,3408,3421],{"type":46,"tag":168,"props":3376,"children":3377},{},[3378,3386,3388,3393],{"type":46,"tag":59,"props":3379,"children":3380},{"href":2732},[3381],{"type":46,"tag":66,"props":3382,"children":3384},{"className":3383},[],[3385],{"type":51,"value":2739},{"type":51,"value":3387}," — repo-wide conventions (confidentiality,\nLinking CVEs, Linking ",{"type":46,"tag":66,"props":3389,"children":3391},{"className":3390},[],[3392],{"type":51,"value":71},{"type":51,"value":3394}," issues and PRs, release-branch\ndefaults).",{"type":46,"tag":168,"props":3396,"children":3397},{},[3398,3406],{"type":46,"tag":59,"props":3399,"children":3400},{"href":3099},[3401],{"type":46,"tag":66,"props":3402,"children":3404},{"className":3403},[],[3405],{"type":51,"value":121},{"type":51,"value":3407}," — handling process, in particular\nstep 13 (fill in CVE tool fields and send advisory from the tool)\nand step 15 (paste the attached JSON into Vulnogram's #source tab,\nmove the CVE to PUBLIC, close the issue).",{"type":46,"tag":168,"props":3409,"children":3410},{},[3411,3419],{"type":46,"tag":59,"props":3412,"children":3413},{"href":1676},[3414],{"type":46,"tag":66,"props":3415,"children":3417},{"className":3416},[],[3418],{"type":51,"value":442},{"type":51,"value":3420}," — the sibling\nskill that populates the tracking issue fields this skill consumes.",{"type":46,"tag":168,"props":3422,"children":3423},{},[3424,3434],{"type":46,"tag":59,"props":3425,"children":3427},{"href":3426},"..\u002F..\u002F..\u002Fskills\u002Fsecurity-issue-fix\u002FSKILL.md",[3428],{"type":46,"tag":66,"props":3429,"children":3431},{"className":3430},[],[3432],{"type":51,"value":3433},"security-issue-fix",{"type":51,"value":3435}," — the other\nsibling skill that opens a public PR and updates the tracking issue\nwith the fix URL.",{"type":46,"tag":3437,"props":3438,"children":3439},"style",{},[3440],{"type":51,"value":3441},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":3443,"total":3537},[3444,3450,3466,3480,3496,3512,3524],{"slug":4,"name":4,"fn":5,"description":6,"org":3445,"tags":3446,"stars":22,"repoUrl":23,"updatedAt":24},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3447,3448,3449],{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},{"name":20,"slug":21,"type":15},{"slug":3451,"name":3451,"fn":3452,"description":3453,"org":3454,"tags":3455,"stars":22,"repoUrl":23,"updatedAt":3465},"magpie-audit-finding-fix","fix findings from code audit tools","For a batch of findings from a non-security audit tool\n(`\u003Caudit-tool>` — ruff \u002F flake8 \u002F mypy \u002F pylint \u002F CodeQL \u002F\nApache Verum \u002F Apache Caer \u002F equivalent; full list in the body)\nagainst `\u003Cupstream>`, draft the smallest fix for each finding.\nRe-runs the tool after each batch to confirm the findings are\ncleared. Produces a commit and a hand-back artefact; never opens\na PR on autopilot or merges.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3456,3459,3462],{"name":3457,"slug":3458,"type":15},"Audit","audit",{"name":3460,"slug":3461,"type":15},"Code Analysis","code-analysis",{"name":3463,"slug":3464,"type":15},"Debugging","debugging","2026-07-12T08:35:13.930479",{"slug":3467,"name":3467,"fn":3468,"description":3469,"org":3470,"tags":3471,"stars":22,"repoUrl":23,"updatedAt":3479},"magpie-ci-runner-audit","audit GitHub Actions workflow runner compatibility","Read-only audit of GitHub Actions workflow runner compatibility\nfor one repository, an explicit repository set, one Apache project\nwith multiple repositories, or the full Apache GitHub org. Finds\nobsolete GitHub-hosted runner labels and macOS runner\u002Ftool\narchitecture mismatches. Produces TSV evidence files; never edits\nworkflows, opens PRs, or posts comments.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3472,3473,3476],{"name":3457,"slug":3458,"type":15},{"name":3474,"slug":3475,"type":15},"CI\u002FCD","ci-cd",{"name":3477,"slug":3478,"type":15},"GitHub Actions","github-actions","2026-07-12T08:34:30.320965",{"slug":3481,"name":3481,"fn":3482,"description":3483,"org":3484,"tags":3485,"stars":22,"repoUrl":23,"updatedAt":3495},"magpie-committer-onboarding","onboard Apache project committers","Post-vote committer and PMC onboarding for Apache projects.\nWalks the nominator through every step from ICLA check to\nwelcome announcement for both incubating podlings and\ngraduated top-level projects.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3486,3489,3492],{"name":3487,"slug":3488,"type":15},"Management","management",{"name":3490,"slug":3491,"type":15},"Operations","operations",{"name":3493,"slug":3494,"type":15},"Process Documentation","process-documentation","2026-07-12T08:33:35.628029",{"slug":3497,"name":3497,"fn":3498,"description":3499,"org":3500,"tags":3501,"stars":22,"repoUrl":23,"updatedAt":3511},"magpie-contributor-activity-sweep","generate contributor activity reports","Read-only GitHub activity card for a named contributor on \u003Cupstream>.\nFetches PR authorship, code-review activity, issues, and PR\u002Fissue\ncomments over a configurable window. Limited to GitHub-visible\nactivity — the body documents the off-GitHub tracks the nominator\nmust supply separately. No readiness verdict is produced; use\ncontributor-nomination for a full nomination brief.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3502,3505,3508],{"name":3503,"slug":3504,"type":15},"Analytics","analytics",{"name":3506,"slug":3507,"type":15},"GitHub","github",{"name":3509,"slug":3510,"type":15},"Reporting","reporting","2026-07-12T08:33:41.715859",{"slug":3513,"name":3513,"fn":3514,"description":3515,"org":3516,"tags":3517,"stars":22,"repoUrl":23,"updatedAt":3523},"magpie-contributor-nomination","generate contributor nomination briefs","Read-only nomination brief for a named GitHub contributor on\n\u003Cupstream>. Aggregates GitHub activity across all contribution\ntracks plus maintainer-supplied off-GitHub signal, and flags\nvendor-neutrality context — the evidence a PMC needs to open\na committer or PMC nomination thread.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3518,3521,3522],{"name":3519,"slug":3520,"type":15},"Engineering","engineering",{"name":3506,"slug":3507,"type":15},{"name":3509,"slug":3510,"type":15},"2026-07-12T08:33:39.211745",{"slug":3525,"name":3525,"fn":3526,"description":3527,"org":3528,"tags":3529,"stars":22,"repoUrl":23,"updatedAt":3536},"magpie-contributor-sentiment","measure contributor sentiment on GitHub repositories","Measures contributor-sentiment signals on \u003Cupstream> over a\nconfigurable window: thread tone (first-response classification),\ntime-to-first-reply (median hours), first-PR retention\n(second-PR rate), and reviewer load (Gini coefficient). Compares\neach signal against a pre-adoption baseline and produces a\nstructured gate report used to decide whether a skill family is\nready to advance from experimental to stable.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3530,3531,3534,3535],{"name":3503,"slug":3504,"type":15},{"name":3532,"slug":3533,"type":15},"Communications","communications",{"name":3519,"slug":3520,"type":15},{"name":3506,"slug":3507,"type":15},"2026-07-12T08:34:09.204167",71,{"items":3539,"total":3688},[3540,3558,3572,3583,3594,3607,3625,3636,3646,3657,3667,3677],{"slug":3541,"name":3541,"fn":3542,"description":3543,"org":3544,"tags":3545,"stars":3555,"repoUrl":3556,"updatedAt":3557},"datafusion-python","write Apache DataFusion Python code","Use when the user is writing datafusion-python (Apache DataFusion Python bindings) DataFrame or SQL code. Covers imports, data loading, DataFrame operations, expression building, SQL-to-DataFrame mappings, idiomatic patterns, and common pitfalls.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3546,3549,3552],{"name":3547,"slug":3548,"type":15},"Data Analysis","data-analysis",{"name":3550,"slug":3551,"type":15},"Python","python",{"name":3553,"slug":3554,"type":15},"SQL","sql",593,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fdatafusion-python","2026-07-12T08:36:04.957626",{"slug":3559,"name":3559,"fn":3560,"description":3561,"org":3562,"tags":3563,"stars":3569,"repoUrl":3570,"updatedAt":3571},"bydbql","generate and execute BanyanDB BydbQL queries","Generate, validate, and optionally execute read-only BanyanDB BydbQL for STREAM, MEASURE, TRACE, and PROPERTY resources. Use when the user asks to query BanyanDB, translate natural language to BydbQL, inspect BanyanDB schema or data, validate BydbQL, or fetch raw BanyanDB records.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3564,3565,3568],{"name":3503,"slug":3504,"type":15},{"name":3566,"slug":3567,"type":15},"Database","database",{"name":3553,"slug":3554,"type":15},344,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fskywalking-banyandb","2026-07-12T08:31:01.294423",{"slug":3573,"name":3573,"fn":3574,"description":3575,"org":3576,"tags":3577,"stars":3569,"repoUrl":3570,"updatedAt":3582},"compiling","compile and build BanyanDB projects","Compile and build the SkyWalking BanyanDB project. Use when the user asks to compile, build, or generate code for this project.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3578,3581],{"name":3579,"slug":3580,"type":15},"Build","build",{"name":3519,"slug":3520,"type":15},"2026-07-12T08:31:06.373309",{"slug":3584,"name":3584,"fn":3585,"description":3586,"org":3587,"tags":3588,"stars":3569,"repoUrl":3570,"updatedAt":3593},"gh-pull-request","create GitHub pull requests for BanyanDB","Create a GitHub pull request for SkyWalking BanyanDB. Use when the user asks to create a PR, submit changes, or open a pull request.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3589,3590],{"name":3506,"slug":3507,"type":15},{"name":3591,"slug":3592,"type":15},"Pull Requests","pull-requests","2026-07-12T08:31:03.792415",{"slug":3595,"name":3595,"fn":3596,"description":3597,"org":3598,"tags":3599,"stars":3569,"repoUrl":3570,"updatedAt":3606},"vendor-update","update Go and Node.js vendor dependencies","Upgrade Go\u002FNode.js vendor dependencies and sync tool versions. Use whenever the user says \"upgrade dependencies\", \"update vendors\", \"vendor update\", \"run vendor-upgrade\", \"bump dependencies\", \"update packages\", or asks to run the `vendor-update` Make target. This skill also checks `scripts\u002Fbuild\u002Fversion.mk` after upgrading to see if any tracked tool versions need updating too, and removes stale binaries from `bin\u002F` when versions change.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3600,3603],{"name":3601,"slug":3602,"type":15},"Go","go",{"name":3604,"slug":3605,"type":15},"Node.js","node-js","2026-07-12T08:31:02.555555",{"slug":3608,"name":3608,"fn":3609,"description":3610,"org":3611,"tags":3612,"stars":3622,"repoUrl":3623,"updatedAt":3624},"cayenne-cgen","generate Cayenne entity Java classes","Use this skill whenever the user wants to (re)generate Cayenne entity Java classes from a DataMap. Trigger on phrases like 'generate Java classes', 'regenerate entities', 'run cgen', 'create the entity classes', 'why is the Artist class missing fields', 'where did the `_Abstract*` classes come from', 'sync the entity classes with the model', or any request to materialize Java from the DataMap. Also trigger as a follow-up after modeling changes (someone added an entity, attribute, or relationship and now the Java side is stale). This skill exclusively uses the `mcp__cayenne__cgen_run` MCP tool — it does NOT use `mvn cayenne:cgen` or the Gradle cgen task.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3613,3616,3619],{"name":3614,"slug":3615,"type":15},"Data Modeling","data-modeling",{"name":3617,"slug":3618,"type":15},"Java","java",{"name":3620,"slug":3621,"type":15},"ORM","orm",343,"https:\u002F\u002Fgithub.com\u002Fapache\u002Fcayenne","2026-07-12T08:32:33.575211",{"slug":3626,"name":3626,"fn":3627,"description":3628,"org":3629,"tags":3630,"stars":3622,"repoUrl":3623,"updatedAt":3635},"cayenne-db-import","import database schema into Cayenne DataMaps","Use this skill when the user wants to import database schema metadata into a Cayenne DataMap — the *model\u002Fmapping only*, not names or Java classes. Trigger on phrases like 'reverse engineer the database', 'import the schema', 'generate a DataMap from my DB', 'add the new tables from the DB into the model', 'import the customer table', 'create entities from these tables', or any request to read database metadata to populate or update a DataMap's XML. This is for *full schema* or *bulk table* import; one-off a-la-carte entity additions belong in the cayenne-modeling skill. IMPORTANT — scope: this imports the mapping ONLY; it does not clean up the Object-layer names or (re)generate Java classes. When the user wants their whole project brought in line with the DB ('sync my project with the database', 'my schema changed, update everything', 'update my entities\u002Fclasses from the DB'), that is the end-to-end `cayenne-full-db-sync` skill, which runs this import and then name cleanup and class generation. To regenerate classes alone use `cayenne-cgen`. The skill runs reverse engineering directly via the `mcp__cayenne__dbimport_run` MCP tool when a DBConnector is already configured; otherwise it opens the CayenneModeler GUI via `mcp__cayenne__open_project` to configure the connection first.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3631,3632,3633,3634],{"name":3566,"slug":3567,"type":15},{"name":3617,"slug":3618,"type":15},{"name":3620,"slug":3621,"type":15},{"name":3553,"slug":3554,"type":15},"2026-07-19T05:40:33.655062",{"slug":3637,"name":3637,"fn":3638,"description":3639,"org":3640,"tags":3641,"stars":3622,"repoUrl":3623,"updatedAt":3645},"cayenne-full-db-sync","synchronize Cayenne projects with database","Use this skill when the user wants to bring their WHOLE Cayenne project in line with the database in one shot — the mapping, the Object-layer names, and the generated Java classes together. This is the end-to-end 'sync with the DB' workflow, and it orchestrates three skills in order: `cayenne-db-import` (import schema metadata into the DataMap) → `cayenne-model-naming` (polish the just-imported names) → `cayenne-cgen` (regenerate Java classes). Trigger on holistic phrases like 'sync my project with the database', 'sync with the DB', 'my schema changed, update everything', 'update my entities\u002Fclasses from the database', 'reverse engineer and regenerate the classes', 'import the new tables and rebuild the entities', 'full DB sync', 'bring the model and classes up to date with the DB'. The distinguishing signal is scope: the user wants the whole project (mapping + names + Java code), not just one stage. For the *model\u002Fmapping only* (no name cleanup, no class generation) use `cayenne-db-import`; to (re)generate classes alone use `cayenne-cgen`; to clean names alone use `cayenne-model-naming`. Uses the `mcp__cayenne__dbimport_run` and `mcp__cayenne__cgen_run` MCP tools via the sub-skills; does NOT use Maven or Gradle goals.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3642,3643,3644],{"name":3566,"slug":3567,"type":15},{"name":3617,"slug":3618,"type":15},{"name":3620,"slug":3621,"type":15},"2026-07-19T06:03:49.112969",{"slug":3647,"name":3647,"fn":3648,"description":3649,"org":3650,"tags":3651,"stars":3622,"repoUrl":3623,"updatedAt":3656},"cayenne-model-naming","clean up Cayenne object-layer names","Use this skill to clean up Object-layer names in a Cayenne DataMap — ObjEntity, ObjAttribute, and ObjRelationship names, plus DbRelationship names (the first-class unit of relationship cleanup — every FK has one whether or not an ObjRelationship was generated; the ObjRelationship name is synced to it when one exists) — so they read as descriptive, consistent Java. Trigger on phrases like 'clean up the model names', 'fix the entity names', 'these names look ugly', 'make the names descriptive', 'normalize the ObjEntity\u002Fattribute\u002Frelationship names', 'why is this relationship called team1', 'rename entities to be consistent', 'the import produced Gametype instead of GameType'. Invoke it on an explicit user request, or as a manual follow-up after a `cayenne-db-import` to polish the just-imported additions — it is never triggered automatically. IMPORTANT: this is a LIGHT polish pass — CayenneModeler's reverse-engineering already produces good names for the common case; only improve the specific things its deterministic algorithm cannot (run-together names with no separators like `gametype`, meaningless numbered names like `team1` from multiple relationships between two tables, and a common entity prefix that leaks into relationship names like `aaOrders`). Do NOT rewrite names that are already correct. This is Obj-layer naming polish; for structural model edits use `cayenne-modeling`, and for regenerating classes afterward use `cayenne-cgen`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3652,3653,3654,3655],{"name":3614,"slug":3615,"type":15},{"name":3566,"slug":3567,"type":15},{"name":3617,"slug":3618,"type":15},{"name":3620,"slug":3621,"type":15},"2026-07-22T05:35:32.342548",{"slug":3658,"name":3658,"fn":3659,"description":3660,"org":3661,"tags":3662,"stars":3622,"repoUrl":3623,"updatedAt":3666},"cayenne-modeler","manage Cayenne projects with CayenneModeler","Use this skill when the user explicitly wants to open CayenneModeler (the GUI) on a Cayenne project, or when the modeling task is inherently visual — reverse engineering (delegated to cayenne-db-import), bulk relationship layout, multi-entity visual refactoring. Trigger on phrases like 'open the Modeler', 'open in CayenneModeler', 'launch the GUI', 'edit visually', 'show me the project in the Modeler'. Do NOT trigger as a fallback for ordinary a-la-carte XML edits — those belong in the cayenne-modeling skill, which is faster and doesn't require the user to context-switch.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3663,3664,3665],{"name":3614,"slug":3615,"type":15},{"name":3617,"slug":3618,"type":15},{"name":3620,"slug":3621,"type":15},"2026-07-12T08:32:37.199428",{"slug":3668,"name":3668,"fn":3669,"description":3670,"org":3671,"tags":3672,"stars":3622,"repoUrl":3623,"updatedAt":3676},"cayenne-modeling","edit and extend Cayenne ORM models","Use this skill whenever the user wants to edit, inspect, or extend the Cayenne ORM model in a project — adding or modifying entities, attributes, relationships, embeddables, named queries, stored procedures, or DataNodes. Trigger on phrases like 'add an ObjEntity', 'add a DbEntity', 'add a relationship', 'expose this column as an attribute', 'create a new DataMap', 'add a named query', 'create an embeddable', 'add a stored procedure', 'change the attribute type', 'mark this column as nullable', 'rename this entity', or any mention of a Cayenne `*.map.xml` or `cayenne-*.xml` file. Also trigger when the user references modeling concepts (ObjEntity, DbEntity, ObjAttribute, DbAttribute, ObjRelationship, DbRelationship, Embeddable, dbEntityName, deleteRule, db-attribute-path, db-relationship-path, defaultPackage) in the context of a Cayenne-using app. This is the *primary* skill for a-la-carte ORM model manipulation — direct XML edits, not the Modeler GUI.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3673,3674,3675],{"name":3566,"slug":3567,"type":15},{"name":3617,"slug":3618,"type":15},{"name":3620,"slug":3621,"type":15},"2026-07-19T05:40:32.6889",{"slug":3678,"name":3678,"fn":3679,"description":3680,"org":3681,"tags":3682,"stars":3622,"repoUrl":3623,"updatedAt":3687},"cayenne-query","write and modify Cayenne database queries","Use this skill whenever the user wants to write or modify a Cayenne query — fetching entities by criteria, joining, prefetching to avoid N+1, ordering, paginating, aggregating, or running raw SQL through Cayenne. Trigger on phrases like 'query for X', 'fetch all artists where ...', 'write an ObjectSelect', 'use SQLSelect', 'use SelectById', 'add a prefetch', 'get distinct values', 'count rows', 'find by ID', 'load by primary key', 'build a Cayenne expression', 'why am I getting N+1', 'how do I paginate', 'select a single column', 'select columns into a DTO', 'named query in the DataMap'. Do NOT trigger for modeling changes (use cayenne-modeling) or runtime bootstrap (use cayenne-runtime).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3683,3684,3685,3686],{"name":3566,"slug":3567,"type":15},{"name":3617,"slug":3618,"type":15},{"name":3620,"slug":3621,"type":15},{"name":3553,"slug":3554,"type":15},"2026-07-12T08:32:35.072322",108]