Update tests

This commit is contained in:
Reinier Criel 2026-01-12 13:04:20 -08:00
parent a43c28fdec
commit 314de32bb3

View file

@ -55,141 +55,102 @@ describe("safeSpawn", () => {
mock.reset(); mock.reset();
}); });
it("should pass basic command and arguments correctly", async () => { // ============================================
// WINDOWS TESTS (shell: true, args as array)
// ============================================
it("should pass basic command and arguments correctly on Windows", async () => {
os = "win32";
await safeSpawn("echo", ["hello"]); await safeSpawn("echo", ["hello"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, "echo hello"); assert.strictEqual(spawnCalls[0].command, "echo");
assert.deepStrictEqual(spawnCalls[0].args, ["hello"]);
assert.strictEqual(spawnCalls[0].options.shell, true); assert.strictEqual(spawnCalls[0].options.shell, true);
}); });
it("should escape arguments containing spaces", async () => { it("should pass arguments with spaces correctly on Windows", async () => {
os = "win32";
await safeSpawn("echo", ["hello world"]); await safeSpawn("echo", ["hello world"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
// Argument should be escaped to prevent shell interpretation assert.strictEqual(spawnCalls[0].command, "echo");
assert.strictEqual(spawnCalls[0].command, 'echo "hello world"'); assert.deepStrictEqual(spawnCalls[0].args, ["hello world"]);
assert.strictEqual(spawnCalls[0].options.shell, true); assert.strictEqual(spawnCalls[0].options.shell, true);
}); });
it("should prevent shell injection attacks", async () => { it("should pass special characters safely on Windows", async () => {
await safeSpawn("ls", ["; rm test123.txt"]); os = "win32";
assert.strictEqual(spawnCalls.length, 1);
// Malicious command should be escaped to prevent execution
assert.strictEqual(spawnCalls[0].command, 'ls "; rm test123.txt"');
assert.strictEqual(spawnCalls[0].options.shell, true);
});
it("should escape single quotes in arguments", async () => {
await safeSpawn("echo", ["don't break"]);
assert.strictEqual(spawnCalls.length, 1);
// Single quote should be properly escaped with double quotes
assert.strictEqual(spawnCalls[0].command, 'echo "don\'t break"');
assert.strictEqual(spawnCalls[0].options.shell, true);
});
it("should handle double quotes with simpler escaping", async () => {
await safeSpawn("echo", ['say "hello"']);
assert.strictEqual(spawnCalls.length, 1);
// If we switch to double quotes, this should be: "say \"hello\""
assert.strictEqual(spawnCalls[0].command, 'echo "say \\"hello\\""');
assert.strictEqual(spawnCalls[0].options.shell, true);
});
it("should not escape arguments with only safe characters", async () => {
await safeSpawn("npm", ["install", "axios", "--save"]); await safeSpawn("npm", ["install", "axios", "--save"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
// Safe arguments (alphanumeric, dash, underscore, dot, slash) shouldn't be quoted assert.strictEqual(spawnCalls[0].command, "npm");
assert.strictEqual(spawnCalls[0].command, "npm install axios --save"); assert.deepStrictEqual(spawnCalls[0].args, ["install", "axios", "--save"]);
assert.strictEqual(spawnCalls[0].options.shell, true); assert.strictEqual(spawnCalls[0].options.shell, true);
}); });
it(`should escape ampersand character`, async () => { it("should handle Python version specifiers with comparison operators on Windows", async () => {
await safeSpawn("npx", ["cypress", "run", "--env", "password=foo&bar"]); os = "win32";
await safeSpawn("pip3", ["install", "Jinja2>=3.1,<3.2"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
// & should be escaped by wrapping the arg in quotes assert.strictEqual(spawnCalls[0].command, "pip3");
assert.strictEqual( assert.deepStrictEqual(spawnCalls[0].args, ["install", "Jinja2>=3.1,<3.2"]);
spawnCalls[0].command,
'npx cypress run --env "password=foo&bar"'
);
assert.strictEqual(spawnCalls[0].options.shell, true); assert.strictEqual(spawnCalls[0].options.shell, true);
}); });
it("should escape dollar signs to prevent variable expansion", async () => { it("should handle Python not-equal version specifiers on Windows", async () => {
await safeSpawn("echo", ["$HOME/test"]); os = "win32";
await safeSpawn("pip3", ["install", "idna!=3.5,>=3.0"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'echo "\\$HOME/test"'); assert.strictEqual(spawnCalls[0].command, "pip3");
assert.deepStrictEqual(spawnCalls[0].args, ["install", "idna!=3.5,>=3.0"]);
assert.strictEqual(spawnCalls[0].options.shell, true);
}); });
it("should escape backticks to prevent command substitution", async () => { it("should handle Python extras with square brackets on Windows", async () => {
await safeSpawn("echo", ["file`whoami`.txt"]); os = "win32";
await safeSpawn("pip3", ["install", "requests[socks]"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'echo "file\\`whoami\\`.txt"'); assert.strictEqual(spawnCalls[0].command, "pip3");
assert.deepStrictEqual(spawnCalls[0].args, ["install", "requests[socks]"]);
assert.strictEqual(spawnCalls[0].options.shell, true);
}); });
it("should escape backslashes properly", async () => { // ============================================
await safeSpawn("echo", ["path\\with\\backslash"]); // UNIX TESTS (no shell, args as array)
// ============================================
it("should resolve full path and pass args as array on Unix", async () => {
os = "darwin";
await safeSpawn("npm", ["install", "axios"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual( assert.strictEqual(spawnCalls[0].command, "/usr/bin/npm");
spawnCalls[0].command, assert.deepStrictEqual(spawnCalls[0].args, ["install", "axios"]);
'echo "path\\\\with\\\\backslash"' assert.deepStrictEqual(spawnCalls[0].options, {});
);
}); });
it("should handle multiple special characters in one argument", async () => { it("should handle Python version specifiers with comparison operators on Unix", async () => {
await safeSpawn("cmd", ['test "quoted" $var `cmd` & more']); os = "darwin";
await safeSpawn("pip3", ["install", "Jinja2>=3.1,<3.2"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual( assert.strictEqual(spawnCalls[0].command, "/usr/bin/pip3");
spawnCalls[0].command, assert.deepStrictEqual(spawnCalls[0].args, ["install", "Jinja2>=3.1,<3.2"]);
'cmd "test \\"quoted\\" \\$var \\`cmd\\` & more"' assert.deepStrictEqual(spawnCalls[0].options, {});
);
}); });
it("should handle pipe character", async () => { it("should handle Python version specifiers with comparison operators on Unix", async () => {
await safeSpawn("echo", ["foo|bar"]); os = "darwin";
await safeSpawn("pip3", ["install", "Jinja2>=3.1,<3.2"]);
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'echo "foo|bar"'); assert.strictEqual(spawnCalls[0].command, "/usr/bin/pip3");
}); assert.deepStrictEqual(spawnCalls[0].args, ["install", "Jinja2>=3.1,<3.2"]);
assert.deepStrictEqual(spawnCalls[0].options, {});
it("should handle parentheses", async () => {
await safeSpawn("echo", ["(test)"]);
assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'echo "(test)"');
});
it("should handle angle brackets for redirection", async () => {
await safeSpawn("echo", ["foo>output.txt"]);
assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'echo "foo>output.txt"');
});
it("should handle wildcard characters", async () => {
await safeSpawn("echo", ["*.txt"]);
assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'echo "*.txt"');
});
it("should handle multiple arguments with mixed escaping needs", async () => {
await safeSpawn("cmd", ["safe", "needs space", "$dangerous", "also-safe"]);
assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(
spawnCalls[0].command,
'cmd safe "needs space" "\\$dangerous" also-safe'
);
}); });
it("should reject command names with special characters", async () => { it("should reject command names with special characters", async () => {
@ -216,43 +177,4 @@ describe("safeSpawn", () => {
assert.strictEqual(spawnCalls.length, 1); assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, "valid_command-123"); assert.strictEqual(spawnCalls[0].command, "valid_command-123");
}); });
it("should handle Python version specifiers with comparison operators on Windows", async () => {
os = "win32";
await safeSpawn("pip3", ["install", "Jinja2>=3.1,<3.2"]);
assert.strictEqual(spawnCalls.length, 1);
// On Windows, args are built into a command string with proper escaping
assert.strictEqual(spawnCalls[0].command, 'pip3 install "Jinja2>=3.1,<3.2"');
assert.strictEqual(spawnCalls[0].options.shell, true);
});
it("should handle Python version specifiers with comparison operators on Unix", async () => {
os = "darwin"; // or "linux"
await safeSpawn("pip3", ["install", "Jinja2>=3.1,<3.2"]);
assert.strictEqual(spawnCalls.length, 1);
// On Unix, resolves full path and passes args as array (no shell interpretation)
assert.strictEqual(spawnCalls[0].command, "/usr/bin/pip3");
assert.deepStrictEqual(spawnCalls[0].args, ["install", "Jinja2>=3.1,<3.2"]);
assert.deepStrictEqual(spawnCalls[0].options, {});
});
it("should handle Python not-equal version specifiers", async () => {
os = "win32";
await safeSpawn("pip3", ["install", "idna!=3.5,>=3.0"]);
assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'pip3 install "idna!=3.5,>=3.0"');
assert.strictEqual(spawnCalls[0].options.shell, true);
});
it("should handle Python extras with square brackets", async () => {
os = "win32";
await safeSpawn("pip3", ["install", "requests[socks]"]);
assert.strictEqual(spawnCalls.length, 1);
assert.strictEqual(spawnCalls[0].command, 'pip3 install "requests[socks]"');
assert.strictEqual(spawnCalls[0].options.shell, true);
});
}); });