Skip to content

Commit 657921a

Browse files
authored
fix(detect-child-process): false positive for destructuring with exec (#102)
* fix(detect-child-process): false positive for destructuring with `exec` * test: add testcase
1 parent 04dae96 commit 657921a

File tree

2 files changed

+52
-8
lines changed

2 files changed

+52
-8
lines changed

rules/detect-child-process.js

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@
99
// Rule Definition
1010
//------------------------------------------------------------------------------
1111

12-
/*
13-
* Stores variable names pointing to child_process to check (child_process).exec()
14-
*/
15-
const names = [];
16-
1712
module.exports = {
1813
meta: {
1914
type: 'error',
@@ -25,22 +20,44 @@ module.exports = {
2520
},
2621
},
2722
create: function (context) {
23+
/*
24+
* Stores variable identifiers pointing to child_process to check (child_process).exec()
25+
*/
26+
const childProcessIdentifiers = new Set();
27+
28+
/**
29+
* Extract identifiers assigned the expression `require("child_process")`.
30+
* @param {Pattern} node
31+
*/
32+
function extractChildProcessIdentifiers(node) {
33+
if (node.type !== 'Identifier') {
34+
return;
35+
}
36+
const variable = context.getScope().set.get(node.name);
37+
if (!variable) {
38+
return;
39+
}
40+
for (const reference of variable.references) {
41+
childProcessIdentifiers.add(reference.identifier);
42+
}
43+
}
44+
2845
return {
2946
CallExpression: function (node) {
3047
if (node.callee.name === 'require') {
3148
const args = node.arguments[0];
3249
if (args && args.type === 'Literal' && args.value === 'child_process') {
3350
if (node.parent.type === 'VariableDeclarator') {
34-
names.push(node.parent.id.name);
51+
extractChildProcessIdentifiers(node.parent.id);
3552
} else if (node.parent.type === 'AssignmentExpression' && node.parent.operator === '=') {
36-
names.push(node.parent.left.name);
53+
extractChildProcessIdentifiers(node.parent.left);
3754
}
3855
return context.report({ node: node, message: 'Found require("child_process")' });
3956
}
4057
}
4158
},
4259
MemberExpression: function (node) {
43-
if (node.property.name === 'exec' && names.indexOf(node.object.name) > -1) {
60+
if (node.property.name === 'exec' && childProcessIdentifiers.has(node.object)) {
4461
if (node.parent && node.parent.arguments && node.parent.arguments.length && node.parent.arguments[0].type !== 'Literal') {
4562
return context.report({ node: node, message: 'Found child_process.exec() with non Literal first argument' });
4663
}

test/detect-child-process.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,32 @@ tester.run(ruleName, rule, {
2525
code: "var child = sinon.stub(require('child_process')); child.exec.returns({});",
2626
errors: [{ message: 'Found require("child_process")' }],
2727
},
28+
{
29+
code: `
30+
var {} = require('child_process');
31+
var result = /hello/.exec(str);`,
32+
parserOptions: { ecmaVersion: 6 },
33+
errors: [{ message: 'Found require("child_process")', line: 2 }],
34+
},
35+
{
36+
code: `
37+
var foo = require('child_process');
38+
function fn () {
39+
var result = foo.exec(str);
40+
}`,
41+
errors: [
42+
{ message: 'Found require("child_process")', line: 2 },
43+
{ message: 'Found child_process.exec() with non Literal first argument', line: 4 },
44+
],
45+
},
46+
{
47+
code: `
48+
var foo = require('child_process');
49+
function fn () {
50+
var foo = /hello/;
51+
var result = foo.exec(str);
52+
}`,
53+
errors: [{ message: 'Found require("child_process")', line: 2 }],
54+
},
2855
],
2956
});

0 commit comments

Comments
 (0)