docs: add supply-chain incident response playbook

Add a repo-level supply-chain incident response playbook for npm/GitHub Actions package-registry incidents, anchored on the May 2026 TanStack compromise and prior Shai-Hulud-style npm incidents.

- add `docs/security/supply-chain-incident-response.md` with exposure checks, immediate response steps, workflow rules, publication rules, and escalation triggers
- link the playbook from `SECURITY.md`
- reject `pull_request_target` workflows that restore or save shared dependency caches
- add a regression test for the new `pull_request_target + actions/cache` guardrail

Validation:
- node tests/ci/validate-workflow-security.test.js (12 passed, 0 failed)
- node scripts/ci/validate-workflow-security.js (validated 7 workflow files)
- npx markdownlint-cli 'SECURITY.md' 'docs/security/supply-chain-incident-response.md'
- npx markdownlint-cli '**/*.md' --ignore node_modules
- git diff --check
- node tests/run-all.js (2377 passed, 0 failed)
- GitHub CI for #1848 green across Ubuntu, Windows, and macOS

No release, tag, npm publish, plugin tag, marketplace submission, or announcement was performed.
This commit is contained in:
Affaan Mustafa
2026-05-13 00:22:28 -04:00
committed by GitHub
parent da04a6e344
commit cbecf5689d
4 changed files with 133 additions and 0 deletions

View File

@@ -99,6 +99,14 @@ function run() {
assert.match(result.stderr, /pull_request\.head\.sha/);
})) passed++; else failed++;
if (test('rejects shared cache use in pull_request_target workflows', () => {
const result = runValidator({
'unsafe-pr-target-cache.yml': `name: Unsafe\non:\n pull_request_target:\n branches: [main]\njobs:\n inspect:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/cache@v5\n with:\n path: ~/.npm\n key: cache\n - run: echo inspect\n`,
});
assert.notStrictEqual(result.status, 0, 'Expected validator to fail on pull_request_target cache use');
assert.match(result.stderr, /pull_request_target workflows must not restore or save shared dependency caches/);
})) passed++; else failed++;
if (test('rejects npm ci without ignore-scripts in workflows with write permissions', () => {
const result = runValidator({
'unsafe-write-install.yml': `name: Unsafe\non:\n workflow_dispatch:\npermissions:\n contents: read\n issues: write\njobs:\n audit:\n runs-on: ubuntu-latest\n steps:\n - run: npm ci\n`,