Files
syft/test/install/5_download_asset_failures_test.sh
T
Alex GoodmanandKeith Zantow ef356eccea fix: sign release checksums with a sigstore bundle (#5362)
* fix: sign release checksums with a sigstore bundle

The cosign update rejects the legacy `--output-certificate` / `--output-signature` flags alongside the new bundle format, which broke signing during the v1.53.0 release.

- checksums are now signed into a single `checksums.txt.sigstore.json` bundle (signature, certificate, and tlog proof)
- `install.sh -v` verifies with `--bundle` for releases >= v1.53.0 and keeps the `.sig` / `.pem` flow for older releases

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* chore: smooth the cutover to sigstore bundle verification

- `install.sh -v` now hints that bundle verification needs cosign v2.5.0 or newer when verification of a bundle-signed release fails
- install tests keep exercising the legacy `.sig` / `.pem` path against v1.52.0 once the latest release is bundle-signed
- touch the install test environment Dockerfiles so the cached images rebuild with a current cosign

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix: only hint at the cosign minimum when cosign is actually too old

- `install.sh -v` used to print the cosign v2.5.0 note on any failed bundle verification, including a missing bundle or a bad signature. It now only prints it when cosign reports it couldn't read the bundle (`bundle does not contain cert`), which is how v2.2.4 through v2.4.1 fail on a sigstore bundle.
- `verify_sign` is now covered with a stub cosign, so the bundle path is exercised before any bundle-signed release is latest

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix: stop the install when a release asset is missing or fails its checksum

- `install.sh` now stops when the checksums file, the signature bundle, or the asset can't be downloaded, instead of handing an empty or error-page file to the next step
- a sha256 mismatch between the asset and the checksums file now stops the install. Before this the mismatch was logged and the asset was installed anyway, so `-v` only ever vouched for `checksums.txt`, not the binary

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* chore: pin cosign in the install test images

The install test images pulled whatever cosign was latest, unverified. They now install cosign v3.1.3 checked against its published sha256, so the install tests always run with a cosign that can verify sigstore bundles (releases >= v1.53.0 need v2.5.0 or newer).

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
2026-10-01 15:00:37 -04:00

85 lines
3.1 KiB
Bash
Executable File

. test_harness.sh
# serve release assets from a local fixture dir instead of the network (a missing file is a failed download)
http_download() {
src="${FIXTURE_DIR}/${2##*/}"
[ -f "${src}" ] || return 1
cp "${src}" "$1"
}
# ensure every missing or mismatched piece of a release stops download_asset before anything is installed
test_download_asset_failures() {
# download_asset [release-url-prefix] [download-path] [name] [os] [arch] [version] [format]
# we are expecting error messages, which is confusing to look at in passing tests... disable logging for now
log_set_priority -1
OG_COSIGN_BINARY=${COSIGN_BINARY}
tmpdir=$(mktemp -d)
FIXTURE_DIR="${tmpdir}/release"
dest="${tmpdir}/dest"
args_file="${tmpdir}/cosign-args"
mkdir -p "${FIXTURE_DIR}" "${dest}"
# stub cosign that records it was called and always verifies
COSIGN_BINARY="${tmpdir}/cosign"
printf '#!/bin/sh\necho "$@" > "%s"\n' "${args_file}" > "${COSIGN_BINARY}"
chmod +x "${COSIGN_BINARY}"
asset="syft_1.54.0_linux_amd64.tar.gz"
echo "the real asset" > "${FIXTURE_DIR}/${asset}"
echo "$(hash_sha256 "${FIXTURE_DIR}/${asset}") ${asset}" > "${FIXTURE_DIR}/syft_1.54.0_checksums.txt"
echo "{}" > "${FIXTURE_DIR}/syft_1.54.0_checksums.txt.sigstore.json"
run() {
rm -rf "${dest:?}"/* "${args_file}"
download_asset "https://example.invalid/v1.54.0" "${dest}" "syft" "linux" "amd64" "1.54.0" "tar.gz"
}
# happy path, verified and unverified
VERIFY_SIGN=false
asset_path=$(run)
assertEquals "0" "$?" "complete release should download"
assertEquals "${dest}/${asset}" "${asset_path}" "unexpected asset path"
VERIFY_SIGN=true
run >/dev/null
assertEquals "0" "$?" "complete release should verify"
assertContains "$(cat "${args_file}")" "--bundle ${dest}/syft_1.54.0_checksums.txt.sigstore.json" "bundle should be passed to cosign"
# missing bundle: fail before cosign is ever called
mv "${FIXTURE_DIR}/syft_1.54.0_checksums.txt.sigstore.json" "${tmpdir}/bundle"
run >/dev/null
assertEquals "1" "$?" "missing bundle should fail"
assertFilesDoesNotExist "${args_file}" "cosign should not be called without a bundle"
mv "${tmpdir}/bundle" "${FIXTURE_DIR}/syft_1.54.0_checksums.txt.sigstore.json"
for VERIFY_SIGN in true false; do
# asset does not match the checksums file
echo "a tampered asset" > "${FIXTURE_DIR}/${asset}"
run >/dev/null
assertEquals "1" "$?" "checksum mismatch should fail (verify=${VERIFY_SIGN})"
echo "the real asset" > "${FIXTURE_DIR}/${asset}"
# missing asset
mv "${FIXTURE_DIR}/${asset}" "${tmpdir}/asset"
run >/dev/null
assertEquals "1" "$?" "missing asset should fail (verify=${VERIFY_SIGN})"
mv "${tmpdir}/asset" "${FIXTURE_DIR}/${asset}"
# missing checksums file
mv "${FIXTURE_DIR}/syft_1.54.0_checksums.txt" "${tmpdir}/checksums"
run >/dev/null
assertEquals "1" "$?" "missing checksums should fail (verify=${VERIFY_SIGN})"
mv "${tmpdir}/checksums" "${FIXTURE_DIR}/syft_1.54.0_checksums.txt"
done
COSIGN_BINARY=${OG_COSIGN_BINARY}
rm -rf -- "${tmpdir}"
log_set_priority 0
}
run_test_case test_download_asset_failures