Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions lib/child_process.js
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,11 @@ function hasPermissionFlagInEnv(nodeOptions) {
);
}

function quoteNodeOption(flag, value) {
const quoted = RegExpPrototypeSymbolReplace(/["\\]/g, value, '\\$&');
return `"${flag}=${quoted}"`;
}

function copyPermissionModelFlagsToEnv(env, key, args) {
// Do not override if permission was already passed to file
if (args.includes('--permission') || args.includes('--permission-audit') ||
Expand All @@ -582,15 +587,33 @@ function copyPermissionModelFlagsToEnv(env, key, args) {

const flagsToCopy = getPermissionModelFlagsToCopy();
const copiedFlags = new SafeSet();
for (const arg of process.execArgv) {
const execArgv = process.execArgv;
for (let i = 0; i < execArgv.length; i++) {
const arg = execArgv[i];
if (allowAllEnv && arg.startsWith('--allow-env')) {
continue;
}
for (const flag of flagsToCopy) {
if (arg.startsWith(flag)) {
copiedFlags.add(flag);
env[key] = `${env[key] ? env[key] + ' ' + arg : arg}`;
if (!arg.startsWith(flag)) {
continue;
}
copiedFlags.add(flag);
if (ArrayIsArray(getOptionValue(flag))) {
let value;
if (arg === flag && i + 1 < execArgv.length) {
value = execArgv[++i];
if (value[0] === '\\' && value[1] === '-') {
value = StringPrototypeSlice(value, 1);
}
} else if (arg[flag.length] === '=') {
value = StringPrototypeSlice(arg, flag.length + 1);
}
if (value !== undefined) {
env[key] = `${env[key] ? env[key] + ' ' : ''}${quoteNodeOption(flag, value)}`;
break;
}
}
env[key] = `${env[key] ? env[key] + ' ' + arg : arg}`;
}
}

Expand All @@ -604,10 +627,7 @@ function copyPermissionModelFlagsToEnv(env, key, args) {
env[key] = `${env[key] ? env[key] + ' ' : ''}${flag}`;
} else if (ArrayIsArray(value)) {
for (const item of value) {
// Values may contain spaces or quotes (e.g. the implicitly allowed
// entry point), so quote them as NODE_OPTIONS expects.
const quoted = RegExpPrototypeSymbolReplace(/["\\]/g, item, '\\$&');
env[key] = `${env[key] ? env[key] + ' ' : ''}"${flag}=${quoted}"`;
env[key] = `${env[key] ? env[key] + ' ' : ''}${quoteNodeOption(flag, item)}`;
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions test/parallel/test-permission-child-process-inherit-flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,51 @@ const childProcess = require('child_process');
assert.strictEqual(worker, 'false');
}

{
const tmpdir = require('../common/tmpdir');
const dir = tmpdir.resolve('inherit flags dir');
const file = `${dir}/file.txt`;

const grandchildSource = `
console.log(process.permission.has('fs.read'));
console.log(process.permission.has('fs.read', ${JSON.stringify(file)}));
console.log(process.permission.has('fs.read', ${JSON.stringify(__filename)}));
`;
const childSource = `
const { status, stdout, stderr } = require('child_process').spawnSync(
process.execPath, ['-e', ${JSON.stringify(grandchildSource)}]);
console.log(JSON.stringify({
status,
stderr: stderr.toString(),
permissions: stdout.toString().trim().split('\\n'),
}));
`;

function run(args) {
const { status, stdout, stderr } = childProcess.spawnSync(
process.execPath,
['--permission', '--allow-child-process', ...args, '-e', childSource],
);
assert.strictEqual(status, 0, stderr.toString());
const grandchild = JSON.parse(stdout.toString());
assert.strictEqual(grandchild.status, 0, grandchild.stderr);
return grandchild.permissions;
}

assert.deepStrictEqual(run(['--allow-fs-read', '*']),
['true', 'true', 'true']);

assert.deepStrictEqual(run(['--allow-fs-read', `${dir}/*`]),
['false', 'true', 'false']);

assert.deepStrictEqual(run([`--allow-fs-read=${dir}/*`]),
['false', 'true', 'false']);

assert.deepStrictEqual(
run(['--allow-fs-read', `${dir}/*`, `--allow-fs-read=${__filename}`]),
['false', 'true', 'true']);
}

{
assert.strictEqual(process.env.NODE_OPTIONS, undefined);
}
Loading