From c0f043400c1a33834c6a4a4fe6996bdbd5af50ed Mon Sep 17 00:00:00 2001 From: Aric Camarata Date: Sun, 25 Oct 2026 10:58:49 -0400 Subject: [PATCH] fix(drill): fail a toolchain-pins tool row that has no sources (D-1184) --- free/ci/internal/toolchain/drill_test.go | 20 ++++++++++++++++++++ scripts/drill/toolchain-pins/run | 7 ++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/free/ci/internal/toolchain/drill_test.go b/free/ci/internal/toolchain/drill_test.go index a5de1737a..46c1b95ec 100644 --- a/free/ci/internal/toolchain/drill_test.go +++ b/free/ci/internal/toolchain/drill_test.go @@ -174,3 +174,23 @@ func TestDrillVerifiesAPinnedImageRow(t *testing.T) { t.Fatalf("vanished pinned image: exit %d %v", exit, c) } } + +// TestDrillFailsWhenAToolRowHasNoSources: a tool row without sources has nothing to verify, so it must fail +// instead of passing with nothing checked (D-1184). +func TestDrillFailsWhenAToolRowHasNoSources(t *testing.T) { + srv := mirror(t) + for name, tail := range map[string]string{ + "absent": "", + "empty": " sources: []\n", + } { + t.Run(name, func(t *testing.T) { + table := "version: 1\nrows:\n - name: nosrc\n kind: tool\n version: \"1.0.0\"\n purpose: p\n owner: o\n probe: [nosrc, --version]\n upstream: {type: github, ref: acme/demo}\n" + tail + doc, exit, raw := runDrill(t, table, srv) + validEvidence(t, raw) + c := resultsByTool(doc)["nosrc"] + if exit != 1 || doc["result"] != "fail" || c["result"] != "fail" || !strings.Contains(c["excerpt"].(string), "no sources") { + t.Fatalf("exit %d result %v check %v", exit, doc["result"], c) + } + }) + } +} diff --git a/scripts/drill/toolchain-pins/run b/scripts/drill/toolchain-pins/run index b4b583eaf..9a9e57899 100755 --- a/scripts/drill/toolchain-pins/run +++ b/scripts/drill/toolchain-pins/run @@ -139,11 +139,16 @@ while IFS= read -r row; do fi continue ;; esac + # A tool row with no sources has nothing to check. Fail it: a process substitution below would swallow the jq error. + if ! sources=$(jq -c '.sources | if type == "array" and length > 0 then .[] else error("no sources") end' <<<"$row" 2>/dev/null); then + emit "$name" "$name" "$version" true fail 1 "tool row has no sources to verify" + continue + fi gone=() while IFS= read -r src; do url=$(jq -r .url <<<"$src") head_ok "$url" || gone+=("$(jq -r '.os + "/" + .arch' <<<"$src")") - done < <(jq -c '.sources[]' <<<"$row") + done <<<"$sources" if [ "${#gone[@]}" -gt 0 ]; then emit "$name" "$name" "$version" true fail "${#gone[@]}" "pinned artifact no longer downloadable for: ${gone[*]}" continue