From 298ac4fa991099d4a41fb184640e0903d02eb6cb Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 9 Sep 2026 21:20:50 +0000 Subject: [PATCH 1/2] ci: lint GitHub Actions workflows with zizmor Add check-workflows.yaml so every PR runs zizmor with Socket Firewall in front. Reconcile Socket Firewall as merged in PR #70. Co-authored-by: Jared Wray --- .github/workflows/check-workflows.yaml | 35 ++++++++++++++++++++++++++ DEFENSE_IN_DEPTH.md | 4 +-- SECURITY.md | 2 +- 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/check-workflows.yaml diff --git a/.github/workflows/check-workflows.yaml b/.github/workflows/check-workflows.yaml new file mode 100644 index 0000000..16a3a23 --- /dev/null +++ b/.github/workflows/check-workflows.yaml @@ -0,0 +1,35 @@ +name: check-workflows + +on: + push: + branches: [main] + pull_request: + +permissions: {} + +jobs: + zizmor: + runs-on: ubuntu-latest + permissions: + contents: read + actions: read + # SARIF upload. GitHub grants read-only on fork PRs regardless; permission + # values cannot be expressions, so the write grant stays and the zizmor + # step below skips Advanced Security on forks. + security-events: write + 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.1" + - name: Run zizmor + uses: zizmorcore/zizmor-action@3dc1ecc9bcb9e94e9b2c709687979e1298497054 # v0.6.2 + with: + # Fork PRs cannot upload SARIF (read-only token). Lint with annotations instead. + advanced-security: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} + annotations: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }} diff --git a/DEFENSE_IN_DEPTH.md b/DEFENSE_IN_DEPTH.md index baca76d..5e7d1a8 100644 --- a/DEFENSE_IN_DEPTH.md +++ b/DEFENSE_IN_DEPTH.md @@ -26,8 +26,8 @@ Profile: npm library · public - [x] `permissions: contents: read` (or `{}` + per-job grants) on every workflow — verified 2026-09-09 - [x] No `contents: write` except jobs whose purpose is mutating the repo (GitHub Release, Changesets version PR); generated output is a workflow artifact, never committed back from CI — verified 2026-09-09 - [x] Every action pinned to a full commit SHA (`npx actions-up`) — PR #69 -- [ ] 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 #70 pending) -- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR +- [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 #70 +- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR (PR pending) - [x] Workflow `name:` and job `name:` contain no spaces (kebab-case) so they can be set as required status checks — verified 2026-09-09 - [ ] `persist-credentials: false` on checkouts that don't push - [x] No `pull_request_target` on workflows that run untrusted PR code — verified 2026-09-09 diff --git a/SECURITY.md b/SECURITY.md index 743f938..a13a130 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -26,7 +26,7 @@ hardening checklist; progress is tracked in [DEFENSE_IN_DEPTH.md](./DEFENSE_IN_D - pnpm is pinned via `packageManager` (`pnpm@12.3.0`). - Dependencies install through pnpm with a 7-day cooldown on new versions, lifecycle scripts blocked by default, `trustPolicy: no-downgrade`, and exotic subdependencies blocked. - The lockfile is committed and CI installs with `--frozen-lockfile`. There is no Dependabot config; dependency updates go through reviewed PRs. -- CI workflows default to read-only `contents: read` permissions; generated output is never committed back from CI; every action is pinned to a full commit SHA. +- CI workflows default to read-only `contents: read` permissions; generated output is never committed back from CI; every action is pinned to a full commit SHA; Socket Firewall (`sfw`) wraps `pnpm install`. - Workflows do not use `pull_request_target`. - The published package sets `repository.url` to this repo so provenance can map back. - `.github/CODEOWNERS` names `@jaredwray` for `/.github/`, `/.vscode/`, `/.cursor/`, `/.devcontainer/`, and `/scripts/`. From 9706008d42a07da4910c5c22ac8c7ac940770c06 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 9 Sep 2026 21:21:13 +0000 Subject: [PATCH 2/2] chore: record PR #71 on the zizmor checklist item Co-authored-by: Jared Wray --- DEFENSE_IN_DEPTH.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEFENSE_IN_DEPTH.md b/DEFENSE_IN_DEPTH.md index 5e7d1a8..952f346 100644 --- a/DEFENSE_IN_DEPTH.md +++ b/DEFENSE_IN_DEPTH.md @@ -27,7 +27,7 @@ Profile: npm library · public - [x] No `contents: write` except jobs whose purpose is mutating the repo (GitHub Release, Changesets version PR); generated output is a workflow artifact, never committed back from CI — verified 2026-09-09 - [x] Every action pinned to a full commit SHA (`npx actions-up`) — PR #69 - [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 #70 -- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR (PR pending) +- [ ] `.github/workflows/check-workflows.yaml` lints workflows with zizmor on every PR (PR #71 pending) - [x] Workflow `name:` and job `name:` contain no spaces (kebab-case) so they can be set as required status checks — verified 2026-09-09 - [ ] `persist-credentials: false` on checkouts that don't push - [x] No `pull_request_target` on workflows that run untrusted PR code — verified 2026-09-09