From f57b375adea0cc275de75eff0cd8631c98d8068b Mon Sep 17 00:00:00 2001 From: SandObserver <260779319+SandObserver@users.noreply.github.com> Date: Tue, 27 Oct 2026 00:07:08 -0400 Subject: [PATCH] Improve: pass the CA workflow values to the shell through env --- .github/workflows/ca-template-changes.yml | 5 ++++- .github/workflows/ca-template-check.yml | 5 ++++- test/repo/workflow-hardening.test.js | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ca-template-changes.yml b/.github/workflows/ca-template-changes.yml index f43af374..8f94eb18 100644 --- a/.github/workflows/ca-template-changes.yml +++ b/.github/workflows/ca-template-changes.yml @@ -41,7 +41,10 @@ jobs: # Python's standard library: the runner image carries no xmllint. - name: Check the result is still well-formed if: steps.changes.outputs.changed == 'true' - run: python3 scripts/ca-validate.py "${{ github.repository }}" "${{ github.event.repository.default_branch }}" + env: + REPO: ${{ github.repository }} + BASE: ${{ github.event.repository.default_branch }} + run: python3 scripts/ca-validate.py "$REPO" "$BASE" # The checkout keeps no credentials, so the token authenticates this one # push and is never left in the runner's git config. diff --git a/.github/workflows/ca-template-check.yml b/.github/workflows/ca-template-check.yml index 1598db8d..b58bac9d 100644 --- a/.github/workflows/ca-template-check.yml +++ b/.github/workflows/ca-template-check.yml @@ -33,4 +33,7 @@ jobs: # Python's standard library, so nothing is installed. The runner image # carries no xmllint. - name: Validate the template and the profile - run: python3 scripts/ca-validate.py "${{ github.repository }}" "${{ github.event.repository.default_branch }}" + env: + REPO: ${{ github.repository }} + BASE: ${{ github.event.repository.default_branch }} + run: python3 scripts/ca-validate.py "$REPO" "$BASE" diff --git a/test/repo/workflow-hardening.test.js b/test/repo/workflow-hardening.test.js index fda33563..30005993 100644 --- a/test/repo/workflow-hardening.test.js +++ b/test/repo/workflow-hardening.test.js @@ -141,3 +141,26 @@ test('the lockfile is committed and CI installs from it', () => { } assert.deepEqual(loose, [], `Use npm ci so CI installs the lockfile:\n ${loose.join('\n ')}`); }); + +/* An expression in a run script is pasted into the shell before it runs. A + value an outsider controls, such as a branch name, then runs as a command. */ +test('no run script holds an expression', () => { + const found = []; + for (const [f, src] of all) { + const lines = src.split('\n'); + let block = -1; + lines.forEach((line, i) => { + const indent = line.match(/^\s*/)[0].length; + const run = line.match(/^(\s*)(- )?run:\s*(.*)$/); + if (run) { + block = /^[|>]/.test(run[3]) ? run[1].length + (run[2] ? 2 : 0) : -1; + if (run[3].includes('${{')) found.push(`${f}:${i + 1}`); + return; + } + if (block === -1) return; + if (line.trim() && indent <= block) block = -1; + else if (line.includes('${{')) found.push(`${f}:${i + 1}`); + }); + } + assert.deepEqual(found, [], `Pass the value through env and read it as a variable:\n ${found.join('\n ')}`); +});