Skip to content

Commit 2017b47

Browse files
authored
feat(install): verify the release checksum by default in install.sh (#709)
1 parent 2ba5715 commit 2017b47

4 files changed

Lines changed: 65 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
- Floating major tag for the GitHub Action: the release process now force-moves `v0` to each release, so workflows can pin `TypedDevs/bashunit@v0` to track the latest release within a major (#700)
88
- `bashunit init` now scaffolds a `.github/workflows/tests.yml` CI workflow using the official action (existing files are left untouched) (#702)
99

10+
### Changed
11+
- `install.sh` now verifies the release checksum by default (set `BASHUNIT_VERIFY_CHECKSUM=false` to opt out); it soft-skips with a warning when a checksum asset is unavailable unless verification was explicitly requested (#703)
12+
1013
## [0.38.0](https://github.com/TypedDevs/bashunit/compare/0.37.0...0.38.0) - 2026-06-07
1114

1215
### Added

docs/installation.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ curl -s https://bashunit.typeddevs.com/install.sh | bash
3030

3131
This will create a file inside a lib folder, such as `lib/bashunit`.
3232

33+
::: tip Automatic checksum verification
34+
`install.sh` verifies the download against the release `checksum` asset by default and
35+
aborts on a mismatch, so a tampered or corrupted download never lands. Set
36+
`BASHUNIT_VERIFY_CHECKSUM=false` to opt out (e.g. for old releases published before
37+
checksum assets existed). The manual check below is only needed when you opt out.
38+
:::
39+
3340
#### Verify
3441

3542
```bash-vue

install.sh

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,31 @@ function compute_sha256() {
2424
# Verify the downloaded 'bashunit' file against the release 'checksum' asset.
2525
# Arguments: $1 - the bashunit download URL. Exits 1 (and removes the binary)
2626
# on any failure so a tampered or unverifiable download never looks successful.
27+
# Handle an inability to verify (missing sha256 tool or checksum asset).
28+
# Strict (fails) when the user explicitly opted in; a soft warning otherwise,
29+
# so installing older releases published before checksum assets existed keeps
30+
# working while a tampered binary (checksum mismatch) is always rejected.
31+
function cannot_verify() {
32+
local reason=$1
33+
if [ "${VERIFY_CHECKSUM_EXPLICIT:-false}" = "true" ]; then
34+
echo "Error: $reason" >&2
35+
rm -f bashunit
36+
exit 1
37+
fi
38+
echo "> Skipping checksum verification: $reason" >&2
39+
}
40+
2741
function verify_checksum() {
2842
local url=$1
2943
local checksum_url="${url%/bashunit}/checksum"
3044

45+
local actual
46+
actual=$(compute_sha256 bashunit)
47+
if [ -z "$actual" ]; then
48+
cannot_verify "no sha256 tool (shasum/sha256sum) available to verify checksum"
49+
return
50+
fi
51+
3152
local expected
3253
if command -v curl >/dev/null 2>&1; then
3354
expected=$(curl -fsSL --retry 3 --retry-delay 2 "$checksum_url" 2>/dev/null | awk '{print $1}')
@@ -36,17 +57,8 @@ function verify_checksum() {
3657
fi
3758

3859
if [ -z "$expected" ]; then
39-
echo "Error: could not download checksum from $checksum_url" >&2
40-
rm -f bashunit
41-
exit 1
42-
fi
43-
44-
local actual
45-
actual=$(compute_sha256 bashunit)
46-
if [ -z "$actual" ]; then
47-
echo "Error: no sha256 tool (shasum/sha256sum) available to verify checksum" >&2
48-
rm -f bashunit
49-
exit 1
60+
cannot_verify "could not download checksum from $checksum_url"
61+
return
5062
fi
5163

5264
if [ "$actual" != "$expected" ]; then
@@ -57,7 +69,7 @@ function verify_checksum() {
5769
exit 1
5870
fi
5971

60-
echo "> Checksum verified ($actual)"
72+
echo "> Checksum verified ($actual)" >&2
6173
}
6274

6375
function build_and_install_beta() {
@@ -108,7 +120,7 @@ function install() {
108120
exit 1
109121
fi
110122

111-
if [ "${BASHUNIT_VERIFY_CHECKSUM:-false}" = "true" ]; then
123+
if [ "$VERIFY_CHECKSUM" = "true" ]; then
112124
verify_checksum "$url"
113125
fi
114126

@@ -123,6 +135,15 @@ function install() {
123135
DIR="lib"
124136
VERSION="latest"
125137

138+
# Checksum verification is on by default. Track whether the user set it
139+
# explicitly so we can be strict on opt-in and lenient on the default.
140+
if [ -n "${BASHUNIT_VERIFY_CHECKSUM+x}" ]; then
141+
VERIFY_CHECKSUM_EXPLICIT="true"
142+
else
143+
VERIFY_CHECKSUM_EXPLICIT="false"
144+
fi
145+
VERIFY_CHECKSUM="${BASHUNIT_VERIFY_CHECKSUM:-true}"
146+
126147
function is_version() {
127148
regex_match "$1" '^[0-9]+\.[0-9]+\.[0-9]+$' || [[ "$1" == "latest" || "$1" == "beta" ]]
128149
}

tests/acceptance/install_test.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,27 @@ function test_install_verifies_checksum_when_enabled() {
151151
"$(./tmp_install/bashunit --version)"
152152
}
153153

154+
function test_install_verifies_checksum_by_default() {
155+
if [[ "$ACTIVE_INTERNET" -eq 1 ]]; then
156+
bashunit::skip "no internet connection" && return
157+
fi
158+
if [[ "$HAS_DOWNLOADER" -eq 0 ]]; then
159+
bashunit::skip "curl or wget not installed" && return
160+
fi
161+
if ! command -v shasum >/dev/null 2>&1 && ! command -v sha256sum >/dev/null 2>&1; then
162+
bashunit::skip "no sha256 tool available" && return
163+
fi
164+
165+
local output
166+
output="$(./install.sh tmp_install 0.38.0 2>&1)"
167+
168+
if [ ! -f "./tmp_install/bashunit" ]; then
169+
bashunit::skip "transient download failure" && return
170+
fi
171+
assert_contains "Checksum verified" "$output"
172+
assert_file_exists "./tmp_install/bashunit"
173+
}
174+
154175
function test_install_downloads_the_given_version() {
155176
if [[ "$ACTIVE_INTERNET" -eq 1 ]]; then
156177
bashunit::skip "no internet connection" && return

0 commit comments

Comments
 (0)