From e02b24883808d8706670c530eeee0a47ac814b75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Jul 2026 06:19:23 +0000 Subject: [PATCH 1/2] Initial plan From 0d28aac89144f5ca5f98fedf362d7926e362d25c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Jul 2026 06:41:03 +0000 Subject: [PATCH 2/2] fix: detect inline require('child_process').() calls in no-child-process-interpolated-command Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../no-child-process-interpolated-command.test.ts | 14 ++++++++++++++ .../rules/no-child-process-interpolated-command.ts | 9 ++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/eslint-factory/src/rules/no-child-process-interpolated-command.test.ts b/eslint-factory/src/rules/no-child-process-interpolated-command.test.ts index b8eff0f5445..74d9f682a7d 100644 --- a/eslint-factory/src/rules/no-child-process-interpolated-command.test.ts +++ b/eslint-factory/src/rules/no-child-process-interpolated-command.test.ts @@ -23,6 +23,8 @@ describe("no-child-process-interpolated-command", () => { { code: `const { execSync } = require("child_process"); let cmd = \`git checkout \${branch}\`; cmd = "git status"; execSync(cmd);` }, { code: `const { execSync } = require("child_process"); (function(cmd) { execSync(cmd); })("git status");` }, { code: `exec.exec(\`git checkout \${branch}\`, []);` }, + { code: `require("child_process").execSync("git status");` }, + { code: `require("node:child_process").execSync(\`git status\`);` }, { code: `import { exec } from "node:child_process"; exec("git status");`, languageOptions: { sourceType: "module" }, @@ -89,6 +91,18 @@ describe("no-child-process-interpolated-command", () => { { messageId: "interpolatedCommand", data: { kind: "dynamic string concatenation", method: "exec" } }, ], }, + { + code: `require("child_process").execSync(\`rm -rf \${userInput}\`);`, + errors: [{ messageId: "interpolatedCommand", data: { kind: "interpolated template literal", method: "execSync" } }], + }, + { + code: `require("node:child_process").execSync("rm -rf " + userInput);`, + errors: [{ messageId: "interpolatedCommand", data: { kind: "dynamic string concatenation", method: "execSync" } }], + }, + { + code: `require("child_process").spawn(\`git checkout \${branch}\`, { shell: true });`, + errors: [{ messageId: "interpolatedCommand", data: { kind: "interpolated template literal", method: "spawn" } }], + }, ], }); }); diff --git a/eslint-factory/src/rules/no-child-process-interpolated-command.ts b/eslint-factory/src/rules/no-child-process-interpolated-command.ts index 8219b01b741..68106cc1cd8 100644 --- a/eslint-factory/src/rules/no-child-process-interpolated-command.ts +++ b/eslint-factory/src/rules/no-child-process-interpolated-command.ts @@ -133,7 +133,14 @@ function resolveChildProcessMethod(node: TSESTree.CallExpression, sourceCode: TS } if (callee.type !== AST_NODE_TYPES.MemberExpression || callee.computed) return null; - if (callee.object.type !== AST_NODE_TYPES.Identifier || callee.property.type !== AST_NODE_TYPES.Identifier) return null; + if (callee.property.type !== AST_NODE_TYPES.Identifier) return null; + + if (callee.object.type === AST_NODE_TYPES.CallExpression && isRequireChildProcess(callee.object)) { + const method = callee.property.name; + return method === "exec" || method === "execSync" || method === "spawn" || method === "spawnSync" || method === "execFile" || method === "execFileSync" ? method : null; + } + + if (callee.object.type !== AST_NODE_TYPES.Identifier) return null; if (!isChildProcessObjectBinding(callee.object.name, callee.object, sourceCode)) return null; const method = callee.property.name;