From 9bd1320a705401ece03af68a352d94052db4d0e5 Mon Sep 17 00:00:00 2001 From: ghost <49853598+JSONbored@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:50:06 -0700 Subject: [PATCH] fix(enrichment): detect quoted workflow uses keys --- review-enrichment/src/analyzers/actions-pin.ts | 2 +- review-enrichment/test/enrichment.test.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/review-enrichment/src/analyzers/actions-pin.ts b/review-enrichment/src/analyzers/actions-pin.ts index 4f0c16e8e8..6aa9fdbe79 100644 --- a/review-enrichment/src/analyzers/actions-pin.ts +++ b/review-enrichment/src/analyzers/actions-pin.ts @@ -4,7 +4,7 @@ // Official actions/* + github/* are excluded (lowest risk, extremely common) to keep the signal high. Line-cited. import type { EnrichRequest, ActionPinFinding } from "../types.js"; -const USES_RE = /^\s*-?\s*uses:\s*["']?([\w.-]+\/[\w./-]+)@([^\s"'#]+)/; +const USES_RE = /^\s*-?\s*["']?uses["']?\s*:\s*["']?([\w.-]+\/[\w./-]+)@([^\s"'#]+)/; const FULL_SHA = /^[0-9a-f]{40}$/; const OFFICIAL = /^(actions|github)\//; const WORKFLOW_PATH = /^\.github\/workflows\/.+\.ya?ml$/; diff --git a/review-enrichment/test/enrichment.test.ts b/review-enrichment/test/enrichment.test.ts index 763bd0aefb..c186fbd516 100644 --- a/review-enrichment/test/enrichment.test.ts +++ b/review-enrichment/test/enrichment.test.ts @@ -433,6 +433,24 @@ test("scanWorkflowPins: flags unpinned third-party actions, skips official + SHA assert.equal(findings[0].line, 3); }); +test("scanWorkflowPins: flags unpinned third-party actions with YAML-equivalent uses keys", () => { + const patch = [ + "@@ -1,0 +1,3 @@", + "+ - uses : tj-actions/changed-files@v44", + "+ - \"uses\": third-party/action@main", + "+ - 'uses' : quoted/action@v1", + ].join("\n"); + const findings = scanWorkflowPins(".github/workflows/ci.yml", patch); + assert.deepEqual( + findings.map(({ action, ref, line }) => ({ action, ref, line })), + [ + { action: "tj-actions/changed-files", ref: "v44", line: 1 }, + { action: "third-party/action", ref: "main", line: 2 }, + { action: "quoted/action", ref: "v1", line: 3 }, + ], + ); +}); + test("scanActionPins: only scans .github/workflows/* files", async () => { const findings = await scanActionPins({ repoFullName: "o/r",