Distribution fix evidence

Status: implemented and accepted live on 2026-10-20 under the owner’s DIP-38 option-A decision. The acceptance receipt records the deployed source, authenticated browser/API/CLI journey and its controls.

Owner source contract verified against a2d52f5cd584120aa15feb62d368b73e3b0b86cf; the console’s served artifact identity and All-scope mapping are verified against b9bdbc30bbcf32ac377744bd5d01f721e0ce41ca. Re-verify the owner path with pwsh ./tools/scripts/test-targeted-xunit.ps1 -Project src/Vulnerabilities/__Tests/StellaOps.Vulnerabilities.WebService.Tests/StellaOps.Vulnerabilities.WebService.Tests.csproj -Method "*BinaryPlaneApiTests*" -Restore -BuildProjectReferences. Re-verification of a deployment additionally requires the authenticated consumer journey below.

Ownership and production inputs

Vulnerabilities owns reusable distribution fix evidence. Findings owns the association between that evidence and an authenticated tenant’s finding, including the installed package version. Consumers cross the owner HTTP boundary; they never read the hub database.

The existing Debian security-tracker and Alpine secdb normalizers, NormalizationPump and FactWriter are the production producer. They already commit normalized fix predicates, source identity, exact retained-document provenance and the normalization checkpoint. The fix-status and evidence APIs derive their answers from those records. This is option A’s hub write path; a second authoritative copy of the same source claim is unnecessary.

The unwritten binaries.cve_fix_index and binaries.fix_evidence stores are retired through a forward startup migration after an empty-table guard. The public hub fix-status capability remains. This changes the original proposed storage mechanism to honor the one-home rule; it does not move evidence ownership to Findings. A populated predecessor store stops the migration for explicit reconciliation instead of losing its contents.

Evidence contract

Findings and console contract

Findings resolves the finding under the authenticated tenant before any owner call. The current active-generation match and SBOM version/component projections supply the component, vulnerability and installed version; callers cannot override that subject through a query, header or body.

The canonical /api/findings/v1/security/findings/{findingId}/backport endpoint accepts the current finding- plus 64-hex identity, binds a current complete generation and returns the console’s existing verdict.verdict wire property. An owned finding can report verified only when the supported distributor evidence and installed version establish the fix. Conflicting, missing or insufficient evidence remains explicit. An unknown or foreign finding returns 404. Owner unavailability or invalid evidence returns an error and never an empty successful verdict.

The response includes the distributor, installed version and evidence references. Upstream commits, patch signatures and diffs are supplied only when actual evidence exists. The obsolete reader for unsupported ledger event types is replaced by the tenant-bound owner read path; unused event labels are not added to the ledger. The never-populated ledger backport paths are withdrawn; /security/triage hosts the Distributor fix tab in its evidence rail. Its route loads the Triage host, which embeds the findings page and the shared evidence leaf. The Artifact column renders the served artifact reference so an operator can identify the selected finding’s artifact independently of its package name. The All-regions/All-environments view omits those query restrictions, including standalone SBOM findings whose location is byos; an explicit subset keeps its existing restriction.

Delivery and acceptance

  1. Prove the real raw-document writer and normalization path, fix-status read and independently checked evidence reference on PostgreSQL. Cover both supported feed formats.
  2. Prove source correction, withdrawal, exact-byte reactivation, replay and restart. Old source revisions must not yield a current positive determination.
  3. Prove Findings’ installed-version boundary, source-package/release binding, tenant isolation, missing evidence, malformed owner responses and owner failures over real HTTP.
  4. Run adjacent native specifications, API contract generation, retention and identity gates. Remove DIP-38’s two exceptions only when their dormant stores are retired and their capability has an implemented owner path. Do not extend the 2027-03-31 sunset.
  5. Deploy the coherent hub web/worker and Findings changes by exact image identity. Verify the deployed images and the source-input binding before running acceptance.
  6. Exercise retained real distributor input through the hub, tenant-owned finding, console and CLI. Record a fixed-version positive, vulnerable-version negative, wrong-release/missing evidence control and foreign-tenant refusal. Create any acceptance finding through its supported API, never through database seeding.
  7. Commit the receipt, release DIP-38 only after its criteria pass, land by fast-forward and retire its worktree. Other open rows keep their parent sprint active.

Native owner qualification runs the production producer and read path on PostgreSQL. The Findings client’s installed-version and refusal cases run its production client over HTTP against the committed Postman owner-contract simulation. Deployed API, CLI and browser acceptance use the retained live corpus; simulated owner failures are not live outage proofs. The live fixed-version control is exclusion of the fixed component from the affected set; the vulnerable component displays its distributor threshold as unverified. This does not manufacture an affected finding for a fixed package or claim a live verified browser badge.

Operational bounds

The implementation adds no per-tenant copy of global advisory payloads and no parallel corpus. Owner and consumer reads have bounded request/response sizes and timeouts. Evidence references use retained owner inputs; source withdrawal and retention expiry remain distinguishable from an affirmative fix. Deployment uses durable Compose inputs and preserves unrelated services.