chore(scripts): read a shell-expanded name as unreadable, and env keys case-insensitively (#2146)

Copilot, seventh review:

- The unreadable-name rules only knew GitHub expression syntax, so
  `ENGINE: firefox` plus `npm run smoke:web:$ENGINE` ran a forbidden pass with
  the guard silent — the shell resolves the name, which makes it exactly as
  unreadable as a ${{ }} expression and forbidden for the same reason. The
  pattern keys off a leading $ or %, covering $VAR, ${VAR}, $env:VAR and cmd's
  %VAR% in one, for both the engine and `local:` families.

- The env-key comparison was case-sensitive, but Windows environment variables
  are not: `env: { smoke_browser: firefox }` on a windows-latest job sets the
  very variable Node reads as SMOKE_BROWSER. Compared case-insensitively now,
  as is the POSIX assignment pattern. On a POSIX runner that spelling would be
  a different variable and harmless, so this is stricter there than it needs to
  be — the right direction for a guard, and the alternative is a verdict that
  depends on a `runs-on` which may itself be an expression.

Signed-off-by: Cliff Hall <cliff@futurescale.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-27 01:54:23 -04:00
commit 47b3c6fc9c

View file

@ -175,6 +175,44 @@ describe("findWorkflowViolations", () => {
text: workflow(" - run: SMOKE_BROWSER= npm run smoke"),
rules: [VIOLATION.BROWSER_ENV],
},
{
// Copilot, seventh review: a shell resolves the name itself, so the
// engine is just as unreadable as it is behind a `${{ }}` expression.
name: "flags an engine pass named through a shell variable",
text: workflow(
" - env:\n ENGINE: firefox\n run: npm run smoke:web:$ENGINE",
),
rules: [VIOLATION.ENGINE_SCRIPT],
},
{
name: "flags the braced and cmd spellings of that too",
text: workflow(
" - run: npm run smoke:web:${ENGINE}\n - run: npm run smoke:web:%ENGINE%",
),
rules: [VIOLATION.ENGINE_SCRIPT, VIOLATION.ENGINE_SCRIPT],
},
{
name: "flags a local: script named through a shell variable",
text: workflow(" - run: npm run local:$TASK"),
rules: [VIOLATION.LOCAL_SCRIPT],
},
{
// Copilot, seventh review: Windows environment variables are
// case-insensitive, so this sets the very variable Node reads as
// SMOKE_BROWSER.
name: "flags a lower-cased env key, which Windows treats as the same var",
text: workflow(
" - env: { smoke_browser: firefox }\n run: npm run smoke",
),
rules: [VIOLATION.BROWSER_ENV],
},
{
name: "allows a lower-cased key set to chromium",
text: workflow(
" - env: { smoke_browser: chromium }\n run: npm run smoke",
),
rules: [],
},
{
// Copilot, sixth review: PowerShell is the DEFAULT shell on a Windows
// runner, so a POSIX-only pattern is silent on exactly the workflow least