repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/strata/__serial__/core.test.ts
Rawimport { execFile } from "node:child_process";
import {
chmod,
copyFile,
mkdir,
mkdtemp,
readFile,
rm,
unlink,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { delimiter, dirname, join } from "node:path";
import { promisify } from "node:util";
import { afterEach, describe, expect, it } from "vitest";
import {
cleanGitEnvironment,
collectSnapshot,
gitForWindowsBinary,
gitText,
isProtectedPath,
MAX_PATCH_BYTES,
parseArgs,
} from "../git";
const execFileAsync = promisify(execFile);
const roots: string[] = [];
async function git(cwd: string, ...args: string[]): Promise<string> {
const { stdout } = await execFileAsync("git", args, {
cwd,
env: cleanGitEnvironment(),
encoding: "utf8",
maxBuffer: 2 * 1024 * 1024,
});
return stdout.trim();
}
async function repository(): Promise<string> {
const root = await mkdtemp(join(tmpdir(), "strata-git-"));
roots.push(root);
await git(root, "init", "--quiet");
await git(root, "config", "user.name", "Strata Test");
await git(root, "config", "user.email", "strata@example.invalid");
return root;
}
async function withFakeGit(
root: string,
program: string,
check: () => Promise<void>,
): Promise<void> {
const bin = join(root, "fake-bin");
await mkdir(bin);
const executable = join(
bin,
process.platform === "win32" ? "git.exe" : "git",
);
const previousOptions = process.env["NODE_OPTIONS"];
await copyFile(process.execPath, executable);
await chmod(executable, 0o755);
const preload = join(bin, "fake-git.cjs");
await writeFile(
preload,
`const original = process.argv.slice(1); original[0] = require("node:path").basename(original[0]); process.argv = [process.execPath, "fake-git", ...(process.execArgv.includes("-c") ? ["-c"] : []), ...original];\n${program}\nprocess.exit(process.exitCode ?? 0);`,
);
process.env["NODE_OPTIONS"] = `--require=${JSON.stringify(preload)}`;
const previous = process.env["PATH"];
process.env["PATH"] = `${bin}${delimiter}${previous ?? ""}`;
try {
await check();
} finally {
if (previous === undefined) delete process.env["PATH"];
else process.env["PATH"] = previous;
if (previousOptions === undefined) delete process.env["NODE_OPTIONS"];
else process.env["NODE_OPTIONS"] = previousOptions;
}
}
async function commitAll(root: string, message: string): Promise<string> {
await git(root, "add", "--all");
await git(root, "commit", "--quiet", "-m", message);
return git(root, "rev-parse", "HEAD");
}
afterEach(async () => {
await Promise.all(
roots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
);
});
describe("parseArgs", () => {
it("accepts only the documented sources and close", () => {
expect(parseArgs(" ")).toEqual({ kind: "working" });
expect(parseArgs("--staged")).toEqual({ kind: "staged" });
expect(parseArgs("--base trunk")).toEqual({ kind: "base", ref: "trunk" });
expect(parseArgs("--pr")).toEqual({ kind: "pr" });
expect(parseArgs("--pr 42")).toEqual({ kind: "pr", identifier: "42" });
expect(parseArgs("close")).toBe("close");
expect(() => parseArgs("cancel")).toThrow(/usage/);
expect(() => parseArgs("--base")).toThrow(/usage/);
expect(() => parseArgs("--base --output")).toThrow(/not an option/);
expect(() => parseArgs("--staged extra")).toThrow(/usage/);
});
});
describe("Git for Windows launcher", () => {
it.skipIf(process.platform !== "win32").each([
{ name: "cwd git.com", location: "cwd" },
{ name: "earlier PATH git.com", location: "earlier" },
{ name: "same-directory git.com", location: "launcher" },
])(
"selects $name before a validated runtime launcher",
async ({ location }) => {
const root = await mkdtemp(join(tmpdir(), "strata-git-com-"));
roots.push(root);
const cwd = join(root, "work");
const earlierPath = join(root, "earlier");
const launcherDirectory = join(root, "installation", "cmd");
const launcher = join(launcherDirectory, "git.exe");
const direct = join(root, "installation", "ucrt64", "bin", "git.exe");
const shadowDirectory =
location === "cwd"
? cwd
: location === "earlier"
? earlierPath
: launcherDirectory;
const shadow = join(shadowDirectory, "git.com");
const preload = join(root, "git-fixture.cjs");
await mkdir(cwd);
await mkdir(earlierPath);
await mkdir(launcherDirectory, { recursive: true });
await mkdir(dirname(direct), { recursive: true });
await copyFile(process.execPath, launcher);
await copyFile(process.execPath, direct);
await writeFile(
preload,
`const args = process.argv.slice(1); if (args.includes("--exec-path")) process.stdout.write(${JSON.stringify(join(root, "installation", "ucrt64", "libexec", "git-core"))} + "\\n"); else if (args.includes("version")) process.stdout.write("git version fixture\\n"); else process.stdout.write(process.execPath.toLowerCase().endsWith("git.com") ? "git.com fixture\\n" : "direct fixture\\n"); process.exit(0);`,
);
const previousPath = process.env["PATH"];
const previousOptions = process.env["NODE_OPTIONS"];
const testPath = [earlierPath, launcherDirectory].join(delimiter);
process.env["PATH"] = testPath;
process.env["NODE_OPTIONS"] = `--require=${JSON.stringify(preload)}`;
try {
expect(await gitText(cwd, [], 1024)).toBe("direct fixture\n");
await copyFile(process.execPath, shadow);
expect(process.env["PATH"]).toBe(testPath);
expect(await gitText(cwd, [], 1024)).toBe("git.com fixture\n");
} finally {
if (previousPath === undefined) delete process.env["PATH"];
else process.env["PATH"] = previousPath;
if (previousOptions === undefined) delete process.env["NODE_OPTIONS"];
else process.env["NODE_OPTIONS"] = previousOptions;
}
},
);
it("bypasses only a validated selected Git-for-Windows cmd launcher", async () => {
if (process.platform !== "win32") return;
const root = await mkdtemp(join(tmpdir(), "strata-git-launcher-"));
roots.push(root);
const launcher = join(root, "cmd", "git.exe");
const direct = join(root, "ucrt64", "bin", "git.exe");
const marker = join(root, "invocations");
await mkdir(join(root, "cmd"));
await mkdir(join(root, "ucrt64", "bin"), { recursive: true });
await copyFile(process.execPath, launcher);
await copyFile(process.execPath, direct);
const preload = join(root, "git-fixture.cjs");
await writeFile(
preload,
`const { appendFileSync } = require("node:fs"); const args = process.argv.slice(1); appendFileSync(${JSON.stringify(marker)}, process.execPath + " " + JSON.stringify(args) + "\\n"); if (args.some((arg) => arg === "version" || arg.endsWith("\\\\version"))) process.stdout.write(process.env.STRATA_GIT_MISMATCH && process.execPath === ${JSON.stringify(direct)} ? "git version other\\n" : "git version fixture\\n"); else if (args.includes("--exec-path")) process.stdout.write(${JSON.stringify(join(root, "ucrt64", "libexec", "git-core"))} + "\\n"); process.exit(0);`,
);
const previous = process.env["NODE_OPTIONS"];
const previousMismatch = process.env["STRATA_GIT_MISMATCH"];
process.env["NODE_OPTIONS"] = `--require=${JSON.stringify(preload)}`;
try {
const resolved = await gitForWindowsBinary(launcher);
expect(resolved).toBe(direct);
const invocations = (await readFile(marker, "utf8")).split(/\r?\n/u);
expect(invocations.some((line) => line.startsWith(launcher))).toBe(true);
expect(invocations.some((line) => line.startsWith(direct))).toBe(true);
process.env["STRATA_GIT_MISMATCH"] = "1";
expect(await gitForWindowsBinary(launcher)).toBe("git");
expect(await gitForWindowsBinary(join(root, "custom", "git.exe"))).toBe(
"git",
);
const controller = new AbortController();
controller.abort(new Error("cancelled identity probe"));
await expect(
gitForWindowsBinary(launcher, controller.signal),
).rejects.toThrow("cancelled identity probe");
} finally {
if (previous === undefined) delete process.env["NODE_OPTIONS"];
else process.env["NODE_OPTIONS"] = previous;
if (previousMismatch === undefined)
delete process.env["STRATA_GIT_MISMATCH"];
else process.env["STRATA_GIT_MISMATCH"] = previousMismatch;
}
});
});
describe("protected path filtering", () => {
it("classifies pure path strings without creating protected fixtures", () => {
expect(isProtectedPath("config/.env.production")).toBe(true);
expect(isProtectedPath("config/.env.production/cache/value.txt")).toBe(
true,
);
expect(isProtectedPath("home/.ssh/id_ed25519")).toBe(true);
expect(isProtectedPath("infra/secrets.auto.tfvars")).toBe(true);
expect(isProtectedPath(".config/gh/hosts.yml")).toBe(true);
expect(isProtectedPath(".pi/google-workspace/tokens/account.json")).toBe(
true,
);
expect(isProtectedPath("gcloud/legacy_credentials/account/token")).toBe(
true,
);
expect(isProtectedPath("pi/agent/auth.json")).toBe(true);
expect(isProtectedPath("ssh/deploy.key")).toBe(true);
expect(isProtectedPath("gh/hosts.yml")).toBe(true);
expect(isProtectedPath("keys/service.pem")).toBe(true);
expect(isProtectedPath("config/.env.example")).toBe(false);
expect(isProtectedPath("config/.env.example/schema/value.txt")).toBe(false);
expect(isProtectedPath("src/environment.ts")).toBe(false);
});
});
describe("collectSnapshot", () => {
it("captures text, additions, deletions, renames, metadata, and special paths while omitting binary and untracked files", async () => {
const root = await repository();
await Promise.all([
writeFile(join(root, "modify.txt"), "before\nshared\n"),
writeFile(join(root, "delete.txt"), "gone\n"),
writeFile(join(root, "rename-old.txt"), "renamed\n"),
writeFile(join(root, "script.sh"), "echo strata\n"),
writeFile(join(root, "space ü.txt"), "old special\n"),
writeFile(join(root, "-leading.txt"), "old leading\n"),
writeFile(join(root, "binary.bin"), Buffer.from([0, 1, 2, 3])),
]);
await commitAll(root, "initial");
await writeFile(join(root, "modify.txt"), "after\nshared\n");
await writeFile(join(root, "added.txt"), "added\n");
await git(root, "add", "--", "added.txt");
await unlink(join(root, "delete.txt"));
await git(root, "mv", "--", "rename-old.txt", "rename new.txt");
await writeFile(join(root, "space ü.txt"), "new special\n");
await writeFile(join(root, "-leading.txt"), "new leading\n");
await writeFile(join(root, "binary.bin"), Buffer.from([0, 9, 8, 7]));
await writeFile(
join(root, "scratch.todo"),
"untracked content is never read\n",
);
const snapshot = await collectSnapshot(root, { kind: "working" });
const paths = new Set(snapshot.hunks.map((hunk) => hunk.path));
expect(paths).toEqual(
new Set([
"-leading.txt",
"added.txt",
"binary.bin",
"delete.txt",
"modify.txt",
"rename new.txt",
"space ü.txt",
]),
);
expect(
snapshot.hunks.find((hunk) => hunk.path === "rename new.txt"),
).toMatchObject({
oldPath: "rename-old.txt",
header: "metadata",
});
const modified = snapshot.hunks.find((hunk) => hunk.path === "modify.txt");
expect(modified?.lines).toEqual([
{ kind: "delete", text: "before", oldLine: 1 },
{ kind: "add", text: "after", newLine: 1 },
{ kind: "context", text: "shared", oldLine: 2, newLine: 2 },
]);
expect(
snapshot.hunks.find((hunk) => hunk.path === "binary.bin"),
).toMatchObject({
header: "metadata",
lines: [
expect.objectContaining({
kind: "meta",
text: expect.stringMatching(/^Binary files /),
}),
],
});
expect(snapshot.skipped).toEqual([
{ path: "binary.bin", reason: "binary" },
{ path: "scratch.todo", reason: "untracked" },
]);
expect(snapshot.base).toMatch(/^[0-9a-f]{40,64}$/);
expect(snapshot.head).toBe(snapshot.base);
expect(snapshot.id).toMatch(/^[0-9a-f]{64}$/);
expect(new Set(snapshot.hunks.map((hunk) => hunk.id)).size).toBe(
snapshot.hunks.length,
);
const repeated = await collectSnapshot(root, { kind: "working" });
expect(repeated).toEqual(snapshot);
await writeFile(join(root, "another.todo"), "also omitted\n");
const changed = await collectSnapshot(root, { kind: "working" });
expect(changed.id).not.toBe(snapshot.id);
expect(changed.hunks.map((hunk) => hunk.id)).toEqual(
snapshot.hunks.map((hunk) => hunk.id),
);
});
it("pins the staged index and excludes unstaged changes", async () => {
const root = await repository();
await writeFile(join(root, "staged.txt"), "old staged\n");
await writeFile(join(root, "unstaged.txt"), "old unstaged\n");
await writeFile(join(root, "script.sh"), "echo strata\n");
const commit = await commitAll(root, "initial");
await writeFile(join(root, "staged.txt"), "new staged\n");
await git(root, "add", "--", "staged.txt");
await git(root, "update-index", "--chmod=+x", "script.sh");
await writeFile(join(root, "unstaged.txt"), "new unstaged\n");
const snapshot = await collectSnapshot(root, { kind: "staged" });
expect(snapshot.base).toBe(commit);
expect(snapshot.head).not.toBe(commit);
expect(snapshot.hunks.map((hunk) => hunk.path)).toEqual([
"script.sh",
"staged.txt",
]);
expect(snapshot.hunks[0]).toMatchObject({
path: "script.sh",
header: "metadata",
lines: [
{ kind: "meta", text: "old mode 100644" },
{ kind: "meta", text: "new mode 100755" },
],
});
expect(snapshot.skipped).toEqual([]);
});
it("preserves mode metadata alongside a textual hunk", async () => {
const root = await repository();
await writeFile(join(root, "script.sh"), "old\n");
await commitAll(root, "initial");
await writeFile(join(root, "script.sh"), "new\n");
await git(root, "add", "--", "script.sh");
await git(root, "update-index", "--chmod=+x", "script.sh");
const snapshot = await collectSnapshot(root, { kind: "staged" });
expect(snapshot.hunks).toHaveLength(1);
expect(snapshot.hunks[0]?.lines).toEqual([
{ kind: "meta", text: "old mode 100644" },
{ kind: "meta", text: "new mode 100755" },
{ kind: "delete", text: "old", oldLine: 1 },
{ kind: "add", text: "new", newLine: 1 },
]);
});
it("pins a merge-base-to-HEAD range and ignores working tree changes", async () => {
const root = await repository();
await writeFile(join(root, "committed.txt"), "first\n");
const first = await commitAll(root, "first");
await writeFile(join(root, "committed.txt"), "second\n");
const head = await commitAll(root, "second");
await writeFile(join(root, "committed.txt"), "working only\n");
const snapshot = await collectSnapshot(root, { kind: "base", ref: first });
expect(snapshot.base).toBe(first);
expect(snapshot.head).toBe(head);
expect(snapshot.hunks).toHaveLength(1);
expect(snapshot.hunks[0]?.lines).toContainEqual({
kind: "add",
text: "second",
newLine: 1,
});
expect(snapshot.hunks[0]?.lines).not.toContainEqual(
expect.objectContaining({ text: "working only" }),
);
});
it("accepts a quoted Git header without requiring an invalid Win32 filename on disk", async () => {
const root = await repository();
const path = 'safe "quoted"\tü.txt';
const patch = `diff --git ${JSON.stringify(`a/${path}`)} ${JSON.stringify(`b/${path}`)}\nindex 1..2 100644\n--- ${JSON.stringify(`a/${path}`)}\n+++ ${JSON.stringify(`b/${path}`)}\n@@ -1 +1 @@\n-old\n+new\n`;
await withFakeGit(
root,
`const args = process.argv.slice(2); const out = value => process.stdout.write(value);
if (args.includes("rev-parse")) out(args.includes("--show-toplevel") ? process.cwd() + "\\n" : "${"a".repeat(40)}\\n");
else if (args[0] === "ls-files") out(args.includes("--others") ? "" : ${JSON.stringify(`${path}\0`)});
else if (args[0] === "ls-tree") out(${JSON.stringify(`${path}\0`)});
else if (args.includes("--name-status")) out(${JSON.stringify(`M\0${path}\0`)});
else if (args.includes("--patch")) out(${JSON.stringify(patch)});`,
async () => {
const snapshot = await collectSnapshot(root, { kind: "working" });
expect(snapshot.hunks[0]).toMatchObject({
path,
lines: [
{ kind: "delete", text: "old", oldLine: 1 },
{ kind: "add", text: "new", newLine: 1 },
],
});
},
);
});
it("rejects a fake Git patch whose quoted header does not identify its metadata path", async () => {
const root = await repository();
await withFakeGit(
root,
`const args = process.argv.slice(2);
const out = (value) => process.stdout.write(value);
if (args.includes("rev-parse")) out(args.includes("--show-toplevel") ? process.cwd() + "\\n" : "${"a".repeat(40)}\\n");
else if (args[0] === "ls-files") out(args.includes("--others") ? "" : "safe \\"quoted\\"\\tü.txt\\0");
else if (args[0] === "ls-tree") out("safe \\"quoted\\"\\tü.txt\\0");
else if (args.includes("--name-status")) out("M\\0safe \\"quoted\\"\\tü.txt\\0");
else if (args.includes("--patch")) out("diff --git a/other.txt b/other.txt\\nindex 1..2 100644\\n--- a/other.txt\\n+++ b/other.txt\\n@@ -1 +1 @@\\n-old\\n+new\\n");`,
async () => {
await expect(
collectSnapshot(root, { kind: "working" }),
).rejects.toThrow(/patch header does not match metadata/);
},
);
});
it("rejects working snapshots when a fake Git manifest changes after the patch", async () => {
const root = await repository();
await withFakeGit(
root,
`const { existsSync, writeFileSync } = require("node:fs");
const { join } = require("node:path");
const args = process.argv.slice(2);
const marker = join(process.cwd(), ".strata-race");
const out = (value) => process.stdout.write(value);
if (args.includes("rev-parse")) out(args.includes("--show-toplevel") ? process.cwd() + "\\n" : "${"a".repeat(40)}\\n");
else if (args[0] === "ls-files") out(args.includes("--others") ? (existsSync(marker) ? "later.todo\\0" : "") : "before.txt\\0later.txt\\0");
else if (args[0] === "ls-tree") out("before.txt\\0later.txt\\0");
else if (args.includes("--name-status")) out(existsSync(marker) ? "M\\0later.txt\\0" : "M\\0before.txt\\0");
else if (args.includes("--patch")) { writeFileSync(marker, "changed"); out("diff --git a/before.txt b/before.txt\\nindex 1..2 100644\\n--- a/before.txt\\n+++ b/before.txt\\n@@ -1 +1 @@\\n-old\\n+new\\n"); }`,
async () => {
await expect(
collectSnapshot(root, { kind: "working" }),
).rejects.toThrow(/working tree changed during snapshot capture/);
},
);
});
it("excludes protected rename sides so the unprotected side remains reviewable", async () => {
const root = await repository();
await withFakeGit(
root,
`const args = process.argv.slice(2);
const out = (value) => process.stdout.write(value);
const protectedPath = "pi/agent/auth.json";
if (args.includes("rev-parse")) out(args.includes("--show-toplevel") ? process.cwd() + "\\n" : "${"a".repeat(40)}\\n");
else if (args[0] === "ls-files") out(args.includes("--others") ? "" : "public.txt\\0" + protectedPath + "\\0");
else if (args[0] === "ls-tree") out("public.txt\\0" + protectedPath + "\\0");
else if (args.includes("--name-status")) out("A\\0public.txt\\0M\\0" + protectedPath + "\\0");
else if (args.includes("--patch")) out("diff --git a/public.txt b/public.txt\\nnew file mode 100644\\nindex 0000000..1111111\\n--- /dev/null\\n+++ b/public.txt\\n@@ -0,0 +1 @@\\n+public\\n");`,
async () => {
const snapshot = await collectSnapshot(root, { kind: "working" });
expect(snapshot.hunks.map((hunk) => hunk.path)).toEqual(["public.txt"]);
expect(snapshot.skipped).toEqual([
{ path: "pi/agent/auth.json", reason: "protected path" },
]);
},
);
});
it("omits both sides of R100 renames touching protected paths", async () => {
const renames: Array<[from: string, to: string, skipped: string]> = [
["pi/agent/auth.json", "public.json", "public.json"],
["public.txt", "pi/agent/auth.json", "pi/agent/auth.json"],
];
for (const [from, to, skipped] of renames) {
const root = await repository();
await mkdir(dirname(join(root, from)), { recursive: true });
await writeFile(join(root, from), "unchanged\n");
await commitAll(root, `add ${from}`);
await mkdir(dirname(join(root, to)), { recursive: true });
await git(root, "mv", "--", from, to);
expect(
await git(
root,
"diff",
"--name-status",
"--find-renames=50%",
"-z",
"HEAD",
),
).toContain(`R100\0${from}\0${to}\0`);
const snapshot = await collectSnapshot(root, { kind: "working" });
expect(snapshot.hunks).toEqual([]);
expect(snapshot.skipped).toEqual([
{ path: skipped, reason: "protected path" },
]);
}
});
it("disables external diff commands and text conversion from repository config", async () => {
const root = await repository();
await writeFile(
join(root, ".gitattributes"),
"external.txt diff=external\nconverted.tc diff=converted\n",
);
await writeFile(join(root, "external.txt"), "old external\n");
await writeFile(join(root, "converted.tc"), "old conversion\n");
await commitAll(root, "initial");
await git(
root,
"config",
"diff.external.command",
"definitely-not-a-command",
);
await git(
root,
"config",
"diff.converted.textconv",
"definitely-not-a-command",
);
await writeFile(join(root, "external.txt"), "new external\n");
await writeFile(join(root, "converted.tc"), "new conversion\n");
const snapshot = await collectSnapshot(root, { kind: "working" });
expect(snapshot.hunks.map((hunk) => hunk.path)).toEqual([
"converted.tc",
"external.txt",
]);
});
it("ignores ambient Git repository redirection", async () => {
const root = await repository();
await writeFile(join(root, "tracked.txt"), "old\n");
await commitAll(root, "initial");
await writeFile(join(root, "tracked.txt"), "new\n");
const previous = process.env["GIT_DIR"];
process.env["GIT_DIR"] = join(root, "missing-git-dir");
try {
const snapshot = await collectSnapshot(root, { kind: "working" });
expect(snapshot.hunks.map((hunk) => hunk.path)).toEqual(["tracked.txt"]);
} finally {
if (previous === undefined) delete process.env["GIT_DIR"];
else process.env["GIT_DIR"] = previous;
}
});
it("refuses oversized patches instead of truncating", async () => {
const root = await repository();
await writeFile(join(root, "large.txt"), "small\n");
await commitAll(root, "initial");
await writeFile(
join(root, "large.txt"),
"x".repeat(MAX_PATCH_BYTES + 8_192),
);
await expect(collectSnapshot(root, { kind: "working" })).rejects.toThrow(
/byte limit/,
);
});
it("honors cancellation before collection", async () => {
const controller = new AbortController();
controller.abort(new Error("cancelled by test"));
await expect(
collectSnapshot("unused", { kind: "working" }, controller.signal),
).rejects.toThrow("cancelled by test");
});
});