Skip to content

docs(feature-map): keep the page's sources in the repo; npm run docs:feature-map #1519

docs(feature-map): keep the page's sources in the repo; npm run docs:feature-map

docs(feature-map): keep the page's sources in the repo; npm run docs:feature-map #1519

name: Dependency Security
# Runs on every PR and every push to main.
# Hard-blocks on Critical npm vulnerabilities.
# Warns on High npm vulnerabilities (non-blocking — devDep false positives are common).
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
# ── npm audit ──────────────────────────────────────────────────────────────
npm-audit:
# A version-bump commit changes four package.json version fields and
# nothing else, so there is nothing here for it to check. It used to carry
# `[skip ci]` for this, but that marker also suppresses the *tag* push that
# rides on the same commit, which silently disabled every release — see
# version-bump.yml. Skipping by message keeps the saving without that cost.
# Guarded on event_name so pull_request runs are never skipped.
if: "${{ github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: bump version') }}"
name: npm audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 22
# npm 10 (what Node 22 ships) cannot resolve this workspace graph
# without a lockfile — arborist dies in #loadPeerSet on vitest with
# "Cannot read properties of null (reading 'edgesOut')". npm 11 does
# it fine. Verified on a clean clone at Node 22.23.1.
- run: npm i -g npm@11
# Generate lockfile on the fly so npm audit has a full dependency graph.
# Consider committing package-lock.json for faster, deterministic CI.
- name: Generate lockfile
run: npm ci --ignore-scripts
# Hard block — Critical vulns in production dependencies.
# Verifies every package in the lockfile against the registry's own
# signatures. `npm audit` answers "is this version known to be
# vulnerable"; this answers "is this tarball the one the registry
# published", which is what catches a tampered or re-published package.
#
# `npm audit signatures` calls the attestations API, which intermittently
# 404s for otherwise-valid packages (e.g. whatwg-url@14.2.0). Treat that
# registry gap as a warning so Critical audit below remains the hard gate.
- name: Verify registry signatures
continue-on-error: true
run: npm audit signatures
- name: Fail on Critical vulnerabilities
run: npm audit --audit-level=critical --omit=dev
# Soft check — High vulns across all deps (informational; common in devDeps).
- name: Warn on High vulnerabilities
run: npm audit --audit-level=high || echo "⚠️ High-severity advisories found — review npm-audit-full.json"
# Upload full JSON report as a build artifact for manual review.
- name: Save full audit report
if: always()
run: npm audit --json > npm-audit-full.json || true
- name: Upload audit report
if: always()
uses: actions/upload-artifact@v5
with:
name: npm-audit-report
path: npm-audit-full.json
retention-days: 30
# ── ESLint security rules ──────────────────────────────────────────────────
eslint-security:
# A version-bump commit changes four package.json version fields and
# nothing else, so there is nothing here for it to check. It used to carry
# `[skip ci]` for this, but that marker also suppresses the *tag* push that
# rides on the same commit, which silently disabled every release — see
# version-bump.yml. Skipping by message keeps the saving without that cost.
# Guarded on event_name so pull_request runs are never skipped.
if: "${{ github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: bump version') }}"
name: ESLint security
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 22
# npm 10 (what Node 22 ships) cannot resolve this workspace graph
# without a lockfile — arborist dies in #loadPeerSet on vitest with
# "Cannot read properties of null (reading 'edgesOut')". npm 11 does
# it fine. Verified on a clean clone at Node 22.23.1.
- run: npm i -g npm@11
- name: Install dependencies
run: npm ci --ignore-scripts
# Errors (inject/eval/ReDoS) cause non-zero exit and block the PR.
# Warnings (detect-non-literal-fs-filename) are informational — legitimate
# server/CLI filesystem operations use variable paths by design.
- name: Run ESLint security rules
run: npx eslint .
# ── node_modules backdoor / unexpected port scan ───────────────────────────
# Dedicated deep scan also lives in deps-backdoor-scan.yml (scheduled weekly).
deps-backdoor-scan:
# A version-bump commit changes four package.json version fields and
# nothing else, so there is nothing here for it to check. It used to carry
# `[skip ci]` for this, but that marker also suppresses the *tag* push that
# rides on the same commit, which silently disabled every release — see
# version-bump.yml. Skipping by message keeps the saving without that cost.
# Guarded on event_name so pull_request runs are never skipped.
if: "${{ github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: bump version') }}"
name: Deps backdoor / port scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: 22
# npm 10 (what Node 22 ships) cannot resolve this workspace graph
# without a lockfile — arborist dies in #loadPeerSet on vitest with
# "Cannot read properties of null (reading 'edgesOut')". npm 11 does
# it fine. Verified on a clean clone at Node 22.23.1.
- run: npm i -g npm@11
- name: Install dependencies (ignore-scripts)
run: npm ci --ignore-scripts
- name: Scan node_modules
run: npm run scan:deps-security -- --report deps-backdoor-report.json
- name: Upload scan report
if: always()
uses: actions/upload-artifact@v5
with:
name: deps-backdoor-report
path: deps-backdoor-report.json
retention-days: 30