@@ -66,6 +66,23 @@ need_cmd() {
6666 fi
6767}
6868
69+ # Detect platform-appropriate SHA256 command
70+ # Returns: Sets RETVAL to command string, returns 0 on success, 1 if no command found
71+ get_sha256_cmd () {
72+ if check_cmd sha256sum; then
73+ RETVAL=" sha256sum"
74+ return 0
75+ elif check_cmd shasum; then
76+ RETVAL=" shasum -a 256"
77+ return 0
78+ elif check_cmd sha256; then
79+ RETVAL=" sha256"
80+ return 0
81+ else
82+ return 1
83+ fi
84+ }
85+
6986# This wraps curl or wget.
7087# Try curl first, if not installed, use wget instead.
7188downloader () {
@@ -111,6 +128,92 @@ download_with_retry() {
111128 return 1
112129}
113130
131+ # Download checksums.txt from GitHub release
132+ # Parameters: $1 = version (e.g., "v1.8.0"), $2 = destination file path
133+ # Returns: 0 on success, 1 on failure
134+ download_checksums () {
135+ local _version=" $1 "
136+ local _dest=" $2 "
137+ local _repo=" https://github.com/buildkite-plugins/monorepo-diff-buildkite-plugin"
138+ local _url=" ${_repo} /releases/download/${_version} /checksums.txt"
139+
140+ if ! downloader " $_url " " $_dest " ; then
141+ return 1
142+ fi
143+
144+ return 0
145+ }
146+
147+ # Verify binary against checksums.txt
148+ # Parameters: $1 = path to binary file, $2 = version (e.g., "v1.8.0"), $3 = architecture (e.g., "darwin_amd64")
149+ # Returns: 0 if valid, 1 if invalid
150+ verify_checksum () {
151+ local _binary_path=" $1 "
152+ local _version=" $2 "
153+ local _arch=" $3 "
154+ local _verify_enabled=" ${BUILDKITE_PLUGIN_MONOREPO_DIFF_VERIFY_CHECKSUM:- false} "
155+
156+ # Check if verification is disabled
157+ if [[ " $_verify_enabled " == " false" ]]; then
158+ return 0
159+ fi
160+
161+ # Detect SHA256 command
162+ if ! get_sha256_cmd; then
163+ say " Warning: No SHA256 command found (sha256sum, shasum, or sha256), skipping verification"
164+ return 0
165+ fi
166+ local _sha256_cmd=" $RETVAL "
167+
168+ # Download checksums.txt to temporary file
169+ local _checksums_file
170+ _checksums_file=$( mktemp)
171+
172+ if ! download_checksums " $_version " " $_checksums_file " ; then
173+ say " Warning: Could not download checksums.txt, skipping verification"
174+ rm -f " $_checksums_file "
175+ return 0
176+ fi
177+
178+ # Get expected checksum from checksums.txt
179+ local _binary_name=" monorepo-diff-buildkite-plugin_${_arch} "
180+ local _expected_checksum
181+ _expected_checksum=$( grep " ${_binary_name} " " $_checksums_file " | awk ' {print $1}' )
182+
183+ if [[ -z " $_expected_checksum " ]]; then
184+ say " Warning: Checksum not found in checksums.txt for ${_binary_name} , skipping verification"
185+ rm -f " $_checksums_file "
186+ return 0
187+ fi
188+
189+ # Calculate actual checksum
190+ local _actual_checksum
191+ if [[ " $_sha256_cmd " == " sha256" ]]; then
192+ # BSD format: SHA256 (file) = hash
193+ _actual_checksum=$( $_sha256_cmd " $_binary_path " | awk ' {print $4}' )
194+ else
195+ # GNU/shasum format: hash file
196+ _actual_checksum=$( $_sha256_cmd " $_binary_path " | awk ' {print $1}' )
197+ fi
198+
199+ # Clean up temporary file
200+ rm -f " $_checksums_file "
201+
202+ # Compare checksums
203+ if [[ " $_actual_checksum " != " $_expected_checksum " ]]; then
204+ red=$( tput setaf 1 2> /dev/null || echo ' ' )
205+ reset=$( tput sgr0 2> /dev/null || echo ' ' )
206+ say " ${red} ERROR${reset} : Checksum verification failed for $_binary_path " >&2
207+ say " Expected: $_expected_checksum " >&2
208+ say " Actual: $_actual_checksum " >&2
209+ say " This may indicate a corrupted download or a security issue." >&2
210+ return 1
211+ fi
212+
213+ say " Checksum verification passed"
214+ return 0
215+ }
216+
114217get_latest_version () {
115218 local _repo=" https://api.github.com/repos/buildkite-plugins/monorepo-diff-buildkite-plugin"
116219 local _version=" "
@@ -121,7 +224,7 @@ get_latest_version() {
121224 _version=$( wget -qO- " ${_repo} /releases/latest" | grep -oE ' "tag_name": "v[0-9]+\.[0-9]+\.[0-9]+"' | cut -d' "' -f4)
122225 fi
123226
124- if [[ " $_version " =~ ^v[0-9]+\. [0-9]+\. [0-9]+ ]]; then
227+ if [[ " $_version " =~ ^v[0-9]+\. [0-9]+\. [0-9]+$ ]]; then
125228 echo " ${_version} "
126229 fi
127230}
@@ -140,7 +243,7 @@ get_version() {
140243 _version=${BASH_REMATCH[1]}
141244 fi
142245
143- if [[ " $_version " =~ ^v[0-9]+\. [0-9]+\. [0-9]+ ]]; then
246+ if [[ " $_version " =~ ^v[0-9]+\. [0-9]+\. [0-9]+$ ]]; then
144247 true
145248 else
146249 _version=" "
@@ -160,17 +263,27 @@ download_binary_and_run() {
160263 local _binary_version=" "
161264 local test_mode=" ${BUILDKITE_PLUGIN_MONOREPO_DIFF_BUILDKITE_PLUGIN_TEST_MODE:- false} "
162265 local _url=" "
266+ local _recovery_mode=false
163267
164268 if check_cmd " ${executable} " ; then
165269 _binary_version=$( get_binary_version)
166270 if [[ -z " $_binary_version " ]]; then
167271 say " Warning: Could not determine binary version, will download fresh copy"
272+ else
273+ # Before reusing cached binary, verify its checksum
274+ if ! verify_checksum " ${executable} " " ${_binary_version} " " ${_arch} " ; then
275+ say " Cached binary failed checksum verification, attempting recovery..."
276+ rm -f " ${executable} "
277+ rm -f " ${executable_version_file} "
278+ _binary_version=" "
279+ _recovery_mode=true
280+ fi
168281 fi
169282 fi
170283
171284 if [[ " $test_mode " == " true" ]]; then
172285 true
173- elif [[ " $_specified_version " =~ ^v[0-9]+\. [0-9]+\. [0-9]+ ]]; then
286+ elif [[ " $_specified_version " =~ ^v[0-9]+\. [0-9]+\. [0-9]+$ ]]; then
174287 if [[ -z " $_binary_version " ]] || [[ " $_binary_version " != " $_specified_version " ]]; then
175288 _url=${_repo} /releases/download/${_specified_version} /monorepo-diff-buildkite-plugin_${_arch}
176289 _binary_version=" ${_specified_version} "
@@ -194,6 +307,21 @@ download_binary_and_run() {
194307 exit 1
195308 fi
196309 echo " ${_binary_version} " > " ${executable_version_file} "
310+
311+ # After successful download, verify checksum
312+ if ! verify_checksum " ${executable} " " ${_binary_version} " " ${_arch} " ; then
313+ rm -f " ${executable} "
314+ if [[ " $_recovery_mode " == " true" ]]; then
315+ err " Recovery download also failed checksum verification. This may indicate a problem with the release artifacts."
316+ else
317+ err " Downloaded binary failed checksum verification and was deleted"
318+ fi
319+ fi
320+
321+ # If this was a recovery download, verify it succeeded
322+ if [[ " $_recovery_mode " == " true" ]]; then
323+ say " Binary recovery successful"
324+ fi
197325 fi
198326
199327 chmod +x " ${executable} "
@@ -211,6 +339,21 @@ run_preinstalled_binary() {
211339 fi
212340 fi
213341
342+ # Best-effort verification for preinstalled binaries (non-blocking)
343+ # Try to detect version and verify, but don't fail if we can't
344+ local _binary_version
345+ _binary_version=$( get_binary_version)
346+ if [[ -n " $_binary_version " ]]; then
347+ get_architecture || true
348+ local _arch=" $RETVAL "
349+ if [[ -n " $_arch " ]]; then
350+ # Attempt verification but don't fail if it doesn't work
351+ if ! verify_checksum " ${_executable} " " ${_binary_version} " " ${_arch} " 2> /dev/null; then
352+ say " Warning: Could not verify checksum for preinstalled binary (version: ${_binary_version} )"
353+ fi
354+ fi
355+ fi
356+
214357 ${_executable} " $@ "
215358}
216359
0 commit comments