-
Notifications
You must be signed in to change notification settings - Fork 0
129 lines (122 loc) · 4.1 KB
/
Copy pathrelease.yml
File metadata and controls
129 lines (122 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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@v7
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run build
- run: npm run test:coverage
- name: CycloneDX 1.6 SBOM
# --ignore-npm-errors: `npm ls` exits non-zero on a harmless dev-only peer
# mismatch (madge→precinct wants TypeScript 5.x while the project pins 6.x);
# the installed tree is valid, so the SBOM is still complete and accurate.
# (Mirrors the same flag in ci.yml's Security job.)
run: npx --yes @cyclonedx/cyclonedx-npm@latest --ignore-npm-errors --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.1.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@v8
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@v6
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