What
In both v2.0.0 and v2.0.1 of dependency-cooldown.yml, astral-sh/setup-uv is silently excluded from the "Packages scanned" list in the scan comment, even when the triggering PR's diff clearly includes a uses: astral-sh/setup-uv@... bump.
Observed on j7an/nexus-mcp#160 across both scanner versions:
The PR diff includes bumps for three actions:
step-security/harden-runner (appears in scan ✓)
trufflesecurity/trufflehog (appears in scan ✓)
astral-sh/setup-uv (absent from scan ❌)
The v2.0.0 scan comment header read:
Packages scanned: step-security/harden-runner, trufflesecurity/trufflehog
After the v2.0.1 rebase it still read:
Packages scanned: step-security/harden-runner (v2.17.0), trufflesecurity/trufflehog (v3.94.3)
In both cases astral-sh/setup-uv is missing despite being in the same diff. This is a silent data loss — a consumer could have a genuine advisory against setup-uv and the scan would report "no known exploits" while never actually asking GHSA or OSV about it.
Why
The likely root cause is in the diff-parsing pipeline that extracts action names from + uses: lines. Current v2.0.1 code (approximately):
while IFS= read -r _uses_line; do
[ -z "$_uses_line" ] && continue
_action_name=$(echo "$_uses_line" | sed -E 's/^\+\s+uses:\s+//' | sed -E 's/@.*//' | sed -E 's/\s*$//')
[ -z "$_action_name" ] && continue
echo "$_action_name" | grep -qE '^(\./|docker://)' && continue
echo "$ACTIONS" | grep -qxF "$_action_name" 2>/dev/null && continue
_action_ver=$(echo "$_uses_line" | grep -oE '#\s*v[0-9][0-9.]*' | sed -E 's/#\s*v//' || true)
ACTIONS="$(printf '%s\n%s' "$ACTIONS" "$_action_name")"
ACTION_VERSIONS["$_action_name"]="$_action_ver"
done <<< "$(echo \"\$DIFF\" | grep -E '^\+\s+uses:' || true)"
Hypotheses (prioritized, all need verification):
- Indentation or step-level context differs.
setup-uv is typically used inside jobs.<job>.steps[].uses at a deeper indent than top-level reusable-workflow uses: calls. The grep -E '^\+\s+uses:' tolerates any leading whitespace, but the sed -E 's/^\+\s+uses:\s+//' assumes a specific shape and might produce a malformed _action_name (with leading whitespace) that then gets caught by a later filter.
- The diff's
+ line has a BOM or non-ASCII whitespace. Unlikely but possible if Dependabot's diff generator varies across action sources.
- Subshell scope on the
while loop. The <<< here-string should execute the loop body in the current shell (bash), so ACTIONS modifications persist. But if a consumer is running this under a non-bash POSIX shell, the entire loop could run in a subshell and discard additions — though we'd see all actions dropped, not just setup-uv. Rule out by inspecting the shell used in CI.
- Dedup false-positive.
grep -qxF "$_action_name" is a full-line fixed-string match so a substring collision is unlikely, but worth ruling out if any other action name in the repo is a prefix or suffix of astral-sh/setup-uv.
- Silent filter via
grep -v -E '^(\./|docker://)' (v2.0.0 code path). Does not apply — astral-sh/setup-uv doesn't start with ./ or docker://. Listed for completeness.
The root cause needs empirical confirmation, not speculation. Step 1 of the fix is reproduction.
How
- Reproduce. Use
gh pr diff 160 --repo j7an/nexus-mcp (or a saved snapshot from before its merge) to capture the actual diff. Run the extraction pipeline locally against the captured diff and observe where astral-sh/setup-uv drops out. Save the reproducer diff as a fixture in the shared-workflows repo.
- Isolate the stage. Test each pipeline stage (
grep -E '^\+\s+uses:', sed 's/^\+\s+uses:\s+//', sed 's/@.*//', sed 's/\s*$//', grep -qE '^(\./|docker://)', grep -qxF dedup) individually against the setup-uv input line. Identify which stage removes it.
- Fix the identified stage with the minimum change. If it's a regex issue, fix the regex; if it's a subshell issue, restructure the loop to run in the current shell.
- Add a regression fixture. Create a fixture diff in
tests/fixtures/ (or wherever shared-workflows keeps test data) that includes an astral-sh/setup-uv bump alongside step-security/harden-runner and trufflesecurity/trufflehog. Add a test that runs the extraction pipeline against the fixture and asserts all three are returned in the packages list.
- Add a sanity-check guard to the main workflow. After extraction, count
+ uses: lines in the diff and compare against the length of $ACTIONS. If they differ, render a ⚠️ Extraction warning section in the scan comment listing the expected-vs-found counts. This makes future silent drops visible instead of silent.
Acceptance Criteria
Related
- Observed during the same 2026-04-12 verification that found the cooldown-enforcement regression and the stale-label issue (separate issues)
- Risk magnitude: a silently-unscanned dependency could ship with a genuine advisory while the scan reports "no known exploits" — this is a correctness issue, not a cosmetic one
What
In both v2.0.0 and v2.0.1 of
dependency-cooldown.yml,astral-sh/setup-uvis silently excluded from the "Packages scanned" list in the scan comment, even when the triggering PR's diff clearly includes auses: astral-sh/setup-uv@...bump.Observed on j7an/nexus-mcp#160 across both scanner versions:
The PR diff includes bumps for three actions:
step-security/harden-runner(appears in scan ✓)trufflesecurity/trufflehog(appears in scan ✓)astral-sh/setup-uv(absent from scan ❌)The v2.0.0 scan comment header read:
After the v2.0.1 rebase it still read:
In both cases
astral-sh/setup-uvis missing despite being in the same diff. This is a silent data loss — a consumer could have a genuine advisory against setup-uv and the scan would report "no known exploits" while never actually asking GHSA or OSV about it.Why
The likely root cause is in the diff-parsing pipeline that extracts action names from
+ uses:lines. Current v2.0.1 code (approximately):Hypotheses (prioritized, all need verification):
setup-uvis typically used insidejobs.<job>.steps[].usesat a deeper indent than top-level reusable-workflowuses:calls. Thegrep -E '^\+\s+uses:'tolerates any leading whitespace, but thesed -E 's/^\+\s+uses:\s+//'assumes a specific shape and might produce a malformed_action_name(with leading whitespace) that then gets caught by a later filter.+line has a BOM or non-ASCII whitespace. Unlikely but possible if Dependabot's diff generator varies across action sources.whileloop. The<<<here-string should execute the loop body in the current shell (bash), soACTIONSmodifications persist. But if a consumer is running this under a non-bash POSIX shell, the entire loop could run in a subshell and discard additions — though we'd see all actions dropped, not justsetup-uv. Rule out by inspecting the shell used in CI.grep -qxF "$_action_name"is a full-line fixed-string match so a substring collision is unlikely, but worth ruling out if any other action name in the repo is a prefix or suffix ofastral-sh/setup-uv.grep -v -E '^(\./|docker://)'(v2.0.0 code path). Does not apply —astral-sh/setup-uvdoesn't start with./ordocker://. Listed for completeness.The root cause needs empirical confirmation, not speculation. Step 1 of the fix is reproduction.
How
gh pr diff 160 --repo j7an/nexus-mcp(or a saved snapshot from before its merge) to capture the actual diff. Run the extraction pipeline locally against the captured diff and observe whereastral-sh/setup-uvdrops out. Save the reproducer diff as a fixture in the shared-workflows repo.grep -E '^\+\s+uses:',sed 's/^\+\s+uses:\s+//',sed 's/@.*//',sed 's/\s*$//',grep -qE '^(\./|docker://)',grep -qxFdedup) individually against thesetup-uvinput line. Identify which stage removes it.tests/fixtures/(or wherever shared-workflows keeps test data) that includes anastral-sh/setup-uvbump alongsidestep-security/harden-runnerandtrufflesecurity/trufflehog. Add a test that runs the extraction pipeline against the fixture and asserts all three are returned in the packages list.+ uses:lines in the diff and compare against the length of$ACTIONS. If they differ, render a⚠️ Extraction warningsection in the scan comment listing the expected-vs-found counts. This makes future silent drops visible instead of silent.Acceptance Criteria
setup-uvbeing dropped is identified and documented in the fix PR description+ uses: astral-sh/setup-uv@<sha> # v<version>producesastral-sh/setup-uvin the extracted listastral-sh/setup-uvin the Packages Scanned section of the scan comment+ uses:lines in the input diff does not equal the count of extracted actions, the scan comment includes a warning section with both counts so future silent drops are immediately visibleRelated