# CNA Publication Service

Vulnerability-Lookup can act as a CVE Numbering Authority (CNA) and submit
CVE records directly to the official CVE Services API (cveawg). This page
covers enabling the feature, configuring instance-level and per-user
credentials, and the publication lifecycle.

:::{note}
You must be an authorized CNA to use this feature. The service forwards
your CNA credentials to cveawg; it does not bypass MITRE's authorization.
:::

## Prerequisites

- Your organisation is registered as a CNA with MITRE.
- Each admin who will reserve, publish, or reject CVEs has their own CVE
  Services credentials (`CVE-API-ORG`, `CVE-API-USER`, `CVE-API-KEY`).

## Configuration

### 1. Enable the feature

In `config/generic.json`, set `cna` to `true`:

```json
{
  "cna": true
}
```

### 2. Create `cna.json`

Copy the sample and edit it:

```bash
cp config/cna.json.sample config/cna.json
```

Generate a Fernet key — used to encrypt every user's CVE API key at rest
in the database:

```bash
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
```

Fill in `cna.json`:

```json
{
  "CVE_URL": "https://cveawg.mitre.org/api",
  "SHORT_NAME": "<your-CNA-short-name>",
  "CNA_CREDENTIAL_ENCRYPTION_KEY": "<your-generated-fernet-key>"
}
```

- `CVE_URL` — base URL of the CVE Services API. Use
  `https://cveawg-test.mitre.org/api` against the test environment while
  validating your setup.
- `SHORT_NAME` — your CNA short name as registered with MITRE.
- `CNA_CREDENTIAL_ENCRYPTION_KEY` — Fernet key. **Treat as a secret.
  Losing it makes every stored user API key unrecoverable** — operators
  would need to re-enter their credentials.

The application checks the Fernet key at startup and refuses to start if
it is missing or malformed, so misconfiguration surfaces immediately
instead of waiting until the first credential is submitted.

## Per-user credentials

CNA credentials are stored **per user**, not per instance. Every admin who
will reserve, publish, or reject CVEs must enter their own credentials at
least once, under `Profile → Your CNA credentials`, before they can use
the publication interface.

```{figure} /_static/img/cna_credentials.png
:alt: CNA credentials.
:target: /_static/img/cna_credentials.png

CNA credentials page (Profile → Your CNA credentials).
```

To rotate the `CVE-API-ORG` or `CVE-API-USER` without re-entering the API
key, leave the **CVE API Key** field empty when submitting — the
previously stored key is preserved.

## Publication lifecycle

Each publication moves through one of these states:

| State                  | Meaning                                                          |
|------------------------|------------------------------------------------------------------|
| `LOCAL_ONLY`           | Created locally; no CVE ID reserved yet.                         |
| `RESERVATION_PENDING`  | A reservation call to cveawg failed; ready for retry.            |
| `RESERVED`             | A CVE ID has been assigned by cveawg.                            |
| `PUBLICATION_PENDING`  | A publish call to cveawg failed; ready for retry.                |
| `PUBLISHED`            | The CVE record has been pushed to cveawg.                        |
| `REJECTION_PENDING`    | A reject call to cveawg failed; ready for retry.                 |
| `REJECTED`             | The CVE record is published as a rejected entry.                 |
| `ABORTED`              | The operator gave up on this publication. No cveawg call.        |

## Usage

Create a publication directly from the vulnerability editor in Vulnogram:

```{figure} /_static/img/cna_vulnogram.png
:alt: Publication Service in Vulnogram.
:target: /_static/img/cna_vulnogram.png

Publication actions in Vulnogram.
```

The publication list is available under `Disclosure → CNA Publications`.
From the publication detail page, admins can:

- **Reserve a CVE ID** — calls cveawg `POST /cve-id` to reserve the next
  available ID for the current year.
- **Publish** — submits the vulnerability record's CNA container to
  cveawg.
- **Reject** — publishes the CVE as a rejected record. A rejection reason
  is required.
- **Abort** — mark the publication as locally abandoned. No cveawg call.

### Error handling

If any call to cveawg fails (network error, 4xx/5xx response), the
publication moves to the corresponding `*_PENDING` state and the
upstream response is saved to `last_error` for inspection. Operators can
retry from the same UI; the publication never silently changes state on
failure.

CVE API keys are scrubbed from any text persisted in `last_error`,
`last_request`, or `last_response` before being written to the database,
so an admin reviewing past attempts cannot accidentally read another
operator's key.
