tests / tools.test.ts
import { strict as assert } from "assert";
import { existsSync, writeFileSync, mkdirSync, rmSync, readFileSync } from "fs";
import { join } from "path";
import { isPathSafe, BLOCKED_DIRS, MAX_FILE_SIZE } from "../src/safety";
const TMP_TEST_DIR = join(__dirname, "..", "tmp-test");
function setup() {
rmSync(TMP_TEST_DIR, { recursive: true, force: true });
mkdirSync(TMP_TEST_DIR, { recursive: true });
mkdirSync(join(TMP_TEST_DIR, "subdir"), { recursive: true });
writeFileSync(join(TMP_TEST_DIR, "hello.txt"), "Hello, World!");
writeFileSync(join(TMP_TEST_DIR, "largfile.bin"), Buffer.alloc(MAX_FILE_SIZE + 1, 0x42));
}
function teardown() {
rmSync(TMP_TEST_DIR, { recursive: true, force: true });
}
// ββ Section 2: Tool Safety β Path Traversal ββββββββββββββββββββββββββ
function test_blocked_absolute_sysdir() {
const r = isPathSafe("C:\\Windows\\System32\\config\\SAM", TMP_TEST_DIR);
assert.equal(r.safe, false, "Should block system dir access");
assert.ok(r.reason!.includes("C:\\Windows"), "Reason should mention blocked dir");
console.log(" PASS: blocked_absolute_sysdir");
}
function test_parent_traversal() {
const resolved = join(TMP_TEST_DIR, "..\\..\\..\\Windows\\win.ini");
const r = isPathSafe(resolved, TMP_TEST_DIR);
assert.equal(r.safe, false, "Should block parent traversal into system dir");
console.log(" PASS: parent_traversal");
}
function test_unicode_traversal() {
const r1 = isPathSafe(join(TMP_TEST_DIR, "..\\..\\etc\\passwd"), TMP_TEST_DIR);
const r2 = isPathSafe(join(TMP_TEST_DIR, "..\\..\\..\\etc\\passwd"), TMP_TEST_DIR);
assert.equal(r1.safe || r2.safe, false, "Should block unicode-style traversal");
console.log(" PASS: unicode_traversal");
}
function test_write_to_system() {
const r = isPathSafe("C:\\Windows\\System32\\evil.dll", TMP_TEST_DIR);
assert.equal(r.safe, false, "Should block write to system dir");
console.log(" PASS: write_to_system");
}
function test_write_with_traversal() {
const resolved = join(TMP_TEST_DIR, "..\\..\\..\\tmp\\malware.exe");
const r = isPathSafe(resolved, TMP_TEST_DIR);
assert.equal(r.safe, false, "Should block traversal write outside wd");
console.log(" PASS: write_with_traversal");
}
// ββ Section 3: Resource & Isolation βββββββββββββββββββββββββββββββββ
function test_blocked_dirs_comprehensive() {
for (const dir of BLOCKED_DIRS) {
const r = isPathSafe(join(dir, "some\\file.txt"), TMP_TEST_DIR);
assert.equal(r.safe, false, `Should block ${dir}`);
}
console.log(` PASS: blocked_dirs_comprehensive (${BLOCKED_DIRS.length} dirs)`);
}
function test_working_dir_allowed() {
const r = isPathSafe(join(TMP_TEST_DIR, "hello.txt"), TMP_TEST_DIR);
assert.equal(r.safe, true, "Should allow files in working dir");
console.log(" PASS: working_dir_allowed");
}
function test_allow_subdir() {
const r = isPathSafe(join(TMP_TEST_DIR, "subdir", "foo.txt"), TMP_TEST_DIR);
assert.equal(r.safe, true, "Should allow subdirs of working dir");
console.log(" PASS: allow_subdir");
}
// ββ Section 6: Functional Reliability ββββββββββββββββββββββββββββββββ
function test_idempotent_write() {
const p = join(TMP_TEST_DIR, "idempotent.txt");
writeFileSync(p, "content");
writeFileSync(p, "content");
const data = readFileSync(p, "utf-8");
assert.equal(data, "content", "Second write should not corrupt");
console.log(" PASS: idempotent_write");
}
function test_missing_dir_write() {
const p = join(TMP_TEST_DIR, "newdir", "nested", "file.txt");
mkdirSync(join(TMP_TEST_DIR, "newdir", "nested"), { recursive: true });
writeFileSync(p, "deep content");
assert.equal(existsSync(p), true, "Should create parent dirs and write file");
console.log(" PASS: missing_dir_write");
}
function test_encoding_utf8() {
const p = join(TMP_TEST_DIR, "utf8.txt");
const content = "Hello, δΈη! π";
writeFileSync(p, content, "utf-8");
const read = readFileSync(p, "utf-8");
assert.equal(read, content, "UTF-8 content should be preserved");
console.log(" PASS: encoding_utf8");
}
// ββ Run All ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
let passed = 0;
let failed = 0;
function run(name: string, fn: () => void) {
try {
console.log(`\n[${name}]`);
fn();
passed++;
} catch (e: any) {
console.log(` FAIL: ${name} β ${e.message}`);
failed++;
}
}
console.log("βββ Tool Safety Tests βββ");
setup();
const tests = [
["blocked_absolute_sysdir", test_blocked_absolute_sysdir],
["parent_traversal", test_parent_traversal],
["unicode_traversal", test_unicode_traversal],
["write_to_system", test_write_to_system],
["write_with_traversal", test_write_with_traversal],
["blocked_dirs_comprehensive", test_blocked_dirs_comprehensive],
["working_dir_allowed", test_working_dir_allowed],
["allow_subdir", test_allow_subdir],
["idempotent_write", test_idempotent_write],
["missing_dir_write", test_missing_dir_write],
["encoding_utf8", test_encoding_utf8],
];
for (const [name, fn] of tests) {
run(name as string, fn as () => void);
}
teardown();
console.log(`\nβββ Results: ${passed} passed, ${failed} failed βββ`);
process.exit(failed > 0 ? 1 : 0);