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:
Output:
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:
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:
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:
- Update toolkit consumers such as
@actions/cache to depend on @actions/glob@0.7.0.
- Add a Windows regression test that executes a Rollup-generated ESM bundle.
- 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.
Description
@actions/glob@0.6.1can 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.1minimatch@^3.0.4The failure ultimately causes
@actions/cache.saveCache()to report:even though the path exists and can be read by Node.
Environment
@actions/cache: 6.2.0@actions/glob: 0.6.1minimatch: 3.1.5@rollup/plugin-commonjs: 29.0.3@rollup/plugin-node-resolve: 16.0.3Minimal reproduction
Install the dependencies:
Create
test.js:Running it directly succeeds:
Output:
Create
rollup.config.js:Bundle and execute it:
npx rollup --config rollup.config.js node bundle.jsOutput:
With debug logging enabled, the bundled version reports the search path but never reports a match:
A real GitHub Actions failure using
@actions/cache@6.2.0produced:Root cause
@actions/glob@0.6.1depends onminimatch@3. That version ofminimatchdetects the platform separator using:@rollup/plugin-commonjsdefaultsignoreTryCatchtotrue. Therefore, it does not convert therequire('path')call because it appears inside atryblock.The resulting ESM bundle still contains:
Because
requireis unavailable in ESM, the resultingReferenceErroris caught andminimatchsilently falls back to:On Windows,
@actions/globconverts its pattern to forward slashes, but the filesystem item passed tominimatch.match()remains backslash-delimited.As a result,
Pattern.match()returnsMatchKind.None, andinternal-globbersilently discards the existing path here:Confirmed workaround
Configuring the CommonJS plugin to convert only
require('path')calls insidetryblocks fixes the bundled output:After rebuilding with that configuration, the bundled reproduction correctly reports:
The same fix allowed
@actions/cacheto resolve and archive an absolute path onC:whileGITHUB_WORKSPACEwas onD:, confirming that separate Windows drives were not the cause.Expected behavior
Bundling a consumer of
@actions/globshould 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.0has already moved fromminimatch@3tominimatch@10.Could the maintainers please confirm whether
0.7.0resolves this bundling issue and, if so:@actions/cacheto depend on@actions/glob@0.7.0.@actions/glob@0.6.1is unsafe when bundled this way.Since
@actions/cache@6.2.0currently uses@actions/glob@^0.6.1, its semver range will not select0.7.0.