Preserve the original #39 fix while adding the missing hardening and regression coverage. Credit to @LuxVTZ for the original fix incorporated here.
73 lines
2.7 KiB
TypeScript
73 lines
2.7 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { chmodSync, existsSync, lstatSync, mkdtempSync, mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { tmpdir } from "node:os";
|
|
|
|
import { ensureManagedTools, resolveToolFromPath } from "../tool-bootstrap.js";
|
|
|
|
function makeExecutable(dir: string, name: string, content = "#!/bin/sh\nexit 0\n"): string {
|
|
const file = join(dir, name);
|
|
writeFileSync(file, content);
|
|
chmodSync(file, 0o755);
|
|
return file;
|
|
}
|
|
|
|
test("resolveToolFromPath finds fd via fdfind fallback", () => {
|
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-tool-bootstrap-resolve-"));
|
|
try {
|
|
makeExecutable(tmp, "fdfind");
|
|
const resolved = resolveToolFromPath("fd", tmp);
|
|
assert.equal(resolved, join(tmp, "fdfind"));
|
|
} finally {
|
|
rmSync(tmp, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("ensureManagedTools provisions fd and rg into managed bin dir", () => {
|
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-tool-bootstrap-provision-"));
|
|
const sourceBin = join(tmp, "source-bin");
|
|
const targetBin = join(tmp, "target-bin");
|
|
|
|
mkdirSync(sourceBin, { recursive: true });
|
|
mkdirSync(targetBin, { recursive: true });
|
|
|
|
try {
|
|
makeExecutable(sourceBin, "fdfind");
|
|
makeExecutable(sourceBin, "rg");
|
|
|
|
const provisioned = ensureManagedTools(targetBin, sourceBin);
|
|
|
|
assert.equal(provisioned.length, 2);
|
|
assert.ok(existsSync(join(targetBin, "fd")));
|
|
assert.ok(existsSync(join(targetBin, "rg")));
|
|
assert.ok(lstatSync(join(targetBin, "fd")).isSymbolicLink() || lstatSync(join(targetBin, "fd")).isFile());
|
|
assert.ok(lstatSync(join(targetBin, "rg")).isSymbolicLink() || lstatSync(join(targetBin, "rg")).isFile());
|
|
} finally {
|
|
rmSync(tmp, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("ensureManagedTools copies executable when symlink target already exists as a broken link", () => {
|
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-tool-bootstrap-copy-"));
|
|
const sourceBin = join(tmp, "source-bin");
|
|
const targetBin = join(tmp, "target-bin");
|
|
const targetFd = join(targetBin, "fd");
|
|
|
|
mkdirSync(sourceBin, { recursive: true });
|
|
mkdirSync(targetBin, { recursive: true });
|
|
|
|
try {
|
|
makeExecutable(sourceBin, "fdfind", "#!/bin/sh\necho fd\n");
|
|
makeExecutable(sourceBin, "rg", "#!/bin/sh\necho rg\n");
|
|
symlinkSync(join(tmp, "missing-target"), targetFd);
|
|
|
|
const provisioned = ensureManagedTools(targetBin, sourceBin);
|
|
|
|
assert.equal(provisioned.length, 2);
|
|
assert.ok(lstatSync(targetFd).isFile(), "fd fallback should replace broken symlink with a copied file");
|
|
assert.match(readFileSync(targetFd, "utf8"), /echo fd/);
|
|
} finally {
|
|
rmSync(tmp, { recursive: true, force: true });
|
|
}
|
|
});
|