Skip to content

feat(pnpm-policy): denyBuilds — declare install scripts that were reviewed and are not needed - #128

Merged
pyramation merged 1 commit into
mainfrom
feat/pnpm-policy-deny-builds
Sep 4, 2026
Merged

feat(pnpm-policy): denyBuilds — declare install scripts that were reviewed and are not needed#128
pyramation merged 1 commit into
mainfrom
feat/pnpm-policy-deny-builds

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

pnpm 11 turns every undecided install script into a hard failure: pnpm install exits 1 with ERR_PNPM_IGNORED_BUILDS, tells the developer to run the interactive pnpm approve-builds, and appends an allowBuilds: { pkg: "set this to true or false" } stub to pnpm-workspace.yaml — outside the pnpm-policy managed block, so it also fails pnpm-policy check. This is what a fresh pgpm init workspace currently hits (constructive-io/constructive-planning#1970), and this repo hits it too (@launchql/protobufjs, nx, unrs-resolver).

pnpm-policy could only allow; there was no way to say "we looked, this script is not needed" other than the settings: passthrough, which replaces the whole allowBuilds map. This adds a first-class denyBuilds:

allowBuilds:
  esbuild: native binary, downloaded at install time
denyBuilds:
  nx: prebuilt binary ships as an optional dep
  "@parcel/watcher": prebuilt binary ships as an optional dep

→ generated (--builds-key allowBuilds, default):

# Install scripts: true runs them, false means reviewed and not needed.
allowBuilds:
  "@parcel/watcher": false # prebuilt binary ships as an optional dep
  esbuild: true # native binary, downloaded at install time
  nx: false # prebuilt binary ships as an optional dep

→ with --builds-key onlyBuiltDependencies (pnpm < 10.16): allowed names go to onlyBuiltDependencies, denied names to a new managed key ignoredBuiltDependencies.

  • PolicyConfig.denyBuilds?: Array<string | DeniedBuild> | Record<string, string | false>; same normalization/sorting as allowBuilds; a name in both lists is a PolicyError.
  • managedKeys() includes ignoredBuiltDependencies only for the legacy key, so it is owned/removed like the others.
  • README section + pnpm-policy init starter gain denyBuilds, and the README says explicitly not to run pnpm approve-builds in a policy-managed workspace.

Also: this repo's own pnpm-workspace.yaml now denies its three undecided scripts so pnpm install on pnpm 11 exits 0 (CI is on pnpm 10.12, which only warned).

Follow-up (needs a release of pnpm-policy): switch the pgpm boilerplates from the settings.allowBuilds passthrough to denyBuilds.

Link to Devin session: https://app.devin.ai/sessions/1ef0d1c209f041afa29e0e4cc4b2cb29
Open in Devin Desktop: https://app.devin.ai/desktop/session/1ef0d1c209f041afa29e0e4cc4b2cb29?variant=devin
Requested by: @pyramation

…ewed and are not needed

pnpm 11 fails the install (ERR_PNPM_IGNORED_BUILDS) for any build script that
is neither allowed nor denied, so a policy that can only allow leaves fresh
clones stuck on the interactive pnpm approve-builds prompt. denyBuilds emits
false entries into the allowBuilds map (ignoredBuiltDependencies for the
legacy key), with reasons, so the decision lives in pnpm-policy.yaml.

Also close the three open questions in this workspace's own
pnpm-workspace.yaml so pnpm 11 installs cleanly.
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@tenki-reviewer

tenki-reviewer Bot commented Sep 4, 2026

Copy link
Copy Markdown

Review complete. 🟡 1 medium

💬 Inline comments (1)

  • 🟡 ignoredBuiltDependencies silently deleted on generatepolicy.ts:230
🧹 Nitpicks (1) — 🟢 1 low
  • 🟢 Missing space after comma in imports (cli.ts:9) — The import in cli.ts line 9 has no space after the comma (reachableFrom,readWorkspaceGraph), inconsistent with the surrounding code style.

This PR introduces the pnpm-policy package, which reads a config, normalizes allow/deny build-policy entries, and generates or validates the pnpm-workspace.yaml build settings (e.g. allowBuilds, ignoredBuiltDependencies). It includes a CLI, config schema/types, generator, and tests, plus a workspace-level pnpm-workspace.yaml change.

Files Change
packages/pnpm-policy/src/* New CLI, config normalization, and policy generation/validation logic.
packages/pnpm-policy/__tests__/policy.test.ts Tests covering config normalization and generated output.
pnpm-workspace.yaml Workspace build-policy settings updated to match the new generator output.

Two findings: a trivial import style issue in cli.ts, and a medium-severity behavior where ignoredBuiltDependencies is silently dropped when regenerating the workspace file.

Reviewed commit: 45fd581

@tenki-reviewer tenki-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Adds a pnpm-policy package that generates and validates pnpm-workspace.yaml build-policy settings from a normalized config.

Key findings

  • 🟡 ignoredBuiltDependencies silently deleted on generatepolicy.ts:230

'minimumReleaseAge',
'minimumReleaseAgeExclude',
buildsKey,
...(buildsKey === 'onlyBuiltDependencies' ? [IGNORED_BUILDS_KEY] : []),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 bug · medium

ignoredBuiltDependencies silently deleted on generate

managedKeys() now lists ignoredBuiltDependencies whenever buildsKey is onlyBuiltDependencies (policy.ts:230), and applyPolicy() deletes every managed key absent from the resolved settings (workspace.ts:53). A workspace that keeps ignoredBuiltDependencies set by hand — via pnpm approve-builds or a manual edit — without a matching denyBuilds in the config loses that key silently on the next pnpm-policy generate, dropping install-script denials it never asked to remove.

📋 Prompt for AI Agents

In packages/pnpm-policy/src/policy.ts around line 230, managedKeys() unconditionally adds IGNORED_BUILDS_KEY when buildsKey === 'onlyBuiltDependencies', and applyPolicy() (workspace.ts:53) deletes every managed key absent from policy.settings. This silently removes a hand-maintained ignoredBuiltDependencies from an existing pnpm-workspace.yaml on the next generate when the config defines no denyBuilds. Make managedKeys() claim ignoredBuiltDependencies only when the resolved policy will emit it (e.g. pass whether denyBuilds is non-empty), so existing persisted denials are preserved during the upgrade.

@pyramation
pyramation merged commit 2f1cf27 into main Sep 4, 2026
62 checks passed
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