Files
maestro/scripts/security/workflow-policy.test.mjs
oss-sync 57702b4f34
CI / build-and-test (push) Canceled after 0s
sync: update from private repo (2336949a)
2026-09-17 11:29:31 +00:00

42 lines
1.7 KiB
JavaScript

import { readFile } from 'node:fs/promises';
import { parse } from 'yaml';
import { describe, expect, it } from 'vitest';
const workflowPath = new URL('../../.gitea/workflows/ci.yml', import.meta.url);
describe('CI workflow semantic security policy', () => {
it('pins actions, minimizes permissions, and leaves no checkout credential', async () => {
const source = await readFile(workflowPath, 'utf8');
const workflow = parse(source);
expect(workflow.permissions).toEqual({ contents: 'read' });
expect(workflow.on).toHaveProperty('pull_request');
expect(source).not.toContain('${{ secrets.');
for (const job of Object.values(workflow.jobs)) {
expect(job.permissions ?? workflow.permissions).toEqual({ contents: 'read' });
for (const step of job.steps ?? []) {
if (!step.uses) continue;
expect(step.uses).toMatch(/^[^@\s]+@[a-f0-9]{40}$/);
expect(step.uses).not.toMatch(/(?:^|\/)cache(?:\/(?:restore|save))?@/);
expect(step.with ?? {}).not.toHaveProperty('cache');
if (step.uses.startsWith('actions/checkout@')) {
expect(step.with?.['persist-credentials']).toBe(false);
}
}
}
});
it('does not invoke repository package hooks before policy or native rebuild', async () => {
const source = await readFile(workflowPath, 'utf8');
expect(source).toContain(
'node scripts/security/dependency-policy.mjs package-lock.json ui/package-lock.json',
);
expect(source).toContain('node scripts/security/rebuild-native.mjs');
expect(source).not.toContain('npm run security:dependency-policy');
expect(source).not.toContain('npm run ci:rebuild-native');
});
});