Skip to content

Commit 709c9d4

Browse files
authored
ci: Harden release workflows (#12711)
## Summary - Reduces default release workflow token scope and grants write/OIDC only where release jobs need it. - Pins release actions, runners, container images, and mutable CLI installs for more reproducible release execution. - Adds SHA/version/branch validation, checksum-verified tool downloads, npm provenance, and removes synthesized release PR checks.
1 parent 382f305 commit 709c9d4

3 files changed

Lines changed: 149 additions & 98 deletions

File tree

.github/workflows/turborepo-library-release.yml

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ on:
88
type: boolean
99

1010
permissions:
11-
contents: write
12-
pull-requests: write
11+
contents: read
1312

1413
jobs:
1514
build:
@@ -21,39 +20,49 @@ jobs:
2120
fail-fast: false
2221
matrix:
2322
settings:
24-
- host: macos-latest
23+
- host: macos-14
2524
target: aarch64-apple-darwin
2625

27-
- host: macos-latest
26+
- host: macos-14
2827
target: x86_64-apple-darwin
2928

30-
- host: ubuntu-latest
29+
- host: ubuntu-24.04
3130
target: aarch64-unknown-linux-gnu
3231
setup: |
3332
sudo apt update
3433
sudo apt install -y g++-aarch64-linux-gnu libc6-dev-arm64-cross xz-utils
3534
mkdir zig
36-
curl --show-error --location https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz | tar -J -xf - -C zig --strip-components 1
35+
curl --fail --show-error --silent --location --output zig.tar.xz https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz
36+
echo "473ec26806133cf4d1918caf1a410f8403a13d979726a9045b421b685031a982 zig.tar.xz" | sha256sum --check --strict
37+
tar -J -xf zig.tar.xz -C zig --strip-components 1
38+
rm zig.tar.xz
3739
export PATH=$PATH:$(pwd)/zig
3840
echo "$(pwd)/zig" >> $GITHUB_PATH
3941
40-
- host: ubuntu-latest
42+
- host: ubuntu-24.04
4143
target: x86_64-unknown-linux-gnu
42-
container: amazon/aws-lambda-nodejs:20
44+
container: amazon/aws-lambda-nodejs:20@sha256:a7ac1ea17664bc42317bf0f4b25482413dc6427e73c319b4e46ac63a2b4cad73
4345
install: |
4446
microdnf install -y gcc gcc-c++ git tar xz make
45-
curl https://sh.rustup.rs -sSf | bash -s -- -y
47+
curl --proto '=https' --tlsv1.2 --fail --show-error --silent --location --output rustup-init https://static.rust-lang.org/rustup/archive/1.29.0/x86_64-unknown-linux-gnu/rustup-init
48+
echo "4acc9acc76d5079515b46346a485974457b5a79893cfb01112423c89aeb5aa10 rustup-init" | sha256sum --check --strict
49+
chmod +x rustup-init
50+
./rustup-init -y
51+
rm rustup-init
4652
npm i -g pnpm@10.28.0
4753
mkdir ../zig
48-
curl --show-error --location https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz | tar -J -xf - -C ../zig --strip-components 1
54+
curl --fail --show-error --silent --location --output zig.tar.xz https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz
55+
echo "473ec26806133cf4d1918caf1a410f8403a13d979726a9045b421b685031a982 zig.tar.xz" | sha256sum --check --strict
56+
tar -J -xf zig.tar.xz -C ../zig --strip-components 1
57+
rm zig.tar.xz
4958
export PATH=$PATH:$(pwd)/../zig
5059
echo "$(pwd)/../zig" >> $GITHUB_PATH
5160
setup: |
52-
pnpm install
61+
pnpm install --frozen-lockfile
5362
54-
- host: ubuntu-latest
63+
- host: ubuntu-24.04
5564
target: x86_64-unknown-linux-musl
56-
container: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-alpine
65+
container: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-alpine@sha256:11bf6f488b38a7d22592c92bfacfbb1479ef61943e42c911f84135c3aae67112
5766
install: |
5867
apk update && apk upgrade
5968
apk add libc6-compat curl
@@ -63,11 +72,11 @@ jobs:
6372
export PATH=/usr/local/cargo/bin/rustup:/root/.cargo/bin:${PATH}
6473
rustup show active-toolchain
6574
dirname $(rustup which cargo) >> ${GITHUB_PATH}
66-
pnpm install
75+
pnpm install --frozen-lockfile
6776
68-
- host: ubuntu-latest
77+
- host: ubuntu-24.04
6978
target: aarch64-unknown-linux-musl
70-
container: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-alpine
79+
container: ghcr.io/napi-rs/napi-rs/nodejs-rust:stable-2023-09-17-alpine@sha256:11bf6f488b38a7d22592c92bfacfbb1479ef61943e42c911f84135c3aae67112
7180
install: |
7281
apk update && apk upgrade
7382
apk add libc6-compat curl
@@ -79,13 +88,13 @@ jobs:
7988
rustup show active-toolchain
8089
rustup target add aarch64-unknown-linux-musl
8190
dirname $(rustup which cargo) >> ${GITHUB_PATH}
82-
pnpm install
91+
pnpm install --frozen-lockfile
8392
rust_env: CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER=/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc RUSTFLAGS="-Ctarget-feature=-crt-static"
8493

85-
- host: windows-latest
94+
- host: windows-2022
8695
target: aarch64-pc-windows-msvc
8796

88-
- host: windows-latest
97+
- host: windows-2022
8998
target: x86_64-pc-windows-msvc
9099

91100
runs-on: ${{ matrix.settings.host }}
@@ -98,7 +107,7 @@ jobs:
98107
if: ${{ matrix.settings.install }}
99108

100109
- name: Checkout
101-
uses: actions/checkout@v4
110+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
102111
with:
103112
fetch-depth: 0
104113
persist-credentials: false
@@ -132,25 +141,27 @@ jobs:
132141
${{ matrix.settings.rust_env }} pnpm build:release --target=${{ matrix.settings.target }}
133142
134143
- name: Upload Artifacts
135-
uses: actions/upload-artifact@v4
144+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
136145
with:
137146
name: turbo-library-${{ matrix.settings.target }}
138147
path: packages/turbo-repository/native
139148

140149
package:
141150
name: Publish to NPM
142-
runs-on: ubuntu-latest
151+
runs-on: ubuntu-24.04
143152
timeout-minutes: 30
144153
permissions:
145154
contents: write
146155
id-token: write # Required for npm Trusted Publishing using OIDC
156+
env:
157+
NPM_CONFIG_PROVENANCE: "true"
147158
needs: [build]
148159
outputs:
149160
version: ${{ steps.version.outputs.version }}
150161
branch: ${{ steps.version.outputs.branch }}
151162
steps:
152163
- name: Checkout
153-
uses: actions/checkout@v4
164+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
154165
with:
155166
fetch-depth: 0
156167
persist-credentials: false
@@ -191,7 +202,7 @@ jobs:
191202
--include-untracked
192203
193204
- name: Download Artifacts
194-
uses: actions/download-artifact@v4
205+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
195206
with:
196207
path: native-packages
197208

@@ -226,7 +237,7 @@ jobs:
226237
mv *.tgz tarballs/
227238
228239
- name: Upload Artifacts
229-
uses: actions/upload-artifact@v4
240+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
230241
with:
231242
name: Upload Tarballs
232243
path: tarballs
@@ -238,20 +249,23 @@ jobs:
238249
cd tarballs
239250
ls
240251
TAG="canary"
241-
npm publish -ddd --tag ${TAG} --access public turbo-repository-darwin-arm64-${VERSION}.tgz
242-
npm publish -ddd --tag ${TAG} --access public turbo-repository-darwin-x64-${VERSION}.tgz
243-
npm publish -ddd --tag ${TAG} --access public turbo-repository-linux-arm64-gnu-${VERSION}.tgz
244-
npm publish -ddd --tag ${TAG} --access public turbo-repository-linux-arm64-musl-${VERSION}.tgz
245-
npm publish -ddd --tag ${TAG} --access public turbo-repository-linux-x64-gnu-${VERSION}.tgz
246-
npm publish -ddd --tag ${TAG} --access public turbo-repository-linux-x64-musl-${VERSION}.tgz
247-
npm publish -ddd --tag ${TAG} --access public turbo-repository-win32-arm64-msvc-${VERSION}.tgz
248-
npm publish -ddd --tag ${TAG} --access public turbo-repository-win32-x64-msvc-${VERSION}.tgz
249-
npm publish -ddd --tag ${TAG} --access public turbo-repository-${VERSION}.tgz
252+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-darwin-arm64-${VERSION}.tgz"
253+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-darwin-x64-${VERSION}.tgz"
254+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-linux-arm64-gnu-${VERSION}.tgz"
255+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-linux-arm64-musl-${VERSION}.tgz"
256+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-linux-x64-gnu-${VERSION}.tgz"
257+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-linux-x64-musl-${VERSION}.tgz"
258+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-win32-arm64-msvc-${VERSION}.tgz"
259+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-win32-x64-msvc-${VERSION}.tgz"
260+
npm publish --provenance --tag "$TAG" --access public "turbo-repository-${VERSION}.tgz"
250261
251262
create-release-pr:
252263
name: Create Release PR
253-
runs-on: ubuntu-latest
264+
runs-on: ubuntu-24.04
254265
timeout-minutes: 10
266+
permissions:
267+
contents: write
268+
pull-requests: write
255269
needs: [package]
256270
if: ${{ !inputs.dry_run }}
257271
steps:
@@ -281,8 +295,10 @@ jobs:
281295
282296
cleanup-on-failure:
283297
name: Cleanup Failed Release
284-
runs-on: ubuntu-latest
298+
runs-on: ubuntu-24.04
285299
timeout-minutes: 10
300+
permissions:
301+
contents: write
286302
needs: [package]
287303
if: ${{ always() && needs.package.result == 'failure' }}
288304
steps:
@@ -292,6 +308,10 @@ jobs:
292308
run: |
293309
BRANCH="${{ needs.package.outputs.branch }}"
294310
if [ -n "${BRANCH}" ]; then
311+
if [[ ! "$BRANCH" =~ ^library-release/[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
312+
echo "::error::Refusing to delete unexpected release branch: $BRANCH"
313+
exit 1
314+
fi
295315
echo "Cleaning up branch ${BRANCH}..."
296316
gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/${BRANCH}" || echo "Branch may already be deleted"
297317
fi

0 commit comments

Comments
 (0)