fix(fs): expandGlob/expandGlobSync don't require full --allow-read perms on granted read permissions (#3692)

Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
This commit is contained in:
Simon Lecoq 2023-10-24 09:51:33 +02:00 committed by GitHub
parent aeb64da6f6
commit dea3b33c7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 19 deletions

View File

@ -79,7 +79,7 @@ function comparePath(a: WalkEntry, b: WalkEntry): number {
export async function* expandGlob(
glob: string | URL,
{
root = Deno.cwd(),
root,
exclude = [],
includeDirs = true,
extended = true,
@ -89,20 +89,22 @@ export async function* expandGlob(
canonicalize,
}: ExpandGlobOptions = {},
): AsyncIterableIterator<WalkEntry> {
const globOptions: GlobOptions = { extended, globstar, caseInsensitive };
const absRoot = resolve(root);
const resolveFromRoot = (path: string): string => resolve(absRoot, path);
const excludePatterns = exclude
.map(resolveFromRoot)
.map((s: string): RegExp => globToRegExp(s, globOptions));
const shouldInclude = (path: string): boolean =>
!excludePatterns.some((p: RegExp): boolean => !!path.match(p));
const {
segments,
isAbsolute: isGlobAbsolute,
hasTrailingSep,
winRoot,
} = split(toPathString(glob));
root ??= isGlobAbsolute ? winRoot ?? "/" : Deno.cwd();
const globOptions: GlobOptions = { extended, globstar, caseInsensitive };
const absRoot = isGlobAbsolute ? root : resolve(root!); // root is always string here
const resolveFromRoot = (path: string): string => resolve(absRoot, path);
const excludePatterns = exclude
.map(resolveFromRoot)
.map((s: string): RegExp => globToRegExp(s, globOptions));
const shouldInclude = (path: string): boolean =>
!excludePatterns.some((p: RegExp): boolean => !!path.match(p));
let fixedRoot = isGlobAbsolute
? winRoot !== undefined ? winRoot : "/"
@ -203,7 +205,7 @@ export async function* expandGlob(
export function* expandGlobSync(
glob: string | URL,
{
root = Deno.cwd(),
root,
exclude = [],
includeDirs = true,
extended = true,
@ -213,20 +215,22 @@ export function* expandGlobSync(
canonicalize,
}: ExpandGlobOptions = {},
): IterableIterator<WalkEntry> {
const globOptions: GlobOptions = { extended, globstar, caseInsensitive };
const absRoot = resolve(root);
const resolveFromRoot = (path: string): string => resolve(absRoot, path);
const excludePatterns = exclude
.map(resolveFromRoot)
.map((s: string): RegExp => globToRegExp(s, globOptions));
const shouldInclude = (path: string): boolean =>
!excludePatterns.some((p: RegExp): boolean => !!path.match(p));
const {
segments,
isAbsolute: isGlobAbsolute,
hasTrailingSep,
winRoot,
} = split(toPathString(glob));
root ??= isGlobAbsolute ? winRoot ?? "/" : Deno.cwd();
const globOptions: GlobOptions = { extended, globstar, caseInsensitive };
const absRoot = isGlobAbsolute ? root : resolve(root!); // root is always string here
const resolveFromRoot = (path: string): string => resolve(absRoot, path);
const excludePatterns = exclude
.map(resolveFromRoot)
.map((s: string): RegExp => globToRegExp(s, globOptions));
const shouldInclude = (path: string): boolean =>
!excludePatterns.some((p: RegExp): boolean => !!path.match(p));
let fixedRoot = isGlobAbsolute
? winRoot !== undefined ? winRoot : "/"

View File

@ -16,6 +16,7 @@ import {
async function expandGlobArray(
globString: string,
options: ExpandGlobOptions,
{ forceRoot = "" } = {},
): Promise<string[]> {
const paths: string[] = [];
for await (const { path } of expandGlob(globString, options)) {
@ -27,7 +28,7 @@ async function expandGlobArray(
);
pathsSync.sort();
assertEquals(paths, pathsSync);
const root = normalize(options.root || Deno.cwd());
const root = normalize(forceRoot || options.root || Deno.cwd());
for (const path of paths) {
assert(path.startsWith(root));
}
@ -181,3 +182,29 @@ Deno.test("expandGlobFollowSymlink without canonicalize", async function () {
["abc", join("link", "abc"), join("subdir", "abc")],
);
});
Deno.test(
"expandGlob doesn't require read permissions when root path is specified",
{
permissions: { read: [EG_OPTIONS.root!] },
},
async function () {
const options = { root: EG_OPTIONS.root! };
assertEquals(await expandGlobArray("abc", options), ["abc"]);
},
);
Deno.test(
"expandGlob doesn't require read permissions when an absolute glob is specified",
{
permissions: { read: [EG_OPTIONS.root!] },
},
async function () {
assertEquals(
await expandGlobArray(`${EG_OPTIONS.root!}/abc`, {}, {
forceRoot: EG_OPTIONS.root!,
}),
["abc"],
);
},
);