Skip to content

chore: migrate to pnpm and harden GitHub Actions workflows (v5)#376

Merged
csandman merged 8 commits into
v5from
chore/pnpm-v5
May 14, 2026
Merged

chore: migrate to pnpm and harden GitHub Actions workflows (v5)#376
csandman merged 8 commits into
v5from
chore/pnpm-v5

Conversation

@csandman
Copy link
Copy Markdown
Owner

@csandman csandman commented May 14, 2026

Summary

Two related changes bundled together: migrate the repo from npm to pnpm workspaces, and harden every GitHub Actions workflow against supply-chain attacks (motivated by the TanStack npm compromise).

Package manager migration: npm → pnpm

  • Added pnpm-workspace.yaml declaring demo and codemod as workspace packages, with esbuild allow-listed for build scripts.
  • Added packageManager: pnpm@11.1.1 to the root package.json so Corepack / pnpm/action-setup can lock to a specific version.
  • Deleted all package-lock.json files (root, demo/, codemod/) and replaced them with a single root pnpm-lock.yaml.
  • Demo now consumes the workspace package directly: "chakra-react-select": "workspace:*" instead of "file:..".
  • Scripts updated:
    • npm:dev:*pnpm:dev:*, npm:lint:*pnpm:lint:* in concurrently invocations.
    • Removed the install:all / install:demo / install:codemod scripts — a single pnpm install at the root now sets up the entire workspace.
    • dev:demo, prepublishOnly, and codemod/prepublishOnly rewritten to use pnpm.
  • .gitignore adds pnpm-debug.log*.
  • CONTRIBUTING.md updated to reference pnpm install / pnpm dev / pnpm lint instead of the npm equivalents.

Supply-chain defenses gained just by being on pnpm 11

Beyond the workflow hardening below, the migration itself raises the security floor:

  • minimumReleaseAge defaults to 1440 minutes (1 day) in pnpm 11. pnpm refuses to install any package version younger than 24 hours. In the TanStack incident the malicious tarballs were live for roughly 30 minutes before detection — pnpm 11 would have rejected them outright. npm has no equivalent built-in.
  • Postinstall / build scripts are opt-in via allowBuilds. pnpm 10+ won't execute lifecycle scripts (preinstall, install, postinstall, etc.) from dependencies unless they're explicitly allow-listed. This branch's pnpm-workspace.yaml allows only esbuild. Compromised tarballs in the npm registry overwhelmingly rely on postinstall payloads for initial execution; this neuters that entire class of attack for unlisted packages.
  • packageManager field pins pnpm itself. Corepack / pnpm/action-setup lock to pnpm@11.1.1 with an integrity hash, so a compromised pnpm release can't silently roll forward in CI or on contributors' machines.
  • Strict, non-hoisted node_modules layout. Each package can only require/import what it explicitly declared as a dependency. A malicious transitive dep can't sneak into the resolution graph of a sibling package the way it can with npm's flat layout.
  • Single pnpm-lock.yaml at the workspace root replaces three separate package-lock.json files. One source of truth to review for unexpected dependency changes, and pnpm install --frozen-lockfile (which pnpm auto-applies in CI) refuses to mutate it.

Dependency bumps

In package.json:

  • react-select: 5.10.x^5.10.2 (switched to semver caret)
  • oxfmt: ^0.x^0.49.0
  • oxlint: ^1.57.0^1.64.0
  • oxlint-tsgolint: ^0.17.4^0.22.1
  • typescript: ^6.0.2^6.0.3

GitHub Actions hardening

Applied to lint.yml, package-size-report.yml, pkg-pr.yml, plus a new zizmor.yml workflow. All changes pass a zizmor audit with zero findings.

Adopted pnpm's recommended CI setup (pnpm.io/continuous-integration):

  • Replaced corepack enable with pnpm/action-setup (auto-reads pnpm version from the packageManager field). More future-proof — Node.js has been moving away from bundling Corepack — and avoids the signature-hash check that occasionally caused intermittent CI failures.
  • Bumped actions/checkout v4 → v6.0.2 and actions/setup-node v4 → v6.4.0.

Supply-chain hardening (motivated by TanStack incident postmortem and follow-up):

  • Pinned every action to a commit SHA with a trailing # vX.Y.Z comment. Defends against a tag being force-pushed to a malicious commit (cf. the tj-actions/changed-files compromise from March 2025).
  • Added persist-credentials: false to every actions/checkout step. By default checkout leaves GITHUB_TOKEN in .git/config; if any subsequent step uploads the workspace as an artifact, the token leaks. None of these workflows need git auth after checkout.
  • Added a top-level permissions: {} (deny-by-default) and minimal per-job permissions blocks:
    • lint.yml: contents: read
    • package-size-report.yml: contents: read, pull-requests: write (for pkg-size comment)
    • pkg-pr.yml: contents: read, pull-requests: write, id-token: write (for pkg-pr-new OIDC + comment)
    • zizmor.yml: contents: read, security-events: write (for SARIF upload)

Trigger pattern standardized across push+PR workflows: push: { branches: [main, v5] } + unrestricted pull_request:. This avoids the duplicate-run problem of PRs firing both events while still covering direct pushes to long-lived branches.

New .github/workflows/zizmor.yml runs zizmor on every PR and push to main/v5, uploading findings as SARIF to GitHub Code Scanning. Future regressions in workflow hygiene (unpinned actions, broad permissions, dangerous triggers, etc.) will surface as Security tab alerts and fail the Code scanning results / Zizmor check at the configured severity threshold.

Test plan

  • pnpm install cleanly resolves at the workspace root with no peer-dep warnings
  • pnpm dev starts the demo at http://localhost:5152 and live-rebuilds the package
  • pnpm lint (lint:src + lint:types + lint:exports) passes
  • pnpm build produces a working dist/
  • Lint, Package Size Report, Publish Pull Requests, and Zizmor workflows all complete successfully on this PR
  • Verify pkg-pr-new comment appears on the PR
  • Verify pkg-size comment appears on the PR
  • Confirm zizmor SARIF upload lands in the repo's Security → Code scanning tab

@bolt-new-by-stackblitz
Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@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
Copy link
Copy Markdown

pkg-pr-new Bot commented May 14, 2026

commit: 6ff74c7

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 14, 2026

📊 Package size report   0.01%↑

File Before After
package.json 2.6 kB 0.3%↑2.6 kB
Total (Includes all files) 155.8 kB 0.01%↑155.9 kB
Tarball size 31.3 kB 0.3%↑31.4 kB
Unchanged files
File Size
dist/index.d.mts 20.0 kB
dist/index.d.ts 20.0 kB
dist/index.js 33.1 kB
dist/index.mjs 31.5 kB
LICENSE.md 1.1 kB
README.md 47.5 kB

🤖 This report was automatically generated by pkg-size-action

@csandman csandman changed the title chore: migrate to pnpm and harden GitHub Actions workflows chore: migrate to pnpm and harden GitHub Actions workflows (v5) May 14, 2026
@csandman csandman merged commit 029905f into v5 May 14, 2026
7 checks passed
@csandman csandman deleted the chore/pnpm-v5 branch May 14, 2026 02:14
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.

2 participants