repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/strata/__tests__/core.test.ts
Rawimport { execFile } from "node:child_process";
import {
chmod,
copyFile,
mkdir,
mkdtemp,
rm,
unlink,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { delimiter, join } from "node:path";
import { promisify } from "node:util";
import { afterEach, describe, expect, it } from "vitest";
import {
cleanGitEnvironment,
collectSnapshot,
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 cancellation", () => {
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("cancel")).toBe("cancel");
expect(() => parseArgs("--base")).toThrow(/usage/);
expect(() => parseArgs("--base --output")).toThrow(/not an option/);
expect(() => parseArgs("--staged extra")).toThrow(/usage/);
});
});
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")) { if (!args.includes(":(exclude,literal)" + protectedPath)) process.exitCode = 2; else out("A\\0public.txt\\0"); }
else if (args.includes("--name-only")) out(protectedPath + "\\0");
else if (args.includes("--patch")) { if (!args.includes(":(exclude,literal)" + protectedPath)) process.exitCode = 2; else 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("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");
});
});