diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6650eea..ba49389 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,8 +20,10 @@ jobs: strategy: fail-fast: false matrix: + # Node 20 is not tested: pnpm 11 is pure ESM and requires Node >=22, so + # `pnpm install` cannot run on it. Node 20 reached end-of-life in April + # 2026, and engines.node is set to >=22 to match what is actually tested. node-version: - - 20.x - 22.x - 24.x steps: diff --git a/package.json b/package.json index 6d9c948..12ecfbd 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,9 @@ "type": "module", "license": "MIT", "author": "Logan Lindquist Land", - "packageManager": "pnpm@10.34.5", + "packageManager": "pnpm@11.18.0", "engines": { - "node": ">=20" + "node": ">=22" }, "repository": { "type": "git", diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..0b1f57e --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,16 @@ +# pnpm 11 supply-chain hardening. +# These are pnpm 11's defaults, stated explicitly so the security posture is +# visible in review and survives future changes to pnpm's own defaults. + +minimumReleaseAge: 1440 # block packages younger than 24h +blockExoticSubdeps: true # no git/tarball transitive deps +strictDepBuilds: true # fail install on unapproved postinstalls +verifyDepsBeforeRun: install # re-check lockfile before `pnpm run` + +# Postinstall allowlist. Empty map = block all build scripts. +# +# Deliberately empty: no dependency in this tree requests a build script. With +# strictDepBuilds enabled, `pnpm install` would fail with ERR_PNPM_IGNORED_BUILDS +# if one appeared, so this staying empty is an enforced property, not an +# oversight. Add an entry only after auditing that package's postinstall. +allowBuilds: {}