From e57c34881eaa773cf2f7f2e64849e321382e2a19 Mon Sep 17 00:00:00 2001 From: jaso0n0818 Date: Thu, 2 Jul 2026 18:33:41 +0000 Subject: [PATCH] fix(enrichment): exclude official actions/github refs case-insensitively MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub org/user names are case-insensitive, so a workflow that pins `Actions/checkout@v4` (or `GitHub/codeql-action@v3`) references the official action. The unpinned-Actions analyzer excluded official refs with a case-sensitive regex, so it mis-flagged these as mutable third-party supply-chain risks — a false positive. This mirrors the same analyzer's isWorkflowPath, which already matches GitHub workflow paths case-insensitively. Add the case-insensitive flag; GitHub reserves the actions/github orgs, so it cannot over-match a real third-party org. --- .../src/analyzers/actions-pin.ts | 5 ++++- review-enrichment/test/actions-pin.test.ts | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/review-enrichment/src/analyzers/actions-pin.ts b/review-enrichment/src/analyzers/actions-pin.ts index 02913191da..63020d80e6 100644 --- a/review-enrichment/src/analyzers/actions-pin.ts +++ b/review-enrichment/src/analyzers/actions-pin.ts @@ -7,7 +7,10 @@ import { isWorkflowPath } from "../workflow-path.js"; const USES_RE = /^\s*-?\s*["']?uses["']?\s*:\s*["']?([\w.-]+\/[\w./-]+)@([^\s"'#]+)/; const FULL_SHA = /^[0-9a-f]{40}$/; -const OFFICIAL = /^(actions|github)\//; +// GitHub org/user names are case-insensitive (mirrors isWorkflowPath's case-insensitive path match), so the +// official-action exclusion matches case-insensitively — otherwise `Actions/checkout` would be mis-flagged as a +// mutable third-party action. GitHub reserves the `actions`/`github` orgs, so this can never over-match a real one. +const OFFICIAL = /^(actions|github)\//i; /** Scan one workflow patch's added lines for unpinned third-party `uses:` refs, line-cited via hunk headers. Pure. */ export function scanWorkflowPins( diff --git a/review-enrichment/test/actions-pin.test.ts b/review-enrichment/test/actions-pin.test.ts index 57021e0936..595a1295dd 100644 --- a/review-enrichment/test/actions-pin.test.ts +++ b/review-enrichment/test/actions-pin.test.ts @@ -36,6 +36,25 @@ test("scanWorkflowPins flags mutable third-party action refs with line citations ]); }); +test("scanWorkflowPins excludes official actions/github refs case-insensitively", () => { + const findings = scanWorkflowPins( + workflowPath, + [ + "@@ -1,0 +5,4 @@", + "+ - uses: Actions/checkout@v4", + "+ - uses: GitHub/codeql-action/init@v3", + "+ - uses: ACTIONS/setup-node@v4", + "+ - uses: pnpm/action-setup@v3", + ].join("\n"), + ); + + // GitHub org names are case-insensitive, so official actions/* and github/* refs are excluded regardless of + // casing; only the genuine mutable third-party ref is flagged. + assert.deepEqual(findings, [ + { file: workflowPath, line: 8, action: "pnpm/action-setup", ref: "v3" }, + ]); +}); + test("scanWorkflowPins accepts quoted uses keys and ignores unchanged uses lines", () => { const findings = scanWorkflowPins( workflowPath,