From fe35dea46b698095654d315f8f5d035b9308cdde Mon Sep 17 00:00:00 2001 From: Wibias <37517432+Wibias@users.noreply.github.com> Date: Tue, 1 Sep 2026 01:22:23 +0200 Subject: [PATCH 1/2] chore(deps): keep CodeQL action pins on the same 4.37.9 SHA Split Dependabot PRs mixed init/autobuild/analyze versions and failed CodeQL. Pin those actions together and group future github/codeql-action updates so the split cannot recur. --- .github/dependabot.yml | 4 ++++ .github/workflows/codeql.yml | 10 +++++----- tests/unit/actions-usage-contract.test.mjs | 12 ++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8c264aa4..51ba59b7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -26,6 +26,10 @@ updates: time: "04:30" timezone: Europe/Berlin open-pull-requests-limit: 10 + groups: + codeql-action: + patterns: + - "github/codeql-action*" - package-ecosystem: nuget directory: "/authority-host/windows/GitHubDeliveryAuthority" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b6cc1a9d..96bf4795 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -83,15 +83,15 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: languages: javascript-typescript - name: Autobuild - uses: github/codeql-action/autobuild@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/autobuild@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 - name: Analyze - uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: category: "/language:javascript-typescript" @@ -123,7 +123,7 @@ jobs: global-json-file: global.json - name: Initialize CodeQL - uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: languages: csharp build-mode: manual @@ -138,6 +138,6 @@ jobs: if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - name: Analyze - uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 + uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 with: category: "/language:csharp" diff --git a/tests/unit/actions-usage-contract.test.mjs b/tests/unit/actions-usage-contract.test.mjs index 8a98d976..726e859f 100644 --- a/tests/unit/actions-usage-contract.test.mjs +++ b/tests/unit/actions-usage-contract.test.mjs @@ -113,6 +113,18 @@ test("superseded expensive PR workflows cancel in progress", () => { } }); +test("CodeQL init, autobuild, and analyze stay on the same pinned SHA", () => { + const pins = [...codeql.matchAll(/github\/codeql-action\/(init|autobuild|analyze)@([0-9a-f]{40})/g)]; + assert.ok(pins.length >= 5, `expected init/autobuild/analyze pins, found ${pins.length}`); + const shas = new Set(pins.map((match) => match[2])); + assert.equal(shas.size, 1, `mixed CodeQL action SHAs: ${[...shas].join(", ")}`); +}); + +test("Dependabot groups github/codeql-action updates", () => { + const dependabot = read(".github/dependabot.yml"); + assert.match(dependabot, /package-ecosystem: github-actions[\s\S]*groups:\s*\n\s*codeql-action:\s*\n\s*patterns:\s*\n\s*- "github\/codeql-action\*"/); +}); + test("CodeQL analyses are scoped from the PR base classifier and fail closed", () => { assert.match(codeql, /node "\$\{TRUSTED_SCOPE\}" --mode codeql/); assert.match(codeql, /git show "\$\{BASE_SHA\}:scripts\/ci-scope\.mjs"/); From e4b0472a9eea5a3fa7da0455fec4bcb24af26bbd Mon Sep 17 00:00:00 2001 From: Wibias <37517432+Wibias@users.noreply.github.com> Date: Tue, 1 Sep 2026 01:24:28 +0200 Subject: [PATCH 2/2] test: require each CodeQL action name in the lockstep pin contract A five-pin count could pass with only init copies. Assert init, autobuild, and analyze are all present so mixed-version Dependabot splits stay fail-closed. --- tests/unit/actions-usage-contract.test.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit/actions-usage-contract.test.mjs b/tests/unit/actions-usage-contract.test.mjs index 726e859f..bafb2acb 100644 --- a/tests/unit/actions-usage-contract.test.mjs +++ b/tests/unit/actions-usage-contract.test.mjs @@ -115,7 +115,11 @@ test("superseded expensive PR workflows cancel in progress", () => { test("CodeQL init, autobuild, and analyze stay on the same pinned SHA", () => { const pins = [...codeql.matchAll(/github\/codeql-action\/(init|autobuild|analyze)@([0-9a-f]{40})/g)]; - assert.ok(pins.length >= 5, `expected init/autobuild/analyze pins, found ${pins.length}`); + const byAction = { init: [], autobuild: [], analyze: [] }; + for (const match of pins) byAction[match[1]].push(match[2]); + assert.ok(byAction.init.length >= 1, "missing init pin"); + assert.ok(byAction.autobuild.length >= 1, "missing autobuild pin"); + assert.ok(byAction.analyze.length >= 1, "missing analyze pin"); const shas = new Set(pins.map((match) => match[2])); assert.equal(shas.size, 1, `mixed CodeQL action SHAs: ${[...shas].join(", ")}`); });