diff --git a/.github/workflows/check-workflows.yaml b/.github/workflows/check-workflows.yaml new file mode 100644 index 0000000..3bf60b3 --- /dev/null +++ b/.github/workflows/check-workflows.yaml @@ -0,0 +1,28 @@ +name: Check Workflows + +on: + push: + branches: [main] + pull_request: + +permissions: {} + +jobs: + zizmor: + runs-on: ubuntu-latest + permissions: + contents: read + actions: read + security-events: write # SARIF upload to code scanning + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Install Socket Firewall + uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 + with: + mode: firewall-free + firewall-version: "1.15.0" + - name: Run zizmor + uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2 diff --git a/.github/workflows/code-coverage.yaml b/.github/workflows/code-coverage.yaml index b160034..2c139fb 100644 --- a/.github/workflows/code-coverage.yaml +++ b/.github/workflows/code-coverage.yaml @@ -15,6 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 with: @@ -36,6 +38,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 with: @@ -61,6 +65,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 with: diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index bdd172f..cc9d4fa 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -40,6 +40,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 diff --git a/.github/workflows/deploy-site.yaml b/.github/workflows/deploy-site.yaml index f66a088..f5b115d 100644 --- a/.github/workflows/deploy-site.yaml +++ b/.github/workflows/deploy-site.yaml @@ -26,6 +26,7 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 + package-manager-cache: false - name: Install Dependencies run: sfw pnpm install --frozen-lockfile diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1102969..1d7c541 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -13,6 +13,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 with: @@ -23,6 +25,7 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 + package-manager-cache: false - name: Install Dependencies run: sfw pnpm install --frozen-lockfile - name: Build @@ -33,6 +36,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 with: @@ -43,6 +48,7 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 + package-manager-cache: false - name: Install Dependencies run: sfw pnpm install --frozen-lockfile - name: Test Services @@ -60,6 +66,8 @@ jobs: id-token: write steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 with: @@ -70,6 +78,7 @@ jobs: uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 + package-manager-cache: false - name: Install Dependencies run: sfw pnpm install --frozen-lockfile - name: Build diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 7d980d9..23ced9b 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -18,6 +18,8 @@ jobs: node-version: ['22', '24', '26'] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Install Socket Firewall uses: SocketDev/action@ba6de6cc0565af1f42295590380973573297e31f # v1.3.2 with: diff --git a/DEFENSE_IN_DEPTH.md b/DEFENSE_IN_DEPTH.md index 742192e..161af17 100644 --- a/DEFENSE_IN_DEPTH.md +++ b/DEFENSE_IN_DEPTH.md @@ -27,13 +27,13 @@ Profile: npm library · public ## 4. GitHub Actions - [x] `permissions: contents: read` (or `{}` + per-job grants) on every workflow — verified 2026-08-17 -- [ ] Every action pinned to a full commit SHA (`npx actions-up`) (PR #113 pending) +- [x] Every action pinned to a full commit SHA (`npx actions-up`) — PR #113 - [x] Every job installs Socket Firewall (`SocketDev/action` SHA-pinned, `firewall-version` pinned); `pnpm install` / `npm install` run as `sfw pnpm install` / `sfw npm install` — PR #111 -- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR -- [ ] `persist-credentials: false` on checkouts that don't push +- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR (PR #116 pending) +- [ ] `persist-credentials: false` on checkouts that don't push (PR #116 pending) - [x] No `pull_request_target` on workflows that run untrusted PR code — verified 2026-08-17 -- [ ] Artifact-publishing workflows disable `actions/setup-node` default caching (`package-manager-cache: false`) to prevent cache poisoning -- [ ] No npm tokens (or other registry credentials) in Actions secrets +- [ ] Artifact-publishing workflows disable `actions/setup-node` default caching (`package-manager-cache: false`) to prevent cache poisoning (PR #116 pending) +- [x] No npm tokens (or other registry credentials) in Actions secrets — verified 2026-08-18 (OIDC `id-token` on publish; no `NPM_TOKEN` in workflows) ## 5. npm publishing — npm libraries only diff --git a/SECURITY.md b/SECURITY.md index 1d4703f..9f221b9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -23,4 +23,5 @@ We will acknowledge receipt, work with you on a coordinated disclosure timeline, This repository follows the [defense-in-depth](https://github.com/jaredwray/agentic/blob/main/skills/security/defense-in-depth-nodejs/SKILL.md) hardening checklist; progress is tracked in [DEFENSE_IN_DEPTH.md](./DEFENSE_IN_DEPTH.md). Measures currently in place: - Codespaces and Cursor Cloud Agents install through Aikido Safe Chain; package-manager shims must not be bypassed. +- CI runs with read-only permissions; every action is pinned to a full commit SHA; Socket Firewall (`sfw`) wraps `pnpm install` / `npm install`; workflows are security-linted with zizmor on every PR. - Dependencies install through pnpm with a 7-day cooldown on new versions, and lifecycle scripts are blocked by default. Socket reviews every dependency change; Aikido scans every build.