feat: prepare postgres sbom cutover
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a028f0-a42f-7582-89a8-ebaad7343834
This commit is contained in:
parent
cf7e3acb78
commit
ba535e1f8f
26 changed files with 1573 additions and 411 deletions
|
|
@ -0,0 +1,74 @@
|
|||
# PostgreSQL and State Hub history rehearsal — 2026-08-22
|
||||
|
||||
## Scope
|
||||
|
||||
Evidence for `SBOM-WP-0001-T05`. No production SBOM authority or State Hub rows
|
||||
were changed. PostgreSQL and Nexus history targets were disposable.
|
||||
|
||||
## PostgreSQL migration/runtime proof
|
||||
|
||||
A disposable `postgres:16-alpine` instance received:
|
||||
|
||||
1. `alembic upgrade head` from an empty database;
|
||||
2. the PostgreSQL API contract test (health, repository upsert, manual ingest,
|
||||
current view, and licence report); and
|
||||
3. `alembic downgrade base`.
|
||||
|
||||
All three completed successfully. The container was stopped and removed after
|
||||
the test.
|
||||
|
||||
The production `Containerfile` also built as `sbom-nexus:test`; a disposable
|
||||
container started as uid 10001 and returned a successful `/state/health`
|
||||
response using its writable `/data` SQLite development default.
|
||||
|
||||
## Live State Hub history baseline
|
||||
|
||||
Read-only source: workstation State Hub at `127.0.0.1:8000`.
|
||||
|
||||
| Measure | Value |
|
||||
| --- | ---: |
|
||||
| Repositories with history | 18 |
|
||||
| Historical snapshots | 22 |
|
||||
| Historical entries | 3,123 |
|
||||
| Oldest snapshot | 2026-03-01T15:12:54.862697Z |
|
||||
| Newest snapshot | 2026-07-08T20:37:48.255925Z |
|
||||
|
||||
## Disposable import result
|
||||
|
||||
The first import created all 22 snapshots in a temporary Nexus SQLite database.
|
||||
Snapshot reconciliation succeeded immediately:
|
||||
|
||||
- expected/matched snapshots: 22/22;
|
||||
- expected/target imported entries: 3,123/3,123;
|
||||
- missing legacy ids: 0;
|
||||
- snapshot field mismatches: 0.
|
||||
|
||||
The initial licence comparison reported a mismatch solely because the two APIs
|
||||
returned equal groups in different orders. Group ordering is not contractual;
|
||||
the importer was corrected to compare normalized groups keyed by licence.
|
||||
|
||||
The second run then proved both correctness and idempotence:
|
||||
|
||||
- `already_present`: 22;
|
||||
- snapshot reconciliation: pass;
|
||||
- licence groups: exact normalized match;
|
||||
- source/target direct-production copyleft count: 4/4;
|
||||
- overall result: pass.
|
||||
|
||||
## Production gate retained
|
||||
|
||||
This is migration-mechanism evidence, not authority cutover approval. Production
|
||||
still requires a managed PostgreSQL service, backup/restore evidence, deployment
|
||||
health, State Hub façade and projection changes, Repo Manager retargeting,
|
||||
Activity Core bounded-ingest activation, and a stabilization window.
|
||||
|
||||
## Consumer handoffs
|
||||
|
||||
State Hub coordination messages were sent from `sbom-nexus` with the cutover
|
||||
plan and explicit ownership boundaries:
|
||||
|
||||
| Consumer | Message id | Requested child slice |
|
||||
| --- | --- | --- |
|
||||
| State Hub | `5a28a4e8-476a-4766-8e11-9c8b4f4cf57a` | reversible compatibility façade and caller retargeting |
|
||||
| Repo Manager | `62d3bd49-9050-458f-9aa9-b6af348f9eb0` | retarget scanner/report interface and remove competing authority |
|
||||
| Activity Core | `3420be55-d0ad-4eb7-93b2-42ac4281c61d` | unblock bounded ingest while retaining deployment gates |
|
||||
|
|
@ -7,9 +7,19 @@ make install
|
|||
make run
|
||||
```
|
||||
|
||||
The API defaults to `127.0.0.1:8010` and `./sbom-nexus.db`. Set
|
||||
`SBOM_NEXUS_DATABASE_PATH` to an explicit durable location for non-development
|
||||
use.
|
||||
The API defaults to `127.0.0.1:8010` and `./sbom-nexus.db`. SQLite schema is
|
||||
created automatically for local development.
|
||||
|
||||
For PostgreSQL, migrate before starting the API:
|
||||
|
||||
```bash
|
||||
export SBOM_NEXUS_DATABASE_URL='postgresql+psycopg://user:password@host/sbom_nexus'
|
||||
make migrate
|
||||
make run
|
||||
```
|
||||
|
||||
PostgreSQL never auto-creates tables unless `SBOM_NEXUS_AUTO_CREATE=1` is set
|
||||
explicitly. Normal production operation must use Alembic.
|
||||
|
||||
## Register and ingest a repository
|
||||
|
||||
|
|
@ -53,13 +63,13 @@ uv run python scripts/import_state_hub.py \
|
|||
|
||||
Imports are idempotent on the State Hub snapshot UUID. Before cutover, compare
|
||||
the source/target repository, snapshot, and entry counts described in the
|
||||
extraction review. The current script reports counts but is not yet the complete
|
||||
production reconciliation gate.
|
||||
extraction review. The command fails unless every legacy snapshot id, repository,
|
||||
timestamp, entry count, licence group, and direct-production copyleft count
|
||||
reconciles.
|
||||
|
||||
## Current production limitations
|
||||
|
||||
- The extraction store is SQLite and intended for local/single-node operation.
|
||||
- Authentication and authorization are not yet integrated.
|
||||
- Structured operational metrics, PostgreSQL migrations, backup/restore proof,
|
||||
and retention policy are required before authority cutover.
|
||||
- Structured operational metrics, backup/restore proof, and retention policy are
|
||||
required before authority cutover.
|
||||
- State Hub and Repo Manager callers have not yet been retargeted.
|
||||
|
|
|
|||
83
docs/production-cutover-plan.md
Normal file
83
docs/production-cutover-plan.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# SBOM Nexus production cutover plan
|
||||
|
||||
**Owner workplan:** `SBOM-WP-0002`
|
||||
|
||||
**Parent coordination:** `CUST-WP-0062`
|
||||
|
||||
**Consumers:** State Hub, Repo Manager, Activity Core
|
||||
|
||||
## Safety model
|
||||
|
||||
Cutover separates durable data movement from caller movement. State Hub remains
|
||||
the rollback read/write path until Nexus history reconciles, the compatibility
|
||||
façade passes, and the bounded Activity Core flow is proven. No step deletes
|
||||
State Hub rows.
|
||||
|
||||
## Sequence
|
||||
|
||||
| Stage | Authority/write path | Exit evidence | Rollback |
|
||||
| --- | --- | --- | --- |
|
||||
| 0. Deploy dark | State Hub | Nexus health, migrated PostgreSQL, backup/restore drill | remove dark deployment |
|
||||
| 1. Import history | State Hub | exact legacy-id, timestamp, entry, and licence reconciliation | discard Nexus database and restore backup |
|
||||
| 2. Projection sync | State Hub | active repo/path projection in Nexus; catch-up counts sampled | stop projection sync |
|
||||
| 3. Read façade | State Hub write; Nexus read behind flag | route compatibility suite and dashboard/MCP samples | flag reads back to State Hub |
|
||||
| 4. Write façade | Nexus write; State Hub projection update | manual and repository ingest parity; truthful attempt/success mapping | flag writes back to State Hub |
|
||||
| 5. Bounded activity | Nexus | at most N terminal outcomes, zero spawned tasks, deterministic progress | disable daily definition |
|
||||
| 6. Stabilize | Nexus | two successful daily fires and one Monday with weekly flood at zero | return façade flags to State Hub |
|
||||
| 7. Retire | Nexus | retention decision and final backup | restore retained State Hub snapshot store during window |
|
||||
|
||||
## Contract ownership
|
||||
|
||||
### SBOM Nexus
|
||||
|
||||
- `/sbom/*`, snapshots, entries, licence report, ingest outcomes, catch-up;
|
||||
- both `last_attempt_at` and `last_success_at`;
|
||||
- imported legacy UUID provenance;
|
||||
- PostgreSQL schema and migration history.
|
||||
|
||||
### State Hub child change
|
||||
|
||||
- introduce a configurable Nexus client and `/sbom/*` façade;
|
||||
- preserve legacy response shapes and `ManagedRepo.last_sbom_at` during the
|
||||
transition;
|
||||
- retarget dashboard, MCP, summary cache, DoI C8, onboarding, and CLI callers;
|
||||
- meter façade reads/writes and retain a reversible flag;
|
||||
- do not add new SBOM product behavior locally.
|
||||
|
||||
### Repo Manager child change
|
||||
|
||||
- retain repository identity, active status, host/checkout paths, and source
|
||||
authority;
|
||||
- change `rmgr sbom scan|licence-report` from independent product behavior to a
|
||||
Nexus client/local compatibility adapter;
|
||||
- pin `sbom-nexus.snapshot.v1` and remove competing historical ownership;
|
||||
- preserve repository-source scanning usability when Nexus is unavailable only
|
||||
as an explicitly non-authoritative local preview.
|
||||
|
||||
### Activity Core child change
|
||||
|
||||
- replace the stale test-double blocker note with the live Nexus contract;
|
||||
- implement at-most-N `POST /sbom/{slug}/ingest` calls for selected targets;
|
||||
- record `ingested` and skip reasons without task creation;
|
||||
- keep the definition disabled until dark deployment and import pass;
|
||||
- enable and capture two-fire plus Monday-window evidence.
|
||||
|
||||
## Timestamp compatibility decision needed
|
||||
|
||||
State Hub has one `last_sbom_at`; Nexus distinguishes attempt from success. The
|
||||
recommended transitional mapping is `last_attempt_at`, because it preserves
|
||||
catch-up fairness and the historical behavior that an ingest call advances the
|
||||
field. New consumers must use `last_success_at` when they mean inventory
|
||||
freshness. The State Hub child workplan must record this explicitly before write
|
||||
cutover.
|
||||
|
||||
## Production acceptance
|
||||
|
||||
- PostgreSQL upgrade and restore are rehearsed against the deployed topology.
|
||||
- Historical import report is `ok: true` with zero missing/mismatched snapshots.
|
||||
- State Hub compatibility routes pass against Nexus.
|
||||
- Repo Manager has no competing durable SBOM store.
|
||||
- Activity Core updates or terminally skips at most N repositories per fire.
|
||||
- The weekly flood remains disabled and creates zero tasks.
|
||||
- After stabilization, State Hub SBOM rows are retained or removed only through
|
||||
an explicit retention decision.
|
||||
Loading…
Add table
Add a link
Reference in a new issue