Skip to content

ci: harden CI/CD security (SHA-pin actions, pnpm 11, zizmor, permissions)#200

Merged
MikeRyanDev merged 4 commits into
mainfrom
worktree-synthetic-dancing-scone
May 15, 2026
Merged

ci: harden CI/CD security (SHA-pin actions, pnpm 11, zizmor, permissions)#200
MikeRyanDev merged 4 commits into
mainfrom
worktree-synthetic-dancing-scone

Conversation

@AlemTuzlak

Copy link
Copy Markdown
Contributor

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

  • 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)

AlemTuzlak and others added 3 commits May 14, 2026 18:36
…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
jpr5 force-pushed the worktree-synthetic-dancing-scone branch from 041e13e to d1c7f2b Compare May 15, 2026 00:41
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
@github-advanced-security

Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@pkg-pr-new

pkg-pr-new Bot commented May 15, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@copilotkit/aimock@200

commit: 806be4f

@MikeRyanDev MikeRyanDev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@MikeRyanDev
MikeRyanDev merged commit e0f82ee into main May 15, 2026
12 checks passed
@MikeRyanDev
MikeRyanDev deleted the worktree-synthetic-dancing-scone branch May 15, 2026 11:56
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants