ci: harden CI/CD security (SHA-pin actions, pnpm 11, zizmor, permissions)#200
Merged
Conversation
…ons)
- SHA-pin every third-party action across 13 workflows (immutable refs,
comments preserve the tag for Dependabot/Renovate)
- Bump pnpm 10.28.2 -> 11.1.2 (lifecycle-script blocking by default);
allowBuilds for esbuild, protobufjs, unrs-resolver in pnpm-workspace.yaml
- Add zizmor static analyser as a CI gate; .github/zizmor.yml allowlists
5 intentional patterns (3 push-back checkouts, 2 dangerous-trigger uses)
with per-rule justifications inline
- Add top-level permissions blocks to the 8 workflows that lacked them;
notify-* get permissions: {} (zero scope); add persist-credentials:false
to every checkout that doesn't push back
- Agent-audit fixes folded in: env-isolate commitlint PR SHAs (script-
injection), gate fix-drift verify/PR steps on autofix outcome (silent-
failure mode), scope GHA buildx cache by event in publish-docker (cache
poisoning), move several secrets.* shell interpolations into env blocks
Closes M-13 from the CI/CD Supply Chain Security Audit.
jpr5
force-pushed
the
worktree-synthetic-dancing-scone
branch
from
May 15, 2026 00:41
041e13e to
d1c7f2b
Compare
Resolve conflicts in fix-drift.yml and publish-release.yml: - fix-drift.yml: keep main's removal of issue-creation step, apply SHA-pinned actions and env-var indirection from security hardening - publish-release.yml: keep main's build/publish job split with artifact transfer and npm environment, apply SHA-pinned actions, top-level permissions, and env-var indirection from security hardening
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
commit: |
MikeRyanDev
approved these changes
May 15, 2026
MikeRyanDev
left a comment
Contributor
There was a problem hiding this comment.
No serious supply-chain or CI hardening blockers found. The release workflow builds in a no-secret build job, publishes from downloaded artifacts with NODE_AUTH_TOKEN only on npm publish, PR Docker cache scope is isolated from release scope, pull_request_target notify paths do not checkout PR code, actions are pinned, and checks are green.
jpr5
pushed a commit
that referenced
this pull request
Jul 15, 2026
…ons) (#200) ## Summary Resolves **M-13** from the [CI/CD Supply Chain Security Audit](https://www.notion.so/35e3aa38185281e589b7cc4096725d15) (deferred SHA-pinning) and aligns aimock with TanStack's [post-incident hardening playbook](https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack). Codeowners excluded — already present. Full write-up: [aimock CI/CD Hardening — Notion](https://www.notion.so/3603aa38185281d49a1efc95fc37fe37). ## What changed - **SHA-pinned every third-party action** across all 13 workflows. Each `uses: action@v*` becomes `uses: action@<40-char-sha> # <tag>` — immutable, Dependabot-bumpable. Pinned to the latest patch within each current major (no silent major bumps). - **pnpm 10.28.2 → 11.1.2.** pnpm 11 blocks lifecycle scripts by default. New `pnpm-workspace.yaml` allowlists `esbuild`, `protobufjs`, `unrs-resolver` with comments explaining why each is trusted. Any future dep that ships a `postinstall` will fail loud. - **Added zizmor.** New `.github/workflows/zizmor.yml` runs on PR/push for `.github/**` changes at `min-severity: medium`. `.github/zizmor.yml` config allowlists 5 intentional patterns (3 push-back checkouts, 2 `dangerous-triggers` cases) with per-rule justifications inline. - **Tightened `GITHUB_TOKEN` permissions** on the 8 workflows that lacked top-level `permissions:` blocks. Default-deny with `contents: read`; jobs grant only what they need. `notify-issue.yml` / `notify-pr.yml` get `permissions: {}` (zero scope). Added `persist-credentials: false` to every checkout that doesn't push back. - **Agent-audit fixes folded in:** - `static-quality.yml` commitlint — moved PR base/head SHAs into `env:` (script-injection) - `fix-drift.yml` — gated verify + PR-creation on `steps.autofix.outcome == 'success'` (silent-failure mode prevented) - `publish-docker.yml` — scoped buildx GHA cache by event (`pr-<num>` vs `release`) to prevent PR-to-release cache poisoning - `publish-release.yml` — added top-level `permissions: contents: read` - `publish-release.yml` / `update-competitive-matrix.yml` / `fix-drift.yml` — moved several `secrets.*` interpolations from `run:` bodies into `env:` blocks ## Deferred (need wider discussion) - **HIGH — `fix-drift.yml` clones `ag-ui:main` HEAD then runs Claude Code with a write-scoped token.** Prompt-injection surface. Mitigations all change drift-detection semantics. - **HIGH — drift-bot `gh pr merge --auto`.** Safe only if branch protection requires a human reviewer on bot PRs. Branch-protection settings live outside the repo. - **MEDIUM — `update-competitive-matrix.yml`** runs its script before creating the throwaway branch, so the push-capable token is in env during script execution. ## Verification - ✅ `zizmor --config .github/zizmor.yml --min-severity medium .github/workflows/` — clean (5 allowlisted, 55 below threshold) - ✅ `pnpm install --frozen-lockfile` with pnpm 11.1.2 - ✅ `pnpm run lint` - ✅ `pnpm run build` - ✅ `pnpm run test` — 2856/2857 pass locally on Windows; the one failure is a pre-existing Windows path-separator quirk in `fixtures-remote.test.ts` (Linux CI unaffected) ## Test plan - [ ] CI green on this PR (all existing workflows + new zizmor) - [ ] Post-merge: trigger `publish-docker.yml` via `workflow_dispatch` on main to confirm SHA-pinned docker actions still build and push - [ ] Next release: confirm `publish-release.yml` still publishes to npm + creates GitHub Release + tag (highest blast radius)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves M-13 from the CI/CD Supply Chain Security Audit (deferred SHA-pinning) and aligns aimock with TanStack's post-incident hardening playbook. Codeowners excluded — already present.
Full write-up: aimock CI/CD Hardening — Notion.
What changed
uses: action@v*becomesuses: action@<40-char-sha> # <tag>— immutable, Dependabot-bumpable. Pinned to the latest patch within each current major (no silent major bumps).pnpm-workspace.yamlallowlistsesbuild,protobufjs,unrs-resolverwith comments explaining why each is trusted. Any future dep that ships apostinstallwill fail loud..github/workflows/zizmor.ymlruns on PR/push for.github/**changes atmin-severity: medium..github/zizmor.ymlconfig allowlists 5 intentional patterns (3 push-back checkouts, 2dangerous-triggerscases) with per-rule justifications inline.GITHUB_TOKENpermissions on the 8 workflows that lacked top-levelpermissions:blocks. Default-deny withcontents: read; jobs grant only what they need.notify-issue.yml/notify-pr.ymlgetpermissions: {}(zero scope). Addedpersist-credentials: falseto every checkout that doesn't push back.static-quality.ymlcommitlint — moved PR base/head SHAs intoenv:(script-injection)fix-drift.yml— gated verify + PR-creation onsteps.autofix.outcome == 'success'(silent-failure mode prevented)publish-docker.yml— scoped buildx GHA cache by event (pr-<num>vsrelease) to prevent PR-to-release cache poisoningpublish-release.yml— added top-levelpermissions: contents: readpublish-release.yml/update-competitive-matrix.yml/fix-drift.yml— moved severalsecrets.*interpolations fromrun:bodies intoenv:blocksDeferred (need wider discussion)
fix-drift.ymlclonesag-ui:mainHEAD then runs Claude Code with a write-scoped token. Prompt-injection surface. Mitigations all change drift-detection semantics.gh pr merge --auto. Safe only if branch protection requires a human reviewer on bot PRs. Branch-protection settings live outside the repo.update-competitive-matrix.ymlruns its script before creating the throwaway branch, so the push-capable token is in env during script execution.Verification
zizmor --config .github/zizmor.yml --min-severity medium .github/workflows/— clean (5 allowlisted, 55 below threshold)pnpm install --frozen-lockfilewith pnpm 11.1.2pnpm run lintpnpm run buildpnpm run test— 2856/2857 pass locally on Windows; the one failure is a pre-existing Windows path-separator quirk infixtures-remote.test.ts(Linux CI unaffected)Test plan
publish-docker.ymlviaworkflow_dispatchon main to confirm SHA-pinned docker actions still build and pushpublish-release.ymlstill publishes to npm + creates GitHub Release + tag (highest blast radius)