Skip to content

Commit d73c93e

Browse files
fix(rust-ci-reusable): wrap bare job-level if: in ${{ }} so GH parses (closes #322) (#334)
## Summary \`rust-ci-reusable.yml\` lines 109 and 149 used a bare \`if:\` expression at job level: \`\`\`yaml if: hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' \`\`\` GH Actions silently fails to parse the entire CALLER workflow when this exact shape (`hashFiles(format(inputs.X))` bare at job-level) is reached in a reusable. Caller manifests as 0s-duration "completed failure" with the workflow name reported as the path (`.github/workflows/rust-ci.yml`) instead of the YAML `name:` field — GitHub's "This run likely failed because of a workflow file issue" diagnostic. ## Root-cause investigation Run on panic-attack#95 (experiment branch, 5 commits), tracking the parsed workflow `name` field via API: | commit | caller pin | caller shape | reusable | parsed name | result | |---|---|---|---|---|---| | `1d0a8b9` | `@cc5a372` | original thin wrapper | `rust-ci-reusable.yml` | path-fallback | ❌ fail | | `d022c8f` | `@main` | original thin wrapper | `rust-ci-reusable.yml` | path-fallback | ❌ fail | | `02c6753` | `@main` | governance.yml shape | `rust-ci-reusable.yml` | path-fallback | ❌ fail | | `6250e19` | `@main` | governance.yml shape | **`governance-reusable.yml`** | `'Rust CI'` ✓ | parses (fails at runtime, expected) | | `cb23224` | `@main` | governance.yml verbatim clone | `governance-reusable.yml` | `'Rust CI'` ✓ | parses | Falsifies #322 hypotheses 1+2+3: - Hypothesis 1 (caller structure) — falsified: changing the caller's YAML to match governance.yml verbatim did NOT fix. - Hypothesis 2 (SHA resolution) — falsified: `@main` floating ref ALSO failed. - Hypothesis 3 (workflow_id cache) — falsified: a fresh \`workflow_id\` 287101574 (created via filename rename) ALSO failed. Root cause: hypothesis 4 (new) — when the caller's \`uses:\` resolves to a reusable whose first job has a bare \`if: hashFiles(format(...))\` at job level, GH's expression evaluator rejects the resolution at workflow-parse time. The audit + coverage jobs (lines 187, 215) were always wrapped in \`\${{ }}\` and worked; the check + test jobs were not. ## The fix Two-line `if:` wrapping. Diff: \`\`\`diff - if: hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' + if: \${{ hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }} \`\`\` ## Estate impact Once this merges, every caller of \`rust-ci-reusable.yml\` should immediately start parsing on its next push — no caller-side action needed for callers using \`@main\` floating refs. SHA-pinned callers will need to bump the pin to a commit at-or-after this merge. ## Follow-up - 43+ panic-attack-tracked callers using SHA-pinned rust-ci-reusable.yml — bumping their pins to the new commit could be a fan-out, but a no-op SHA bump is sufficient once \`@main\` resolution is confirmed clean. - Audit other reusables (\`governance-reusable.yml\`, \`secret-scanner-reusable.yml\`, etc.) for the same anti-pattern via grep: \`^\\s*if: [^$]\` followed by \`hashFiles\\|format\\|inputs\\.\` — none found in governance-reusable on inspection but worth a sweep. ## Refs - Closes #322 - Investigation PR (panic-attack side): hyperpolymath/panic-attack#95 - Original symptom report PRs: panic-attack#84 (orphan-SHA hypothesis, falsified), panic-attack#92 (SHA-bump experiment, falsified) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3f34549 commit d73c93e

1 file changed

Lines changed: 2 additions & 2 deletions

File tree

.github/workflows/rust-ci-reusable.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ jobs:
106106
check:
107107
name: Cargo check + clippy + fmt
108108
runs-on: ${{ inputs.runs-on }}
109-
if: hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != ''
109+
if: ${{ hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
110110
permissions:
111111
contents: read
112112
defaults:
@@ -146,7 +146,7 @@ jobs:
146146
name: Cargo test
147147
runs-on: ${{ inputs.runs-on }}
148148
needs: check
149-
if: hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != ''
149+
if: ${{ hashFiles(format('{0}/Cargo.toml', inputs.working_directory)) != '' }}
150150
permissions:
151151
contents: read
152152
defaults:

0 commit comments

Comments
 (0)