Skip to content

Commit 34e126a

Browse files
committed
test: add network failure and SHA256 mismatch tests for download script
1 parent 2498735 commit 34e126a

4 files changed

Lines changed: 175 additions & 70 deletions

File tree

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
{"status": "open"}
1+
{
2+
"status" : "closed",
3+
"resolution" : "implemented",
4+
"target_branch" : "v2.1"
5+
}

plugin/scripts/download-git-filter-repo.sh

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -171,24 +171,8 @@ if [[ -f "${CACHED_BINARY}" ]] && [[ -z "${GFR_FORCE_DOWNLOAD:-}" ]]; then
171171
fi
172172

173173
# Construct GitHub release download URL
174-
REPO_OWNER=$(grep -E '^REPO_OWNER=' "${CONF}" | sed 's/^REPO_OWNER="\(.*\)"$/\1/' | head -1 || true)
175-
if [[ -z "${REPO_OWNER}" ]]; then
176-
echo "ERROR: REPO_OWNER not found in ${CONF}" >&2
177-
exit 1
178-
fi
179-
if ! echo "${REPO_OWNER}" | grep -qE '^[a-zA-Z0-9_-]+$'; then
180-
echo "ERROR: REPO_OWNER in ${CONF} has unexpected format: ${REPO_OWNER}" >&2
181-
exit 1
182-
fi
183-
REPO_NAME=$(grep -E '^REPO_NAME=' "${CONF}" | sed 's/^REPO_NAME="\(.*\)"$/\1/' | head -1 || true)
184-
if [[ -z "${REPO_NAME}" ]]; then
185-
echo "ERROR: REPO_NAME not found in ${CONF}" >&2
186-
exit 1
187-
fi
188-
if ! echo "${REPO_NAME}" | grep -qE '^[a-zA-Z0-9_-]+$'; then
189-
echo "ERROR: REPO_NAME in ${CONF} has unexpected format: ${REPO_NAME}" >&2
190-
exit 1
191-
fi
174+
REPO_OWNER="cowwoc"
175+
REPO_NAME="cat"
192176
BINARY_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/${RELEASE_TAG}/${BINARY_NAME}"
193177

194178
if ! mkdir -p "${CACHE_DIR}"; then
@@ -205,7 +189,7 @@ trap "rm -f '${TMP_BINARY}'" EXIT
205189

206190
echo "Downloading git-filter-repo standalone binary for ${PLATFORM}..." >&2
207191
echo " URL: ${BINARY_URL}" >&2
208-
if ! curl -fsSL --max-time 120 -o "${TMP_BINARY}" "${BINARY_URL}"; then
192+
curl -fsSL --max-time 120 -o "${TMP_BINARY}" "${BINARY_URL}" || {
209193
CURL_EXIT=$?
210194
echo "ERROR: Failed to download git-filter-repo" >&2
211195
echo " URL: ${BINARY_URL}" >&2
@@ -217,7 +201,7 @@ if ! curl -fsSL --max-time 120 -o "${TMP_BINARY}" "${BINARY_URL}"; then
217201
*) echo " See 'man curl' for exit code ${CURL_EXIT} details." >&2 ;;
218202
esac
219203
exit 1
220-
fi
204+
}
221205

222206
if [[ ! -s "${TMP_BINARY}" ]]; then
223207
echo "ERROR: Downloaded file is empty or missing: ${TMP_BINARY}" >&2

tests/download-git-filter-repo.bats

Lines changed: 154 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ setup() {
6060
# Write the standard release.conf
6161
write_release_conf
6262

63+
# Copy sha256sum-portable.sh into the fake plugin root so the download script can source it
64+
mkdir -p "${FAKE_PLUGIN_ROOT}/scripts"
65+
cp "${SCRIPT_DIR}/plugin/scripts/sha256sum-portable.sh" "${FAKE_PLUGIN_ROOT}/scripts/"
66+
6367
# Create a stub bin dir for PATH overrides
6468
STUB_BIN_DIR="$(mktemp -d)"
6569
export STUB_BIN_DIR
@@ -169,50 +173,6 @@ EOF
169173
[ "${output}" = "${CACHE_DIR}/${BINARY_NAME}" ]
170174
}
171175

172-
# ---------------------------------------------------------------------------
173-
# sha256sum output with hex-like filename (regression: no false-positive hash extraction)
174-
# ---------------------------------------------------------------------------
175-
176-
@test "sha256sum output with hex-like filename does not cause false-positive hash extraction" {
177-
# No python3, no git-filter-repo on PATH — force tier-3 resolution
178-
write_python3_stub
179-
180-
# Fix platform to linux-x64 for deterministic binary name
181-
cat > "${STUB_BIN_DIR}/uname" <<'EOF'
182-
#!/usr/bin/env bash
183-
if [[ "$1" == "-s" ]]; then
184-
echo "Linux"
185-
elif [[ "$1" == "-m" ]]; then
186-
echo "x86_64"
187-
fi
188-
EOF
189-
chmod +x "${STUB_BIN_DIR}/uname"
190-
191-
BINARY_NAME="git-filter-repo-linux-x64"
192-
CACHE_DIR="${FAKE_PLUGIN_ROOT}/lib"
193-
mkdir -p "${CACHE_DIR}"
194-
195-
# Create a cached binary and its version file matching RELEASE_TAG
196-
echo "fake binary content" > "${CACHE_DIR}/${BINARY_NAME}"
197-
echo "git-filter-repo-v2.38.0" > "${CACHE_DIR}/${BINARY_NAME}.version"
198-
199-
# Write a sha256sum stub whose output filename contains a 64-char hex segment.
200-
# The first field (the hash) is FAKE_SHA256_LINUX_X64 (correct); the second field
201-
# is a filename that itself embeds another 64-char hex string. The script must
202-
# extract only the first field and not be confused by the hex in the filename.
203-
mkdir -p "${STUB_BIN_DIR}"
204-
cat > "${STUB_BIN_DIR}/sha256sum" <<EOF
205-
#!/usr/bin/env bash
206-
printf '%s git-filter-repo-linux-x64-${FAKE_SHA256_LINUX_X64}\n' "${FAKE_SHA256_LINUX_X64}"
207-
EOF
208-
chmod +x "${STUB_BIN_DIR}/sha256sum"
209-
210-
run env PATH="${STUB_BIN_DIR}:${SAFE_PATH}" bash "${DOWNLOAD_SCRIPT}"
211-
212-
[ "${status}" -eq 0 ]
213-
[ "${output}" = "${CACHE_DIR}/${BINARY_NAME}" ]
214-
}
215-
216176
# ---------------------------------------------------------------------------
217177
# release.conf missing RELEASE_TAG (error handling)
218178
# ---------------------------------------------------------------------------
@@ -477,6 +437,9 @@ EOF
477437
# Stub sha256sum so SHA256 verification of cache also fails gracefully (no cached binary exists)
478438
write_sha256sum_stub "${STUB_BIN_DIR}" "${FAKE_SHA256_LINUX_X64}"
479439

440+
CACHE_DIR="${FAKE_PLUGIN_ROOT}/lib"
441+
mkdir -p "${CACHE_DIR}"
442+
480443
# Stub curl to return a connection failure exit code
481444
cat > "${STUB_BIN_DIR}/curl" <<'EOF'
482445
#!/usr/bin/env bash
@@ -488,4 +451,151 @@ EOF
488451

489452
[ "${status}" -ne 0 ]
490453
[[ "${output}" == *"ERROR"* ]] || [[ "${lines[*]}" == *"ERROR"* ]]
454+
# CACHED_BINARY must not exist
455+
[ ! -f "${CACHE_DIR}/git-filter-repo-linux-x64" ]
456+
# No .tmp. files must remain in the cache directory
457+
TMP_COUNT=$(find "${CACHE_DIR}" -name "*.tmp.*" 2>/dev/null | wc -l)
458+
[ "${TMP_COUNT}" -eq 0 ]
459+
}
460+
461+
@test "curl timeout (exit 28) leaves no partial file in cache directory" {
462+
# Stub python3 to fail so we reach download phase; git-filter-repo excluded via SAFE_PATH
463+
write_python3_stub
464+
465+
# Fix platform to linux-x64 for deterministic binary name
466+
cat > "${STUB_BIN_DIR}/uname" <<'EOF'
467+
#!/usr/bin/env bash
468+
if [[ "$1" == "-s" ]]; then
469+
echo "Linux"
470+
elif [[ "$1" == "-m" ]]; then
471+
echo "x86_64"
472+
fi
473+
EOF
474+
chmod +x "${STUB_BIN_DIR}/uname"
475+
476+
write_sha256sum_stub "${STUB_BIN_DIR}" "${FAKE_SHA256_LINUX_X64}"
477+
478+
CACHE_DIR="${FAKE_PLUGIN_ROOT}/lib"
479+
mkdir -p "${CACHE_DIR}"
480+
481+
# Stub curl: write partial bytes to the -o output file then exit 28 (timeout)
482+
cat > "${STUB_BIN_DIR}/curl" <<'EOF'
483+
#!/usr/bin/env bash
484+
for ((i=1; i<=$#; i++)); do
485+
if [[ "${!i}" == "-o" ]]; then
486+
next=$((i+1))
487+
printf 'partial' > "${!next}"
488+
break
489+
fi
490+
done
491+
exit 28
492+
EOF
493+
chmod +x "${STUB_BIN_DIR}/curl"
494+
495+
run env PATH="${STUB_BIN_DIR}:${SAFE_PATH}" bash "${DOWNLOAD_SCRIPT}"
496+
497+
[ "${status}" -ne 0 ]
498+
[[ "${output}" == *"ERROR"* ]] || [[ "${lines[*]}" == *"ERROR"* ]]
499+
[[ "${output}" == *"timeout"* ]] || [[ "${lines[*]}" == *"timeout"* ]]
500+
# CACHED_BINARY must not exist
501+
[ ! -f "${CACHE_DIR}/git-filter-repo-linux-x64" ]
502+
# No .tmp. files must remain in the cache directory
503+
TMP_COUNT=$(find "${CACHE_DIR}" -name "*.tmp.*" 2>/dev/null | wc -l)
504+
[ "${TMP_COUNT}" -eq 0 ]
505+
}
506+
507+
@test "partial download (curl exits 0, wrong SHA256) triggers SHA256 failure and cleanup" {
508+
# Stub python3 to fail so we reach download phase; git-filter-repo excluded via SAFE_PATH
509+
write_python3_stub
510+
511+
# Fix platform to linux-x64 for deterministic binary name
512+
cat > "${STUB_BIN_DIR}/uname" <<'EOF'
513+
#!/usr/bin/env bash
514+
if [[ "$1" == "-s" ]]; then
515+
echo "Linux"
516+
elif [[ "$1" == "-m" ]]; then
517+
echo "x86_64"
518+
fi
519+
EOF
520+
chmod +x "${STUB_BIN_DIR}/uname"
521+
522+
# Stub sha256sum to return all-zeros hash (will not match FAKE_SHA256_LINUX_X64)
523+
WRONG_HASH="0000000000000000000000000000000000000000000000000000000000000000"
524+
write_sha256sum_stub "${STUB_BIN_DIR}" "${WRONG_HASH}"
525+
526+
CACHE_DIR="${FAKE_PLUGIN_ROOT}/lib"
527+
mkdir -p "${CACHE_DIR}"
528+
529+
# Stub curl: write a few bytes (partial content) then exit 0
530+
cat > "${STUB_BIN_DIR}/curl" <<'EOF'
531+
#!/usr/bin/env bash
532+
for ((i=1; i<=$#; i++)); do
533+
if [[ "${!i}" == "-o" ]]; then
534+
next=$((i+1))
535+
printf 'partial' > "${!next}"
536+
break
537+
fi
538+
done
539+
exit 0
540+
EOF
541+
chmod +x "${STUB_BIN_DIR}/curl"
542+
543+
run env PATH="${STUB_BIN_DIR}:${SAFE_PATH}" bash "${DOWNLOAD_SCRIPT}"
544+
545+
[ "${status}" -ne 0 ]
546+
[[ "${output}" == *"SHA256"* ]] || [[ "${output}" == *"checksum"* ]] || \
547+
[[ "${lines[*]}" == *"SHA256"* ]] || [[ "${lines[*]}" == *"checksum"* ]]
548+
# CACHED_BINARY must not exist after failed SHA256 verification
549+
[ ! -f "${CACHE_DIR}/git-filter-repo-linux-x64" ]
550+
# No .tmp. files must remain in the cache directory
551+
TMP_COUNT=$(find "${CACHE_DIR}" -name "*.tmp.*" 2>/dev/null | wc -l)
552+
[ "${TMP_COUNT}" -eq 0 ]
553+
}
554+
555+
@test "successful download with SHA256 mismatch triggers cleanup (no CACHED_BINARY left)" {
556+
# Stub python3 to fail so we reach download phase; git-filter-repo excluded via SAFE_PATH
557+
write_python3_stub
558+
559+
# Fix platform to linux-x64 for deterministic binary name
560+
cat > "${STUB_BIN_DIR}/uname" <<'EOF'
561+
#!/usr/bin/env bash
562+
if [[ "$1" == "-s" ]]; then
563+
echo "Linux"
564+
elif [[ "$1" == "-m" ]]; then
565+
echo "x86_64"
566+
fi
567+
EOF
568+
chmod +x "${STUB_BIN_DIR}/uname"
569+
570+
# Stub sha256sum to return all-f's hash (will not match FAKE_SHA256_LINUX_X64)
571+
WRONG_HASH="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
572+
write_sha256sum_stub "${STUB_BIN_DIR}" "${WRONG_HASH}"
573+
574+
CACHE_DIR="${FAKE_PLUGIN_ROOT}/lib"
575+
mkdir -p "${CACHE_DIR}"
576+
577+
# Stub curl: write "wrong content" (simulates a full download of wrong data) then exit 0
578+
cat > "${STUB_BIN_DIR}/curl" <<'EOF'
579+
#!/usr/bin/env bash
580+
for ((i=1; i<=$#; i++)); do
581+
if [[ "${!i}" == "-o" ]]; then
582+
next=$((i+1))
583+
echo "wrong content" > "${!next}"
584+
break
585+
fi
586+
done
587+
exit 0
588+
EOF
589+
chmod +x "${STUB_BIN_DIR}/curl"
590+
591+
run env PATH="${STUB_BIN_DIR}:${SAFE_PATH}" bash "${DOWNLOAD_SCRIPT}"
592+
593+
[ "${status}" -ne 0 ]
594+
[[ "${output}" == *"SHA256"* ]] || [[ "${output}" == *"checksum"* ]] || \
595+
[[ "${lines[*]}" == *"SHA256"* ]] || [[ "${lines[*]}" == *"checksum"* ]]
596+
# CACHED_BINARY must not exist after failed SHA256 verification
597+
[ ! -f "${CACHE_DIR}/git-filter-repo-linux-x64" ]
598+
# No .tmp. files must remain in the cache directory
599+
TMP_COUNT=$(find "${CACHE_DIR}" -name "*.tmp.*" 2>/dev/null | wc -l)
600+
[ "${TMP_COUNT}" -eq 0 ]
491601
}

tests/sha256sum-portable.bats

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,19 @@ sha256sum_portable /dev/null
3737
}
3838

3939
@test "sha256sum_portable falls back to shasum when sha256sum is absent" {
40-
cat > "${STUB_BIN_DIR}/shasum" <<'EOF'
41-
#!/usr/bin/env bash
42-
echo "1111111111111111111111111111111111111111111111111111111111111111 $1"
40+
# Use absolute shebang so the stub works without /usr/bin in PATH.
41+
cat > "${STUB_BIN_DIR}/shasum" <<EOF
42+
#!${STUB_BIN_DIR}/bash
43+
echo "1111111111111111111111111111111111111111111111111111111111111111 \$1"
4344
EOF
4445
chmod +x "${STUB_BIN_DIR}/shasum"
4546

46-
run env PATH="${STUB_BIN_DIR}:${SAFE_PATH}" bash -c "
47+
# Symlink bash and awk into the stub dir so the helper script can use them
48+
# without /usr/bin in PATH, keeping sha256sum genuinely absent.
49+
ln -sf /usr/bin/bash "${STUB_BIN_DIR}/bash"
50+
ln -sf /usr/bin/awk "${STUB_BIN_DIR}/awk"
51+
52+
run env PATH="${STUB_BIN_DIR}" /usr/bin/bash -c "
4753
source '${HELPER_SCRIPT}'
4854
sha256sum_portable /dev/null
4955
"
@@ -53,7 +59,8 @@ sha256sum_portable /dev/null
5359
}
5460

5561
@test "sha256sum_portable exits non-zero when neither sha256sum nor shasum is available" {
56-
run env PATH="${STUB_BIN_DIR}:${SAFE_PATH}" bash -c "
62+
# Do NOT include /usr/bin in PATH so that neither sha256sum nor shasum is present.
63+
run env PATH="${STUB_BIN_DIR}" /usr/bin/bash -c "
5764
source '${HELPER_SCRIPT}'
5865
sha256sum_portable /dev/null
5966
"

0 commit comments

Comments
 (0)