-
Notifications
You must be signed in to change notification settings - Fork 0
187 lines (176 loc) · 7.73 KB
/
Copy pathrelease.yml
File metadata and controls
187 lines (176 loc) · 7.73 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
name: Release
on:
push:
tags: ['v*']
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
jobs:
# Preflight: require the tagged commit to have a green CI run before anything
# else starts. This closes the gap that let the first v0.9.1 release attempt
# (run 24641035038) reach Sign-and-Release despite a failing commit.
verify-ci:
name: Verify CI passed on tagged commit
runs-on: [self-hosted, Linux]
timeout-minutes: 5
steps:
- name: Require latest CI run on this SHA to be success
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
SHA: ${{ github.sha }}
run: |
set -euo pipefail
echo "Checking CI status for $REPO @ $SHA"
# Use curl + jq (always present on self-hosted runners) — avoids
# a hard dep on the gh CLI, which is not installed on every
# [self-hosted, Linux] label in our fleet (see release run
# 24915505204 where the gate died with `gh: command not found`).
response=$(curl -fsS \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${REPO}/actions/workflows/ci.yml/runs?head_sha=${SHA}&per_page=1")
echo "$response" | jq '.workflow_runs[0] | {head_sha, status, conclusion, html_url}'
# Belt-and-braces: pin the picked run to the exact tagged SHA.
# The head_sha query param is a filter, but defending against a
# future API edge case (or a forced-push race) costs one jq
# filter and stops a green-on-different-sha run from being
# accepted as proof. (DevOps P1 hardening.)
run_sha=$(echo "$response" | jq -r '.workflow_runs[0].head_sha // "missing"')
conclusion=$(echo "$response" | jq -r '.workflow_runs[0].conclusion // "missing"')
if [[ "$run_sha" != "$SHA" ]]; then
echo "::error::No CI run found for ${SHA} (got head_sha=${run_sha}). Aborting release."
exit 1
fi
if [[ "$conclusion" != "success" ]]; then
echo "::error::CI has not passed on ${SHA}: conclusion=${conclusion}. Aborting release."
exit 1
fi
echo "CI is green for this SHA."
build-linux:
name: Build static musl binary
needs: [verify-ci]
runs-on: [self-hosted, Linux]
timeout-minutes: 30
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: ./.github/actions/rust-setup
with:
targets: x86_64-unknown-linux-musl
cache-prefix: release-musl
- name: Install musl toolchain
run: |
if ! command -v musl-gcc &> /dev/null; then
sudo apt-get update
sudo apt-get install -y musl-tools
fi
- name: Build static binary (with PQC support)
run: cargo build --release --features pqc --target x86_64-unknown-linux-musl -p pki-client
- name: Strip binary
run: strip target/x86_64-unknown-linux-musl/release/pki
- name: Verify static linking
run: |
ldd_out=$(ldd target/x86_64-unknown-linux-musl/release/pki 2>&1 || true)
if echo "$ldd_out" | grep -Eq "statically linked|not a dynamic"; then
echo "OK: statically linked"
else
echo "ERROR: binary is not fully static"
echo "$ldd_out"
exit 1
fi
ls -lh target/x86_64-unknown-linux-musl/release/pki
- name: Stage release artifact
env:
TAG_NAME: ${{ github.ref_name }}
run: |
set -euo pipefail
VERSION="${TAG_NAME#v}"
ASSET="pki-${VERSION}-linux-x86_64-musl"
cp target/x86_64-unknown-linux-musl/release/pki "$ASSET"
chmod +x "$ASSET"
ls -lh "$ASSET"
# Smoke-test: the binary itself runs and reports the right version.
./"$ASSET" --version
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: pki-linux-musl
path: pki-*-linux-x86_64-musl
sign-and-release:
name: Sign and Release
needs: [verify-ci, build-linux]
runs-on: [self-hosted, Linux]
permissions:
contents: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
merge-multiple: true
- name: Install gh CLI
run: |
if ! command -v gh &> /dev/null; then
if command -v dnf &> /dev/null; then
sudo dnf install -y 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo rpm --import https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x23F3D4EA75716059
sudo dnf install -y gh
elif command -v apt-get &> /dev/null; then
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt-get update
sudo apt-get install -y gh
else
echo "ERROR: No supported package manager found (dnf or apt-get)"
exit 1
fi
fi
# --- Supply chain security: Sigstore cosign signing ---
# Signing order matters for checksum coverage:
# 1. Sign the binary first, producing a .bundle file.
# 2. Generate SHA256SUMS.txt over both deliverables (binary + bundle).
# 3. Sign SHA256SUMS.txt itself, producing SHA256SUMS.txt.bundle.
# Users who download SHA256SUMS.txt can sha256sum-verify the binary;
# SHA256SUMS.txt.bundle is the Sigstore root of trust for the file.
- name: Install cosign
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3
- name: Sign binary with cosign (keyless)
run: |
set -euo pipefail
for f in pki-*-linux-x86_64-musl; do
cosign sign-blob --yes --bundle "${f}.bundle" "$f"
done
- name: Generate checksums (binary + bundle)
run: |
set -euo pipefail
sha256sum pki-*-linux-x86_64-musl pki-*-linux-x86_64-musl.bundle > SHA256SUMS.txt
cat SHA256SUMS.txt
- name: Verify checksums round-trip
run: sha256sum -c SHA256SUMS.txt
- name: Sign SHA256SUMS.txt with cosign (keyless)
run: cosign sign-blob --yes --bundle SHA256SUMS.txt.bundle SHA256SUMS.txt
# --- Supply chain security: SLSA provenance (signed assets only) ---
- name: Attest build provenance (binary)
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: pki-*-linux-x86_64-musl
- name: Attest build provenance (checksums)
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: SHA256SUMS.txt
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ github.ref_name }}
run: |
gh release create "$TAG_NAME" \
--title "$TAG_NAME" \
--generate-notes \
pki-*-linux-x86_64-musl SHA256SUMS.txt *.bundle