Enable daily bounded SBOM catch-up
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 6s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a028f0-a42f-7582-89a8-ebaad7343834
This commit is contained in:
tegwick 2026-08-22 20:59:15 +02:00
parent 91ae8dc9a8
commit c2f797f8d5
3 changed files with 79 additions and 7 deletions

View file

@ -1,10 +1,10 @@
---
id: daily-sbom-catchup
name: Daily SBOM Catch-up
enabled: false
enabled: true
owner: custodian-agent
governance: custodian
status: paused
status: active
trigger:
type: cron
cron_expression: "15 9 * * 1-5" # weekdays 09:15, after the daily triage window
@ -25,9 +25,9 @@ context_sources:
# Daily SBOM Catch-up
> **Disabled until production enable evidence is ready.** The `sbom-nexus`
> ranked and terminal ingest/skip APIs are now available. Keep this definition
> off until cluster reachability and a bounded manual fire are proven.
> **Enabled after production proof on 2026-08-22.** Two bounded manual fires
> processed three distinct repositories each, spawned zero tasks, and persisted
> terminal `no-checkout` evidence. The superseded weekly schedule remains off.
Replaces `weekly-sbom-staleness` / `flag-stale-sbom` (ACTIVITY-WP-0030).
The weekly check reported the backlog — 111 / 111 repos stale on 2026-08-18,

View file

@ -43,6 +43,50 @@ metadata:
app.kubernetes.io/name: activity-core
app.kubernetes.io/part-of: activity-core
data:
daily-sbom-catchup.md: |
---
id: daily-sbom-catchup
name: Daily SBOM Catch-up
enabled: true
owner: custodian-agent
governance: custodian
status: active
trigger:
type: cron
cron_expression: "15 9 * * 1-5"
timezone: Europe/Berlin
misfire_policy: skip
context_sources:
- type: sbom-nexus
query: catch_up
required: true
params:
limit: 3
apply: true
bind_to: context.catchup
---
# Daily SBOM Catch-up
Ranked, bounded SBOM catch-up. Each fire processes at most three
repositories through sbom-nexus and deliberately contains no task rule.
```instruction
id: daily-sbom-catchup-report
trusted_fields: []
model: deterministic
temperature: 0
max_tokens: 1
prompt: |
Deterministic SBOM catch-up report from context.catchup (no LLM).
output_schema: ""
review_required: false
report_sinks:
- type: state-hub-progress
event_type: sbom_catchup
author: activity-core
topic_id: cee7bedf-2b48-46ef-8601-006474f2ad7a
```
openbao-retention-closeout.md: |
---
id: "e274defb-28f2-571e-abcb-c17b57eab473"

View file

@ -424,14 +424,14 @@ def test_deterministic_report_carries_t02_ingest_outcomes() -> None:
assert "1 updated, 1 skipped" in report["summary"]
def test_daily_definition_is_bounded_and_disabled() -> None:
def test_daily_definition_is_bounded_and_enabled() -> None:
from pathlib import Path
from activity_core.definition_parser import parse_file
definition = parse_file(Path("activity-definitions/daily-sbom-catchup.md"))
assert definition.enabled is False
assert definition.enabled is True
# No rule block: the weekly flood came from `for_each` over every stale repo.
assert definition.rules == []
source = definition.context_sources[0]
@ -443,3 +443,31 @@ def test_daily_definition_is_bounded_and_disabled() -> None:
instruction = definition.instructions[0]
assert instruction["model"] == "deterministic"
assert instruction["report_sinks"][0]["event_type"] == "sbom_catchup"
def test_railiance_projection_enables_the_same_bounded_contract(tmp_path) -> None:
from pathlib import Path
import yaml
from activity_core.definition_parser import parse_file
documents = list(
yaml.safe_load_all(Path("k8s/railiance/20-runtime.yaml").read_text())
)
config = next(
item
for item in documents
if isinstance(item, dict)
and item.get("kind") == "ConfigMap"
and item.get("metadata", {}).get("name")
== "actcore-external-activity-definitions"
)
projected = tmp_path / "daily-sbom-catchup.md"
projected.write_text(config["data"]["daily-sbom-catchup.md"])
definition = parse_file(projected)
assert definition.enabled is True
assert definition.rules == []
source = definition.context_sources[0]
assert source["params"] == {"limit": 3, "apply": True}