Skip to content

Commit 6328c38

Browse files
basvandijkclaude
andauthored
fix(ci): verify execlog2csv against a pinned sha256 (#11310)
## What The shared bazel composite action downloaded the `execlog2csv` zip from `github.com/dfinity/execlog2csv` release assets, unzipped it, installed it to `/usr/local/bin` with `sudo` and ran it — trusting nothing but the URL. This pins the sha256 of each release zip in this repo and checks the download **before** unpacking or executing any of it, following the pattern already used for bazelisk in [`ci/container/Dockerfile`](https://github.com/dfinity/ic/blob/master/ci/container/Dockerfile#L34-L36). ## Why GitHub release assets are mutable under an existing tag — the API reports `"immutable": false` for `v0.0.2` — so anyone with release access to that separate, low-profile repo got code execution inside every ic CI job that enables execlogs. That includes `bazel-test-all` on release builds, where the binary runs *after* `configure-aws-credentials` has exported the artifact-upload role into the job env and while `CF_AWS_ACCESS_KEY_ID`/`CF_AWS_SECRET_ACCESS_KEY` are present. The hashes come from the release's `execlog2csv_0.0.2_SHA256SUMS` asset. Verifying against that asset *at runtime* would be worthless: it is a mutable asset in the same release, so whoever can swap the zip can swap the sums file alongside it. The hashes have to live here, in a reviewed tree. ## Notes on the implementation - A `case` rather than `declare -A`: macOS ships bash 3.2, which has no associative arrays, and this script supports darwin. - `shasum -a 256` fallback for the same reason — macOS has no coreutils `sha256sum`. - `curl -SLO` → `-fSLO`, so an HTTP error page fails at the real cause instead of as a hash mismatch. - All four os/arch combos the script can construct are pinned; an unpinned combo exits 1 rather than silently skipping verification. - Pinned version `0.0.2` is already the latest release, so no version bump was needed. ## Fails closed, and that blocks release uploads The step runs under GitHub's `shell: bash` default (`-eo pipefail`), so a mismatch aborts the step and fails the job. In `bazel-test-all` the composite action's first invocation completes *before* the job's `Upload artifacts` step, which has no `if: always()` — so on a release build a hash mismatch also stops publication to `download.dfinity.systems`. This is not a behavioural regression: a failing `curl` or `unzip` already fails the step today. ## Verification Ran against the live upstream release: - **Positive** — step runs end-to-end, logs `execlog2csv_0.0.2_linux_amd64.zip: OK`, binary installs and `--help` works. - **Negative** — one flipped hex char → `WARNING: 1 computed checksum did NOT match`, exit 1, and no `execlog2csv_v0.0.2` extracted, confirming the check precedes `unzip`. - **Unpinned platform** — forcing `freebsd_amd64` prints `no pinned sha256 for 'freebsd_amd64'` and exits 1. - **darwin `shasum` branch** — OK/exit 0 on the real hash, FAILED/exit 1 on a corrupted one. - All four pinned hashes re-checked programmatically against upstream's `SHA256SUMS` — 4/4 match. CI itself exercises this in all three execlog-enabled invocations: `Bazel Test All` (Run Bazel Commands + Run Tests) and `Build IC`. ## Scope / residual risk - A pin authenticates bytes, not intent. On `pull_request` events the composite action comes from the PR tree, so a PR author can edit the hash alongside the URL; this protects protected-branch and release builds, where the tree is reviewed. - Defence-in-depth follow-up outside this repo: ask `dfinity/execlog2csv` to publish **immutable releases** and build-provenance attestations, then verify with `gh attestation verify`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 96c981b commit 6328c38

1 file changed

Lines changed: 30 additions & 3 deletions

File tree

.github/actions/bazel/action.yaml

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ runs:
120120
# https://github.com/dfinity/execlog2csv/releases/latest
121121
if [[ $(uname -m) == "x86_64" ]]; then
122122
arch="amd64"
123-
elif [[ $(uname -m) == "aarch64" ]]; then
123+
# Linux reports aarch64 here, Darwin (Apple Silicon) reports arm64.
124+
elif [[ $(uname -m) == "aarch64" || $(uname -m) == "arm64" ]]; then
124125
arch="arm64"
125126
else
126127
echo "unexpected architecture: '$(uname -m)'"
@@ -132,15 +133,41 @@ runs:
132133
elif [[ $(uname) == "Darwin" ]]; then
133134
os="darwin"
134135
else
135-
echo "unexpected os: '$(uname -m)'"
136+
echo "unexpected os: '$(uname)'"
136137
exit 1
137138
fi
138139
139140
filename="execlog2csv_${version}_${os}_${arch}"
140141
echo "filename: $filename"
142+
143+
# sha256 of the release zips.
144+
#
145+
# GitHub release assets are mutable under an existing tag, so the download is
146+
# only trustworthy when checked against a hash recorded here, in this repo.
147+
# NOTE: these MUST be updated together with `version` above. Refresh with:
148+
# curl -fsSL "https://github.com/dfinity/execlog2csv/releases/download/v$version/execlog2csv_${version}_SHA256SUMS"
149+
case "${os}_${arch}" in
150+
linux_amd64) sha256=cfbeeae1b2138742e3953ad0a7d55cbd11e0bf0dfe96d00e75b45c46e186244e ;;
151+
linux_arm64) sha256=f68aa6317becf85436db8983f76cd06fea7544ec25e0a75e71d8fc8178e2d2b2 ;;
152+
darwin_amd64) sha256=095dcb5f07b1c6e8edb0293b6abad60c519dea1d0b25090dadc15bf42539700f ;;
153+
darwin_arm64) sha256=1ca6ebc9b2b4a5e50fad9013978398c8f5cc7f33318cb1528e6fb0879f32b5c6 ;;
154+
*)
155+
echo "no pinned sha256 for '${os}_${arch}'"
156+
exit 1
157+
;;
158+
esac
159+
141160
dl_url="https://github.com/dfinity/execlog2csv/releases/download/v$version/$filename.zip"
142161
echo "downloading '$dl_url'"
143-
curl -SLO "$dl_url"
162+
curl -fSLO "$dl_url"
163+
164+
# Verify the download before unpacking or executing any of it.
165+
if command -v sha256sum >/dev/null; then
166+
echo "$sha256 $filename.zip" | sha256sum --check
167+
else
168+
echo "$sha256 $filename.zip" | shasum -a 256 --check
169+
fi
170+
144171
unzip "$filename.zip"
145172
sudo mv "./execlog2csv_v$version" /usr/local/bin/execlog2csv
146173
rm "$filename.zip"

0 commit comments

Comments
 (0)