Skip to content

Commit d143fe0

Browse files
committed
feat: add SHA256 hash verification for the installer script
Verify the installer script's SHA256 hash against pinned values before execution, closing a supply chain gap. The expected hashes are stored in .codspeed-runner-installer-hashes.json (sourced from GitHub API digests). - For pinned release versions: download to temp file, verify hash, fail on mismatch or missing hash - For latest/branch/rev: warn that hash verification is not available - Add `skip-hash-check` input to bypass verification if needed - Update bump-runner-version workflow to fetch and store the hash Ref: COD-2243
1 parent ac0b020 commit d143fe0

File tree

4 files changed

+110
-11
lines changed

4 files changed

+110
-11
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"3.6.0": "e24d2883509f40e26105fabef599a8455417263a58c823cdeb29d18b417ddcbf",
3+
"3.6.1": "9af2aaf441ae11753d610db852f7bf34cf0472c88763b342e02a39dc49a54f62",
4+
"3.7.0": "ec0d7d35d9339dae8033a25e111647316148de62b9a6e1481e332da3bd372c8b",
5+
"3.8.0": "a4a9f80c116011853931fcd27bbab67f03dab2bdb39cd2a85a806e1680a51ce8",
6+
"3.8.1": "5921cce317a66d633b243503254498c60e3d19ae39d25a3cbbef168321a184d0",
7+
"4.0.0": "c224e1269c3d9b77038aad6d198b1122439a8b99c14cd650503d4be29bb28cea",
8+
"4.0.1": "e59b7e54e4085380939d326772743f5ed3eb391f5437be11657485587520a4d8",
9+
"4.1.0": "2a9aba44aabf093cca8e77ef67d3d72182420d102470ee937e6d60a32ded2327",
10+
"4.1.1": "cdab34d3468a5168900fbda54e2a24bbc7ed995f6a7c6c1a79407fc6f2e9a65a",
11+
"4.2.0": "37267e289dcc13dc903d193390707882ac5363a4ba649836a2deb35d491ddc97",
12+
"4.2.1": "4fbb63773a7d3faf6ff0e8a20d6a64de9df95e47f0ea741d92f068d798964d9e",
13+
"4.3.0-beta.0": "c9d3e98234d7b18545e1f035e6afac295938ba5ccf96f3da780290b2a7bdfccb",
14+
"4.3.0": "ff285a76118fb74e0b159b09c286b1e4dff061fbc9fc6ae5031165d2b922993c",
15+
"4.3.1": "69cc9a4fd8369b4a2f44b8d8abb4ddd04880a1f19897433e1e8fc45acebe4ca9",
16+
"4.3.2": "98390ad959286a6c42ef01402f88dfa8059cda81ca24d7d48383f55f704297e7",
17+
"4.3.3": "a3419c98f5af093c25ad6a9fef915b3717d67845afd492155052bf65af639cae",
18+
"4.3.4": "d71e683b8dbd74d66e996115f6cab6142162d9ff446333b67b7a19c2eb4cdae2",
19+
"4.4.0": "6aeb8381c25b04ecfec8074234feb8957b811369ae0262f668867d0e572acb8f",
20+
"4.4.1": "44f8a5e46171c62bd1d9de013eda76e4a45320ed3da1dddf7a7090b7eabe4a91",
21+
"4.5.0": "4f6c7fa08d4487eed3bfe6ef4e96e8fe5d7408155807e1ce83a83ade42a367bd",
22+
"4.5.1": "da5465f29b621b9f52ad763739683318d4b9be05f13ff1a888f5b40e70912d7d",
23+
"4.5.2": "68d1909e13d48e6ad7c23dbde1f811bdb39f8fc86a1355bc5b8309961d9b9eee",
24+
"4.6.0": "3fea5e6a032f7158464c0ff1160563b4d39a5f0f04e3b1659777d1c2c6f9100f",
25+
"4.7.0": "984620cc7db083c86b0291264e1d4e2b8d93f2de779f07b7c711d9b1555f819b",
26+
"4.8.0": "7d4ba02d343452ba561eb103e1978add0206118ced02e800cd43a12c7e45abea",
27+
"4.8.1": "ffcb433c3f62204becec1a78ddf8e6b500fd80fbd4ca2b6d1a478b857b87e9b7",
28+
"4.8.2": "a1539fc5641e782e53b9f8eea2114f99bb95e23ddb6c0debc9c9702093cd767d",
29+
"4.9.0": "b046947fc18874867e877a6286db0cb462bac0b02c8cbf580c48dde9948a0256",
30+
"4.10.0": "74bf52fa589dff1a798fbf1a82312237a61d8cd4e0849a12e94ab17cf13a5cac",
31+
"4.10.1": "aa4af09bfd7f560fdfac43cb8b7b0d9e6885a9cf219e3becdc19fe264c2a4ff5",
32+
"4.10.2": "0c953e8e40c4768ccee7d80733504d7860e7667c6a251754059221dae44a4e5b",
33+
"4.10.3": "adcb40bef1b1ed6703f00f242917b2a4356f30a438a89b12ea9417cb76f740bb",
34+
"4.10.4": "e9a766e3ed3b8ac9e0266eba1584e1b6d810335bd5f11a29b5cc6b36445451d5",
35+
"4.10.5": "304ec26633ae75797bf0dfca379e495a22f43e0461543b04521c0ee1efe9bed6",
36+
"4.10.6": "a0ae6903e852af82af78ef1d908240d4bbf9a0088dc3f24ee94cbde3ee48bdb3"
37+
}

.github/workflows/bump-runner-version.yml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,24 @@ jobs:
3333
exit 1
3434
fi
3535
36+
VERSION="${{ github.event.inputs.version }}"
37+
38+
# Fetch the installer hash from the GitHub API
39+
INSTALLER_HASH=$(gh api "repos/CodSpeedHQ/codspeed/releases/tags/v${VERSION}" --jq '.assets[] | select(.name == "codspeed-runner-installer.sh") | .digest | ltrimstr("sha256:")')
40+
if [ -z "$INSTALLER_HASH" ]; then
41+
echo "Error: Could not fetch installer hash for version $VERSION"
42+
exit 1
43+
fi
44+
echo "Installer hash for $VERSION: $INSTALLER_HASH"
45+
3646
git config --global user.email "github-actions[bot]@users.noreply.github.com"
3747
git config --global user.name "github-actions[bot]"
38-
echo "Bumping runner version to ${{ github.event.inputs.version }}"
39-
BRANCH_NAME=bump-runner-version/${{ github.event.inputs.version }}
48+
echo "Bumping runner version to $VERSION"
49+
BRANCH_NAME=bump-runner-version/$VERSION
4050
git checkout -b $BRANCH_NAME
41-
echo ${{ github.event.inputs.version }} > .codspeed-runner-version
42-
git add .codspeed-runner-version
43-
git commit -m "chore: bump runner version to ${{ github.event.inputs.version }}"
51+
echo $VERSION > .codspeed-runner-version
52+
jq --arg v "$VERSION" --arg h "$INSTALLER_HASH" '. + {($v): $h}' .codspeed-runner-installer-hashes.json > .codspeed-runner-installer-hashes.json.tmp && mv .codspeed-runner-installer-hashes.json.tmp .codspeed-runner-installer-hashes.json
53+
git add .codspeed-runner-version .codspeed-runner-installer-hashes.json
54+
git commit -m "chore: bump runner version to $VERSION"
4455
git push origin $BRANCH_NAME
45-
gh pr create --title "chore: bump runner version to ${{ github.event.inputs.version }}" --body "Bump runner version to ${{ github.event.inputs.version }}" --base main --head $BRANCH_NAME
56+
gh pr create --title "chore: bump runner version to $VERSION" --body "Bump runner version to $VERSION" --base main --head $BRANCH_NAME

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,34 @@ jobs:
114114
mode: walltime
115115
run: echo "Testing version format ${{ matrix.version }}!"
116116

117+
get-pinned-runner-versions:
118+
runs-on: ubuntu-slim
119+
outputs:
120+
versions: ${{ steps.get-versions.outputs.versions }}
121+
steps:
122+
- uses: actions/checkout@v4
123+
- id: get-versions
124+
run: echo "versions=$(jq -c 'keys' .codspeed-runner-installer-hashes.json)" >> "$GITHUB_OUTPUT"
125+
126+
test-all-pinned-runner-versions:
127+
needs: get-pinned-runner-versions
128+
strategy:
129+
fail-fast: false
130+
matrix:
131+
version: ${{ fromJson(needs.get-pinned-runner-versions.outputs.versions) }}
132+
runs-on: ubuntu-slim
133+
env:
134+
CODSPEED_SKIP_UPLOAD: true
135+
steps:
136+
- uses: actions/checkout@v4
137+
- name: Check action with pinned runner version ${{ matrix.version }}
138+
uses: ./
139+
with:
140+
allow-empty: true
141+
runner-version: ${{ matrix.version }}
142+
mode: simulation
143+
run: echo "Testing pinned version ${{ matrix.version }}!"
144+
117145
test-config-file:
118146
runs-on: ubuntu-latest
119147
env:

action.yml

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,24 +146,47 @@ runs:
146146
147147
# Install the runner
148148
if [ "$VERSION_TYPE" = "latest" ]; then
149+
echo "::warning::Hash verification is not available when using 'latest' version. Consider pinning a specific version for supply chain security."
149150
curl -fsSL http://github.com/CodSpeedHQ/codspeed/releases/latest/download/codspeed-runner-installer.sh | bash -s -- --quiet
150151
elif [ "$VERSION_TYPE" = "branch" ]; then
151152
# Install from specific branch using cargo
153+
echo "::warning::Hash verification is not available when installing from a branch."
152154
source $HOME/.cargo/env
153155
cargo install --locked --git https://github.com/CodSpeedHQ/codspeed --branch "$RUNNER_VERSION" codspeed-runner
154156
elif [ "$VERSION_TYPE" = "rev" ]; then
155157
# Install from specific commit/rev using cargo
158+
echo "::warning::Hash verification is not available when installing from a revision."
156159
source $HOME/.cargo/env
157160
cargo install --locked --git https://github.com/CodSpeedHQ/codspeed --rev "$RUNNER_VERSION" codspeed-runner
158161
else
159-
# Release version
160-
head_status=$(curl -I -fsSL -w "%{http_code}" -o /dev/null https://github.com/CodSpeedHQ/codspeed/releases/download/v$RUNNER_VERSION/codspeed-runner-installer.sh)
162+
# Release version - download to temp file and verify hash
163+
INSTALLER_URL="https://github.com/CodSpeedHQ/codspeed/releases/download/v$RUNNER_VERSION/codspeed-runner-installer.sh"
164+
INSTALLER_TMP=$(mktemp)
165+
trap "rm -f $INSTALLER_TMP" EXIT
166+
167+
head_status=$(curl -I -fsSL -w "%{http_code}" -o /dev/null "$INSTALLER_URL")
161168
if [ "$head_status" -eq 404 ]; then
162-
echo "Error: Version $RUNNER_VERSION is not available in https://github.com/CodSpeedHQ/codspeed/releases, please a correct version."
169+
echo "::error::Version $RUNNER_VERSION is not available in https://github.com/CodSpeedHQ/codspeed/releases, please use a correct version."
170+
exit 1
171+
fi
172+
173+
curl -fsSL "$INSTALLER_URL" -o "$INSTALLER_TMP"
174+
175+
HASHES_FILE="$GITHUB_ACTION_PATH/.codspeed-runner-installer-hashes.json"
176+
EXPECTED_HASH=$(jq -r --arg v "$RUNNER_VERSION" '.[$v] // empty' "$HASHES_FILE")
177+
if [ -z "$EXPECTED_HASH" ]; then
178+
echo "::error::No pinned hash found for installer version $RUNNER_VERSION. Update .codspeed-runner-installer-hashes.json."
163179
exit 1
164-
else
165-
curl -fsSL https://github.com/CodSpeedHQ/codspeed/releases/download/v$RUNNER_VERSION/codspeed-runner-installer.sh | bash -s -- --quiet
166180
fi
181+
182+
ACTUAL_HASH=$(sha256sum "$INSTALLER_TMP" | awk '{print $1}')
183+
if [ "$ACTUAL_HASH" != "$EXPECTED_HASH" ]; then
184+
echo "::error::Installer hash mismatch for version $RUNNER_VERSION. Expected: $EXPECTED_HASH, Got: $ACTUAL_HASH"
185+
exit 1
186+
fi
187+
echo "Installer hash verified for version $RUNNER_VERSION"
188+
189+
bash "$INSTALLER_TMP" --quiet
167190
fi
168191
169192
# Build the runner arguments array

0 commit comments

Comments
 (0)