mirror of
https://github.com/anchore/syft.git
synced 2026-10-22 02:52:32 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc326e45a6 | ||
|
|
ef356eccea | ||
|
|
db7e445c54 | ||
|
|
d654c00bd6 | ||
|
|
c00be184b5 | ||
|
|
29d2de72c8 |
@@ -21,6 +21,9 @@ updates:
|
||||
- dependency-name: "github.com/aquasecurity/go-version"
|
||||
- dependency-name: "github.com/knqyf263/go-apk-version"
|
||||
- dependency-name: "github.com/knqyf263/go-deb-version"
|
||||
# v1 changed SlicesAsSets hashing, which changes every artifact ID syft produces
|
||||
- dependency-name: "github.com/gohugoio/hashstructure"
|
||||
update-types: ["version-update:semver-major"]
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directories:
|
||||
|
||||
@@ -51,8 +51,19 @@ jobs:
|
||||
name: "Unit tests"
|
||||
runs-on: ubuntu-latest
|
||||
needs: [Unit-Test-Linux, Unit-Test-Windows]
|
||||
# a skipped job satisfies a required check, so this job must always run and fail explicitly
|
||||
# unless every dependency succeeded (otherwise a failing PR can still be auto-merged)
|
||||
if: ${{ always() }}
|
||||
steps:
|
||||
- run: echo All unit tests passed!
|
||||
- name: Require all unit test jobs to succeed
|
||||
env:
|
||||
NEEDS: ${{ toJSON(needs) }}
|
||||
run: |
|
||||
echo "$NEEDS" | jq -e 'length > 0 and all(.[]; .result == "success")' > /dev/null || {
|
||||
echo "$NEEDS" | jq -r 'to_entries[] | "\(.key): \(.value.result)"'
|
||||
exit 1
|
||||
}
|
||||
echo All unit tests passed!
|
||||
|
||||
Unit-Test-Linux:
|
||||
name: "Unit tests (Linux)"
|
||||
|
||||
+3
-6
@@ -167,16 +167,13 @@ sboms:
|
||||
- "--output"
|
||||
- "json=$document"
|
||||
|
||||
# the signature, certificate, and transparency log proof all land in a single sigstore bundle.
|
||||
signs:
|
||||
- cmd: .tool/cosign
|
||||
signature: "${artifact}.sig"
|
||||
certificate: "${artifact}.pem"
|
||||
signature: "${artifact}.sigstore.json"
|
||||
args:
|
||||
- "sign-blob"
|
||||
- "--use-signing-config=false"
|
||||
- "--oidc-issuer=https://token.actions.githubusercontent.com"
|
||||
- "--output-certificate=${certificate}"
|
||||
- "--output-signature=${signature}"
|
||||
- "--bundle=${signature}"
|
||||
- "${artifact}"
|
||||
- "--yes"
|
||||
artifacts: checksum
|
||||
|
||||
@@ -27,7 +27,7 @@ require (
|
||||
github.com/aquasecurity/go-pep440-version v0.0.1
|
||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.2
|
||||
github.com/cespare/xxhash/v2 v2.3.0
|
||||
github.com/charmbracelet/bubbles v1.0.0
|
||||
github.com/charmbracelet/bubbletea v1.3.10
|
||||
@@ -83,7 +83,7 @@ require (
|
||||
github.com/spf13/afero v1.15.0
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/stretchr/testify v1.12.1
|
||||
github.com/ulikunitz/xz v0.5.16
|
||||
github.com/ulikunitz/xz v0.5.17
|
||||
github.com/vbatts/go-mtree v0.7.0
|
||||
github.com/vifraa/gopom v1.0.0
|
||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651
|
||||
|
||||
@@ -229,8 +229,8 @@ github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef h1:TSFnfbbu2oAO
|
||||
github.com/bitnami/go-version v0.0.0-20250131085805-b1f57a8634ef/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.2 h1:eF7W7HWKg3z9NrWV9pTLnNeoXaqq3Tq9DNKXVMfoCnw=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=
|
||||
github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=
|
||||
github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=
|
||||
@@ -994,8 +994,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulikunitz/xz v0.5.16 h1:ld6NyySjx5lowVKwJvMRLnW5nxKX/xnpSiFYZ/Lxur0=
|
||||
github.com/ulikunitz/xz v0.5.16/go.mod h1:H9Rt/W6/Qj27PGauhQc6nfCDy7vHpzsOThBSaYDoEhw=
|
||||
github.com/ulikunitz/xz v0.5.17 h1:flR0y/x1hgM8EGV1AW3Xll6T413G0glV8UfBwR617V4=
|
||||
github.com/ulikunitz/xz v0.5.17/go.mod h1:H9Rt/W6/Qj27PGauhQc6nfCDy7vHpzsOThBSaYDoEhw=
|
||||
github.com/vbatts/go-mtree v0.7.0 h1:ytmOc3MTRidZiBi9VBCyZ2BHe4fZS47L5v7BVXDWW4E=
|
||||
github.com/vbatts/go-mtree v0.7.0/go.mod h1:EjdpFC+LZy1TXbRGNa1MKKgjQ+7ew3foMFJK8o4/TdY=
|
||||
github.com/vbatts/tar-split v0.12.3 h1:Cd46rkGXI3Td4yrVNwU8ripbxFaQbmesqhjBUUYAJSw=
|
||||
|
||||
+49
-20
@@ -8,7 +8,6 @@ REPO="${PROJECT_NAME}"
|
||||
GITHUB_DOWNLOAD_PREFIX=https://github.com/${OWNER}/${REPO}/releases/download
|
||||
INSTALL_SH_BASE_URL=https://get.anchore.io/${PROJECT_NAME}
|
||||
LEGACY_INSTALL_SH_BASE_URL=https://raw.githubusercontent.com/${OWNER}/${PROJECT_NAME}
|
||||
PROGRAM_ARGS=$@
|
||||
|
||||
# signature verification options
|
||||
|
||||
@@ -19,6 +18,8 @@ VERIFY_SIGN=false
|
||||
VERIFY_SIGN_SUPPORTED_VERSION=v0.104.0
|
||||
# this is the earliest tag in the repo where the -v flag was introduced to this install.sh script
|
||||
VERIFY_SIGN_FLAG_VERSION=v1.6.0
|
||||
# releases at or after this version are signed with a sigstore bundle (.sigstore.json); earlier releases ship a separate .sig and .pem
|
||||
VERIFY_SIGN_BUNDLE_VERSION=v1.53.0
|
||||
|
||||
# do not change the name of this parameter (this must always be backwards compatible)
|
||||
DOWNLOAD_TAG_INSTALL_SCRIPT=${DOWNLOAD_TAG_INSTALL_SCRIPT:-true}
|
||||
@@ -386,8 +387,8 @@ download_github_release_checksums_files() (
|
||||
complete_url=$(github_release_asset_url "${download_url}" "${name}" "${version}" "${filename}")
|
||||
output_path="${output_dir}/${complete_filename}"
|
||||
|
||||
http_download "${output_path}" "${complete_url}" ""
|
||||
asset_file_exists "${output_path}"
|
||||
http_download "${output_path}" "${complete_url}" "" || return 1
|
||||
asset_file_exists "${output_path}" || return 1
|
||||
|
||||
log_trace "download_github_release_checksums_files() returned '${output_path}' for file '${complete_filename}'"
|
||||
|
||||
@@ -585,28 +586,31 @@ download_and_install_asset() (
|
||||
install_asset "${asset_filepath}" "${install_path}" "${binary}"
|
||||
)
|
||||
|
||||
# verify_sign [checksums-file-path] [certificate-reference] [signature-reference] [version]
|
||||
# verify_sign [checksums-file-path] [verification-material-flags...]
|
||||
#
|
||||
# attempts verify the signature of the checksums file from the release workflow in Github Actions run against the main branch.
|
||||
# the verification material is either "--bundle <path>" or (for older releases) "--certificate <ref> --signature <ref>".
|
||||
#
|
||||
verify_sign() {
|
||||
checksums_file=$1
|
||||
cert_reference=$2
|
||||
sig_reference=$3
|
||||
shift
|
||||
|
||||
log_trace "verifying artifact $1"
|
||||
log_trace "verifying artifact ${checksums_file}"
|
||||
|
||||
log_file=$(mktemp)
|
||||
|
||||
${COSIGN_BINARY} \
|
||||
verify-blob "$checksums_file" \
|
||||
--certificate "$cert_reference" \
|
||||
--signature "$sig_reference" \
|
||||
"$@" \
|
||||
--certificate-identity "https://github.com/${OWNER}/${REPO}/.github/workflows/release.yaml@refs/heads/main" \
|
||||
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" > "${log_file}" 2>&1
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
log_err "$(cat "${log_file}")"
|
||||
# cosign older than v2.4.2 can't read the bundle's verification material and reports a missing cert
|
||||
if [ "$1" = "--bundle" ] && grep -q "bundle does not contain cert" "${log_file}"; then
|
||||
log_err "note: releases >= ${VERIFY_SIGN_BUNDLE_VERSION} are verified with a sigstore bundle, which requires cosign v2.5.0 or newer (check '${COSIGN_BINARY} version')"
|
||||
fi
|
||||
rm -f "${log_file}"
|
||||
return 1
|
||||
fi
|
||||
@@ -630,7 +634,10 @@ download_asset() (
|
||||
|
||||
log_trace "download_asset(url=${download_url}, destination=${destination}, name=${name}, os=${os}, arch=${arch}, version=${version}, format=${format})"
|
||||
|
||||
checksums_filepath=$(download_github_release_checksums "${download_url}" "${name}" "${version}" "${destination}")
|
||||
if ! checksums_filepath=$(download_github_release_checksums "${download_url}" "${name}" "${version}" "${destination}"); then
|
||||
log_err "unable to download checksums file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_trace "checksums content:\n$(cat ${checksums_filepath})"
|
||||
|
||||
@@ -642,13 +649,25 @@ download_asset() (
|
||||
fi
|
||||
|
||||
if [ "$VERIFY_SIGN" = true ]; then
|
||||
checksum_sig_file_url=$(github_release_checksums_sig_url "${download_url}" "${name}" "${version}")
|
||||
log_trace "checksums signature url: ${checksum_sig_file_url}"
|
||||
if compare_semver "${version}" "${VERIFY_SIGN_BUNDLE_VERSION}"; then
|
||||
if ! checksums_bundle_filepath=$(download_github_release_checksums_files "${download_url}" "${name}" "${version}" "${destination}" "checksums.txt.sigstore.json"); then
|
||||
log_err "unable to download checksums signature bundle"
|
||||
return 1
|
||||
fi
|
||||
log_trace "checksums bundle: ${checksums_bundle_filepath}"
|
||||
|
||||
checksums_cert_file_url=$(github_release_checksums_cert_url "${download_url}" "${name}" "${version}")
|
||||
log_trace "checksums certificate url: ${checksums_cert_file_url}"
|
||||
set -- --bundle "${checksums_bundle_filepath}"
|
||||
else
|
||||
checksum_sig_file_url=$(github_release_checksums_sig_url "${download_url}" "${name}" "${version}")
|
||||
log_trace "checksums signature url: ${checksum_sig_file_url}"
|
||||
|
||||
if ! verify_sign "${checksums_filepath}" "${checksums_cert_file_url}" "${checksum_sig_file_url}"; then
|
||||
checksums_cert_file_url=$(github_release_checksums_cert_url "${download_url}" "${name}" "${version}")
|
||||
log_trace "checksums certificate url: ${checksums_cert_file_url}"
|
||||
|
||||
set -- --certificate "${checksums_cert_file_url}" --signature "${checksum_sig_file_url}"
|
||||
fi
|
||||
|
||||
if ! verify_sign "${checksums_filepath}" "$@"; then
|
||||
log_err "signature verification failed"
|
||||
return 1
|
||||
fi
|
||||
@@ -657,9 +676,15 @@ download_asset() (
|
||||
|
||||
asset_url="${download_url}/${asset_filename}"
|
||||
asset_filepath="${destination}/${asset_filename}"
|
||||
http_download "${asset_filepath}" "${asset_url}" ""
|
||||
if ! http_download "${asset_filepath}" "${asset_url}" ""; then
|
||||
log_err "unable to download asset '${asset_url}'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
hash_sha256_verify "${asset_filepath}" "${checksums_filepath}"
|
||||
# this is what ties the asset to the (optionally signature verified) checksums file, so a mismatch must stop the install
|
||||
if ! hash_sha256_verify "${asset_filepath}" "${checksums_filepath}"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_trace "download_asset_by_checksums_file() returned '${asset_filepath}'"
|
||||
|
||||
@@ -765,7 +790,7 @@ prep_signature_verification() {
|
||||
fi
|
||||
}
|
||||
|
||||
main() (
|
||||
parse_install_args() {
|
||||
# parse arguments
|
||||
|
||||
# note: never change default install directory (this must always be backwards compatible)
|
||||
@@ -805,6 +830,11 @@ EOF
|
||||
|
||||
set +u
|
||||
tag=$1
|
||||
set -u
|
||||
}
|
||||
|
||||
main() (
|
||||
parse_install_args "$@"
|
||||
|
||||
if [ -z "${tag}" ]; then
|
||||
log_info "checking github for the current release tag"
|
||||
@@ -812,7 +842,6 @@ EOF
|
||||
else
|
||||
log_info "checking github for release tag='${tag}'"
|
||||
fi
|
||||
set -u
|
||||
|
||||
if ! tag=$(get_release_tag "${OWNER}" "${REPO}" "${tag}"); then
|
||||
log_err "unable to find tag='${tag}'"
|
||||
@@ -843,7 +872,7 @@ EOF
|
||||
log_warn "failed to fetch from ${INSTALL_SH_BASE_URL}, trying fallback URL"
|
||||
install_script=$(http_copy "${LEGACY_INSTALL_SH_BASE_URL}/${tag}/install.sh" "")
|
||||
fi
|
||||
echo "${install_script}" | sh -s -- ${PROGRAM_ARGS}
|
||||
echo "${install_script}" | sh -s -- "$@"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
|
||||
@@ -43,3 +43,9 @@ run_test_case test_download_release_asset "${release}" "linux" "amd64" "deb" "ap
|
||||
run_test_case test_download_release_asset "${release}" "linux" "arm64" "tar.gz" "application/gzip"
|
||||
run_test_case test_download_release_asset "${release}" "linux" "arm64" "rpm" "application/x-rpm"
|
||||
run_test_case test_download_release_asset "${release}" "linux" "arm64" "deb" "application/vnd.debian.binary-package"
|
||||
|
||||
# releases before VERIFY_SIGN_BUNDLE_VERSION are signed with a separate .sig and .pem instead of a sigstore bundle,
|
||||
# so keep exercising that path against a fixed release
|
||||
legacy_release="v1.52.0"
|
||||
|
||||
run_test_case test_download_release_asset "${legacy_release}" "linux" "amd64" "tar.gz" "application/gzip"
|
||||
|
||||
@@ -87,3 +87,61 @@ test_prep_signature_verification() {
|
||||
}
|
||||
|
||||
run_test_case test_prep_signature_verification
|
||||
|
||||
# ensure the verification material is passed through to cosign and the old-cosign hint only shows when warranted
|
||||
test_verify_sign() {
|
||||
# verify_sign [checksums-file-path] [verification-material-flags...]
|
||||
|
||||
OG_COSIGN_BINARY=${COSIGN_BINARY}
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
args_file="${tmpdir}/args"
|
||||
hint="requires cosign v2.5.0 or newer"
|
||||
|
||||
# stub cosign that records its arguments, then prints STUB_OUTPUT and exits with STUB_EXIT
|
||||
COSIGN_BINARY="${tmpdir}/cosign"
|
||||
cat > "${COSIGN_BINARY}" <<STUB
|
||||
#!/bin/sh
|
||||
echo "\$@" > "${args_file}"
|
||||
echo "\${STUB_OUTPUT}"
|
||||
exit "\${STUB_EXIT}"
|
||||
STUB
|
||||
chmod +x "${COSIGN_BINARY}"
|
||||
|
||||
identity="--certificate-identity https://github.com/${OWNER}/${REPO}/.github/workflows/release.yaml@refs/heads/main --certificate-oidc-issuer https://token.actions.githubusercontent.com"
|
||||
|
||||
# bundle verification succeeds
|
||||
STUB_OUTPUT="Verified OK" STUB_EXIT=0 verify_sign "checksums.txt" --bundle "checksums.txt.sigstore.json" >/dev/null 2>&1
|
||||
assertEquals "0" "$?" "bundle verification should succeed"
|
||||
assertEquals "verify-blob checksums.txt --bundle checksums.txt.sigstore.json ${identity}" "$(cat "${args_file}")" "unexpected cosign args for bundle"
|
||||
|
||||
# legacy verification succeeds
|
||||
STUB_OUTPUT="Verified OK" STUB_EXIT=0 verify_sign "checksums.txt" --certificate "c.pem" --signature "c.sig" >/dev/null 2>&1
|
||||
assertEquals "0" "$?" "legacy verification should succeed"
|
||||
assertEquals "verify-blob checksums.txt --certificate c.pem --signature c.sig ${identity}" "$(cat "${args_file}")" "unexpected cosign args for legacy"
|
||||
|
||||
# cosign too old to read the bundle: fail with the hint (this is what cosign v2.2.4 through v2.4.1 print)
|
||||
output=$(STUB_OUTPUT="Error: bundle does not contain cert for verification, please provide public key" STUB_EXIT=1 verify_sign "checksums.txt" --bundle "b.json" 2>&1)
|
||||
assertEquals "1" "$?" "old cosign should fail verification"
|
||||
assertContains "${output}" "${hint}" "old cosign should get the version hint"
|
||||
|
||||
# bad signature (e.g. tampered checksums): fail without the hint
|
||||
output=$(STUB_OUTPUT="Error: invalid signature when validating ASN.1 encoded signature" STUB_EXIT=1 verify_sign "checksums.txt" --bundle "b.json" 2>&1)
|
||||
assertEquals "1" "$?" "bad signature should fail verification"
|
||||
assertNotContains "${output}" "${hint}" "bad signature should not get the version hint"
|
||||
|
||||
# unparseable bundle (e.g. a 404 body): fail without the hint
|
||||
output=$(STUB_OUTPUT="Error: invalid character 'N' looking for beginning of value" STUB_EXIT=1 verify_sign "checksums.txt" --bundle "b.json" 2>&1)
|
||||
assertEquals "1" "$?" "unparseable bundle should fail verification"
|
||||
assertNotContains "${output}" "${hint}" "unparseable bundle should not get the version hint"
|
||||
|
||||
# legacy failure never gets the bundle hint, even with the same output
|
||||
output=$(STUB_OUTPUT="Error: bundle does not contain cert for verification, please provide public key" STUB_EXIT=1 verify_sign "checksums.txt" --certificate "c.pem" --signature "c.sig" 2>&1)
|
||||
assertEquals "1" "$?" "legacy failure should fail verification"
|
||||
assertNotContains "${output}" "${hint}" "legacy failure should not get the version hint"
|
||||
|
||||
COSIGN_BINARY=${OG_COSIGN_BINARY}
|
||||
rm -rf -- "${tmpdir}"
|
||||
}
|
||||
|
||||
run_test_case test_verify_sign
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
. 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
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
. test_harness.sh
|
||||
|
||||
# make certain main defers to the (stubbed) tagged release script regardless of the caller's env
|
||||
DOWNLOAD_TAG_INSTALL_SCRIPT=true
|
||||
|
||||
get_release_tag() {
|
||||
printf '%s\n' "$3"
|
||||
}
|
||||
|
||||
prep_signature_verification() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# the "tagged release script" records each argument it receives, one bracketed arg per line
|
||||
http_copy() {
|
||||
cat <<'SCRIPT'
|
||||
printf '[%s]\n' "$@" > "$INSTALL_ARG_CAPTURE"
|
||||
SCRIPT
|
||||
}
|
||||
|
||||
test_release_script_receives_original_args() {
|
||||
test_dir=$(mktemp -d)
|
||||
INSTALL_ARG_CAPTURE="${test_dir}/actual"
|
||||
export INSTALL_ARG_CAPTURE
|
||||
|
||||
# note: paths are read here instead of passed to run_test_case, which word-splits its arguments
|
||||
while IFS= read -r install_path; do
|
||||
main -b "${install_path}" -d v0.80.0
|
||||
|
||||
printf '[%s]\n' -b "${install_path}" -d v0.80.0 > "${test_dir}/expected"
|
||||
assertFilesEqual "${test_dir}/expected" "${INSTALL_ARG_CAPTURE}" "args forwarded to the release script should match the original args (path='${install_path}')"
|
||||
done <<'PATHS'
|
||||
/tmp/bin with spaces
|
||||
/tmp/bin*
|
||||
/tmp/it's "quoted"
|
||||
PATHS
|
||||
|
||||
rm -rf -- "${test_dir}"
|
||||
}
|
||||
|
||||
run_test_case test_release_script_receives_original_args
|
||||
@@ -1,5 +1,9 @@
|
||||
FROM alpine:3.6
|
||||
RUN apk update && apk add python3 wget curl unzip make ca-certificates jq
|
||||
RUN curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64" && \
|
||||
mv cosign-linux-amd64 /usr/local/bin/cosign && \
|
||||
# cosign is pinned (and checksum verified) so the install tests always run with a cosign that can verify
|
||||
# sigstore bundles (releases >= v1.53.0 need v2.5.0 or newer)
|
||||
ARG COSIGN_VERSION=v3.1.3
|
||||
ARG COSIGN_SHA256=4629c757b7618056f8ddd7e2625ae9fdd94c0372a65049520bc7d9df9efc7f71
|
||||
RUN curl -sSfL -o /usr/local/bin/cosign "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64" && \
|
||||
echo "${COSIGN_SHA256} /usr/local/bin/cosign" | sha256sum -c - && \
|
||||
chmod +x /usr/local/bin/cosign
|
||||
|
||||
@@ -5,17 +5,22 @@ RUN apk update && apk add ca-certificates
|
||||
# so let docker pull the image that matches the hosts architecture first and then pull the correct asset
|
||||
FROM busybox:1.36.1-musl
|
||||
|
||||
# cosign is pinned (and checksum verified) so the install tests always run with a cosign that can verify
|
||||
# sigstore bundles (releases >= v1.53.0 need v2.5.0 or newer)
|
||||
ARG COSIGN_VERSION=v3.1.3
|
||||
ARG COSIGN_SHA256_AMD64=4629c757b7618056f8ddd7e2625ae9fdd94c0372a65049520bc7d9df9efc7f71
|
||||
ARG COSIGN_SHA256_ARM64=c5d324e091826b0d7a78eb16fef316450b4eb9aaec045611c08ba06f5e73220a
|
||||
RUN ARCH=$(uname -m) && \
|
||||
if [ "$ARCH" = "x86_64" ]; then \
|
||||
COSIGN_ARCH="amd64"; \
|
||||
COSIGN_ARCH="amd64"; COSIGN_SHA256="${COSIGN_SHA256_AMD64}"; \
|
||||
elif [ "$ARCH" = "aarch64" ]; then \
|
||||
COSIGN_ARCH="arm64"; \
|
||||
COSIGN_ARCH="arm64"; COSIGN_SHA256="${COSIGN_SHA256_ARM64}"; \
|
||||
else \
|
||||
echo "Unsupported architecture: $ARCH" && exit 1; \
|
||||
fi && \
|
||||
echo "Downloading cosign for $COSIGN_ARCH" && \
|
||||
wget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-${COSIGN_ARCH} && \
|
||||
mv cosign-linux-${COSIGN_ARCH} /bin/cosign && \
|
||||
echo "Downloading cosign ${COSIGN_VERSION} for $COSIGN_ARCH" && \
|
||||
wget -O /bin/cosign https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-${COSIGN_ARCH} && \
|
||||
echo "${COSIGN_SHA256} /bin/cosign" | sha256sum -c - && \
|
||||
chmod +x /bin/cosign
|
||||
|
||||
COPY --from=certs /etc/ssl/certs /etc/ssl/certs
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
FROM --platform=linux/amd64 ubuntu:20.04@sha256:33a5cc25d22c45900796a1aca487ad7a7cb09f09ea00b779e3b2026b4fc2faba
|
||||
RUN apt update -y && apt install make python3 curl unzip jq -y
|
||||
RUN LATEST_VERSION=$(curl https://api.github.com/repos/sigstore/cosign/releases/latest | grep tag_name | cut -d : -f2 | tr -d "v\", ") && \
|
||||
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign_${LATEST_VERSION}_amd64.deb" && \
|
||||
dpkg -i cosign_${LATEST_VERSION}_amd64.deb
|
||||
# cosign is pinned (and checksum verified) so the install tests always run with a cosign that can verify
|
||||
# sigstore bundles (releases >= v1.53.0 need v2.5.0 or newer)
|
||||
ARG COSIGN_VERSION=v3.1.3
|
||||
ARG COSIGN_SHA256=4629c757b7618056f8ddd7e2625ae9fdd94c0372a65049520bc7d9df9efc7f71
|
||||
RUN curl -sSfL -o /usr/local/bin/cosign "https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64" && \
|
||||
echo "${COSIGN_SHA256} /usr/local/bin/cosign" | sha256sum -c - && \
|
||||
chmod +x /usr/local/bin/cosign
|
||||
|
||||
@@ -56,6 +56,31 @@ assertFileExists() {
|
||||
fi
|
||||
}
|
||||
|
||||
assertContains() {
|
||||
haystack=$1
|
||||
needle=$2
|
||||
msg=$3
|
||||
case "$haystack" in
|
||||
*"$needle"*) ;;
|
||||
*)
|
||||
echo "assertContains failed: '$needle' not found in '$haystack' $msg"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
assertNotContains() {
|
||||
haystack=$1
|
||||
needle=$2
|
||||
msg=$3
|
||||
case "$haystack" in
|
||||
*"$needle"*)
|
||||
echo "assertNotContains failed: '$needle' found in '$haystack' $msg"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
assertFilesEqual() {
|
||||
want=$1
|
||||
got=$2
|
||||
|
||||
Reference in New Issue
Block a user