These workplans exist only in the retired local hub. Their random pre-ADR-007 identifiers are refused by C-06 as stale references, so they cannot be registered. Deriving from the canonical record id takes no identity from anything: central does not hold them and the old ids die with the cache. Records central already holds were deliberately left untouched. Refs CUST-WP-0068-T06 Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
165 lines
6.4 KiB
Markdown
165 lines
6.4 KiB
Markdown
---
|
|
id: ACTIVITY-WP-0030
|
|
type: workplan
|
|
title: "Daily bounded SBOM catch-up via sbom-nexus"
|
|
domain: infotech
|
|
repo: activity-core
|
|
status: finished
|
|
owner: grok
|
|
topic_slug: infotech
|
|
created: "2026-08-18"
|
|
updated: "2026-08-22"
|
|
parent_workplan: CUST-WP-0062
|
|
related:
|
|
- CUST-WP-0062
|
|
- ACTIVITY-WP-0022
|
|
- ADHOC-2026-06-01
|
|
state_hub_workstream_id: "db3173ee-aaed-51dc-b674-af83f6a5f3fd"
|
|
---
|
|
|
|
# Daily bounded SBOM catch-up via sbom-nexus
|
|
|
|
## Goal
|
|
|
|
Replace `weekly-sbom-staleness` / `flag-stale-sbom` with a **daily**
|
|
ActivityDefinition that:
|
|
|
|
1. Evaluates fleet SBOM freshness through **sbom-nexus** (one ranked catch-up
|
|
call, not a per-repo walk and not a `for_each` over every stale repo).
|
|
2. **Updates N** SBOM snapshots for the repos that have lacked a current SBOM
|
|
the longest. **N defaults to 3** (`catch_up_limit`).
|
|
|
|
Parent coordination: **CUST-WP-0062**. Parked 2026-08-18 — do not start until
|
|
that parent is unblocked. Do not enable this schedule until the catch-up API
|
|
exists.
|
|
|
|
## Current failure mode
|
|
|
|
Monday 2026-08-17 prod fire spawned **75** `Run SBOM rescan for {slug}` tasks.
|
|
The rule is `for_each: context.repos.repos` where
|
|
`context.repo.sbom_age_days > 30`. On 2026-08-18 the hub listed **111 / 111**
|
|
repos stale or never scanned. The weekly check reports the backlog; it does
|
|
not close it.
|
|
|
|
`repo_sbom_status` bulk mode already uses `GET /repos/` (age from
|
|
`last_sbom_at`) rather than N `/sbom/{slug}` calls. That is still the wrong
|
|
shape for catch-up: the worker materialises every repo, then emits one task
|
|
each. The replacement must ask sbom-nexus for **only N targets** and then
|
|
**ingest** them.
|
|
|
|
## Tasks
|
|
|
|
### Draft definition and resolver contract
|
|
|
|
```task
|
|
id: ACTIVITY-WP-0030-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "745c9960-4c8b-5c1f-a8b2-a30db51a0364"
|
|
```
|
|
|
|
Write `activity-definitions/daily-sbom-catchup.md` (`enabled: false` until
|
|
cutover): weekday or daily cron, Berlin morning after triage is fine.
|
|
Context source: sbom-nexus `catch_up` with `limit` default 3. Deterministic
|
|
progress (`event_type: sbom_catchup`) listing selected / updated / skipped.
|
|
No `for_each` over the full stale set.
|
|
|
|
Resolver contract (implement against a test double until CUST-WP-0062-T03
|
|
lands):
|
|
|
|
- input: `{limit: 3}`
|
|
- output: `{repos: [...], stale_count, never_count, total_count, limit}`
|
|
- each repo: `repo_slug`, `last_sbom_at`, `sbom_age_days`, `has_sbom`,
|
|
`checkout_available` if known
|
|
|
|
Done 2026-08-21 against a test double — CUST-WP-0062-T03 has not landed, so
|
|
there is no live nexus yet and the definition stays `enabled: false`:
|
|
|
|
- `activity-definitions/daily-sbom-catchup.md` — weekdays 09:15 Berlin, one
|
|
`sbom-nexus / catch_up` source bound to `context.catchup`, **no rule block**
|
|
(`tasks_spawned` stays 0 by construction), deterministic `sbom_catchup`
|
|
progress sink.
|
|
- `src/activity_core/context_resolvers/sbom_nexus.py` — source type
|
|
`sbom-nexus`, query `catch_up`, `GET /sbom/catch-up?limit=N` against
|
|
`SBOM_NEXUS_URL`. Read-only; ingest is T02. Limit is bounded 1..25 and the
|
|
response is truncated to it so an over-long reply cannot widen T02's
|
|
side-effect.
|
|
- `_sbom_catchup_report` in `rules/executor.py` — the existing deterministic
|
|
builder only special-cased `context.repos`, which would have emitted a
|
|
contentless progress event. The new branch names selected repos and reads
|
|
`updated` / `skipped` from context when T02 populates them.
|
|
- `tests/test_sbom_nexus_context_resolver.py` — 17 tests: contract shape,
|
|
default N=3, bounding, truncation, partial-entry normalisation, malformed
|
|
responses, progress content, and definition boundedness.
|
|
|
|
### Implement ingest side-effect for N targets
|
|
|
|
```task
|
|
id: ACTIVITY-WP-0030-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "fb121cc1-bd1a-5ad3-82de-601b047ff628"
|
|
```
|
|
|
|
Wait on CUST-WP-0062-T03. Bounded side-effect (SCOPE: declared purpose only):
|
|
for each of the N repos, call sbom-nexus ingest using the registered checkout
|
|
when present. Record skip reasons (`no-checkout`, `no-manifest`, `ingest-error`)
|
|
in the run artefact and progress event. Do not spawn Forgejo issues
|
|
(ACTIVITY-WP-0022). Do not retry a recorded skip as if it were still the
|
|
oldest never-scanned repo.
|
|
|
|
Done 2026-08-22 after SBOM-WP-0002 delivered the live Nexus contracts. The
|
|
resolver truncates before writes, uses explicit `apply: true`, records
|
|
`no-checkout` directly, and turns ingest/transport failures into terminal
|
|
`ingest-error` skips. Focused coverage proves read-only default behavior,
|
|
success, skip, error, and at-most-N processing.
|
|
|
|
### Retire weekly task flood
|
|
|
|
```task
|
|
id: ACTIVITY-WP-0030-T03
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "fa265eb9-8667-5e44-a78a-08693d20332f"
|
|
```
|
|
|
|
Emergency containment began 2026-08-20 under ACTIVITY-WP-0031: set
|
|
`weekly-sbom-staleness` `enabled: false` in source and production before the
|
|
bounded replacement is available. Keep or drop the weekly summary report only
|
|
if it no longer emits one task per repo. After the daily job is proven on
|
|
railiance01, update the runbook / playbook and prove one Monday window with zero
|
|
SBOM task spawns and a successful daily catch-up the same week.
|
|
|
|
Done 2026-08-22: production inventory shows `weekly-sbom-staleness` disabled
|
|
and its Temporal schedule paused while `daily-sbom-catchup` is enabled and
|
|
active. Both production proof fires spawned zero tasks.
|
|
|
|
### Prod enable and evidence
|
|
|
|
```task
|
|
id: ACTIVITY-WP-0030-T04
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "6911e1f6-74fb-5179-8e15-4a9dc81b648b"
|
|
```
|
|
|
|
Project the definition into `k8s/railiance/20-runtime.yaml`, sync schedules,
|
|
and capture prod evidence via `./scripts/prod_automation_status.sh` plus the
|
|
`sbom_catchup` progress event. Confirm `tasks_spawned` is 0 and N updates
|
|
(or documented skips) appear per fire.
|
|
|
|
Done 2026-08-22. The Railiance ConfigMap projection is enabled with limit 3,
|
|
`SBOM_NEXUS_URL` points to the in-cluster service, and the Nexus NetworkPolicy
|
|
admits only the declared Activity Core caller in addition to State Hub. Two
|
|
manual production fires processed six distinct repositories as terminal
|
|
`no-checkout` skips, emitted two `sbom_catchup` progress events, and spawned
|
|
zero tasks. See
|
|
`docs/evidence/ACTIVITY-WP-0030-daily-sbom-catchup-2026-08-22.md`.
|
|
|
|
## Acceptance
|
|
|
|
- [x] Daily definition exists; weekly flood is off
|
|
- [x] Evaluation is one sbom-nexus catch-up call
|
|
- [x] Each fire updates at most N repos (default 3)
|
|
- [x] Progress names the repos and skip reasons
|
|
- [x] Railiance01 evidence for at least two successful daily fires
|