-
Notifications
You must be signed in to change notification settings - Fork 2
310 lines (272 loc) · 11.3 KB
/
Copy pathcli-release.yml
File metadata and controls
310 lines (272 loc) · 11.3 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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
name: cli-release
on:
push:
tags:
- "cli-v*"
# Required secrets:
# HOMEBREW_TAP_TOKEN — fine-grained GitHub PAT with `contents: write`
# on vul-os/homebrew-tap (used by brew-tap job).
# The old goreleaser pipeline called this
# GORELEASER_TAP_TOKEN; rename or alias as needed.
# GITHUB_TOKEN — standard Actions token; used for release uploads
# and cosign OIDC (id-token: write below).
permissions:
contents: write
id-token: write # required for Sigstore keyless OIDC signing via cosign
packages: write
jobs:
build-release:
name: build (${{ matrix.target }})
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
archive: tar.gz
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
archive: tar.gz
- target: x86_64-apple-darwin
os: macos-latest
archive: tar.gz
- target: aarch64-apple-darwin
os: macos-latest
archive: tar.gz
- target: x86_64-pc-windows-msvc
os: windows-latest
archive: zip
runs-on: ${{ matrix.os }}
# cli/ is a standalone crate, so cargo must run inside it rather than
# against the engine workspace at the repo root.
defaults:
run:
working-directory: cli
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
# cross-linker for aarch64 linux on the amd64 runner
- name: Install aarch64 cross toolchain (Linux only)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update -q
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Set CARGO_TARGET env for cross-linker
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> "$GITHUB_ENV"
- name: Build release binary
run: cargo build --release --locked --target ${{ matrix.target }}
# taiki-e/upload-rust-binary-action packages, checksums, and uploads
# the binary to the GitHub release created by the tag push.
- uses: taiki-e/upload-rust-binary-action@v1
with:
bin: basin
target: ${{ matrix.target }}
archive: basin_$tag_$target
token: ${{ secrets.GITHUB_TOKEN }}
# `uses:` steps ignore defaults.run.working-directory, so the
# manifest has to be named explicitly from the repo root.
manifest-path: cli/Cargo.toml
# ── Sigstore keyless signing ────────────────────────────────────────
# Signs the release checksums file + each per-target archive with
# cosign in keyless (OIDC) mode. The signing identity is the Actions
# OIDC token for this workflow at the release tag, so no private keys
# are stored. Produces .sig + .pem (certificate) alongside each asset.
# Downstream verification:
# cosign verify-blob --certificate basin_<ver>_<target>.tar.gz.pem \
# --signature basin_<ver>_<target>.tar.gz.sig \
# --certificate-identity-regexp \
# '^https://github\.com/vul-os/basin/\.github/workflows/cli-release\.yml@refs/tags/cli-v.*$' \
# --certificate-oidc-issuer https://token.actions.githubusercontent.com \
# basin_<ver>_<target>.tar.gz
#
# The identity is the Fulcio SAN: repo-root-relative workflow path, `@`, then
# the triggering ref — `refs/tags/cli-v*` here, since this workflow only fires
# on `cli-v*` (bare `v*` is the engine's release). Keep this and cli/README.md
# in step; the README's copy named a `tree/main/cli/.../release.yml@refs/tags/v.*`
# identity that matched no certificate this job has ever minted.
sign:
name: cosign keyless signing
runs-on: ubuntu-latest
needs: build-release
permissions:
contents: write
id-token: write # mint OIDC token for keyless cosign
steps:
- uses: actions/checkout@v4
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Download release assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${GITHUB_REF_NAME}"
mkdir -p release-assets
gh release download "$TAG" --dir release-assets
- name: Sign all release assets (keyless, OIDC)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${GITHUB_REF_NAME}"
for asset in release-assets/*; do
# Skip files that are already signatures or certificates
[[ "$asset" == *.sig ]] && continue
[[ "$asset" == *.pem ]] && continue
echo "Signing: $asset"
cosign sign-blob --yes \
--output-signature="${asset}.sig" \
--output-certificate="${asset}.pem" \
"$asset"
done
# Upload .sig + .pem files back to the release
for sig in release-assets/*.sig release-assets/*.pem; do
[ -f "$sig" ] || continue
gh release upload "$TAG" "$sig" --clobber
done
# Docker image pushed to GHCR (linux amd64 + arm64 manifest list).
# Mirrors what goreleaser's dockers: + docker_manifests: blocks did.
docker:
name: docker (ghcr.io)
runs-on: ubuntu-latest
needs: build-release
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: docker/setup-qemu-action@v3
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/vul-os/basin
tags: |
type=semver,pattern={{version}}
type=raw,value=latest
# NOTE (pre-existing, carried over from bas-in/basin-cli unchanged):
# cli/Dockerfile is a distroless image whose only instruction is
# `COPY basin /usr/local/bin/basin`, i.e. it expects a prebuilt binary
# at the context root. This job sets up the Rust toolchain but never
# runs cargo, and never downloads the build-release artifacts — so the
# COPY has nothing to copy. Left as-is rather than guessed at; fixing
# it means deciding how the per-arch binaries reach the build context.
- name: Build and push multi-arch image
uses: docker/build-push-action@v6
with:
context: cli
file: cli/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# ── Homebrew tap auto-update ────────────────────────────────────────
# Generates and pushes an updated Formula/basin.rb to vul-os/homebrew-tap
# after all binaries are uploaded. Mirrors the goreleaser brews: block:
# name: basin, tap: vul-os/homebrew-tap, license: Apache-2.0,
# install: bin.install "basin".
# Requires HOMEBREW_TAP_TOKEN — a fine-grained PAT with contents: write
# on vul-os/homebrew-tap (the old goreleaser pipeline called this
# GORELEASER_TAP_TOKEN; same token, renamed for clarity).
brew-tap:
name: homebrew tap update
runs-on: ubuntu-latest
needs: build-release
steps:
- uses: actions/checkout@v4
- name: Compute release asset SHA256s + generate Formula/basin.rb
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#cli-v}"
BASE_URL="https://github.com/vul-os/basin/releases/download/${TAG}"
mkdir -p release-assets
gh release download "$TAG" --dir release-assets \
--pattern 'basin_*darwin*' --pattern 'basin_*linux*'
darwin_amd64_file=$(ls release-assets/basin_*x86_64-apple-darwin* 2>/dev/null | head -1)
darwin_arm64_file=$(ls release-assets/basin_*aarch64-apple-darwin* 2>/dev/null | head -1)
linux_amd64_file=$(ls release-assets/basin_*x86_64-unknown-linux-gnu* 2>/dev/null | head -1)
linux_arm64_file=$(ls release-assets/basin_*aarch64-unknown-linux-gnu* 2>/dev/null | head -1)
sha_darwin_amd64=$(sha256sum "$darwin_amd64_file" | awk '{print $1}')
sha_darwin_arm64=$(sha256sum "$darwin_arm64_file" | awk '{print $1}')
sha_linux_amd64=$(sha256sum "$linux_amd64_file" | awk '{print $1}')
sha_linux_arm64=$(sha256sum "$linux_arm64_file" | awk '{print $1}')
darwin_amd64=$(basename "$darwin_amd64_file")
darwin_arm64=$(basename "$darwin_arm64_file")
linux_amd64=$(basename "$linux_amd64_file")
linux_arm64=$(basename "$linux_arm64_file")
cat > Formula_basin.rb <<EOF
# Formula generated by basin-cli release workflow (vul-os/basin/.github/workflows/cli-release.yml)
# Do not edit manually — this file is overwritten on every release.
class Basin < Formula
desc "Basin Cloud control plane CLI"
homepage "https://basin.run"
license "Apache-2.0"
version "${VERSION}"
on_macos do
on_intel do
url "${BASE_URL}/${darwin_amd64}"
sha256 "${sha_darwin_amd64}"
end
on_arm do
url "${BASE_URL}/${darwin_arm64}"
sha256 "${sha_darwin_arm64}"
end
end
on_linux do
on_intel do
url "${BASE_URL}/${linux_amd64}"
sha256 "${sha_linux_amd64}"
end
on_arm do
url "${BASE_URL}/${linux_arm64}"
sha256 "${sha_linux_arm64}"
end
end
def install
bin.install "basin"
end
test do
system "#{bin}/basin", "--version"
end
end
EOF
- name: Push Formula/basin.rb to vul-os/homebrew-tap
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#cli-v}"
git config --global user.email "bot@basin.run"
git config --global user.name "basin-release-bot"
git clone \
"https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/vul-os/homebrew-tap.git" \
homebrew-tap
mkdir -p homebrew-tap/Formula
cp Formula_basin.rb homebrew-tap/Formula/basin.rb
cd homebrew-tap
git add Formula/basin.rb
if git diff --cached --quiet; then
echo "Formula unchanged — nothing to commit."
else
git commit -m "formula: bump basin to ${VERSION}"
git push origin main
fi