diff --git a/review-enrichment/src/analyzers/actions-pin.ts b/review-enrichment/src/analyzers/actions-pin.ts index 6aa9fdbe79..d6a7324883 100644 --- a/review-enrichment/src/analyzers/actions-pin.ts +++ b/review-enrichment/src/analyzers/actions-pin.ts @@ -9,6 +9,10 @@ const FULL_SHA = /^[0-9a-f]{40}$/; const OFFICIAL = /^(actions|github)\//; const WORKFLOW_PATH = /^\.github\/workflows\/.+\.ya?ml$/; +function isWorkflowPath(path: string): boolean { + return WORKFLOW_PATH.test(path.replace(/\\/g, "/").toLowerCase()); +} + /** Scan one workflow patch's added lines for unpinned third-party `uses:` refs, line-cited via hunk headers. Pure. */ export function scanWorkflowPins( path: string, @@ -46,7 +50,7 @@ export async function scanActionPins( ): Promise { const findings: ActionPinFinding[] = []; for (const file of req.files ?? []) { - if (WORKFLOW_PATH.test(file.path) && file.patch) { + if (isWorkflowPath(file.path) && file.patch) { findings.push(...scanWorkflowPins(file.path, file.patch)); } } diff --git a/review-enrichment/test/actions-pin.test.ts b/review-enrichment/test/actions-pin.test.ts index 0c25cb035e..57021e0936 100644 --- a/review-enrichment/test/actions-pin.test.ts +++ b/review-enrichment/test/actions-pin.test.ts @@ -118,3 +118,29 @@ test("scanActionPins scans only changed workflow YAML files with patches", async }, ]); }); + +test("scanActionPins matches workflow paths case-insensitively", async () => { + const findings = await scanActionPins({ + repoFullName: "o/r", + prNumber: 1, + files: [ + { + path: ".github/Workflows/CI.YML", + patch: "@@ -1,0 +5,1 @@\n+ - uses: pnpm/action-setup@v3", + }, + { + path: "docs/workflow.yml", + patch: "@@ -1,0 +1,1 @@\n+ - uses: vendor/not-a-workflow@main", + }, + ], + }); + + assert.deepEqual(findings, [ + { + file: ".github/Workflows/CI.YML", + line: 5, + action: "pnpm/action-setup", + ref: "v3", + }, + ]); +});