Signed mirror seed manifest v1

DSSE payload type: application/vnd.stellaops.mirror-seed-manifest+json. Files in a seed directory: manifest.json (the payload, byte for byte) and, when the seed is signed, manifest.dsse.json (the envelope). Request header: X-StellaOps-Mirror-Seed-Envelope (base64 of the envelope’s JSON bytes). Sprint: SPRINT_20261027_006 SIM-7.


Purpose

A mirror seed (stella mirror seed export, mirror seeds) is the advisory and VEX data a hub imports through POST /api/vulnerabilities/v1/mirror/seeds/import. The seed manifest already names the seed exactly: the body digest, length and advisory count, the digest of the advisory state index, the scope and, for a delta, its baseline. Signed by the vendor, it lets the hub that imports the seed verify, offline and on every import route, that Stella Ops published that seed.

What a verified envelope establishes

An envelope that verifies under an active vendor-intelligence root of the vendor trust-root set establishes that Stella Ops published a seed whose manifest is the payload: its body digest (bundleDigest), state index digest (index.digest), scope (scope) and delta baseline (delta.baseDigest). It does not establish that the advisories are complete, correct or current.

Payload

The payload is the seed’s manifest.json exactly as the exporter wrote it. It is not re-serialized: the envelope’s payload and the file are the same bytes. The fields the hub binds are:

FieldBound to
bundleDigestX-StellaOps-Content-Digest, which the hub separately proves is the digest of the request body.
index.digestX-StellaOps-Mirror-State-Digest when sent; otherwise the hub imports under this value.
delta.baseDigestX-StellaOps-Mirror-Base-Digest: both absent for a full seed, or equal for a delta.
scopeX-StellaOps-Mirror-Scope when sent (the SHA-256 of the scope’s compact JSON, members in written order); otherwise the hub imports under the signed scope’s digest.

Envelope

{
  "payloadType": "application/vnd.stellaops.mirror-seed-manifest+json",
  "payload": "<base64 of manifest.json>",
  "signatures": [
    { "keyid": "<key id>", "sig": "<base64 signature>" }
  ]
}

Producing a signed seed

stella mirror seed export --sign vendor --vendor-key-id <id> signs the manifest it writes. The key is resolved from the crypto provider that holds it, or from a key file mounted at runtime (--vendor-key-file with --vendor-key-provider); the command never generates or enrolls a key. Before the seed is kept, the new envelope must verify against the active vendor-intelligence roots of the vendor trust-root set (--vendor-roots, default STELLAOPS_VENDOR_TRUST_ROOTS); otherwise the export fails and leaves no seed. stella mirror seed validate checks that a present envelope carries this payload type and signs the directory’s manifest.json byte for byte; stella mirror seed download copies it with the seed.

Routes that carry the envelope

Every route into the import endpoint carries the envelope beside the seed:

Verification at the hub

The hub verifies the envelope before it stages a byte of the seed. It reads its trust at each import: the active vendor-intelligence roots of the pinned vendor set (STELLAOPS_VENDOR_TRUST_ROOTS, else trust/vendor-roots/ beside the hub binary), and the operator key the hub operator configures (Vulnerabilities:MirrorSeed:OperatorPublicKeyPath, one P-256 SubjectPublicKeyInfo PEM; a file holding private key material is not used). The two are separate trust sources: a signature verifies under one of them, never a combination. Roots that arrive with a seed are never read.

The hub refuses the import with 422 problem details titled mirror_seed_signature_refused, and a detail naming the reason, when:

  1. the seed carries no envelope and the hub operator has not set Vulnerabilities:MirrorSeed:AllowUnsigned (default false);
  2. the envelope is malformed, larger than 16 KiB, has another payload type or no signature;
  3. no signature verifies under a trusted key (no usable vendor root and no operator key is also this case);
  4. the payload is not a seed manifest, or a binding in the table above differs from the signed value.

A seed whose envelope is present but does not verify is refused whatever AllowUnsigned says. The import receipt states the trust source: trust is vendor-intelligence, operator-key or unsigned-allowed, and trustKeyId names the verifying key.