Skip to content

Commit 9b271cd

Browse files
authored
Add SHA256 checksum validation to install script (disabled by default) (#6295)
1 parent 7cf886b commit 9b271cd

5 files changed

Lines changed: 219 additions & 1 deletion

File tree

.github/workflows/release.lock.yml

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/release.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@ jobs:
5151
go_version_file: go.mod
5252
build_script_override: scripts/build-release.sh
5353

54+
- name: Upload checksums file
55+
env:
56+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
run: |
58+
RELEASE_TAG="${GITHUB_REF#refs/tags/}"
59+
if [ -f "dist/checksums.txt" ]; then
60+
echo "Uploading checksums file to release: $RELEASE_TAG"
61+
gh release upload "$RELEASE_TAG" dist/checksums.txt --clobber
62+
echo "✓ Checksums file uploaded to release"
63+
else
64+
echo "Warning: checksums.txt not found in dist/"
65+
fi
66+
5467
- name: Get release ID
5568
id: get_release
5669
env:

install-gh-aw.sh

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,28 @@
44
# Supports: Linux, macOS (Darwin), FreeBSD, Windows (Git Bash/MSYS/Cygwin)
55
# Usage: ./install-gh-aw.sh [version]
66
# If no version is specified, it will fetch and use the latest release
7+
# Note: Checksum validation is currently skipped by default (will be enabled in future releases)
78
# Example: ./install-gh-aw.sh v1.0.0
89

910
set -e # Exit on any error
1011

12+
# Parse arguments
13+
SKIP_CHECKSUM=true # Default to true until checksums are available in releases
14+
VERSION=""
15+
for arg in "$@"; do
16+
case $arg in
17+
--skip-checksum)
18+
SKIP_CHECKSUM=true
19+
shift
20+
;;
21+
*)
22+
if [ -z "$VERSION" ]; then
23+
VERSION="$arg"
24+
fi
25+
;;
26+
esac
27+
done
28+
1129
# Colors for output
1230
RED='\033[0;31m'
1331
GREEN='\033[0;32m'
@@ -50,6 +68,23 @@ if command -v jq &> /dev/null; then
5068
HAS_JQ=true
5169
fi
5270

71+
# Check if sha256sum or shasum is available (for checksum verification)
72+
HAS_CHECKSUM_TOOL=false
73+
CHECKSUM_CMD=""
74+
if command -v sha256sum &> /dev/null; then
75+
HAS_CHECKSUM_TOOL=true
76+
CHECKSUM_CMD="sha256sum"
77+
elif command -v shasum &> /dev/null; then
78+
HAS_CHECKSUM_TOOL=true
79+
CHECKSUM_CMD="shasum -a 256"
80+
fi
81+
82+
if [ "$SKIP_CHECKSUM" = false ] && [ "$HAS_CHECKSUM_TOOL" = false ]; then
83+
print_warning "Neither sha256sum nor shasum is available. Checksum verification will be skipped."
84+
print_warning "To suppress this warning, use --skip-checksum flag."
85+
SKIP_CHECKSUM=true
86+
fi
87+
5388
# Determine OS and architecture
5489
OS=$(uname -s)
5590
ARCH=$(uname -m)
@@ -167,7 +202,7 @@ fetch_release_data() {
167202
}
168203

169204
# Get version (use provided version or fetch latest)
170-
VERSION=${1:-""}
205+
# VERSION is already set from argument parsing
171206
REPO="githubnext/gh-aw"
172207

173208
if [ -z "$VERSION" ]; then
@@ -201,11 +236,13 @@ fi
201236

202237
# Construct download URL and paths
203238
DOWNLOAD_URL="https://github.com/$REPO/releases/download/$VERSION/$PLATFORM"
239+
CHECKSUMS_URL="https://github.com/$REPO/releases/download/$VERSION/checksums.txt"
204240
if [ "$OS_NAME" = "windows" ]; then
205241
DOWNLOAD_URL="${DOWNLOAD_URL}.exe"
206242
fi
207243
INSTALL_DIR="$HOME/.local/share/gh/extensions/gh-aw"
208244
BINARY_PATH="$INSTALL_DIR/$BINARY_NAME"
245+
CHECKSUMS_PATH="$INSTALL_DIR/checksums.txt"
209246

210247
print_info "Download URL: $DOWNLOAD_URL"
211248
print_info "Installation directory: $INSTALL_DIR"
@@ -243,6 +280,71 @@ for attempt in $(seq 1 $MAX_RETRIES); do
243280
fi
244281
done
245282

283+
# Download and verify checksums if not skipped
284+
if [ "$SKIP_CHECKSUM" = false ]; then
285+
print_info "Downloading checksums file..."
286+
CHECKSUMS_DOWNLOADED=false
287+
288+
for attempt in $(seq 1 $MAX_RETRIES); do
289+
if curl -L -f -o "$CHECKSUMS_PATH" "$CHECKSUMS_URL" 2>/dev/null; then
290+
CHECKSUMS_DOWNLOADED=true
291+
print_success "Checksums file downloaded successfully"
292+
break
293+
else
294+
if [ "$attempt" -eq "$MAX_RETRIES" ]; then
295+
print_warning "Failed to download checksums file after $MAX_RETRIES attempts"
296+
print_warning "Checksum verification will be skipped for this version."
297+
print_info "This may occur for older releases that don't include checksums."
298+
break
299+
else
300+
print_warning "Checksum download attempt $attempt failed. Retrying in 2s..."
301+
sleep 2
302+
fi
303+
fi
304+
done
305+
306+
# Verify checksum if we downloaded it successfully
307+
if [ "$CHECKSUMS_DOWNLOADED" = true ]; then
308+
print_info "Verifying binary checksum..."
309+
310+
# Determine the expected filename in the checksums file
311+
EXPECTED_FILENAME="$PLATFORM"
312+
if [ "$OS_NAME" = "windows" ]; then
313+
EXPECTED_FILENAME="${PLATFORM}.exe"
314+
fi
315+
316+
# Extract the expected checksum from the checksums file
317+
EXPECTED_CHECKSUM=$(grep "$EXPECTED_FILENAME" "$CHECKSUMS_PATH" | awk '{print $1}')
318+
319+
if [ -z "$EXPECTED_CHECKSUM" ]; then
320+
print_warning "Checksum for $EXPECTED_FILENAME not found in checksums file"
321+
print_warning "Checksum verification will be skipped."
322+
else
323+
# Compute the actual checksum of the downloaded binary
324+
ACTUAL_CHECKSUM=$($CHECKSUM_CMD "$BINARY_PATH" | awk '{print $1}')
325+
326+
if [ "$ACTUAL_CHECKSUM" = "$EXPECTED_CHECKSUM" ]; then
327+
print_success "Checksum verification passed!"
328+
print_info "Expected: $EXPECTED_CHECKSUM"
329+
print_info "Actual: $ACTUAL_CHECKSUM"
330+
else
331+
print_error "Checksum verification failed!"
332+
print_error "Expected: $EXPECTED_CHECKSUM"
333+
print_error "Actual: $ACTUAL_CHECKSUM"
334+
print_error "The downloaded binary may be corrupted or tampered with."
335+
print_info "To skip checksum verification, use: ./install-gh-aw.sh $VERSION --skip-checksum"
336+
rm -f "$BINARY_PATH"
337+
exit 1
338+
fi
339+
fi
340+
341+
# Clean up checksums file
342+
rm -f "$CHECKSUMS_PATH"
343+
fi
344+
else
345+
print_warning "Checksum verification skipped (--skip-checksum flag used)"
346+
fi
347+
246348
# Make it executable
247349
print_info "Making binary executable..."
248350
chmod +x "$BINARY_PATH"

scripts/build-release.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,21 @@ done
5757

5858
echo "Build complete. Binaries:"
5959
ls -lh dist/
60+
61+
# Generate checksums file
62+
echo ""
63+
echo "Generating checksums..."
64+
cd dist
65+
# Use sha256sum if available (Linux), otherwise use shasum (macOS)
66+
if command -v sha256sum &> /dev/null; then
67+
sha256sum * > checksums.txt
68+
elif command -v shasum &> /dev/null; then
69+
shasum -a 256 * > checksums.txt
70+
else
71+
echo "error: neither sha256sum nor shasum is available" >&2
72+
exit 1
73+
fi
74+
cd ..
75+
76+
echo "Checksums generated:"
77+
cat dist/checksums.txt

scripts/test-install-script.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,5 +292,65 @@ else
292292
exit 1
293293
fi
294294

295+
# Test 10: Verify checksum validation functionality
296+
echo ""
297+
echo "Test 10: Verify checksum validation functionality"
298+
299+
# Check for --skip-checksum flag
300+
if grep -q "\-\-skip-checksum" "$PROJECT_ROOT/install-gh-aw.sh"; then
301+
echo " ✓ PASS: --skip-checksum flag is documented"
302+
else
303+
echo " ✗ FAIL: --skip-checksum flag not found"
304+
exit 1
305+
fi
306+
307+
# Check for checksum tool detection
308+
if grep -q "sha256sum\|shasum" "$PROJECT_ROOT/install-gh-aw.sh"; then
309+
echo " ✓ PASS: Script checks for sha256sum or shasum"
310+
else
311+
echo " ✗ FAIL: Script doesn't check for checksum tools"
312+
exit 1
313+
fi
314+
315+
# Check for checksums URL construction
316+
if grep -q 'CHECKSUMS_URL=.*checksums.txt' "$PROJECT_ROOT/install-gh-aw.sh"; then
317+
echo " ✓ PASS: Checksums URL is constructed"
318+
else
319+
echo " ✗ FAIL: Checksums URL construction not found"
320+
exit 1
321+
fi
322+
323+
# Check for checksum verification logic
324+
if grep -q "Verifying binary checksum" "$PROJECT_ROOT/install-gh-aw.sh"; then
325+
echo " ✓ PASS: Checksum verification logic exists"
326+
else
327+
echo " ✗ FAIL: Checksum verification logic not found"
328+
exit 1
329+
fi
330+
331+
# Check for checksum failure handling
332+
if grep -q "Checksum verification failed" "$PROJECT_ROOT/install-gh-aw.sh"; then
333+
echo " ✓ PASS: Checksum failure is handled"
334+
else
335+
echo " ✗ FAIL: Checksum failure handling not found"
336+
exit 1
337+
fi
338+
339+
# Check for graceful handling when checksums file is not available
340+
if grep -q "Checksum verification will be skipped" "$PROJECT_ROOT/install-gh-aw.sh"; then
341+
echo " ✓ PASS: Script handles missing checksums gracefully"
342+
else
343+
echo " ✗ FAIL: Missing checksums handling not found"
344+
exit 1
345+
fi
346+
347+
# Check for SKIP_CHECKSUM flag logic
348+
if grep -q "SKIP_CHECKSUM=true" "$PROJECT_ROOT/install-gh-aw.sh" && grep -q 'if \[ "\$SKIP_CHECKSUM" = false \]' "$PROJECT_ROOT/install-gh-aw.sh"; then
349+
echo " ✓ PASS: SKIP_CHECKSUM flag logic is implemented"
350+
else
351+
echo " ✗ FAIL: SKIP_CHECKSUM flag logic not found"
352+
exit 1
353+
fi
354+
295355
echo ""
296356
echo "=== All tests passed ==="

0 commit comments

Comments
 (0)