From 7f1afcb30f72968b7409f14c24d1b05994fe4865 Mon Sep 17 00:00:00 2001 From: Aashil Date: Tue, 29 Sep 2026 16:33:36 +0545 Subject: [PATCH] Fix SCOPE_ARGS quoting bug that silently runs 0 tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SCOPE_ARGS="--area '$X'" (or --spec) baked literal single-quote characters into the string, then expanded it unquoted at the call site. Bash word-splits an unquoted expansion but never re-parses embedded quote characters as shell syntax, so run-suite.mjs received an --area/--spec value with stray quotes glued onto it, matched nothing, and silently ran 0 tests — reported as a harness failure (exit 2), not a red suite. Found on everest-forms PR #1669: a commit that only added a new spec file put the workflow on the `--spec` branch, which exposed the bug. Switches SCOPE_ARGS to a bash array and expands it as "${SCOPE_ARGS[@]}", which is immune to this class of bug regardless of what the area/spec value contains. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/suite.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/suite.yml b/.github/workflows/suite.yml index a7e0199..840427c 100644 --- a/.github/workflows/suite.yml +++ b/.github/workflows/suite.yml @@ -609,12 +609,17 @@ jobs: # SAFE by construction: any changed source file that matches no # area_paths pattern falls back to the full tier, so an unmapped # change costs runner time rather than coverage. - SCOPE_ARGS="" + # + # A bash ARRAY, not a string: `SCOPE_ARGS="--area '$X'"` followed by + # an unquoted `$SCOPE_ARGS` does NOT re-parse those embedded quotes + # as shell syntax — word-splitting just hands run-suite.mjs a value + # with literal quote characters glued onto it, matching nothing and + # silently running 0 tests (a harness failure, not a red suite). + SCOPE_ARGS=() # The scope gate already resolved this, for pull requests and for # everything else. `scope: full` still means the whole tier. - SCOPE_ARGS="--area ${{ steps.scope.outputs.areas }}" - if [ -z "${{ steps.scope.outputs.areas }}" ] || [ "${{ inputs.scope }}" = "full" ]; then - SCOPE_ARGS="" + if [ -n "${{ steps.scope.outputs.areas }}" ] && [ "${{ inputs.scope }}" != "full" ]; then + SCOPE_ARGS=(--area "${{ steps.scope.outputs.areas }}") fi # `scope: specs` REPLACES the area filter with the spec files this @@ -627,11 +632,11 @@ jobs: # on a runner that cannot support it. if [ "${{ inputs.scope }}" = "specs" ] && [ "${{ steps.scope.outputs.mode }}" = "specs" ] \ && [ -n "${{ steps.scope.outputs.specs }}" ]; then - SCOPE_ARGS="--spec ${{ steps.scope.outputs.specs }}" + SCOPE_ARGS=(--spec "${{ steps.scope.outputs.specs }}") fi node ../claudegrill/plugins/claudegrill/scripts/run-suite.mjs \ - --tier fresh --json --full-results $SCOPE_ARGS \ + --tier fresh --json --full-results "${SCOPE_ARGS[@]}" \ --timeout-ms ${{ inputs.timeout_ms }} \ --test-timeout-ms ${{ inputs.test_timeout_ms }} \ --max-failures ${{ inputs.max_failures }} \