chore(work): decompose security-headers-rate-limit-sbom epic

Generated 1 epic + 11 stories under docs/work/epics/ from the approved
PRD docs/work/prds/security-headers-rate-limit-sbom.prd.md. Stories
cover rate-limit type primitives + implementations + ESLint rule +
withRateLimit wrapper, auth.signIn rate-limit backfill, security
headers core module + framework adapters, app wiring across web-next /
web-tanstack / cms, SBOM CI workflow, and documentation. Ready for
`pnpm work dispatch --execute`.
This commit is contained in:
2026-05-20 10:14:54 +02:00
parent 352a7c64c1
commit a633561c82
13 changed files with 762 additions and 3 deletions

View File

@@ -0,0 +1,45 @@
---
id: 10-sbom-ci-workflow
epic: security-headers-rate-limit-sbom
title: SBOM CI workflow and ADR-023 amendment
type: technical-story
status: todo
feature: ci
depends-on: []
blocks: []
created: 2026-05-20T00:00:00Z
updated: 2026-05-20T08:14:55.907Z
---
## Goal
Amend `.github/workflows/release-please.yml` to generate a CycloneDX SBOM and upload it as a GitHub release asset whenever release-please cuts a release, and capture the concrete workflow step as an amendment to ADR-023 §10.
## Why
Consumers pursuing SOC 2 / ISO 27001 / FedRAMP / EU CRA must answer "what's in version X" without inventory inspection. A CycloneDX SBOM attached to every GitHub release gives auditors a machine-readable, per-release artifact. `pnpm dlx` avoids adding `@cyclonedx/cyclonedx-npm` to the lockfile (CI-only tool per ADR-022). The Renovate-pinned SHA on `softprops/action-gh-release` follows the established ADR-023 pattern.
## Done when
- `.github/workflows/release-please.yml` has a conditional step that runs `pnpm dlx @cyclonedx/cyclonedx-npm --output-file sbom-<tag>.cdx.json --output-format json` when `steps.release.outputs.releases_created == 'true'`.
- A `softprops/action-gh-release@<SHA>` step (Renovate-managed SHA per ADR-023) uploads the SBOM JSON file as a release asset with `tag_name: ${{ steps.release.outputs.tag_name }}`.
- `docs/decisions/adr-023-ci-security-and-supply-chain.md` contains a new amendment subsection capturing the SBOM step's concrete shape and rationale.
- Local validation: `pnpm dlx @cyclonedx/cyclonedx-npm --output-file sbom-test.cdx.json` succeeds and produces valid CycloneDX JSON.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass.
## In scope
- `.github/workflows/release-please.yml` — conditional SBOM generation + upload steps.
- `softprops/action-gh-release@<SHA>` with Renovate-managed SHA (choose a recent stable release; Renovate will keep it current).
- `docs/decisions/adr-023-ci-security-and-supply-chain.md` — amendment subsection §10 SBOM.
## Out of scope
- Per-PR SBOM generation — release-only per PRD.
- SBOM signing / SLSA provenance attestation — bare CycloneDX only; attestation is a future PRD.
- Per-package SBOMs — root SBOM covers all workspace packages; industry practice for monorepos.
- `@cyclonedx/cyclonedx-npm` added to `package.json` — invoked via `pnpm dlx` only.
## Tasks
- [ ] Add conditional SBOM generation step (`pnpm dlx @cyclonedx/cyclonedx-npm --output-file sbom-${{ steps.release.outputs.tag_name }}.cdx.json --output-format json`) and upload step (`softprops/action-gh-release@<SHA>` with `files:` pointing to the SBOM and `tag_name:` from release-please output) to `.github/workflows/release-please.yml`; add amendment subsection to `docs/decisions/adr-023-ci-security-and-supply-chain.md` documenting the concrete step shape and rationale; all gates pass.