Skip to content

Roll out pnpm supply-chain policy (recipe A) - #114

Merged
pyramation merged 1 commit into
mainfrom
feat/pnpm-policy
Aug 6, 2026
Merged

Roll out pnpm supply-chain policy (recipe A)#114
pyramation merged 1 commit into
mainfrom
feat/pnpm-policy

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

What changed

Rolls out the org's pnpm supply-chain policy (recipe A) to this repo.

  • Added pnpm-policy.yaml at the workspace root: minimumReleaseAge: 2d, blockExoticSubdeps: true, maintainers: [pyramation], our owned scopes (@constructive-io, @constructive-db, @launchql, @pgpm, @pgpmjs, @pgsql), and an allowBuilds map with real reasons.
  • Added @constructive-io/pnpm-policy as a dev dependency, pinned exact at 0.2.1 (the currently published version — no caret), plus pnpm-policy (the CLI, caret is fine there).
  • Added pnpm run policy (pnpm-policy generate) and pnpm run policy:check (pnpm-policy check) scripts.
  • pnpm-workspace.yaml now carries a generated Managed by pnpm-policy block (minimumReleaseAge, minimumReleaseAgeExclude, blockExoticSubdeps, allowBuilds).

nx carryover

This repo already hand-listed onlyBuiltDependencies: [nx]. That key is deleted in this same commit; nx now lives in allowBuilds with reason native task-runner binary. Two more packages this lockfile resolves also needed build approval and got real reasons instead of a bare allowlist:

allowBuilds:
  "@launchql/protobufjs": true # compiles protobuf definitions via native bindings, pulled in through pg-proto-parser for the pgpm CLI toolchain
  nx: true # native task-runner binary
  unrs-resolver: true # native module resolver used by jest-resolve during test runs

CI

Wired: added a Check pnpm supply-chain policy step (pnpm run policy:check) right after the existing Install (pnpm install) step in .github/workflows/ci.yml (the workflow with the Build step — there's no separate lint workflow). integration-test.yml was left alone since it has no natural attach point beyond a duplicate install.

Deviation worth flagging: both workflows pin pnpm/action-setup@v2 with version: 9. There's no packageManager field in package.json pinning a version. pnpm 9 predates the build-approval gate entirely (it runs install scripts unconditionally regardless of allowBuilds or the older onlyBuiltDependencies), so the generated key name doesn't change CI's enforcement either way. I generated with the default allowBuilds key rather than --builds-key onlyBuiltDependencies, because that's what pnpm >= 10.16 (what a current local install actually resolves to via corepack) needs to gate builds correctly — verified onlyBuiltDependencies-only did not satisfy pnpm 11.11.0's native ignored-builds check locally (hard failure, ERR_PNPM_IGNORED_BUILDS), while allowBuilds does. If CI's pnpm pin is ever raised past 10.16, no further change is needed. Noted in a comment at the top of pnpm-policy.yaml.

Verification (all run and passing)

$ pnpm run policy:check
pnpm-workspace.yaml matches the policy

$ pnpm install --frozen-lockfile
Done in 144ms using pnpm v11.11.0   # also re-verified from a clean node_modules

$ shasum pnpm-workspace.yaml && pnpm run policy && shasum pnpm-workspace.yaml
417b6f6beb74692297d82b94c1202391dd5561a2  pnpm-workspace.yaml
Unchanged ...
417b6f6beb74692297d82b94c1202391dd5561a2  pnpm-workspace.yaml   # identical, deterministic

Also confirmed blockExoticSubdeps: true is safe here — no transitive dependency resolves from git or a URL (checked the lockfile and every packages/*/package.json; the only "git" hits are repository.type: git metadata).

Note on the lockfile diff

pnpm-lock.yaml's diff is large (~11.7k lines) but is almost entirely YAML quote-style reformatting (double quotes to single quotes) from installing with the locally available pnpm 11.11.0 rather than the pnpm 9 the lockfile was last written with — not a dependency-tree rewrite. The actual new entries are @constructive-io/pnpm-policy@0.2.1 and pnpm-policy@0.2.2 plus their transitive deps.

Ref: constructive-io/constructive-planning#1464


🤖 Generated with Claude Code

https://claude.ai/code/session_01CEswUi4ANuB58rva48aHge

Adds pnpm-policy.yaml plus @constructive-io/pnpm-policy (pinned exact
at 0.2.1) and its pnpm-policy generate/check CLI, which patch a
managed block into pnpm-workspace.yaml. Third-party releases wait 2
days before install: a compromised release is normally reported and
yanked within hours, so the short wait catches it without stalling
upgrades. The exemption list (our scopes, first-party packages this
lockfile resolves) is generated from the pinned inventory package
rather than hand-maintained, so it can't drift out of sync with what
we actually publish.

The hand-listed `onlyBuiltDependencies: [nx]` is folded into the new
policy's `allowBuilds`, alongside two more packages this lockfile
newly resolves that also need to run install scripts
(@launchql/protobufjs for protobuf codegen via pg-proto-parser,
unrs-resolver as jest's native module resolver) — each with a real
reason instead of a bare allowlist.

Wires `pnpm run policy:check` into ci.yml right after the existing
`pnpm install` step so a hand-edited pnpm-workspace.yaml or a stale
policy fails CI instead of silently drifting.

Ref: constructive-io/constructive-planning#1464
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​constructive-io/​pnpm-policy@​0.2.17610010091100
Addedpnpm-policy@​0.2.27610010090100

View full report

@pyramation
pyramation merged commit d674e57 into main Aug 6, 2026
25 checks passed
@pyramation
pyramation deleted the feat/pnpm-policy branch August 6, 2026 04:26
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.

1 participant