#!/usr/bin/env bash # # check-advisories-selftest.sh — check-advisories.py can fail. # # A check that cannot fail is decoration. This feeds the check pre-captured # `cargo audit --json` documents through `--from-json` and asserts that it # 1. passes when every advisory found is allowed and every allowed advisory # is found; # 2. fails when an advisory is reported that the allow list does not name # (the case this check exists for); # 3. fails when an allow-list entry matches nothing, so an excuse cannot # outlive the exposure it was written for; # 4. fails, and says it could not audit, when the document does not parse: # an error is never read as "clean". # # Nothing here runs cargo or reads the advisory database, so it needs no # network and no lockfile. set -uo pipefail here=$(cd "$(dirname "$0")" && pwd) check="$here/check-advisories.py" tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT # Every advisory the check allows, read from the check itself so the two cannot # drift apart. # (a read loop, not `mapfile`: macOS ships bash 3.2, where mapfile does not exist) allowed=() while IFS= read -r id; do allowed+=("$id"); done < <( grep -oE '^ "RUSTSEC-[0-9]{4}-[0-9]{4}"' "$check" | tr -d ' "' ) if [ ${#allowed[@]} -eq 0 ]; then echo "selftest: could not read the allow list out of $check" >&2 exit 2 fi # write_json ... — a cargo-audit document reporting exactly these. write_json() { local out=$1; shift { printf '{"vulnerabilities":{"found":true,"count":%d,"list":[' "$#" local first=1 id for id in "$@"; do [ $first -eq 1 ] || printf ',' first=0 printf '{"advisory":{"id":"%s","title":"t"},"package":{"name":"c","version":"1.0.0"}}' "$id" done printf ']},"warnings":{}}' } > "$out" } fails=0 expect() { # expect [text the output must hold] -- local want=$1 what=$2 needle=$3; shift 3; [ "${1:-}" = -- ] && shift local out rc out=$(python3 -I "$check" --from-json "$@" 2>&1); rc=$? if [ "$want" = pass ] && [ $rc -ne 0 ]; then echo "FAIL $what: the check failed"; printf '%s\n' "$out" | sed 's/^/ /'; fails=$((fails+1)); return fi if [ "$want" = fail ] && [ $rc -eq 0 ]; then echo "FAIL $what: the check passed"; printf '%s\n' "$out" | sed 's/^/ /'; fails=$((fails+1)); return fi if [ -n "$needle" ] && ! grep -q -- "$needle" <<<"$out"; then echo "FAIL $what: the output does not say '$needle'"; printf '%s\n' "$out" | sed 's/^/ /'; fails=$((fails+1)); return fi echo "ok $what" } write_json "$tmp/all.json" "${allowed[@]}" expect pass "every advisory allowed and every allowance used passes" "" -- "$tmp/all.json" write_json "$tmp/extra.json" "${allowed[@]}" "RUSTSEC-2099-0001" expect fail "an advisory the allow list does not name fails" "not in the allow list" -- "$tmp/extra.json" write_json "$tmp/short.json" "${allowed[@]:1}" expect fail "an allowance that matches nothing fails" "no longer match anything" -- "$tmp/short.json" printf 'this is not json\n' > "$tmp/broken.json" expect fail "a document that does not parse fails as unaudited, not as clean" "Could not be audited" -- "$tmp/broken.json" if [ $fails -ne 0 ]; then echo "check-advisories-selftest: $fails failure(s)"; exit 1; fi echo "check-advisories-selftest: the check passes a reviewed tree and fails each way it should."