[pull] main from pnpm:main#330
Merged
Merged
Conversation
Add several CodeRabbit settings: - path_filters: skip generated/vendored/snapshot files (lockfiles, dist, fixtures, snapshots, changelogs) so reviews focus on hand-written code. - pre_merge_checks.title: enforce Conventional Commits on the PR title, which becomes the commit message under squash merge (the commit-msg hook only validates per-commit messages). - knowledge_base.learnings scoped to local so maintainer corrections are remembered without crossing repo boundaries. - issue_enrichment labeling: auto-apply the durable area/type taxonomy to issues, where long-lived labels actually aid triage and search. - poem disabled. Secret scanners (gitleaks, semgrep, trufflehog) are already enabled by default, so they are not added explicitly.
…s omitted (#11696) * feat(view): support searching package.json upward when package name is omitted * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix: apply review * fix: apply review * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix: update --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…#12462) * ci: label and notify on CodeRabbit approval Add a workflow that fires on pull_request_review and, when CodeRabbit submits an approving review, applies the informational "reviewed: coderabbit" label and (if a DISCORD_WEBHOOK secret is configured) posts a notice to Discord. PR fields reach the steps through the environment rather than script interpolation, so an attacker-controlled PR title cannot inject shell commands. The Discord step is skipped when the webhook secret is unset. * ci: flag maintainer-approved PRs for automerge Rename the approval workflow to cover both review automations and add a second job: when zkochan submits an approving review, apply the existing "state: automerge" label. Like the CodeRabbit job, the PR number is passed through the environment rather than interpolated into the run script. * ci: harden PR review automation per review feedback - Scope permissions to each job (top-level permissions: {}) instead of granting pull-requests: write workflow-wide (zizmor). - Set allowed_mentions to {parse: []} on the Discord payload so a PR title containing `@everyone`/`@here` cannot ping the server. - Add connect/overall timeouts and retries to the Discord curl call.
## What - preserve existing `workspace:` dependency specifiers when `updateProjectManifest` saves updated direct dependencies and `preserveWorkspaceProtocol` is enabled - keep catalog specifiers taking precedence over resolver-normalized specs - add focused coverage for preserved and normalized local spec behavior - add a changeset for the published `@pnpm/installing.deps-resolver` change ### pacquet parity Ported the same fix to pacquet's `update` command. Previously `pacquet update --latest` routed every direct dependency through a registry `latest` lookup, so a `workspace:` local-path dependency (e.g. `workspace:../packages/foo/dist`) was rewritten into a registry version — corrupting the manifest (in the regression test it became `0.0.1-security`). Both `--latest` rewrite sites now skip registry resolution for such specs via `is_workspace_local_path_specifier`, a faithful port of pnpm's `isWorkspaceLocalPathSpecifier`. The gate is unconditional in the `--latest` path because `preserveWorkspaceProtocol` is always on there (its only override derives from `linkWorkspacePackages` under `--workspace`, which cannot be combined with `--latest`). Fixes #3902 --------- Co-authored-by: morning-verlu <258725120+morning-verlu@users.noreply.github.com> Co-authored-by: Zoltan Kochan <z@kochan.io>
* fix(update): handle mixed direct and transitive selectors * test(update): strengthen regression test and port to pacquet The pnpm regression test passed with and without the fix: the fixture's `latest` dist-tag made a fresh install of `^100.0.0` already resolve to 100.1.0, so the assertion was trivially true. Pin the transitive dep-of-pkg-with-1-dep to 100.0.0 before install so the test genuinely fails without the fix and passes with it. Add pacquet parity regression tests for the same mixed direct/transitive selector scenario (exact-name and glob forms). pacquet has no equivalent source change to make — its `update` matches every bare-name/glob selector against direct deps and locked snapshot names in one pass, so a direct selector never gates the transitive one — but the behavior is guarded by tests to lock in #12103 parity. --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
The pr-review-automation workflow merged in #12462 fails at the label step with 'Resource not accessible by integration (addLabelsToLabelable)'. gh pr edit --add-label uses the GraphQL addLabelsToLabelable mutation, which requires issues: write even when labeling a PR; pull-requests: write alone is insufficient. Grant it per job, matching pacquet-integrated-benchmark-comment.yml.
…date (#12158) * fix(deps-installer): re-resolve catalog-referencing overrides on update When `pnpm.overrides` reference a catalog (e.g. `overrides: { foo: 'catalog:' }`), `pnpm update` bumped the catalog entry during resolution but left the resolved `overrides` in the lockfile pointing at the old version. The lockfile's `catalogs` advanced while `overrides` stayed stale, producing an internally inconsistent lockfile that fails a later `pnpm install --frozen-lockfile` with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH. After resolution, re-resolve the overrides against the catalog merged with the update's `updatedCatalogs`, so the lockfile `overrides` track the bumped catalog just like `catalogs` and direct catalog dependencies do. * fix(deps-installer): re-resolve catalog overrides before afterAllResolved Address review feedback: - Run the catalog-override re-resolution before the `afterAllResolved` pnpmfile hook instead of after it, so a hook that edits `lockfile.overrides` still sees and can amend the final value (the block previously ran after the hook and would clobber its edits whenever a catalog entry was updated). - Drop the dead `opts.catalogs ?? {}` fallback; `opts.catalogs` is required on the install options and always defaulted to `{}`, so it is never nullish here. * test(pacquet): cover catalog-referencing override sync on update --latest Mirrors pnpm's regression test for keeping lockfile overrides that resolve through a catalog in sync when `update --latest` bumps that catalog. pacquet already behaves correctly (it threads the bumped catalogs through to override parsing), so this is a guard against a future refactor reintroducing the inconsistency that #12158 fixes on the TypeScript side. --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
…2351) External processes like SSH passphrase prompts can write to the terminal between progress updates. The previous renderer used `ansi-diff`, which only overwrites the characters it knows changed, so leftover characters from the external output stayed visible on the progress line — e.g. `added 0sa':`, where `sa':` is a fragment of `Enter passphrase for key '.../.ssh/id_rsa':`. Closes #12350 ## Summary The interactive (non-append-only) reporter now redraws the whole frame in place on each update instead of incrementally diffing it: - return the cursor to the top-left of the previous frame (`ESC[<rows>A` followed by a carriage return, so the redraw starts at column 0 even if an external process left the cursor mid-line), - erase from there to the end of the display (`ESC[0J`), - reprint the frame — all in a single atomic write, so there is no flicker. Because the whole region is erased on every frame, any characters an external process wrote in between are cleared. This matches pacquet's `Output::Frame` rendering (the column-reset hardening was applied to both stacks). The now-unused `ansi-diff` dependency has been removed. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Zoltan Kochan <z@kochan.io>
The update command already honors --no-save and the docs already mention it, but the flag was missing from the update command metadata. Add the option entry so pnpm update --help shows it and the CLI surface matches the documented behavior.
* feat(sbom): add monorepo workspace support for SBOM generation When --filter selects a single workspace, the SBOM root component now uses that workspace's name, version, description, license, and author instead of the workspace root's metadata. Author, repository, and license fall back to the root manifest when the workspace package doesn't define them. Workspace inter-dependencies (workspace: protocol) and their transitive dependencies are now included in the SBOM. Dev-only workspace deps are correctly excluded when --prod is used, and lockfile-only mode skips workspace resolution entirely to avoid unexpected disk reads. * fix(sbom): add recursiveByDefault so --filter works in workspaces Without recursiveByDefault, the sbom command in a workspace didn't enter the recursive code path that populates selectedProjectsGraph from --filter. The handler received no filter info and always used the workspace root manifest for the root component. * feat(sbom): add --out and --split for per-package SBOM generation Add --out <path> to write SBOM to a file instead of stdout. Supports %s (package name) and %v (version) placeholders. When %s is present, generates one SBOM per workspace package automatically. Add --split to output NDJSON (one compact JSON per line) to stdout, for piping into tooling that processes multiple SBOMs. Add compact option to CycloneDX and SPDX serializers so NDJSON lines are single-line JSON without re-parsing. Sanitize %s and %v values to prevent path traversal in output paths. * fix: use sbom-out instead of sboms to pass spellcheck * fix(sbom): expand %v in single-output path and fix workspace dep parent relationships Two bugs found by CodeRabbit: 1. --out with %v but no %s wrote a literal %v filename. Now both %s and %v are expanded in the single-output path using the SBOM root component's name and version. 2. The lockfile walker used rootPurl as parent for every importer, including additional workspace dep importers. This caused shared-lib's external deps (like is-odd) to appear as direct deps of the root package. Now each importer's walk uses the correct parent PURL based on whether it's an original or workspace dep importer. * fix(sbom): fall back to workspace root manifest for filtered package metadata Read the root manifest from rootProjectManifest/rootProjectManifestDir instead of opts.dir so license/author/repository/description fall back to the workspace root when a filtered package omits them. Add the missing rootDescription fallback. Fix the per-package CycloneDX test assertions to match the standard group/name split for scoped names. * fix(sbom): harden path handling and fix lockfile-only/versionless workspace deps - Neutralize '.', '..' and blank segments in --out path templates so a crafted package name/version cannot escape the output directory. - Skip lockfile link: targets that resolve outside the workspace root, and guard the workspace manifest reads with a containment check, preventing arbitrary package.json reads from a malicious lockfile. - Honor --lockfile-only inside collectSbomComponents so workspace links and their transitive deps are no longer traversed. - Include workspace packages that omit a version (default to 0.0.0, matching the root component). - Bound workspace manifest reads with p-limit to avoid EMFILE on large monorepos. * fix(sbom): error on per-package output path collisions and use O(n) workspace BFS - Throw SBOM_OUT_PATH_COLLISION when two workspace packages sanitize to the same --out path instead of silently overwriting one SBOM with another. - Replace the resolveWorkspaceDeps BFS queue.shift() (O(n) per dequeue) with a moving head index for O(n) traversal on large workspaces. * fix(sbom): strip control chars from output paths and skip unreadable workspace importers - Strip ASCII control characters (incl. newlines) in sanitizePathSegment so a crafted package name/version cannot inject lines into the --split --out summary or produce confusing filenames. - Skip walking a reachable workspace importer when its package info is missing (e.g. unreadable manifest) instead of misattributing its deps to the root. - Bound importer-walker fan-out with p-limit to avoid resource pressure on large workspaces. * perf(sbom): reuse workspace manifests across split outputs and use a Set for path collisions - Read workspace package manifests once into SharedContext (keyed by importer id) from the project graph, so split mode no longer re-reads them from disk for every emitted SBOM. - Track written --out paths in a Set instead of Array#includes to make collision detection O(1) per package rather than O(n2) overall. * fix(sbom): support %s in single-project --out, harden importer lookup, cache root license - Only treat %s in --out as per-package (split) mode when a workspace project graph is present; in a single-project repo %s/%v interpolate from the root component on the single-output path. Adds a regression test. - Use an own-property check for lockfile importer existence so a crafted link: target cannot follow inherited keys (e.g. toString) via the prototype chain. - Fast-path resolveRootLicense when the manifest already declares an SPDX license and cache the workspace-root license in SharedContext, avoiding redundant on-disk LICENSE probing per emitted SBOM. --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
Mark fixture trees (package.json, lockfiles) as linguist-generated in .gitattributes so GitHub's dependency graph ignores them. This stops Dependabot from raising alerts and opening automatic security-update PRs for packages that appear in fixtures only as test data — e.g. the js-cookie bump in #11840. The `@pnpm/test-fixtures` helper package is real source and is intentionally left unmarked.
…11425) ## Problem `pnpm version --recursive` did not bump the workspace packages the user selected. In recursive mode the command re-derived the workspace selection itself (via `filterProjectsFromDir`) using an incomplete set of options, so it could resolve a different set of packages than the CLI's actual `--filter`/`--recursive` resolution. Fixes #11348. ## Change - In recursive mode, bump the projects in `selectedProjectsGraph` — the selection the pnpm CLI (`main.ts`) already computes from the workspace filter, exactly the way `pnpm publish --recursive` works. - Remove the in-handler `filterProjectsFromDir` fallback. It duplicated the CLI's filtering logic and was unreachable in production (`main.ts` always passes `selectedProjectsGraph` for a recursive run). `@pnpm/workspace.projects-filter` becomes a dev-only dependency of `@pnpm/releasing.commands`. - No global/config plumbing is needed for `--recursive`: `@pnpm/cli.parse-cli-args` already recognizes `recursive` (and the `-r` shorthand) for every command, the config reader passes it through to the handler, and the `version` command already declares `recursive` in its own `cliOptionsTypes`. --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
* perf(package-manager): drop redundant Arc around process-global compat extender The built-in `@yarnpkg/extensions` compatibility database is built once per process and cached in a `OnceLock`. Wrapping it in an `Arc` added an allocation plus per-install refcount churn for no benefit: a `OnceLock` already hands out a stable `&'static` reference, and every consumer (`PackageExtender::apply` / `apply_to_arc`, both `&self`) is satisfied by `&'static PackageExtender` — which is `Copy + Send + Sync + 'static` and so moves cleanly into the resolver's `ManifestHook` closure. Store the extender as `OnceLock<PackageExtender>` returning a `&'static` reference. The per-install user-provided extender keeps its `Arc`, since it is constructed fresh each install and shared into the resolver hook. * refactor(store-dir): borrow &StoreIndexWriter in upload instead of &Arc `upload` only reads through the writer — a single `queue_side_effects_upload` call, no `Arc::clone` — so it never needed shared ownership. Borrowing `&Arc<StoreIndexWriter>` forced the signature to advertise reference counting it does not use. Take `&StoreIndexWriter` instead; the sole caller passes a `&Arc<StoreIndexWriter>` that deref-coerces at the call site, so it is unchanged. --------- Co-authored-by: Claude <noreply@anthropic.com>
…11095) Fixes #11056 ## Problem On macOS, pnpm imports files from its content-addressable store into `node_modules` via copy, reflink/clone, or hardlink. All three preserve extended attributes, including `com.apple.quarantine`. If a store blob carries that xattr — e.g. it was first written under a Gatekeeper-enabled app such as a Git client (`LSFileQuarantineEnabled=YES`) — the quarantine propagates into `node_modules`. Gatekeeper then blocks ad-hoc-signed native binaries (`.node`, `.dylib`, `.so`) from loading, even though pnpm has already verified each file's integrity against `pnpm-lock.yaml`. ## Solution After importing a package from the store, strip `com.apple.quarantine` from its native binaries — mirroring Homebrew's behaviour of dropping quarantine from downloads after checksum verification. --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
## Problem During warm installs, pnpm relinked existing packages more broadly than necessary when only some child dependencies changed. In the narrowed relinking path, removed child aliases could also remain behind as stale links after dependency updates. ## Solution Only pass changed child edges through the relinking path for existing packages. When a child alias is no longer present in the updated dependency set, remove the obsolete link before relinking. Added regression tests for both cases: - unchanged child dependencies are not relinked unnecessarily - deleted child dependencies do not remain as stale links after a warm install --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
## Issue When `injectWorkspacePackages: true` is set and a workspace package depends on another workspace package that has its own dependencies, running `pnpm rm` from inside the dependent package's directory switches the lockfile protocol from `link:` to `file:`. Reproduction (workspace where `a` depends on workspace `b`, and `b` has any dependency of its own): ``` cd packages/a pnpm add redis pnpm rm redis # pnpm-lock.yaml: a's "b" entry switched from link:../b to file:packages/b ``` ## Root Cause The fix in #10575 added a defensive guard in `dedupeInjectedDeps` that skipped deduplication whenever the target workspace project's children weren't in `dependenciesByProjectId`: ```ts if (!targetProjectDeps) { if (children.length > 0) continue } ``` In single-project operations (`mutateModulesInSingleProject`, used by `pnpm rm` from inside a package directory) only the operated-on project is resolved. `dependenciesByProjectId` then only has that one project, so the guard fires for any workspace dependency whose target has children, and the protocol stays `file:`. ## Solution In single-project mode the injected dep is resolved against the same workspace package source, so dedupe is safe — *except* for peer-suffixed depPaths, whose resolution depends on the importer's peer context (a plain `link:` would lose it). The new code dedupes whenever `targetProjectDeps` is missing for a known workspace project and the depPath has no peer suffix. The peer-suffix check compares the depPath against its peer-free `pkgIdWithPatchHash` (depPaths are built as `${pkgIdWithPatchHash}${peerDepGraphHash}`), so it's exact rather than a `(`-substring heuristic. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Zoltan Kochan <z@kochan.io>
* chore(cargo): bump object_store from 0.12.5 to 0.13.2 Bumps [object_store](https://github.com/apache/arrow-rs-object-store) from 0.12.5 to 0.13.2. - [Changelog](https://github.com/apache/arrow-rs-object-store/blob/main/CHANGELOG-old.md) - [Commits](apache/arrow-rs-object-store@v0.12.5...v0.13.2) --- updated-dependencies: - dependency-name: object_store dependency-version: 0.13.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * fix(pnpr): import ObjectStoreExt for object_store 0.13 method move object_store 0.13 moved get/put/delete off the ObjectStore trait onto the new ObjectStoreExt trait. Import it so the S3 hosted-store backend keeps compiling. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Zoltan Kochan <z@kochan.io>
* chore: stop configuring CodeRabbit pre-merge checks Defining any pre-merge check turned on the whole pre-merge-checks subsystem, which under Request Changes Workflow replaces the auto-approve flow: CodeRabbit emits a pre-merge-checks status block instead of approving once review threads are resolved, leaving PRs at REVIEW_REQUIRED even with all threads cleared and all checks green. Remove the title check (added in #12460) to restore auto-approval and document why the block is intentionally absent. Conventional Commits on the squash title stay covered by the commit-msg hook and the squash-title convention. * fix: declare Qodo auto-approval under [config] enable_auto_approval and auto_approve_for_no_suggestions were declared under [pr_reviewer], where Qodo never reads them, so auto-approval never ran. Per the Qodo docs both keys belong under [config]. Move them and drop the now-empty [pr_reviewer] section. * chore: stop applying labels from Qodo Product labels are applied by CodeRabbit (auto_apply_labels + labeling_instructions in .coderabbit.yaml). Having Qodo also publish labels via enable_custom_labels/publish_labels/custom_labels meant two tools managing the same labels. Drop the Qodo label config and leave labeling to CodeRabbit. * ci: tag Qodo-approved PRs and fix the label step Add an on-qodo-approval job that applies the 'reviewed: qodo' label when qodo-free-for-open-source-projects[bot] approves, mirroring the existing CodeRabbit job. The label step used 'gh pr edit --add-label', which is broken (it errors on the deprecated Projects-v1 GraphQL field), so adding the label failed on approval. Switch all three jobs to the issues REST API (POST /repos/{owner}/{repo}/issues/{number}/labels) instead.
CodeRabbit's effective config (from the `@coderabbitai configuration` command) showed request_changes_workflow: false, which is why it only ever commented and never approved — CodeRabbit submits approving reviews only when this is true. The dashboard toggle wasn't taking effect, so declare it in-repo. Also explicitly disable pre_merge_checks: they're enabled by default and in the dashboard (removing the block from the config did not turn them off), and they add a status block without review value here. Title enforcement stays covered by the commit-msg hook and squash-title convention.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )