Skip to content

fix(core): replace minimatch with picomatch - #36567

Draft
jaysoo wants to merge 3 commits into
masterfrom
NXC-4762
Draft

fix(core): replace minimatch with picomatch#36567
jaysoo wants to merge 3 commits into
masterfrom
NXC-4762

Conversation

@jaysoo

@jaysoo jaysoo commented Aug 4, 2026

Copy link
Copy Markdown
Member

Current Behavior

nx and several plugins depend on minimatch, which pulls brace-expansion (GHSA-rgw5-rvv9-x895 DoS, third CVE in that package this year).

Expected Behavior

All minimatch usages replaced with picomatch (nx, devkit, jest, playwright, react, rsbuild); minimatch/brace-expansion/balanced-match leave the published nx runtime dependency closure (some @nx/* plugins still pull minimatch transitively via upstream deps, e.g. @nx/jest via @jest/reporters). Not pure 1:1: picomatch does not give **/ zero-segment treatment inside {a,b} brace alternation, so combined plugin globs are split (splitGlobPatterns) and hasher filesets are brace-expanded (expandGlobPatternBraces); empty-pattern throws are guarded. The jest workspaces matcher and tree-aware glob now honor negated patterns correctly (previously negations made everything match), which can change inferred jest targets for workspaces using negated entries. brace-expansion override bumped to patched 5.0.9 for the remaining dev-tree transitives.

Related Issue(s)

Fixes NXC-4762


View session information ↗.

@netlify

netlify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploy Preview for nx-dev failed. Why did it fail? →

Name Link
🔨 Latest commit 2f65d28
🔍 Latest deploy log https://app.netlify.com/projects/nx-dev/deploys/6a74a164bee6a40008a15d5d

@netlify

netlify Bot commented Aug 4, 2026

Copy link
Copy Markdown

Deploy Preview for nx-docs failed. Why did it fail? →

Name Link
🔨 Latest commit 2f65d28
🔍 Latest deploy log https://app.netlify.com/projects/nx-docs/deploys/6a74a16482ac480008cb637d

@nx-cloud

nx-cloud Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 476add0

Command Status Duration Result
nx affected --targets=lint,test,build,e2e,e2e-c... ❌ Failed 35m 21s View ↗
nx run-many -t check-imports check-lock-files c... ✅ Succeeded 2s View ↗
nx-cloud record -- pnpm nx-cloud conformance:check ✅ Succeeded 42s View ↗
nx build workspace-plugin ✅ Succeeded <1s View ↗
nx-cloud record -- nx sync:check ✅ Succeeded 15s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 5s View ↗

☁️ Nx Cloud last updated this comment at 2026-08-05 20:47:10 UTC

nx-cloud[bot]

This comment was marked as outdated.

@jaysoo
jaysoo force-pushed the NXC-4762 branch 2 times, most recently from 8a07d19 to 521c1ce Compare August 4, 2026 20:31
nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx and several plugins depend on minimatch, which pulls brace-expansion
(GHSA-rgw5-rvv9-x895 DoS, third CVE in that package this year).

All minimatch usages replaced with picomatch (nx, devkit, jest,
playwright, react, rsbuild). minimatch, brace-expansion and
balanced-match leave the published nx runtime dependency closure.

Not pure 1:1:
- picomatch only lets a leading `**/` match zero path segments in
  standalone patterns, not inside `{a,b}` brace alternation, so
  combineGlobPatterns output missed root-level files. New
  splitGlobPatterns() (local copy in devkit for the +/-1 nx major
  compat contract); jest plugin and project-glob-changes pass pattern
  arrays instead.
- picomatch throws on empty patterns and invalid makeRe input where
  minimatch returned false/null: guards added at the affected sites.
- `!(x)` is a real extglob now (micromatch semantics), which makes the
  min-release-age yarn matcher closer to yarn's own behavior.

Dev-tree transitives (eslint, glob, verdaccio, typedoc) still pull
minimatch, so the pnpm overrides stay; brace-expansion override bumped
to 5.0.9 (the patched version).

Fixes NXC-4762
nx-cloud[bot]

This comment was marked as outdated.

Co-authored-by: jaysoo <jaysoo@users.noreply.github.com>

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nx Cloud is proposing a fix for your failed CI:

We updated getPackageManagerCommand in e2e/utils/command-utils.ts to use yarn install --no-immutable for yarn berry (v2+), mirroring the existing pnpm install --no-frozen-lockfile pattern that addresses the same CI-immutable-mode problem. This fixes the YN0028 error that the PR triggered by introducing picomatch as a new runtime dependency: that addition caused yarn 4's lockfile migration to need 401+ new package entries, which was deterministically blocked by yarn's default --immutable mode when CI=true. With --no-immutable, the beforeAll lockfile-refresh step can proceed as intended.

Warning

We could not verify this fix.

diff --git a/e2e/utils/command-utils.ts b/e2e/utils/command-utils.ts
index 66cd0fd9..76b4c287 100644
--- a/e2e/utils/command-utils.ts
+++ b/e2e/utils/command-utils.ts
@@ -164,7 +164,12 @@ export function getPackageManagerCommand({
           ? 'yarn nx'
           : `yarn --silent nx`,
       runUninstalledPackage: 'npx --yes',
-      install: 'yarn',
+      // --no-immutable: yarn berry (v2+) detects CI and would otherwise default
+      // to --immutable, blocking lockfile updates in e2e setup steps.
+      install:
+        yarnMajorVersion && +yarnMajorVersion >= 2
+          ? 'yarn install --no-immutable'
+          : 'yarn',
       ciInstall: 'yarn --frozen-lockfile',
       addProd: isYarnWorkspace ? 'yarn add -W' : 'yarn add',
       addDev: isYarnWorkspace ? 'yarn add -DW' : 'yarn add -D',

🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.

Apply fix via Nx Cloud  Reject fix via Nx Cloud


Or Apply changes locally with:

npx nx-cloud apply-locally sOm5-yPMY

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

Follow-up to the minimatch -> picomatch swap, addressing defects in the
compatibility code rather than the swap itself.

expandGlobPatternBraces:
- scan past comma-free groups instead of bailing on the first one, so a
  range or `{token}` before an alternation no longer disables expansion
- treat backslash-escaped braces as literals; splitting them produced
  patterns that matched neither what minimatch nor raw picomatch matched
- build results with a loop; the spread hit the argument limit and
  reported a misleading RangeError
- correct the docstring: results are not brace-free, groups without a
  top-level comma are what gets skipped, and output is the product of
  the alternation widths

splitGlobPatterns now never emits an empty pattern, in both the nx and
devkit copies. picomatch rejects '' where minimatch matched nothing, so
every downstream length check becomes correct for free.

filterUsingGlobPatterns:
- drop empty expansion products so `{,a}` and a bare `!` stop throwing
- remove the './' strip, which existed for a minimatch limitation
  picomatch does not have and was what manufactured the empty pattern.
  This also restores the `<root>/**/*` fast path for root-level projects
- pass `posix: true` so `[!a]` stays a negated class; without it the
  match inverted, which silently changed the hashed file set
- skip compiling positive matchers when the fast path already matches

glob() / globAsync():
- apply splitGlobPatterns, so a combined `{**/a,**/b}` glob keeps
  matching root-level files
- treat a list of only negations as everything not excluded, matching
  NxGlobSet::is_match in src/native/glob.rs
- leave `!(` extglobs to picomatch instead of stripping the `!`
- name the offending entry in the error instead of a synthesized glob

@nx/jest now reuses nx core's buildPackageJsonPatterns and
buildPackageJsonWorkspacesMatcher rather than a local copy, so the two
can no longer disagree about which package.json files are in the
workspaces. picomatch is no longer a dependency of @nx/jest.

buildPackageJsonPatterns also learns the `!(` extglob guard.

hasRsbuildPlugin matches a project directory rather than a file, so it
passes `strictSlashes: true` to keep `<root>/**` from matching `<root>`.

Docs and one comment updated to stop naming minimatch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants