| <!-- START doctoc generated TOC please keep comment here to allow auto update --> |
| <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> |
| **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* |
| |
| - [Vulnogram — record management](#vulnogram--record-management) |
| - [Record URLs](#record-urls) |
| - [`#source` paste flow](#source-paste-flow) |
| - [State machine](#state-machine) |
| - [Reviewer-comment signal](#reviewer-comment-signal) |
| - [Record-generator round trip](#record-generator-round-trip) |
| - [Release-manager checklist](#release-manager-checklist) |
| |
| <!-- END doctoc generated TOC please keep comment here to allow auto update --> |
| |
| <!-- SPDX-License-Identifier: Apache-2.0 |
| https://www.apache.org/licenses/LICENSE-2.0 --> |
| |
| # Vulnogram — record management |
| |
| The Vulnogram-side mechanics of **maintaining** a CVE record from |
| allocation through publication. The generic handling process (steps |
| 13–15 of [`../../README.md`](../../README.md)) describes *what* has |
| to happen; this file documents the **Vulnogram-specific** *how*. |
| |
| Per-project URL templates live in |
| [`../../<project-config>/project.md`](../../<project-config>/project.md#cve-tooling) |
| (`cve_tool_record_url_template`, `cve_tool_source_tab_url_template`). |
| |
| ## Record URLs |
| |
| | Purpose | URL | |
| |---|---| |
| | Record page (human-readable + edit surface) | `https://cveprocess.apache.org/cve5/<CVE-ID>` | |
| | `#source` tab (paste-the-JSON target) | `https://cveprocess.apache.org/cve5/<CVE-ID>#source` | |
| | `#json` tab (rendered view of the stored JSON) | `https://cveprocess.apache.org/cve5/<CVE-ID>#json` | |
| | `#email` tab (preview the advisory email before sending) | `https://cveprocess.apache.org/cve5/<CVE-ID>#email` | |
| |
| The `#email` tab is the **email-preview** surface: it renders the |
| advisory exactly as Vulnogram will send it to `<users-list>` and |
| `<announce-list>` — same subject, same body, same recipient list. |
| The release-manager checklist in |
| [the *Release-manager checklist* section below](#release-manager-checklist) |
| calls this out as a load-bearing checkpoint **before** hitting Send, |
| because the preview surfaces formatting issues (truncation, broken |
| markdown, missing patch links) that the JSON view does not. |
| |
| The ASF CVE tool requires ASF OAuth; non-security-team members can |
| see a record only after it has moved to `PUBLIC` (at which point the |
| mirrored record at `cve.org/CVERecord?id=<CVE-ID>` is the canonical |
| public link per the *"Linking CVEs"* section of |
| [`../../AGENTS.md`](../../AGENTS.md)). |
| |
| ## `#source` paste flow |
| |
| The generic release-manager workflow is *"push the final CVE record |
| and close the issue"* (step 15). On Vulnogram that decomposes into: |
| |
| 1. Open the record's `#source` tab at |
| `https://cveprocess.apache.org/cve5/<CVE-ID>#source`. |
| 2. Copy the CVE JSON from the tracking issue's embedded attachment |
| (regenerated by the `generate-cve-json` tool on every sync — |
| see the *"Record-generator round trip"* section below). |
| 3. Paste into the `#source` form and **Save**. |
| 4. Use the UI action to move the record from `REVIEW` to `PUBLIC` |
| (or from `DRAFT` to `REVIEW` first if the record is still in the |
| pre-review state). |
| |
| `PUBLIC` is the terminal state — Vulnogram pushes the record to |
| `cve.org` via the CNA feed once the state lands there. |
| |
| ## State machine |
| |
| Vulnogram wraps every record in a `CNA_private` envelope whose |
| `state` field drives the visibility + CNA-feed push. The four |
| states the generic skills interact with: |
| |
| | State | Set by | What it means | |
| |---|---|---| |
| | `DRAFT` | Allocation (initial state post-allocation) | Record exists, ID is reserved, but content is still being filled in. Not visible on `cve.org`. | |
| | `REVIEW` | Release manager once the content is complete | Ready for CNA review. ASF CNA reviewers may leave reviewer comments at this point (see *"Reviewer-comment signal"* below). Still not on `cve.org`. | |
| | `READY` | Release manager once review feedback is addressed (or immediately after `REVIEW` if no feedback arrived) | Content is final and the record is staged for the advisory-send step. The advisory emails are dispatched from Vulnogram while in `READY`. Still not on `cve.org`. | |
| | `PUBLIC` | Release manager as the terminal step | Record pushed to `cve.org`. World-readable. The generic tracking-issue lifecycle terminates at the `close` action once this state has been reached. | |
| |
| **`DRAFT` → `REVIEW`** happens when all required fields are populated. |
| The release manager moves the record to `REVIEW` after the first |
| JSON paste, opening the window for CNA reviewers to leave comments. |
| |
| **`REVIEW` → `READY`** happens once any reviewer comments have been |
| addressed (via the body-field round-trip described in the |
| *Record-generator round trip* section below), or immediately after |
| `REVIEW` when no comments arrive. `READY` is the state Vulnogram |
| expects when the release manager triggers the advisory email send. |
| |
| **`READY` → `PUBLIC`** is a human release-manager click in Vulnogram |
| after the advisory archive URL has been captured on the tracker. The |
| generic `sync-security-issue` skill's Step 2b does not propose this |
| transition — it is a Step 15 release-manager action. The |
| publication-ready notification comment (see |
| [*Release-manager checklist*](#release-manager-checklist) below) |
| gives the RM the explicit go-ahead. |
| |
| `PUBLISHED` is sometimes used as a synonym for `PUBLIC` in older |
| Vulnogram documentation; the current action is literally labelled |
| `PUBLIC` in the UI. |
| |
| The `generate-cve-json` tool decides `REVIEW` versus `DRAFT` for the |
| generated `CNA_private.state` field by inspecting whether the tracker's |
| *public-advisory-url* body field is populated and whether a |
| `vendor-advisory` reference landed in the generated `references[]`; |
| see the *`_is_cna_ready_for_review`* helper in |
| `generate-cve-json/src/…/cve_json.py` for the exact predicate. The |
| `READY` state itself is set by hand in Vulnogram after the |
| post-`REVIEW` body-field stabilisation — the generator does not emit |
| `READY` directly because it cannot tell, from the tracker body alone, |
| whether reviewer comments are still pending. |
| |
| ## Reviewer-comment signal |
| |
| ASF CNA reviewers leave comments on `REVIEW`-state records. Those |
| comments do **not** surface on the tracking issue directly — |
| Vulnogram notifies by email to the project's `security_list` |
| instead, with the CVE ID in the subject line. The `sync-security-issue` |
| skill's Step 1e reads those emails (Gmail search recipe lives in |
| [`../gmail/search-queries.md`](../gmail/search-queries.md#sync-security-issue--cve-review-comment-search)) |
| and surfaces each open reviewer comment in Step 2b as an actionable |
| body-field proposal on the tracker. |
| |
| The round trip is: reviewer leaves comment in Vulnogram → Vulnogram |
| emails `security_list` → sync skill reads email → sync skill proposes |
| a tracker body-field update → user confirms → `generate-cve-json` |
| re-emits the JSON attachment on the next sync → release manager |
| re-pastes the updated JSON into `#source` → `sync` detects the |
| comment is resolved on the next run. This indirection keeps the |
| single source of truth on the **tracking issue body** (which the |
| skills can read + write) rather than inside Vulnogram (which is |
| OAuth-gated and not readable from skill context). |
| |
| The `cveprocess.apache.org/cve5/<CVE-ID>.json` endpoint exists but |
| is behind ASF OAuth and is **not** readable from agent-skill |
| context — the `sync-security-issue` skill therefore never curls it; |
| Gmail is the load-bearing signal source. |
| |
| ## Record-generator round trip |
| |
| The `generate-cve-json` tool under |
| [`generate-cve-json/`](generate-cve-json/) reads a tracker issue and |
| emits a paste-ready CVE JSON record in the exact shape Vulnogram's |
| `#source` tab accepts — CNA container, `CNA_private` envelope, |
| sorted references, deterministic byte output. The tool's behavioural |
| contract lives in |
| [`generate-cve-json/SKILL.md`](generate-cve-json/SKILL.md); the |
| local-setup / test workflow lives in |
| [`generate-cve-json/README.md`](generate-cve-json/README.md). |
| |
| Skills that update the tracker body call the tool with `--attach` so |
| the embedded CVE JSON in the tracker body stays in lock-step with |
| the body fields — every sync, every allocate-CVE wire-back, every |
| dedupe merge regenerates the attachment. The release manager then |
| has one canonical JSON to paste into `#source` at step 15. |
| |
| ## Release-manager checklist |
| |
| When the `<upstream>` release containing a fix ships, the |
| `sync-security-issue` skill swaps the tracker's `pr merged` label to |
| `fix released`, reassigns the issue to the release manager, and posts |
| an explicit **release-manager hand-off comment** on the tracker (the |
| template body lives in |
| [`release-manager-handoff-comment.md`](release-manager-handoff-comment.md)). |
| The numbered checklist below is the standalone authoritative recipe |
| the comment links to — keep them in lock-step when one changes. |
| |
| The flow has **two pastes** in the common case (no reviewer comments) |
| and **three** when reviewer comments arrive: |
| |
| 1. **First paste — `DRAFT` → `REVIEW`.** Open the `#source` tab on |
| the CVE record. Copy the CVE JSON embedded in the tracking issue |
| (regenerated by `generate-cve-json` on every sync — see |
| [*Record-generator round trip*](#record-generator-round-trip) |
| above). Paste, **Save**. Move the record `DRAFT` → `REVIEW` via |
| the Vulnogram UI. |
| |
| 2. **(conditional) Re-paste after reviewer comments.** ASF CNA |
| reviewers may leave comments while the record sits in `REVIEW` |
| (see [*Reviewer-comment signal*](#reviewer-comment-signal) above). |
| The `sync-security-issue` skill detects them automatically and |
| proposes matching body-field updates on the tracker; the security |
| team confirms and the embedded JSON regenerates. Once the body has |
| settled (no more pending reviewer-comment proposals), re-paste the |
| regenerated JSON into `#source` and **Save**. **Skip this step if |
| no reviewer comments arrived** (the common case for well-formed |
| records). |
| |
| 3. **Set `READY`.** Vulnogram UI action — moves the record from |
| `REVIEW` to `READY` and stages it for the advisory-send step. |
| |
| 4. **Preview the advisory email** on the |
| [`#email` tab](#record-urls). The preview renders the advisory |
| exactly as Vulnogram will send it — same subject, same body, same |
| recipient list. The preview is the load-bearing checkpoint for |
| formatting issues (truncation, broken markdown, missing patch |
| links) that the JSON view does not surface. **Always preview |
| before sending.** If anything needs to change, edit the |
| corresponding body field on the tracker, wait for the JSON to |
| regenerate, re-paste in `#source`, and re-preview. |
| |
| 5. **Send the advisory emails.** Vulnogram dispatches to |
| `<users-list>` and `<announce-list>`. On the tracker, add the |
| `announced - emails sent` label and remove `fix released`. |
| |
| 6. **Wait for the publication-ready notification comment.** The |
| `sync-security-issue` skill scans the public users-list archive |
| for the CVE ID on every run. Once it finds the archived advisory, |
| it populates the tracker's *Public advisory URL* body field, |
| regenerates the CVE JSON to carry the archive URL as a |
| `vendor-advisory` reference, adds the `announced` label, **and |
| posts a publication-ready notification comment** on the tracker |
| (the template body lives in |
| [`release-manager-publication-comment.md`](release-manager-publication-comment.md)). |
| That comment is the explicit go-ahead for steps 7-8. |
| |
| 7. **Second paste — `READY` → `PUBLIC`.** *Only after the |
| publication-ready notification fires.* Re-open `#source`, paste |
| the now-final JSON (carrying the archive URL in `references[]`), |
| **Save**, move the record `READY` → `PUBLIC` via the Vulnogram UI. |
| The record propagates to `cve.org` once the state lands. |
| |
| 8. **Close the tracker.** Close as completed; do not update any |
| labels. The `sync-security-issue` skill's apply step archives the |
| project-board item afterwards (per the *archive-from-board* recipe |
| in [`../github/project-board.md`](../github/project-board.md)) |
| so the closed tracker leaves the active board. |
| |
| The "twice paste" framing in the hand-off comment maps to steps 1 and |
| 7 of the checklist above; step 2 is the rare conditional middle paste. |