actions / actions/toolkit

@actions/glob 0.6.1 silently fails to match Windows paths when bundled as ESM with Rollup

Open
#2,484 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
5.9k
Forks
1.8k
PR merge metrics
No merged PRs in 30d

Description

Description

@actions/glob@0.6.1 can silently fail to match valid Windows paths when it is bundled into an ES module using Rollup and @rollup/plugin-commonjs.

The same code works when executed directly with Node, but returns no matches after being bundled.

This also affects custom JavaScript actions using @actions/cache@6.2.0, because it depends on:

  • @actions/glob@^0.6.1
  • minimatch@^3.0.4

The failure ultimately causes @actions/cache.saveCache() to report:

Path Validation Error: Path(s) specified in the action for caching do(es) not exist

even though the path exists and can be read by Node.

Environment
  • OS: Windows
  • Node.js: 24.6.0
  • @actions/cache: 6.2.0
  • @actions/glob: 0.6.1
  • minimatch: 3.1.5
  • Rollup: 4.62.3
  • @rollup/plugin-commonjs: 29.0.3
  • @rollup/plugin-node-resolve: 16.0.3
  • Bundle format: ESM
Minimal reproduction

Install the dependencies:

npm install @actions/glob@0.6.1
npm install --save-dev rollup @rollup/plugin-commonjs @rollup/plugin-node-resolve

Create test.js:

import * as glob from '@actions/glob';

const pattern = 'C:\\Windows';
const globber = await glob.create(pattern, {
  implicitDescendants: false,
});

console.log(await globber.glob());

Running it directly succeeds:

node test.js

Output:

[ 'C:\\Windows' ]

Create rollup.config.js:

import commonjs from '@rollup/plugin-commonjs';
import { nodeResolve } from '@rollup/plugin-node-resolve';

export default {
  input: 'test.js',
  output: {
    file: 'bundle.js',
    format: 'es',
  },
  plugins: [
    commonjs(),
    nodeResolve({ preferBuiltins: true }),
  ],
};

Bundle and execute it:

npx rollup --config rollup.config.js
node bundle.js

Output:

[]

With debug logging enabled, the bundled version reports the search path but never reports a match:

Search path 'C:\Windows'

A real GitHub Actions failure using @actions/cache@6.2.0 produced:

Search path 'C:\Program Files\My Software'
Cache Paths:
[]
Path Validation Error: Path(s) specified in the action for caching do(es) not exist
Root cause

@actions/glob@0.6.1 depends on minimatch@3. That version of minimatch detects the platform separator using:

var path = (function () {
  try {
    return require('path');
  } catch (e) {}
})() || {
  sep: '/',
};

@rollup/plugin-commonjs defaults ignoreTryCatch to true. Therefore, it does not convert the require('path') call because it appears inside a try block.

The resulting ESM bundle still contains:

try {
  return require('path');
} catch (e) {}

Because require is unavailable in ESM, the resulting ReferenceError is caught and minimatch silently falls back to:

{ sep: '/' }

On Windows, @actions/glob converts its pattern to forward slashes, but the filesystem item passed to minimatch.match() remains backslash-delimited.

As a result, Pattern.match() returns MatchKind.None, and internal-globber silently discards the existing path here:

const match = patternHelper.match(patterns, item.path);
const partialMatch =
  !!match || patternHelper.partialMatch(patterns, item.path);

if (!match && !partialMatch) {
  continue;
}
Confirmed workaround

Configuring the CommonJS plugin to convert only require('path') calls inside try blocks fixes the bundled output:

commonjs({
  ignoreTryCatch: id => id !== 'path',
})

After rebuilding with that configuration, the bundled reproduction correctly reports:

Matched: C:/Windows
Cache Paths:
["C:/Windows"]

The same fix allowed @actions/cache to resolve and archive an absolute path on C: while GITHUB_WORKSPACE was on D:, confirming that separate Windows drives were not the cause.

Expected behavior

Bundling a consumer of @actions/glob should not change whether valid Windows paths match.

At minimum, the package should not silently interpret Windows paths using POSIX separator behavior merely because it was included in an ESM bundle.

Suggested resolution

It appears that @actions/glob@0.7.0 has already moved from minimatch@3 to minimatch@10.

Could the maintainers please confirm whether 0.7.0 resolves this bundling issue and, if so:

  1. Update toolkit consumers such as @actions/cache to depend on @actions/glob@0.7.0.
  2. Add a Windows regression test that executes a Rollup-generated ESM bundle.
  3. Consider documenting that @actions/glob@0.6.1 is unsafe when bundled this way.

Since @actions/cache@6.2.0 currently uses @actions/glob@^0.6.1, its semver range will not select 0.7.0.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the @actions/glob internal-globber path matching and its minimatch dependency, then run the test.js and rollup.config.js reproduction on Windows. Check the bundled ESM output and verify that valid backslash-delimited paths still match; done means a regression test covers the Rollup bundle and the affected dependency behavior is resolved or documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
nodejs, rollup, typescript
Domain
build-system, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.