Files
music_library/.pi/extensions/sensitive-file-guard/extractCommandNames.test.ts
T
2026-05-11 22:26:38 +01:00

313 lines
9.1 KiB
TypeScript

/**
* Tests for extractCommandNames from ast.ts using Node.js built-in node:test runner.
*
* Run with: node --experimental-strip-types --test extractCommandNames.test.ts
*/
import { describe, it } from "node:test";
import * as assert from "node:assert/strict";
import { extractCommandNames } from "./ast.ts";
// ── Test helpers ────────────────────────────────────────────────────────────
const blocked = new Set(["printenv", "env"]);
function checkBlocked(
cmd: string,
expected: "BLOCKED" | "ALLOWED",
_reason: string,
): void {
const names = extractCommandNames(cmd);
const hasBlocked = [...names].some((n) => blocked.has(n));
const actual = hasBlocked ? "BLOCKED" : "ALLOWED";
assert.equal(
actual,
expected,
`cmd: "${cmd}" — names found: [${[...names].join(", ")}]`,
);
}
// ── BLOCKED: Simple commands ────────────────────────────────────────────────
describe("extractCommandNames — simple commands", () => {
it("blocks a simple blocked command", () => {
checkBlocked("printenv", "BLOCKED", "Simple command match");
});
it("blocks env with prefix assignment", () => {
checkBlocked("env FOO=bar", "BLOCKED", "Simple command match");
});
it("blocks printenv with assignment prefix", () => {
checkBlocked(
"FOO=bar printenv",
"BLOCKED",
"Assignment prefix — printenv is still the command",
);
});
it("blocks env with assignment prefix", () => {
checkBlocked(
"FOO=bar env",
"BLOCKED",
"Assignment prefix — env is still the command",
);
});
});
// ── BLOCKED: Command substitution ──────────────────────────────────────────
describe("extractCommandNames — command substitution", () => {
it("blocks $(env)", () => {
checkBlocked("$(env)", "BLOCKED", "Command substitution");
});
it("blocks $(printenv)", () => {
checkBlocked("$(printenv)", "BLOCKED", "Command substitution");
});
it("blocks backtick env", () => {
checkBlocked("`env`", "BLOCKED", "Backtick command substitution");
});
it("blocks env inside command substitution in echo argument", () => {
checkBlocked(
"echo $(env)",
"BLOCKED",
"env inside command substitution in echo argument",
);
});
it("blocks env inside command substitution in assignment value", () => {
checkBlocked(
"FOO=$(env) echo hi",
"BLOCKED",
"env inside command substitution in assignment value",
);
});
});
// ── BLOCKED: Subshell ──────────────────────────────────────────────────────
describe("extractCommandNames — subshell", () => {
it("blocks env in subshell", () => {
checkBlocked("(env)", "BLOCKED", "Subshell — env runs inside");
});
});
// ── BLOCKED: Pipeline ──────────────────────────────────────────────────────
describe("extractCommandNames — pipeline", () => {
it("blocks env as first command in pipeline", () => {
checkBlocked(
"env | grep FOO",
"BLOCKED",
"Pipeline — env is first command",
);
});
it("blocks env as second command in pipeline", () => {
checkBlocked(
"grep FOO | env",
"BLOCKED",
"Pipeline — env is second command",
);
});
it("blocks both blocked commands in pipeline", () => {
checkBlocked(
"printenv | env",
"BLOCKED",
"Both blocked commands in pipeline",
);
});
});
// ── BLOCKED: Compound lists and control flow ───────────────────────────────
describe("extractCommandNames — compound lists and control flow", () => {
it("blocks env in for loop body", () => {
checkBlocked("for f in *; do env; done", "BLOCKED", "env in for loop body");
});
it("blocks env in for wordlist command substitution", () => {
checkBlocked(
"for f in $(env); do echo $f; done",
"BLOCKED",
"env in for wordlist command substitution",
);
});
it("blocks env in arithmetic for", () => {
checkBlocked(
"for ((i=0;i<10;i++)); do env; done",
"BLOCKED",
"env in arithmetic for",
);
});
it("blocks env in while body", () => {
checkBlocked("while true; do env; done", "BLOCKED", "env in while body");
});
it("blocks env in until body (parsed as While with kind:until)", () => {
checkBlocked(
"until false; do env; done",
"BLOCKED",
"env in until body (parsed as While with kind:until)",
);
});
it("blocks env in if-then", () => {
checkBlocked("if true; then env; fi", "BLOCKED", "env in if-then");
});
it("blocks env in case body", () => {
checkBlocked("case x in a) env;; esac", "BLOCKED", "env in case body");
});
it("blocks env in Case.word substitution", () => {
checkBlocked(
"case $(env) in a) echo hi;; esac",
"BLOCKED",
"env in Case.word substitution",
);
});
it("blocks env in AndOr (&&)", () => {
checkBlocked("true && env", "BLOCKED", "env in AndOr (&&)");
});
it("blocks env in select wordlist", () => {
checkBlocked(
"select f in $(env); do echo $f; done",
"BLOCKED",
"env in select wordlist",
);
});
});
// ── BLOCKED: Function definition, brace group, coproc ──────────────────────
describe("extractCommandNames — function, brace, coproc", () => {
it("blocks env in function body", () => {
checkBlocked("foo() { env; }", "BLOCKED", "env in function body");
});
it("blocks env in brace group", () => {
checkBlocked("{ env; }", "BLOCKED", "env in brace group");
});
it("blocks env in coproc body", () => {
checkBlocked("coproc env", "BLOCKED", "env in coproc body");
});
});
// ── ALLOWED: Blocked name at non-executable position ───────────────────────
describe("extractCommandNames — blocked name not at executable position", () => {
it("allows printenv as argument to echo", () => {
checkBlocked(
"echo printenv",
"ALLOWED",
"printenv is an argument to echo, not a command",
);
});
it("allows printenv in comment", () => {
checkBlocked("# printenv", "ALLOWED", "Comment — not executed");
});
it("allows env in double-quoted string", () => {
checkBlocked(
'echo "use env to..."',
"ALLOWED",
"Inside double-quoted string",
);
});
it("allows printenv in single-quoted string", () => {
checkBlocked("echo 'printenv'", "ALLOWED", "Inside single-quoted string");
});
it("allows printenv as argument to echo inside subshell", () => {
checkBlocked(
"(echo printenv)",
"ALLOWED",
"printenv is argument to echo inside subshell",
);
});
it("allows env as argument to echo inside command substitution", () => {
checkBlocked(
"$(echo env)",
"ALLOWED",
"env is argument to echo inside command substitution",
);
});
it("allows env in double-quoted string in pipeline", () => {
checkBlocked(
'echo "use env" | grep FOO',
"ALLOWED",
"env in double-quoted string in pipeline",
);
});
});
// ── ALLOWED: Command not in blocked set ────────────────────────────────────
describe("extractCommandNames — command not in blocked set", () => {
it("allows export", () => {
checkBlocked(
"export FOO=bar",
"ALLOWED",
"export is not in blocked_commands",
);
});
it("allows ls", () => {
checkBlocked("ls -la", "ALLOWED", "ls is not in blocked_commands");
});
it("allows semicolon-separated harmless commands", () => {
checkBlocked(
"echo hi; echo there",
"ALLOWED",
"Semicolon-separated harmless commands",
);
});
it("allows OR-separated harmless commands", () => {
checkBlocked(
"echo hi || echo fail",
"ALLOWED",
"Or-separated harmless commands",
);
});
it("allows TestCommand ([[ ... ]])", () => {
checkBlocked(
"[[ -f file ]]",
"ALLOWED",
"TestCommand — no commands executed",
);
});
});
// ── ALLOWED: No command at all ─────────────────────────────────────────────
describe("extractCommandNames — no command at all", () => {
it("allows empty command", () => {
checkBlocked("", "ALLOWED", "Empty command");
});
it("allows bare assignment with no command name", () => {
checkBlocked("FOO=bar", "ALLOWED", "Bare assignment, no command name");
});
it("allows redirection only with no command name", () => {
checkBlocked(">/dev/null", "ALLOWED", "Redirection only, no command name");
});
});