From 5922a142ea877d0aa7c36cf40a6c666fb2effd0d Mon Sep 17 00:00:00 2001 From: Joey Mussalli Date: Mon, 24 Aug 2026 15:03:37 -0400 Subject: [PATCH] fix(scan): check for required commands before scanning Nothing guarantees the script's dependencies are present when it runs. The CodePipeline buildspec tries to install jq and curl like this: - command -v jq >/dev/null 2>&1 || { yum -y install jq || (apt-get ...); } >/dev/null 2>&1 || true which discards the output and ends in `|| true`, so an install that fails -- unsupported base image, no network, no package manager, not root -- leaves the build going with the tool missing and nothing said about it. The CodeCatalyst workflow attempts no install at all; it just runs the script. The failure that follows is misattributed. With jq absent, the guard that validates trustabl.json cannot parse it and the run fails with "no usable trustabl.json -- results cannot be trusted", pointing the user at the scan result when the real problem is the build image. Worse is grep or head going missing: the checksum lookup quietly yields an empty EXPECTED, the script prints "not listed in checksums.txt -- skipping verification", and the release binary runs unverified. - Check curl, jq, tar, awk, grep, head and uname up front; on failure name every missing command at once and exit 2, the code docs/EVALUATION.md already documents as "scanner or I/O error ... the output should not be trusted". - `git` is deliberately excluded. Every call is inside a guard, and without it the script degrades to BR=unknown and REPO=$TARGET rather than breaking, so requiring it would reject build images that work fine today. - `tr` and `seq` are excluded because they ship in coreutils alongside `head`, which is checked. Left the buildspec's `|| true` alone on purpose. That fallback only matters when the tool is genuinely absent and the install genuinely failed, and in that case the preflight's message is more useful than a raw package-manager error would be. Removing it would trade a clear diagnosis for a noisier one. Verified against a sandboxed PATH: silent and exit 0 with everything present; exit 2 naming exactly the missing tools for one, two and three of them removed; and still exit 0 with git removed, confirming it stays optional. --- scan/trustabl-scan.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/scan/trustabl-scan.sh b/scan/trustabl-scan.sh index caa6314..6409dfa 100644 --- a/scan/trustabl-scan.sh +++ b/scan/trustabl-scan.sh @@ -27,6 +27,29 @@ JSON_FILE="${JSON_FILE:-trustabl.json}" RISK_THRESHOLD="${RISK_SCORE_THRESHOLD:-0}" SEV_THRESHOLD="${SEVERITY_THRESHOLD:-none}" BRANCH_INPUT="${BRANCH:-}" + +# ---- preflight: required commands ---- +# The CodePipeline buildspec's install phase ends in `|| true` and hides its +# output, and the CodeCatalyst workflow installs nothing at all, so a build +# image can reach this point missing a dependency with nothing having said so. +# Naming the missing tool here beats the alternative: the first symptom is +# otherwise a downstream guard blaming the scan result for a missing binary. +# +# `git` is deliberately not required — every call is guarded, and without it +# the script degrades to BR=unknown and REPO=$TARGET. `tr` and `seq` are left +# out because they ship in coreutils alongside `head`. +MISSING="" +for _cmd in curl jq tar awk grep head uname; do + command -v "$_cmd" >/dev/null 2>&1 || MISSING="$MISSING $_cmd" +done +if [ -n "$MISSING" ]; then + echo "Missing required command(s):$MISSING" + echo "Install them on the build image before scanning; the CodeBuild image" + echo "aws/codebuild/standard:7.0 ships all of them." + exit 2 +fi +unset _cmd MISSING + [ "${DEBUG:-false}" = "true" ] && set -x set -e