Skip to content

Commit cad2307

Browse files
committed
test: expand permission Worker execArgv ceiling coverage
Signed-off-by: yunshingng <yunshingng25@gmail.com>
1 parent c3467e6 commit cad2307

1 file changed

Lines changed: 171 additions & 17 deletions

File tree

‎test/parallel/test-permission-worker-empty-execargv.js‎

Lines changed: 171 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ const tmpdir = require('../common/tmpdir');
1313
tmpdir.refresh();
1414
const allowedDir = tmpdir.path;
1515
const allowedFile = path.join(allowedDir, 'ok.txt');
16-
const subFile = path.join(allowedDir, 'sub', 'nested.txt');
17-
fs.mkdirSync(path.dirname(subFile), { recursive: true });
16+
const subDir = path.join(allowedDir, 'sub');
17+
const subFile = path.join(subDir, 'nested.txt');
18+
fs.mkdirSync(subDir, { recursive: true });
1819
const deniedDir = fs.mkdtempSync(path.join(path.dirname(tmpdir.path), 'perm-deny-'));
1920
const deniedFile = path.join(deniedDir, 'secret.txt');
2021
fs.writeFileSync(allowedFile, 'allowed\n');
2122
fs.writeFileSync(subFile, 'nested\n');
2223
fs.writeFileSync(deniedFile, 'secret\n');
2324

24-
function runWorkerCase(workerBody, execArgvFragment) {
25+
// Trailing-slash allow path (NormalizePathForCompare)
26+
const allowedDirSlash = allowedDir.endsWith(path.sep)
27+
? allowedDir
28+
: allowedDir + path.sep;
29+
30+
function runWithParent(parentArgs, workerBody, execArgvFragment) {
2531
const code = `
2632
const { Worker } = require('worker_threads');
2733
const w = new Worker(${JSON.stringify(workerBody)}, {
@@ -36,14 +42,23 @@ function runWorkerCase(workerBody, execArgvFragment) {
3642
`;
3743
return spawnSync(
3844
process.execPath,
39-
['--permission', `--allow-fs-read=${allowedDir}`, '--allow-worker', '-e', code],
45+
parentArgs.concat(['-e', code]),
4046
{ encoding: 'utf8', timeout: 30000, env: { ...process.env } },
4147
);
4248
}
4349

50+
function baseParent(extra = []) {
51+
return [
52+
'--permission',
53+
`--allow-fs-read=${allowedDir}`,
54+
'--allow-worker',
55+
...extra,
56+
];
57+
}
58+
4459
function parseLastJsonLine(stdout) {
4560
const lines = stdout.trim().split('\n').filter(Boolean);
46-
assert.ok(lines.length > 0, 'expected worker JSON output');
61+
assert.ok(lines.length > 0, `expected JSON, got: ${stdout}`);
4762
return JSON.parse(lines[lines.length - 1]);
4863
}
4964

@@ -62,6 +77,19 @@ function workerRead(filePath) {
6277
`;
6378
}
6479

80+
function workerWrite(filePath) {
81+
return `
82+
const { parentPort } = require('worker_threads');
83+
const fs = require('fs');
84+
try {
85+
fs.writeFileSync(${JSON.stringify(filePath)}, 'w');
86+
parentPort.postMessage({ ok: true });
87+
} catch (err) {
88+
parentPort.postMessage({ ok: false, code: err.code });
89+
}
90+
`;
91+
}
92+
6593
function assertAccessDenied(msg) {
6694
assert.strictEqual(msg.ok, false, JSON.stringify(msg));
6795
assert.strictEqual(msg.code, 'ERR_ACCESS_DENIED');
@@ -72,63 +100,189 @@ function assertOk(msg) {
72100
}
73101

74102
try {
103+
// default Worker inherits
75104
{
76-
const r = runWorkerCase(workerRead(deniedFile), '');
105+
const r = runWithParent(baseParent(), workerRead(deniedFile), '');
77106
assert.strictEqual(r.status, 0, r.stderr);
78107
assertAccessDenied(parseLastJsonLine(r.stdout));
79108
}
109+
110+
// execArgv: []
80111
{
81-
const denied = runWorkerCase(workerRead(deniedFile), 'execArgv: [],');
112+
const denied = runWithParent(baseParent(), workerRead(deniedFile), 'execArgv: [],');
82113
assert.strictEqual(denied.status, 0, denied.stderr);
83114
assertAccessDenied(parseLastJsonLine(denied.stdout));
84-
const allowed = runWorkerCase(workerRead(allowedFile), 'execArgv: [],');
115+
const allowed = runWithParent(baseParent(), workerRead(allowedFile), 'execArgv: [],');
85116
assert.strictEqual(allowed.status, 0, allowed.stderr);
86117
assertOk(parseLastJsonLine(allowed.stdout));
87-
const nested = runWorkerCase(workerRead(subFile), 'execArgv: [],');
118+
const nested = runWithParent(baseParent(), workerRead(subFile), 'execArgv: [],');
88119
assert.strictEqual(nested.status, 0, nested.stderr);
89120
assertOk(parseLastJsonLine(nested.stdout));
90121
}
122+
123+
// non-permission flag preserved + ceiling
91124
{
92-
const denied = runWorkerCase(workerRead(deniedFile), 'execArgv: ["--no-warnings"],');
125+
const denied = runWithParent(
126+
baseParent(),
127+
workerRead(deniedFile),
128+
'execArgv: ["--no-warnings"],',
129+
);
93130
assert.strictEqual(denied.status, 0, denied.stderr);
94131
assertAccessDenied(parseLastJsonLine(denied.stdout));
95-
const allowed = runWorkerCase(workerRead(allowedFile), 'execArgv: ["--no-warnings"],');
132+
const allowed = runWithParent(
133+
baseParent(),
134+
workerRead(allowedFile),
135+
'execArgv: ["--no-warnings"],',
136+
);
96137
assert.strictEqual(allowed.status, 0, allowed.stderr);
97138
assertOk(parseLastJsonLine(allowed.stdout));
98139
}
140+
141+
// worker permission on, no fs-read → empty grants
99142
{
100143
const frag = `execArgv: ${JSON.stringify(['--permission', '--allow-worker'])},`;
101-
const d = runWorkerCase(workerRead(deniedFile), frag);
144+
const d = runWithParent(baseParent(), workerRead(deniedFile), frag);
102145
assert.strictEqual(d.status, 0, d.stderr);
103146
assertAccessDenied(parseLastJsonLine(d.stdout));
104-
const a = runWorkerCase(workerRead(allowedFile), frag);
147+
const a = runWithParent(baseParent(), workerRead(allowedFile), frag);
105148
assert.strictEqual(a.status, 0, a.stderr);
106149
assertAccessDenied(parseLastJsonLine(a.stdout));
107150
}
151+
152+
// escalate * clamped
108153
{
109-
const frag = `execArgv: ${JSON.stringify(['--permission', '--allow-fs-read=*', '--allow-worker'])},`;
110-
const r = runWorkerCase(workerRead(deniedFile), frag);
154+
const frag = `execArgv: ${JSON.stringify([
155+
'--permission', '--allow-fs-read=*', '--allow-worker',
156+
])},`;
157+
const r = runWithParent(baseParent(), workerRead(deniedFile), frag);
111158
assert.strictEqual(r.status, 0, r.stderr);
112159
assertAccessDenied(parseLastJsonLine(r.stdout));
113160
}
161+
162+
// repeated allow flags cannot exceed parent
114163
{
115164
const frag = `execArgv: ${JSON.stringify([
116165
'--permission',
117166
`--allow-fs-read=${allowedDir}`,
118167
`--allow-fs-read=${deniedFile}`,
119168
'--allow-worker',
120169
])},`;
121-
const r = runWorkerCase(workerRead(deniedFile), frag);
170+
const r = runWithParent(baseParent(), workerRead(deniedFile), frag);
122171
assert.strictEqual(r.status, 0, r.stderr);
123172
assertAccessDenied(parseLastJsonLine(r.stdout));
124173
}
174+
175+
// subset path under parent dir
125176
{
126177
const frag = `execArgv: ${JSON.stringify([
127178
'--permission',
128179
`--allow-fs-read=${subFile}`,
129180
'--allow-worker',
130181
])},`;
131-
const r = runWorkerCase(workerRead(subFile), frag);
182+
const r = runWithParent(baseParent(), workerRead(subFile), frag);
183+
assert.strictEqual(r.status, 0, r.stderr);
184+
assertOk(parseLastJsonLine(r.stdout));
185+
}
186+
187+
// trailing slash parent allow (NormalizePathForCompare)
188+
{
189+
const parent = [
190+
'--permission',
191+
`--allow-fs-read=${allowedDirSlash}`,
192+
'--allow-worker',
193+
];
194+
const r = runWithParent(parent, workerRead(allowedFile), 'execArgv: [],');
195+
assert.strictEqual(r.status, 0, r.stderr);
196+
assertOk(parseLastJsonLine(r.stdout));
197+
}
198+
199+
// parent has wildcard * → worker * / paths not stripped by Filter
200+
{
201+
const parent = ['--permission', '--allow-fs-read=*', '--allow-worker'];
202+
const frag = `execArgv: ${JSON.stringify([
203+
'--permission',
204+
`--allow-fs-read=${deniedFile}`,
205+
'--allow-worker',
206+
])},`;
207+
const r = runWithParent(parent, workerRead(deniedFile), frag);
208+
assert.strictEqual(r.status, 0, r.stderr);
209+
assertOk(parseLastJsonLine(r.stdout));
210+
}
211+
212+
// permission-audit on parent + empty execArgv
213+
{
214+
const parent = [
215+
'--permission',
216+
'--permission-audit',
217+
`--allow-fs-read=${allowedDir}`,
218+
'--allow-worker',
219+
];
220+
const r = runWithParent(parent, workerRead(allowedFile), 'execArgv: [],');
221+
assert.strictEqual(r.status, 0, r.stderr);
222+
assertOk(parseLastJsonLine(r.stdout));
223+
}
224+
225+
// fs-write: parent no write → worker cannot escalate write
226+
{
227+
const writeTarget = path.join(allowedDir, 'w.txt');
228+
const frag = `execArgv: ${JSON.stringify([
229+
'--permission',
230+
`--allow-fs-write=${allowedDir}`,
231+
'--allow-worker',
232+
])},`;
233+
const r = runWithParent(baseParent(), workerWrite(writeTarget), frag);
234+
assert.strictEqual(r.status, 0, r.stderr);
235+
assertAccessDenied(parseLastJsonLine(r.stdout));
236+
}
237+
238+
// fs-write allowed when parent grants write
239+
{
240+
const writeTarget = path.join(allowedDir, 'w2.txt');
241+
const parent = [
242+
'--permission',
243+
`--allow-fs-read=${allowedDir}`,
244+
`--allow-fs-write=${allowedDir}`,
245+
'--allow-worker',
246+
];
247+
const frag = `execArgv: ${JSON.stringify([
248+
'--permission',
249+
`--allow-fs-write=${allowedDir}`,
250+
'--allow-worker',
251+
])},`;
252+
const r = runWithParent(parent, workerWrite(writeTarget), frag);
253+
assert.strictEqual(r.status, 0, r.stderr);
254+
assertOk(parseLastJsonLine(r.stdout));
255+
}
256+
257+
// boolean allow intersection: worker asks allow-net, parent does not
258+
{
259+
const frag = `execArgv: ${JSON.stringify([
260+
'--permission',
261+
`--allow-fs-read=${allowedDir}`,
262+
'--allow-net',
263+
'--allow-worker',
264+
])},`;
265+
// still cannot read denied; net flag just exercises Intersect path
266+
const r = runWithParent(baseParent(), workerRead(deniedFile), frag);
267+
assert.strictEqual(r.status, 0, r.stderr);
268+
assertAccessDenied(parseLastJsonLine(r.stdout));
269+
}
270+
271+
// multiple boolean flags in rebuild path
272+
{
273+
const parent = [
274+
'--permission',
275+
`--allow-fs-read=${allowedDir}`,
276+
'--allow-worker',
277+
'--allow-addons',
278+
];
279+
const frag = `execArgv: ${JSON.stringify([
280+
'--permission',
281+
`--allow-fs-read=${allowedDir}`,
282+
'--allow-worker',
283+
'--allow-addons',
284+
])},`;
285+
const r = runWithParent(parent, workerRead(allowedFile), frag);
132286
assert.strictEqual(r.status, 0, r.stderr);
133287
assertOk(parseLastJsonLine(r.stdout));
134288
}

0 commit comments

Comments
 (0)