security: scope release oidc publishing

This commit is contained in:
Affaan Mustafa
2026-05-18 13:41:10 -04:00
parent 386326df8e
commit 7911af4a39
5 changed files with 124 additions and 16 deletions

View File

@@ -45,6 +45,7 @@ const NPM_AUDIT_PATTERN = /\bnpm\s+audit\b(?!\s+signatures\b)/;
const NPM_AUDIT_SIGNATURES_PATTERN = /\bnpm\s+audit\s+signatures\b/;
const ACTIONS_CACHE_PATTERN = /uses:\s*['"]?actions\/cache@/m;
const ID_TOKEN_WRITE_PATTERN = /^\s*id-token:\s*write\b/m;
const TOP_LEVEL_JOBS_PATTERN = /^jobs:\s*$/m;
const UNSAFE_INSTALL_PATTERNS = [
{
pattern: /\bnpm\s+ci\b(?![^\n]*--ignore-scripts)/g,
@@ -121,6 +122,8 @@ function extractCheckoutSteps(source) {
function findViolations(filePath, source) {
const violations = [];
const checkoutSteps = extractCheckoutSteps(source);
const jobsIndex = source.search(TOP_LEVEL_JOBS_PATTERN);
const workflowHeader = jobsIndex >= 0 ? source.slice(0, jobsIndex) : source;
for (const rule of RULES) {
if (!rule.eventPattern.test(source)) {
@@ -175,6 +178,16 @@ function findViolations(filePath, source) {
}
if (ID_TOKEN_WRITE_PATTERN.test(workflowHeader)) {
violations.push({
filePath,
event: 'workflow-scoped id-token',
description: 'id-token: write must be scoped to a publish-only job, not the entire workflow',
expression: 'top-level id-token: write',
line: getLineNumber(source, source.search(ID_TOKEN_WRITE_PATTERN)),
});
}
for (const installRule of UNSAFE_INSTALL_PATTERNS) {
for (const match of source.matchAll(installRule.pattern)) {
violations.push({