mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-19 07:13:07 +08:00
security: scope release oidc publishing
This commit is contained in:
@@ -244,12 +244,27 @@ function run() {
|
||||
|
||||
if (test('rejects actions/cache in workflows with id-token write', () => {
|
||||
const result = runValidator({
|
||||
'unsafe-oidc-cache.yml': `name: Unsafe\non:\n push:\npermissions:\n contents: read\n id-token: write\njobs:\n release:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/cache@v5\n with:\n path: ~/.npm\n key: cache\n`,
|
||||
'unsafe-oidc-cache.yml': `name: Unsafe\non:\n push:\npermissions:\n contents: read\njobs:\n release:\n runs-on: ubuntu-latest\n permissions:\n contents: read\n id-token: write\n steps:\n - uses: actions/cache@v5\n with:\n path: ~/.npm\n key: cache\n`,
|
||||
});
|
||||
assert.notStrictEqual(result.status, 0, 'Expected validator to fail on id-token workflow cache use');
|
||||
assert.match(result.stderr, /id-token: write must not restore or save shared dependency caches/);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('rejects workflow-scoped id-token write', () => {
|
||||
const result = runValidator({
|
||||
'unsafe-workflow-oidc.yml': `name: Unsafe\non:\n push:\npermissions:\n contents: read\n id-token: write\njobs:\n verify:\n runs-on: ubuntu-latest\n steps:\n - run: npm ci --ignore-scripts\n`,
|
||||
});
|
||||
assert.notStrictEqual(result.status, 0, 'Expected validator to fail on workflow-level id-token write');
|
||||
assert.match(result.stderr, /id-token: write must be scoped to a publish-only job/);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('allows job-scoped id-token for publish-only jobs', () => {
|
||||
const result = runValidator({
|
||||
'safe-publish-oidc.yml': `name: Safe\non:\n push:\npermissions:\n contents: read\njobs:\n publish:\n runs-on: ubuntu-latest\n permissions:\n contents: write\n id-token: write\n steps:\n - run: npm publish package.tgz --access public --provenance\n`,
|
||||
});
|
||||
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('rejects npm audit without registry signature verification', () => {
|
||||
const result = runValidator({
|
||||
'unsafe-audit.yml': `name: Unsafe\non:\n push:\njobs:\n audit:\n runs-on: ubuntu-latest\n steps:\n - run: npm audit --audit-level=high\n`,
|
||||
|
||||
@@ -32,9 +32,11 @@ for (const workflow of [
|
||||
'.github/workflows/reusable-release.yml',
|
||||
]) {
|
||||
const content = load(workflow);
|
||||
const workflowHeader = content.slice(0, content.indexOf('\njobs:\n'));
|
||||
|
||||
test(`${workflow} grants id-token for npm provenance`, () => {
|
||||
assert.match(content, /permissions:\s*[\s\S]*id-token:\s*write/m);
|
||||
test(`${workflow} scopes id-token to the publish job for npm provenance`, () => {
|
||||
assert.doesNotMatch(workflowHeader, /id-token:\s*write/);
|
||||
assert.match(content, /\n\s+permissions:\n\s+contents:\s*write\n\s+id-token:\s*write/m);
|
||||
});
|
||||
|
||||
test(`${workflow} configures the npm registry`, () => {
|
||||
@@ -51,7 +53,7 @@ for (const workflow of [
|
||||
});
|
||||
|
||||
test(`${workflow} publishes new tag versions to npm`, () => {
|
||||
assert.match(content, /npm publish --access public --provenance/);
|
||||
assert.match(content, /npm publish "\$\{\{ needs\.verify\.outputs\.package_file \}\}" --access public --provenance/);
|
||||
assert.match(content, /NODE_AUTH_TOKEN:\s*\$\{\{\s*secrets\.NPM_TOKEN\s*\}\}/);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user