-
Notifications
You must be signed in to change notification settings - Fork 0
199 lines (185 loc) · 7.37 KB
/
Copy path_release_harden.yml
File metadata and controls
199 lines (185 loc) · 7.37 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
name: _release_harden (reusable)
# Reusable release-hardening workflow shared by the TinkerNorth release
# pipelines (satellite, dish-linux, dish-windows). One job: download every
# per-platform build artifact, Grype-scan it, emit SPDX + CycloneDX SBOMs,
# generate SHA256SUMS, cosign-sign every file (keyless), and upload the lot
# as the `release-bundle` artifact the caller's provenance + publish jobs
# consume.
#
# Source of truth: TinkerNorth/satellite/.github/workflows/_release_harden.yml
# Re-sync a copy with:
# cp ../satellite/.github/workflows/_release_harden.yml .github/workflows/_release_harden.yml
#
# Callers invoke this with:
#
# jobs:
# harden:
# needs: [<all platform build jobs>]
# permissions:
# contents: read
# id-token: write # cosign keyless
# security-events: write # Grype SARIF upload to code scanning
# uses: ./.github/workflows/_release_harden.yml
# with:
# artifact-pattern: 'linux-*' # download-artifact glob
# product: 'dish' # SBOM filename prefix
# grype-ignore-name-regex: '' # optional CPE-collision ignore
#
# The caller then feeds `needs.harden.outputs.hashes` to the SLSA generic
# generator and publishes the `release-bundle` artifact.
#
# Pin map (owner/repo @ tag → 40-char SHA), verify on update with
# gh api repos/<owner>/<repo>/git/ref/tags/<tag>:
# actions/download-artifact @ v8.0.1 → 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
# actions/upload-artifact @ v7.0.1 → 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
# anchore/scan-action @ v7.4.0 → e1165082ffb1fe366ebaf02d8526e7c4989ea9d2
# anchore/sbom-action @ v0.24.0 → e22c389904149dbc22b58101806040fa8d37a610
# github/codeql-action @ v4.37.7 → ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd
on:
workflow_call:
inputs:
artifact-pattern:
description: "download-artifact glob matching the per-platform build artifacts"
required: true
type: string
product:
description: "SBOM filename prefix (e.g. dish, satellite)"
required: true
type: string
grype-ignore-name-regex:
description: "Optional Grype package-name regex ignored as a CPE collision with first-party artifact names"
required: false
default: ""
type: string
outputs:
hashes:
description: "base64-encoded sha256sum block over every non-signature file, for the SLSA generic generator"
value: ${{ jobs.harden.outputs.hashes }}
jobs:
harden:
name: scan, SBOM, sign
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read
id-token: write
security-events: write
outputs:
hashes: ${{ steps.hashes.outputs.hashes }}
steps:
- name: Download platform artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: ${{ inputs.artifact-pattern }}
merge-multiple: true
path: release
- name: Show what arrived
shell: bash
run: find release -type f -printf '%p\n'
- name: Ignore CPE name collisions against first-party artifact names
if: ${{ inputs.grype-ignore-name-regex != '' }}
shell: bash
env:
IGNORE_REGEX: ${{ inputs.grype-ignore-name-regex }}
run: |
set -euo pipefail
printf 'ignore:\n - package:\n name: "%s"\n' "${IGNORE_REGEX}" > .grype.yaml
cat .grype.yaml
# Anchore Grype: scan every artifact in release/ for CVEs.
- name: Vulnerability scan (Grype)
uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0
id: grype
with:
path: release/
severity-cutoff: high
fail-build: true
only-fixed: false
add-cpes-if-none: true
output-format: sarif
- name: Upload Grype SARIF to code scanning
if: ${{ always() && steps.grype.outputs.sarif != '' }}
continue-on-error: true
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
sarif_file: ${{ steps.grype.outputs.sarif }}
category: release-grype
# Syft: produce SPDX + CycloneDX SBOMs over the whole bundle.
- name: Generate SBOM (SPDX)
uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2
with:
path: release/
format: spdx-json
output-file: release/${{ inputs.product }}.sbom.spdx.json
upload-artifact: false
upload-release-assets: false
- name: Generate SBOM (CycloneDX)
uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2
with:
path: release/
format: cyclonedx-json
output-file: release/${{ inputs.product }}.sbom.cdx.json
upload-artifact: false
upload-release-assets: false
- name: Install cosign (upstream binary)
shell: bash
env:
COSIGN_VERSION: "2.6.5"
# Pin upstream SHA-256 of cosign-linux-amd64. Verify with:
# gh release download v${COSIGN_VERSION} -R sigstore/cosign -p cosign_checksums.txt -O -
COSIGN_SHA256: "c3b4f5410e608af03a5eb0aaac84a4313d8da131248e08ff1759ac70c79d1644" # cosign-linux-amd64 v2.6.5
run: |
set -euo pipefail
curl -fsSL -o /tmp/cosign \
"https://github.com/sigstore/cosign/releases/download/v${COSIGN_VERSION}/cosign-linux-amd64"
echo "${COSIGN_SHA256} /tmp/cosign" | sha256sum -c -
chmod +x /tmp/cosign
sudo mv /tmp/cosign /usr/local/bin/cosign
cosign version
- name: Generate SHA256SUMS
shell: bash
run: |
set -euo pipefail
cd release
# `sha256sum --binary` produces deterministic, byte-mode digests.
# Sort so the file order is stable regardless of how artifacts
# arrived.
find . -maxdepth 1 -type f ! -name 'SHA256SUMS*' -printf '%f\n' \
| LC_ALL=C sort \
| xargs -d '\n' sha256sum --binary > SHA256SUMS
cat SHA256SUMS
- name: Cosign-sign each artifact + SHA256SUMS (keyless)
shell: bash
env:
COSIGN_EXPERIMENTAL: "1"
run: |
set -euo pipefail
cd release
for f in *; do
case "$f" in
*.sig|*.crt|SHA256SUMS.sig|SHA256SUMS.crt) continue ;;
esac
cosign sign-blob --yes \
--output-signature "${f}.sig" \
--output-certificate "${f}.crt" \
"$f"
done
ls -l
- name: Compute base64 SHA256 hashes for SLSA provenance
id: hashes
shell: bash
run: |
set -euo pipefail
cd release
# SLSA generic generator wants `<base64> <name>` lines, base64-encoded.
h=$(find . -maxdepth 1 -type f ! -name '*.sig' ! -name '*.crt' \
-printf '%f\n' \
| LC_ALL=C sort \
| xargs -d '\n' sha256sum \
| base64 -w0)
echo "hashes=${h}" >> "$GITHUB_OUTPUT"
- name: Upload hardened bundle
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-bundle
path: release/
retention-days: 14