Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a028f0-a42f-7582-89a8-ebaad7343834
260 lines
11 KiB
Markdown
260 lines
11 KiB
Markdown
# Product Requirements Document — SBOM Nexus
|
|
|
|
**Status:** initial extraction baseline
|
|
|
|
**Date:** 2026-08-22
|
|
|
|
**Primary coordination:** `CUST-WP-0062`
|
|
|
|
**Initial implementation workplan:** `SBOM-WP-0001`
|
|
|
|
## 1. Product summary
|
|
|
|
SBOM Nexus is a headless service that captures software-composition evidence,
|
|
normalizes it into immutable per-repository snapshots, reports licence and
|
|
coverage signals, and selects a bounded oldest-stale queue for recurring
|
|
catch-up. It replaces State Hub as the SBOM store and product API and supersedes
|
|
Repo Manager's interim in-process scanner as the durable product owner.
|
|
|
|
## 2. Background
|
|
|
|
The current State Hub implementation provides snapshot and entry tables,
|
|
lockfile parsers, manual ingest, latest-snapshot queries, licence grouping,
|
|
MCP tools, dashboard views, and a `last_sbom_at` repository projection. A later
|
|
retirement slice reproduced the source-derived scanner in Repo Manager.
|
|
|
|
The operational trigger for extraction is `CUST-WP-0062`: a weekly freshness
|
|
rule created 75 tasks on 2026-08-17 while 111 of 111 registered repositories
|
|
were stale or never scanned. The desired control loop evaluates the fleet once,
|
|
selects the N oldest eligible repositories, and attempts no more than N updates
|
|
per run. N defaults to 3.
|
|
|
|
## 3. Goals
|
|
|
|
- Establish SBOM Nexus as the single durable SBOM product owner.
|
|
- Preserve State Hub's existing snapshot history and compatibility surface.
|
|
- Reuse and improve the repository-derived parsers already proven in State Hub
|
|
and Repo Manager.
|
|
- Provide one efficient, deterministic oldest-N catch-up query.
|
|
- Record success, empty evidence, unavailable checkout, and ingest failure so a
|
|
permanently impossible repository cannot block the queue.
|
|
- Keep `last_sbom_at` projections truthful throughout cutover.
|
|
- Give Activity Core a bounded read and ingest contract that can replace the
|
|
disabled weekly task-flood rule.
|
|
|
|
## 4. Non-goals for the extraction release
|
|
|
|
- Vulnerability correlation or exploitability analysis.
|
|
- Full licence-policy adjudication or legal advice.
|
|
- Adding ecosystems beyond those already handled by the source implementation.
|
|
- Build-time signing, attestations, or admission control.
|
|
- A new human dashboard; existing views are retargeted during cutover.
|
|
- An unbounded background scanner owned by SBOM Nexus.
|
|
|
|
## 5. Users and jobs
|
|
|
|
| User | Job |
|
|
| --- | --- |
|
|
| Fleet operator | Find and update the oldest stale SBOMs without creating an unbounded workload |
|
|
| Repository maintainer | Scan a checkout, see parser errors and provenance, and retrieve the current snapshot |
|
|
| Activity Core | Fetch at most N ordered targets and record bounded ingest/skip outcomes |
|
|
| State Hub compatibility clients | Continue using the current `/sbom/*` read and ingest contract during migration |
|
|
| Compliance/security consumer | Query components, licence distribution, and direct production copyleft triage signals |
|
|
| Migration operator | Import historical snapshots while preserving ids, timestamps, sources, and repository association |
|
|
|
|
## 6. Functional requirements
|
|
|
|
### FR-1 Repository representation
|
|
|
|
The service shall maintain the minimum repository projection required for SBOM
|
|
operations: stable slug, active/in-scope flag, optional checkout path, last
|
|
attempt time, last successful ingest time, and latest outcome/source. Repo
|
|
Manager remains upstream authority for repository identity and paths.
|
|
|
|
### FR-2 Source detection and parsing
|
|
|
|
The extraction release shall detect sources recursively while excluding
|
|
dependency/build directories. It shall support:
|
|
|
|
- `uv.lock` and `requirements.txt` (Python);
|
|
- `package-lock.json` and `yarn.lock` (Node);
|
|
- `Cargo.lock` (Rust);
|
|
- `go.sum` with `go.mod` direct-dependency hints;
|
|
- `.terraform.lock.hcl`;
|
|
- `ansible/requirements.yml` and `.yaml` below an `ansible` directory;
|
|
- reviewed root `sbom-tools.yaml`.
|
|
|
|
Every detected source shall have a repository-relative path, SHA-256 digest,
|
|
entry count, and any parser error. A repository Git revision is captured when
|
|
available.
|
|
|
|
### FR-3 Immutable snapshots
|
|
|
|
Every manual ingest, checkout scan, skip, error, or historical import shall
|
|
create a new immutable snapshot. Entries belong to exactly one snapshot.
|
|
Previous snapshots remain queryable. Snapshot status and source distinguish at
|
|
least `ingested`, `no-checkout`, `no-manifest`, `ingest-error`, and `imported`.
|
|
|
|
### FR-4 Current inventory queries
|
|
|
|
The service shall return:
|
|
|
|
- all snapshots, optionally filtered by repository;
|
|
- a snapshot and its entries;
|
|
- entries from the latest snapshot per repository with existing State Hub
|
|
filters (`ecosystem`, `license_spdx`, `is_direct`, `is_dev`);
|
|
- the latest repository SBOM view;
|
|
- fleet and per-repository freshness metadata.
|
|
|
|
### FR-5 Licence report
|
|
|
|
The extraction release shall group latest-snapshot entries by SPDX licence
|
|
text, identify simple copyleft-family triage matches, and count/list direct
|
|
non-development matches. The API and documentation shall label this as a signal
|
|
rather than a complete SPDX expression or legal-policy evaluation.
|
|
|
|
### FR-6 Bounded catch-up
|
|
|
|
`GET /sbom/catch-up?limit=N` shall:
|
|
|
|
- default N to 3 and constrain it to 1..25;
|
|
- consider only active/in-scope repositories;
|
|
- use a configurable stale threshold, initially 30 days;
|
|
- order never-attempted repositories first, then oldest attempt, then slug for
|
|
deterministic ties;
|
|
- return no more than N repositories;
|
|
- include `stale_count`, `never_count`, `total_count`, and effective `limit`;
|
|
- return per target `repo_slug`, `last_sbom_at`, `sbom_age_days`, `has_sbom`,
|
|
and `checkout_available` when known.
|
|
|
|
### FR-7 Bounded ingest and skip
|
|
|
|
A repository ingest operation shall use the registered checkout unless an
|
|
explicit authorized path is supplied. It shall create one of these terminal
|
|
outcomes:
|
|
|
|
- `ingested`: supported sources parsed and snapshot stored;
|
|
- `no-checkout`: no reachable checkout;
|
|
- `no-manifest`: checkout exists but no supported source exists;
|
|
- `ingest-error`: one or more sources could not be parsed.
|
|
|
|
Every outcome advances the repository's last-attempt time. Only `ingested`
|
|
advances last-success time. This prevents a permanently unavailable repository
|
|
from remaining first forever without falsely claiming a successful SBOM.
|
|
|
|
### FR-8 Compatibility
|
|
|
|
During cutover, SBOM Nexus shall preserve the response intent of State Hub's:
|
|
|
|
- `POST /sbom/ingest/`;
|
|
- `GET /sbom/`;
|
|
- `GET /sbom/{repo_slug}`;
|
|
- `GET /sbom/snapshots/` and `/sbom/snapshots/{id}`;
|
|
- `GET /sbom/report/licences/`.
|
|
|
|
Differences required for provenance or correctness shall be additive and
|
|
documented. State Hub may proxy these routes until callers move.
|
|
|
|
### FR-9 Historical migration
|
|
|
|
An import tool shall read historical State Hub snapshots in chronological
|
|
order and recreate their repository association, timestamp, source, entries,
|
|
and legacy identifier provenance. Import shall be idempotent. Migration must be
|
|
verified before State Hub rows are retired.
|
|
|
|
### FR-10 Operator interfaces
|
|
|
|
The repository shall provide commands to run the API, scan a checkout locally,
|
|
run tests/lint, and import State Hub history. Configuration shall be supplied
|
|
through explicit environment variables and contain no secrets in source.
|
|
|
|
## 7. Data model
|
|
|
|
```text
|
|
Repository 1 ─── * Snapshot 1 ─── * Entry
|
|
│
|
|
└── source records/errors/provenance
|
|
```
|
|
|
|
- **Repository:** slug, active, checkout path, last attempt/success, last status.
|
|
- **Snapshot:** UUID, repository, timestamp, status/source, source revision,
|
|
entry count, legacy id, structured errors.
|
|
- **Entry:** package name/version, ecosystem, licence text, direct/dev flags,
|
|
source path.
|
|
|
|
SQLite remains supported for extraction tests and single-node development.
|
|
Production uses PostgreSQL through the same transactional store and managed
|
|
Alembic migrations. Production cutover still requires backup/restore evidence
|
|
and explicit retention settings.
|
|
|
|
## 8. API contract
|
|
|
|
| Method | Path | Purpose |
|
|
| --- | --- | --- |
|
|
| GET | `/state/health` | Liveness and store readiness |
|
|
| PUT | `/repositories/{slug}` | Upsert the minimum Repo Manager projection |
|
|
| GET | `/repositories/` | List repository SBOM status |
|
|
| GET | `/sbom/catch-up?limit=N` | Select bounded oldest-stale targets |
|
|
| POST | `/sbom/{slug}/ingest` | Scan registered checkout and record terminal outcome |
|
|
| POST | `/sbom/{slug}/skip` | Record an explicit bounded skip outcome |
|
|
| POST | `/sbom/ingest/` | State Hub-compatible entry ingest |
|
|
| GET | `/sbom/` | Latest entries with filters |
|
|
| GET | `/sbom/{slug}` | Latest repository view |
|
|
| GET | `/sbom/snapshots/` | Snapshot history |
|
|
| GET | `/sbom/snapshots/{id}` | Snapshot detail |
|
|
| GET | `/sbom/report/licences/` | Latest-snapshot licence report |
|
|
|
|
## 9. Quality and operational requirements
|
|
|
|
- Catch-up ordering and bounds are covered by deterministic tests.
|
|
- A recorded skip demonstrably advances queue position.
|
|
- Ingest is transactional: a snapshot and its entries appear together.
|
|
- Paths returned by APIs are repository-relative unless explicitly operator-only.
|
|
- Parser failure in one source is visible; it must not silently produce a
|
|
successful snapshot.
|
|
- The API must not follow paths supplied by an untrusted remote caller in the
|
|
production profile; registered checkout paths are operator-managed inputs.
|
|
- Structured logs and metrics shall distinguish attempts, successes, skips,
|
|
errors, duration, and entry counts before production cutover.
|
|
- Backups and a restore drill are required before historical authority moves.
|
|
|
|
## 10. Migration and rollout
|
|
|
|
1. Establish this repo, intent, PRD, inventory, package, and tests.
|
|
2. Implement the compatible API, scanner, persistence, and catch-up contract.
|
|
3. Register/synchronize repository projections from Repo Manager.
|
|
4. Import and reconcile State Hub history; compare repository/snapshot/entry
|
|
counts and sampled licence reports.
|
|
5. Put State Hub `/sbom/*` behind a proxy/strangler and retarget MCP/dashboard.
|
|
6. Enable Activity Core's bounded ingest side effect, then its disabled daily
|
|
definition; retain the weekly flood disabled.
|
|
7. Observe at least two successful production fires and verify at most N
|
|
terminal outcomes per fire.
|
|
8. Remove State Hub ownership only after compatibility and retention gates pass.
|
|
|
|
## 11. Acceptance criteria
|
|
|
|
- Existing parser fixtures and State Hub-compatible route behaviors pass in
|
|
SBOM Nexus.
|
|
- `limit=3` returns exactly the three oldest eligible stale repositories when
|
|
at least three exist, with never-attempted repositories first.
|
|
- Recording a no-checkout or no-manifest outcome removes that repository from
|
|
the head of the immediate queue.
|
|
- Historical State Hub snapshot and entry counts reconcile, with documented
|
|
treatment of any invalid legacy row.
|
|
- State Hub is no longer the permanent SBOM store.
|
|
- Activity Core performs no more than N ingests/skips per fire and spawns zero
|
|
per-repository catch-up tasks.
|
|
- `last_sbom_at` compatibility projections are derived from a documented Nexus
|
|
timestamp and remain truthful.
|
|
|
|
## 12. Deferred product decisions
|
|
|
|
- Canonical component identity and deduplication across ecosystems.
|
|
- Full SPDX expression parsing and policy ownership.
|
|
- SPDX/CycloneDX import/export profiles and conformance level.
|
|
- Vulnerability, VEX, attestation, signing, and deployment correlation.
|
|
- Artifact Store integration and snapshot retention policy.
|
|
- Multi-tenant authorization via Tenant Engine and Flex Auth.
|
|
- Whether `last_sbom_at` compatibility maps to last attempt or last successful
|
|
inventory; Nexus retains both so consumers can migrate to precise fields.
|