repo-manager/docs/sbom-nexus-client-contract_v1.md
tegwick e6cc18bf18 feat(sbom): project immutable Forgejo source refs
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a023c0-a0a3-7c03-b395-5a0d2757214d
2026-08-22 23:34:01 +02:00

5.8 KiB
Raw Blame History

SBOM Nexus client contract v1

Repo Manager consumes SBOM Nexus; it does not implement a second scanner, snapshot store, freshness model, licence classifier, or catch-up scheduler. This contract pins the boundary used by RMGR-WP-0011.

Authority modes

Mode Surface Authoritative Persisted Advances Nexus state
Local preview `rmgr sbom scan licence-reportsbom-nexus scan` no no
Service operation configured SBOM Nexus HTTP client yes Nexus decides yes, according to the route outcome

Every compatibility-command result carries:

{
  "repo_manager_context": {
    "mode": "local-preview",
    "authoritative": false,
    "persisted": false,
    "advances_last_attempt_at": false,
    "advances_last_success_at": false,
    "creates_snapshot_history": false
  }
}

Writing preview JSON to a file creates optional local evidence only. It does not turn the result into an authoritative snapshot or ingest receipt.

Pinned snapshot envelope

Repo Manager accepts schema: sbom-nexus.snapshot.v1. Additive fields are compatible. An unknown schema or omission of any of these fields is a contract error: schema, ok, repo_slug, source_revision, generated_at, entry_count, entries, sources, licence_report, and errors.

Repo Manager may project the existing licence-report compatibility shape from that envelope. It must not recalculate licence groups or copyleft signals.

Authoritative service routes

The production client may consume these Nexus-owned routes without depending on Nexus tables or migrations:

Purpose Route
Upsert repository projection PUT /repositories/{repo_slug}
Read repository projections GET /repositories/
Persist scan outcome POST /sbom/{repo_slug}/ingest
Persist terminal skip outcome POST /sbom/{repo_slug}/skip
Read latest repository SBOM GET /sbom/{repo_slug}
Read immutable snapshot detail GET /sbom/snapshots/{snapshot_id}
Read licence report GET /sbom/report/licences/

Calls use a bounded timeout and surface deterministic transport, HTTP, and contract errors. Credentials enter only through the platform runtime path and must never appear in files, command output, or logs.

Authoritative client usage

The Python client requires SBOM_NEXUS_URL. SBOM_NEXUS_TIMEOUT_SECONDS defaults to 30 seconds and is bounded to 0.1300 seconds. An optional SBOM_NEXUS_TOKEN may be injected at runtime; its value is excluded from configuration representations and all structured errors.

from repo_manager.sbom_client import SBOMNexusClient, SBOMNexusConfig

client = SBOMNexusClient(SBOMNexusConfig.from_environment())
client.upsert_repository(
    "example",
    nexus_checkout_path="/srv/controlled/example/abc123",
    active=True,
)
receipt = client.ingest_repository(
    "example",
    expected_source_revision="abc123",
    operation_id="stable-operation-id",
)
latest = client.latest_snapshot("example")
report = client.licence_report()

The client URL-escapes repository slugs, accepts only object responses with the pinned route-specific fields, and adds an authoritative-service context. It does not retry mutations automatically: a timeout or server failure can occur after Nexus commits. Structured errors therefore expose mutation_may_have_committed; callers must resolve the stable operation id or read the resulting snapshot before deciding whether to retry.

When an expected source revision is supplied, an ingested receipt for any other revision fails closed as source_revision_mismatch and explicitly notes that the mutation may already have committed. The checkout path sent to Nexus is Nexus-local controlled-source identity, never authorization to mount a workstation path into the cluster.

Forgejo archive source-reference projection

The CUST-WP-0064 v1 source mechanism is available through a read-only resolution command:

rmgr sbom source-ref --path /path/to/checkout --slug example

Repo Manager reads the selected Git remote only to normalize identity. It then uses the anonymous Forgejo API—not local HEAD, the working tree, or a cached remote-tracking ref—to read repository visibility, default branch, and its full 40-character commit SHA. The result contains kind: forgejo-archive-v1, exact coulomb/<slug> identity, revision, observed_ref, and a canonical UTC observed_at.

V1 returns supported: false and no source_ref for a missing remote, non-Coulomb identity, slug mismatch, private repository, unavailable Forgejo record, invalid branch response, or unresolved full SHA. It never falls back to a workstation path or local revision.

Projection is an explicit mutation and requires both service configuration and confirmation:

export SBOM_NEXUS_URL=https://sbom-nexus.example
rmgr sbom source-ref --path /path/to/checkout --slug example \
  --project --confirm-authoritative

The projection sends checkout_path: null plus the structured source reference. It succeeds only when Nexus returns the exact same source_ref; an older server that silently ignores the additive field fails closed. This makes the command a direct readiness probe for the SBOM Nexus side of CUST-WP-0064.

Repository source identity and provenance

Repo Manager remains authoritative for repository slug, active state, checkout/source identity, and Git revision. An authoritative scan request must refer to a controlled source artifact or checkout pinned to that revision. It must not infer identity from a path string or repository name, and it must not mount a workstation filesystem into the cluster.

CUST-WP-0064 owns the coordinated source-input topology. Until that topology is live, local checkout scans remain previews even when their Git revision is known. SBOM Nexus alone records the resulting authoritative snapshot and attempt/success history.