diff --git a/scripts/lib/workflow-gate.mjs b/scripts/lib/workflow-gate.mjs index 0a17dd78..902c1dd9 100644 --- a/scripts/lib/workflow-gate.mjs +++ b/scripts/lib/workflow-gate.mjs @@ -185,9 +185,14 @@ const BROWSER_ASSIGNMENTS = [ value: 1, }, // .NET, reachable from PowerShell: SetEnvironmentVariable("NAME", "value"). + // The value arm accepts an UNQUOTED second argument as well — `$engine`, or a + // `${{ }}` expression — because that spelling sets the environment just the + // same, and an engine the guard cannot read is forbidden for the reason + // `smoke:web:engine` is (Copilot). Bare values stop at `,` or `)` so a third + // argument (`"Process"`) is not swallowed. { re: new RegExp( - String.raw`SetEnvironmentVariable\s*\(\s*["']${BROWSER_ENV_VAR}["']\s*,\s*["']([^"']*)["']`, + String.raw`SetEnvironmentVariable\s*\(\s*["']${BROWSER_ENV_VAR}["']\s*,\s*("[^"]*"|'[^']*'|[^,)]*)`, "gi", ), value: 1, diff --git a/scripts/lib/workflow-gate.test.mjs b/scripts/lib/workflow-gate.test.mjs index 4d3263e9..323acca4 100644 --- a/scripts/lib/workflow-gate.test.mjs +++ b/scripts/lib/workflow-gate.test.mjs @@ -230,6 +230,23 @@ describe("findWorkflowViolations", () => { ), rules: [VIOLATION.BROWSER_ENV], }, + { + // Copilot, ninth review: an unquoted second argument sets the environment + // just the same, and an engine the guard cannot read is forbidden for the + // reason `smoke:web:engine` is. + name: "flags a SetEnvironmentVariable call with a dynamic value", + text: workflow( + ' - run: |\n [Environment]::SetEnvironmentVariable("SMOKE_BROWSER", $engine)\n npm run smoke', + ), + rules: [VIOLATION.BROWSER_ENV], + }, + { + name: "allows a SetEnvironmentVariable call pinning chromium", + text: workflow( + ' - run: |\n [Environment]::SetEnvironmentVariable("SMOKE_BROWSER", "chromium", "Process")\n npm run smoke', + ), + rules: [], + }, { name: "flags a .NET SetEnvironmentVariable call", text: workflow(