Merge pull request #41 from andreibesleaga/feat/v2.0 #3
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release (SBOM · SLSA provenance · Sigstore) | |
| # Triggered on version tags. Produces a CycloneDX SBOM, SLSA build provenance, | |
| # and a cosign keyless signature for supply-chain verifiability. | |
| on: | |
| push: | |
| tags: ["v*"] | |
| permissions: | |
| contents: read | |
| jobs: | |
| build: | |
| name: Build · test · SBOM | |
| runs-on: ubuntu-latest | |
| outputs: | |
| hashes: ${{ steps.hash.outputs.hashes }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: "npm" | |
| - run: npm ci | |
| - run: npm run build | |
| - run: npm run test:coverage | |
| - name: CycloneDX 1.6 SBOM | |
| run: npx --yes @cyclonedx/cyclonedx-npm@latest --output-format JSON --spec-version 1.6 --output-file sbom.json | |
| - name: Pack tarball (from a staging dir → Apache-2.0 LICENSE, no GPL leak) | |
| # The published library is Apache-2.0 but the repo root LICENSE is GPL-3.0 | |
| # (the app/aggregate). `npm pack` force-includes the root LICENSE; pack from | |
| # a clean staging dir whose only LICENSE is LICENSE-APACHE. See docs/RELEASE.md. | |
| run: bash scripts/pack-staging.sh | |
| - name: Subject hashes (for provenance) | |
| id: hash | |
| run: echo "hashes=$(sha256sum *.tgz sbom.json | base64 -w0)" >> "$GITHUB_OUTPUT" | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: release-artifacts | |
| path: | | |
| *.tgz | |
| sbom.json | |
| provenance: | |
| name: SLSA provenance | |
| needs: [build] | |
| permissions: | |
| actions: read | |
| id-token: write | |
| contents: write | |
| uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 | |
| with: | |
| base64-subjects: ${{ needs.build.outputs.hashes }} | |
| upload-assets: true | |
| sign: | |
| name: Cosign keyless signing | |
| needs: [build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: release-artifacts | |
| - uses: sigstore/cosign-installer@v3 | |
| - name: Sign artifacts (keyless OIDC) | |
| run: | | |
| for f in *.tgz sbom.json; do | |
| cosign sign-blob --yes "$f" \ | |
| --output-signature "$f.sig" --output-certificate "$f.pem" | |
| done | |
| - uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| *.tgz | |
| sbom.json | |
| *.sig | |
| *.pem | |
| image: | |
| name: Build · push · sign container image | |
| needs: [build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: docker/setup-buildx-action@v4 | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=ref,event=tag | |
| - id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| - uses: sigstore/cosign-installer@v3 | |
| - name: Sign the image (keyless OIDC) | |
| env: | |
| DIGEST: ${{ steps.build.outputs.digest }} | |
| # Pass the (multi-line) tag list via env, not inline interpolation, so a | |
| # second tag doesn't break the shell. Iterate line-by-line. | |
| TAGS: ${{ steps.meta.outputs.tags }} | |
| run: | | |
| echo "$TAGS" | while read -r tag; do | |
| [ -n "$tag" ] && cosign sign --yes "${tag}@${DIGEST}" | |
| done |