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
22 changes: 22 additions & 0 deletions lib/child_process.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const {
ObjectPrototypeHasOwnProperty,
PromiseWithResolvers,
RegExpPrototypeExec,
RegExpPrototypeSymbolReplace,
SafeSet,
StringPrototypeIncludes,
StringPrototypeIndexOf,
Expand Down Expand Up @@ -75,6 +76,7 @@ const {
} = require('internal/errors');
const { clearTimeout, setTimeout } = require('timers');
const { getValidatedPath } = require('internal/fs/utils');
const { getOptionValue } = require('internal/options');
const {
validateAbortSignal,
validateArray,
Expand Down Expand Up @@ -579,17 +581,37 @@ function copyPermissionModelFlagsToEnv(env, key, args) {
const allowAllEnv = !permission.isAuditMode();

const flagsToCopy = getPermissionModelFlagsToCopy();
const copiedFlags = new SafeSet();
for (const arg of process.execArgv) {
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}`;
}
}
}

// Flags set through --config-file are not part of process.execArgv.
for (const flag of flagsToCopy) {
if (copiedFlags.has(flag) || (allowAllEnv && flag === '--allow-env')) {
continue;
}
const value = getOptionValue(flag);
if (value === true) {
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}"`;
}
}
}

if (allowAllEnv) {
env[key] = `${env[key] ? env[key] + ' ' : ''}--allow-env=*`;
}
Expand Down
16 changes: 16 additions & 0 deletions test/fixtures/permission/child-process-inherit-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { spawnSync } = require('child_process');
const { status, stdout, stderr } = spawnSync(process.execPath, [
'-p',
`JSON.stringify([
typeof process.permission,
process.permission.has("fs.read"),
process.permission.has("fs.write"),
process.permission.has("child"),
process.permission.has("worker"),
])`,
]);
console.log(JSON.stringify({
status,
stdout: stdout.toString().trim(),
stderr: stderr.toString(),
}));
9 changes: 9 additions & 0 deletions test/fixtures/permission/config-child-inherit-allow-only.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"permission": {
"allow-child-process": true,
"allow-worker": true,
"allow-fs-read": [
"*"
]
}
}
11 changes: 11 additions & 0 deletions test/fixtures/permission/config-child-inherit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"permission": {
"permission": true,
"allow-child-process": true,
"allow-worker": true,
"allow-fs-read": [
"*",
"/nonexistent/dir with \"quotes\" and \\backslash"
]
}
}
34 changes: 34 additions & 0 deletions test/parallel/test-permission-config-file.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,40 @@ describe('Permission model config file support', () => {
}
});

it('should propagate config file permissions to child processes', {
skip: process.config.variables.node_without_node_options && 'missing NODE_OPTIONS support',
}, async () => {
const childTestPath = fixtures.path('permission/child-process-inherit-test.js');
const expected = JSON.stringify(['object', true, false, true, true]);

// --permission set in the config file
{
const configPath = fixtures.path('permission/config-child-inherit.json');
const result = await spawnPromisified(process.execPath, [
`--config-file=${configPath}`,
childTestPath,
]);
assert.strictEqual(result.code, 0, result.stderr);
const child = JSON.parse(result.stdout);
assert.strictEqual(child.status, 0, child.stderr);
assert.strictEqual(child.stdout, expected);
}

// --permission set in the command line
{
const configPath = fixtures.path('permission/config-child-inherit-allow-only.json');
const result = await spawnPromisified(process.execPath, [
'--permission',
`--config-file=${configPath}`,
childTestPath,
]);
assert.strictEqual(result.code, 0, result.stderr);
const child = JSON.parse(result.stdout);
assert.strictEqual(child.status, 0, child.stderr);
assert.strictEqual(child.stdout, expected);
}
});

it('should load network and inspector permissions from config file', async () => {
const configPath = fixtures.path('permission/config-net-inspector.json');
const readOnlyConfigPath = fixtures.path('permission/config-fs-read-only.json');
Expand Down
Loading