From b48be002e863e95b7004cb9048dd77e99832c64f Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sun, 30 Aug 2026 22:27:27 -0700 Subject: [PATCH 1/2] Disable inherited Git hooks in temporary test repositories Fixture commits inherit the operator core.hooksPath, so an allowed-emails hook can reject t@t.test and fail bun run check. Local identity plus an empty hooksPath keeps those hooks out without touching global config. --- src/agent/environment.test.ts | 9 +- src/permission/gate.test.ts | 9 +- src/permission/permission.test.ts | 13 +- src/session/project-key.test.ts | 5 +- src/session/session-dir.test.ts | 5 +- src/subagent/spawn-agent-worktree.test.ts | 5 +- src/subagent/task-tool-worktree.test.ts | 5 +- tests/helpers/temporary-git-repo.test.ts | 119 ++++++++++++++++++ tests/helpers/temporary-git-repo.ts | 33 +++++ tests/integration/git-push-scoped.test.ts | 5 +- .../unit/prepare-homebrew-tap-release.test.ts | 8 +- tests/unit/tui/at-mention-resolution.test.ts | 5 +- tests/unit/verify-corbits-only-scope.test.ts | 6 +- 13 files changed, 185 insertions(+), 42 deletions(-) create mode 100644 tests/helpers/temporary-git-repo.test.ts create mode 100644 tests/helpers/temporary-git-repo.ts diff --git a/src/agent/environment.test.ts b/src/agent/environment.test.ts index 17ab46ad6..91e74480b 100644 --- a/src/agent/environment.test.ts +++ b/src/agent/environment.test.ts @@ -6,6 +6,7 @@ import { join } from "node:path"; import { promisify } from "node:util"; import { gatherEnvironment, getGitBranch } from "./environment.js"; +import { initTemporaryGitRepo } from "../../tests/helpers/temporary-git-repo.js"; const run = promisify(execFile); @@ -22,9 +23,7 @@ test("gatherEnvironment detects a git work tree and lists its top level", async // a runner may check out a detached HEAD, which has no branch name. const dir = await mkdtemp(join(tmpdir(), "corbits-env-repo-")); try { - await run("git", ["init"], { cwd: dir }); - await run("git", ["config", "user.email", "t@t.test"], { cwd: dir }); - await run("git", ["config", "user.name", "t"], { cwd: dir }); + initTemporaryGitRepo(dir); await run("git", ["checkout", "-b", "trunk"], { cwd: dir }); await mkdir(join(dir, "src")); await writeFile(join(dir, "src", "seed.ts"), "export const seed = 1;\n"); @@ -43,9 +42,7 @@ test("gatherEnvironment detects a git work tree and lists its top level", async test("gatherEnvironment gathers branch and dirty status from the same work tree", async () => { const dir = await mkdtemp(join(tmpdir(), "corbits-env-")); try { - await run("git", ["init"], { cwd: dir }); - await run("git", ["config", "user.email", "t@t.test"], { cwd: dir }); - await run("git", ["config", "user.name", "t"], { cwd: dir }); + initTemporaryGitRepo(dir); await run("git", ["checkout", "-b", "trunk"], { cwd: dir }); await writeFile(join(dir, "seed.txt"), "seed"); await run("git", ["add", "."], { cwd: dir }); diff --git a/src/permission/gate.test.ts b/src/permission/gate.test.ts index 09344b153..835b2266a 100644 --- a/src/permission/gate.test.ts +++ b/src/permission/gate.test.ts @@ -8,6 +8,7 @@ import { createPermissionGate, isRequestCoveredByGrant, preGrantGuardReason } fr import { createPathRestriction } from "./path-restriction.js"; import { createWorktreeRootsProvider } from "./worktree-roots.js"; import type { Approval, PermissionRequest } from "./types.js"; +import { initTemporaryGitRepo } from "../../tests/helpers/temporary-git-repo.js"; const shellCall = (command: string): ToolCall => ({ id: "c", @@ -112,9 +113,7 @@ describe("grant coverage rebinds relative paths to the request process cwd", () const sessionCwd = join(root, "main"); const git = (args: string[], cwd: string) => execFileSync("git", args, { cwd, stdio: "ignore" }); mkdirSync(sessionCwd); - git(["init", "-q"], sessionCwd); - git(["config", "user.email", "t@example.com"], sessionCwd); - git(["config", "user.name", "t"], sessionCwd); + initTemporaryGitRepo(sessionCwd, { initArgs: ["-q"] }); writeFileSync(join(sessionCwd, "seed.txt"), "seed\n"); git(["add", "."], sessionCwd); git(["commit", "-qm", "seed"], sessionCwd); @@ -171,9 +170,7 @@ describe("standing grant covers a later git worktree command (CL-5638)", () => { const sessionCwd = join(root, "main"); const git = (args: string[], cwd: string) => execFileSync("git", args, { cwd, stdio: "ignore" }); mkdirSync(sessionCwd); - git(["init", "-q"], sessionCwd); - git(["config", "user.email", "t@example.com"], sessionCwd); - git(["config", "user.name", "t"], sessionCwd); + initTemporaryGitRepo(sessionCwd, { initArgs: ["-q"] }); writeFileSync(join(sessionCwd, "seed.txt"), "seed\n"); git(["add", "."], sessionCwd); git(["commit", "-qm", "seed"], sessionCwd); diff --git a/src/permission/permission.test.ts b/src/permission/permission.test.ts index b9aff9d81..5f6cdbc5a 100644 --- a/src/permission/permission.test.ts +++ b/src/permission/permission.test.ts @@ -28,6 +28,7 @@ import { import { listWorktreeRoots, createWorktreeRootsProvider } from "./worktree-roots.js"; import { createPathRestriction, resolveWorkspacePath } from "./path-restriction.js"; import type { Approval, PermissionRequest } from "./types.js"; +import { initTemporaryGitRepo } from "../../tests/helpers/temporary-git-repo.js"; import { secretGuardPlugin } from "../plugins/secret-guard-plugin.js"; import { pathEscapePlugin } from "../plugins/path-escape-plugin.js"; @@ -3275,8 +3276,8 @@ describe("listWorktreeRoots", () => { const repo = join(base, "repo"); const worktree = join(base, "secondary"); mkdirSync(repo); - git(repo, "init", "-b", "main"); - git(repo, "-c", "user.email=t@t", "-c", "user.name=t", "commit", "--allow-empty", "-m", "init"); + initTemporaryGitRepo(repo, { initArgs: ["-b", "main"] }); + git(repo, "commit", "--allow-empty", "-m", "init"); git(repo, "worktree", "add", worktree); return { repo, worktree }; }; @@ -3376,8 +3377,8 @@ describe("createWorktreeRootsProvider lazy re-discovery", () => { const base = mkdtempSync(join(tmpdir(), "corbits-lazy-")); const repo = join(base, "repo"); mkdirSync(repo); - git(repo, "init", "-b", "main"); - git(repo, "-c", "user.email=t@t", "-c", "user.name=t", "commit", "--allow-empty", "-m", "init"); + initTemporaryGitRepo(repo, { initArgs: ["-b", "main"] }); + git(repo, "commit", "--allow-empty", "-m", "init"); return repo; }; @@ -3707,8 +3708,8 @@ describe("project-scoped grants match sub-agent worktree requests (CL-5662)", () const repo = join(base, "repo"); const worktree = join(base, "sibling-worktree"); mkdirSync(repo); - git(repo, "init", "-b", "main"); - git(repo, "-c", "user.email=t@t", "-c", "user.name=t", "commit", "--allow-empty", "-m", "init"); + initTemporaryGitRepo(repo, { initArgs: ["-b", "main"] }); + git(repo, "commit", "--allow-empty", "-m", "init"); git(repo, "worktree", "add", worktree); return { repo, worktree }; }; diff --git a/src/session/project-key.test.ts b/src/session/project-key.test.ts index 0810d7e25..49f1fec88 100644 --- a/src/session/project-key.test.ts +++ b/src/session/project-key.test.ts @@ -6,6 +6,7 @@ import { tmpdir } from "node:os"; import { execFileSync } from "node:child_process"; import { projectKeyFor, projectRootFor, projectSessionsRoot, projectsRoot } from "./project-key.js"; +import { initTemporaryGitRepo } from "../../tests/helpers/temporary-git-repo.js"; let root = ""; @@ -19,9 +20,7 @@ afterEach(async () => { }); function initGitRepo(dir: string): void { - execFileSync("git", ["init"], { cwd: dir, stdio: "ignore" }); - execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: dir, stdio: "ignore" }); - execFileSync("git", ["config", "user.name", "test"], { cwd: dir, stdio: "ignore" }); + initTemporaryGitRepo(dir); } async function commitReadme(dir: string): Promise { diff --git a/src/session/session-dir.test.ts b/src/session/session-dir.test.ts index 7392979d5..71e98dd53 100644 --- a/src/session/session-dir.test.ts +++ b/src/session/session-dir.test.ts @@ -13,6 +13,7 @@ import { migrateLegacySessionIfNeeded, sessionDir, } from "./index.js"; +import { initTemporaryGitRepo } from "../../tests/helpers/temporary-git-repo.js"; let cwd = ""; let home = ""; @@ -84,9 +85,7 @@ test("listSessions finds legacy sessions and migrates them", async () => { test("migrateLegacySessionIfNeeded does not migrate main-repo .agent-state from a worktree cwd", async () => { const main = join(cwd, "main"); await mkdir(main, { recursive: true }); - execFileSync("git", ["init"], { cwd: main, stdio: "ignore" }); - execFileSync("git", ["config", "user.email", "test@example.com"], { cwd: main, stdio: "ignore" }); - execFileSync("git", ["config", "user.name", "test"], { cwd: main, stdio: "ignore" }); + initTemporaryGitRepo(main); await writeFile(join(main, "README"), "x"); execFileSync("git", ["add", "README"], { cwd: main, stdio: "ignore" }); execFileSync("git", ["commit", "-m", "init"], { cwd: main, stdio: "ignore" }); diff --git a/src/subagent/spawn-agent-worktree.test.ts b/src/subagent/spawn-agent-worktree.test.ts index a94f8f38b..2df032975 100644 --- a/src/subagent/spawn-agent-worktree.test.ts +++ b/src/subagent/spawn-agent-worktree.test.ts @@ -10,6 +10,7 @@ import { createSubAgentSessionStore } from "./session-store.js"; import { createPermissionGate } from "../permission/gate.js"; import type { RunSubAgentParams, RunSubAgentResult } from "./types.js"; import type { Telemetry } from "../telemetry/index.js"; +import { initTemporaryGitRepo } from "../../tests/helpers/temporary-git-repo.js"; const run = promisify(execFile); @@ -49,9 +50,7 @@ afterEach(async () => { async function makeRepo(): Promise { const dir = await mkdtemp(join(tmpdir(), "corbits-spawn-wt-")); - await run("git", ["init"], { cwd: dir }); - await run("git", ["config", "user.email", "t@t.test"], { cwd: dir }); - await run("git", ["config", "user.name", "t"], { cwd: dir }); + initTemporaryGitRepo(dir); await writeFile(join(dir, "seed.txt"), "seed"); await run("git", ["add", "."], { cwd: dir }); await run("git", ["commit", "-m", "seed"], { cwd: dir }); diff --git a/src/subagent/task-tool-worktree.test.ts b/src/subagent/task-tool-worktree.test.ts index f52e30535..3bb27fd04 100644 --- a/src/subagent/task-tool-worktree.test.ts +++ b/src/subagent/task-tool-worktree.test.ts @@ -9,6 +9,7 @@ import { createTaskTool } from "./task-tool.js"; import type { RunSubAgentParams } from "./types.js"; import { createPermissionGate } from "../permission/gate.js"; import type { Telemetry } from "../telemetry/index.js"; +import { initTemporaryGitRepo } from "../../tests/helpers/temporary-git-repo.js"; const run = promisify(execFile); @@ -51,9 +52,7 @@ async function callTask( async function makeRepo(): Promise { const dir = await mkdtemp(join(tmpdir(), "corbits-worktree-")); - await run("git", ["init"], { cwd: dir }); - await run("git", ["config", "user.email", "t@t.test"], { cwd: dir }); - await run("git", ["config", "user.name", "t"], { cwd: dir }); + initTemporaryGitRepo(dir); await writeFile(join(dir, "seed.txt"), "seed"); await run("git", ["add", "."], { cwd: dir }); await run("git", ["commit", "-m", "seed"], { cwd: dir }); diff --git a/tests/helpers/temporary-git-repo.test.ts b/tests/helpers/temporary-git-repo.test.ts new file mode 100644 index 000000000..0d85d3ec4 --- /dev/null +++ b/tests/helpers/temporary-git-repo.test.ts @@ -0,0 +1,119 @@ +import { afterEach, expect, test } from "bun:test"; +import { execFileSync } from "node:child_process"; +import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { initTemporaryGitRepo } from "./temporary-git-repo.js"; + +const tempRoots: string[] = []; + +afterEach(() => { + while (tempRoots.length > 0) { + const dir = tempRoots.pop(); + if (dir !== undefined) rmSync(dir, { recursive: true, force: true }); + } +}); + +function tempRoot(): string { + const dir = mkdtempSync(join(tmpdir(), "corbits-temp-git-")); + tempRoots.push(dir); + return dir; +} + +function rejectingHostConfig(root: string): { configPath: string; env: NodeJS.ProcessEnv } { + const hooksDir = join(root, "host-hooks"); + mkdirSync(hooksDir); + const preCommit = join(hooksDir, "pre-commit"); + writeFileSync(preCommit, "#!/bin/sh\necho 'host hook rejected fixture commit' >&2\nexit 1\n"); + chmodSync(preCommit, 0o755); + const configPath = join(root, "host-gitconfig"); + writeFileSync(configPath, `[core]\n\thooksPath = ${hooksDir}\n`); + return { + configPath, + env: { + ...process.env, + GIT_CONFIG_GLOBAL: configPath, + GIT_CONFIG_NOSYSTEM: "1", + }, + }; +} + +function gitStatus( + cwd: string, + args: string[], + env: NodeJS.ProcessEnv, +): { status: number; stderr: string } { + const proc = Bun.spawnSync(["git", ...args], { cwd, env, stdout: "pipe", stderr: "pipe" }); + return { + status: proc.exitCode ?? 1, + stderr: proc.stderr.toString(), + }; +} + +test("a naive fixture commit fails when the host config points at a rejecting hook", () => { + const root = tempRoot(); + const { env } = rejectingHostConfig(root); + const repo = join(root, "naive"); + mkdirSync(repo); + execFileSync("git", ["init"], { cwd: repo, env, stdio: "ignore" }); + execFileSync("git", ["config", "--local", "user.email", "t@t.test"], { + cwd: repo, + env, + stdio: "ignore", + }); + execFileSync("git", ["config", "--local", "user.name", "t"], { + cwd: repo, + env, + stdio: "ignore", + }); + const commit = gitStatus(repo, ["commit", "--allow-empty", "-m", "init"], env); + expect(commit.status).not.toBe(0); + expect(commit.stderr).toContain("host hook rejected fixture commit"); +}); + +test("initTemporaryGitRepo fixture commit succeeds under a rejecting host hooksPath", () => { + const root = tempRoot(); + const { configPath, env } = rejectingHostConfig(root); + const before = readFileSync(configPath, "utf8"); + const repo = join(root, "hermetic"); + mkdirSync(repo); + + initTemporaryGitRepo(repo); + + const commit = gitStatus(repo, ["commit", "--allow-empty", "-m", "init"], env); + expect(commit.status).toBe(0); + expect(commit.stderr).not.toContain("host hook rejected fixture commit"); + execFileSync("git", ["rev-parse", "HEAD"], { cwd: repo, env, stdio: "ignore" }); + expect(readFileSync(configPath, "utf8")).toBe(before); +}); + +test("initTemporaryGitRepo sets local identity and core.hooksPath without touching global config", () => { + const root = tempRoot(); + const { configPath, env } = rejectingHostConfig(root); + const before = readFileSync(configPath, "utf8"); + const repo = join(root, "local-only"); + mkdirSync(repo); + + initTemporaryGitRepo(repo); + + const email = execFileSync("git", ["config", "--local", "--get", "user.email"], { + cwd: repo, + env, + encoding: "utf8", + }).trim(); + const name = execFileSync("git", ["config", "--local", "--get", "user.name"], { + cwd: repo, + env, + encoding: "utf8", + }).trim(); + const hooksPath = execFileSync("git", ["config", "--local", "--get", "core.hooksPath"], { + cwd: repo, + env, + encoding: "utf8", + }).trim(); + expect(email).toBe("t@t.test"); + expect(name).toBe("t"); + expect(hooksPath.length).toBeGreaterThan(0); + expect(readFileSync(configPath, "utf8")).toBe(before); +}); diff --git a/tests/helpers/temporary-git-repo.ts b/tests/helpers/temporary-git-repo.ts new file mode 100644 index 000000000..90263534f --- /dev/null +++ b/tests/helpers/temporary-git-repo.ts @@ -0,0 +1,33 @@ +import { execFileSync } from "node:child_process"; +import { mkdirSync } from "node:fs"; +import { join } from "node:path"; + +export interface InitTemporaryGitRepoOpts { + /** Extra arguments after `git init` (`-b main`, `--bare`, `-q`). */ + initArgs?: readonly string[]; +} + +/** + * Initialize a throwaway Git repository for tests. + * + * Sets a local identity and points `core.hooksPath` at an empty directory + * inside the repo so machine-level hooks cannot reject fixture commits. + * Never writes global or system Git configuration and does not use + * `GIT_CONFIG_*` env workarounds. + */ +export function initTemporaryGitRepo(dir: string, opts: InitTemporaryGitRepoOpts = {}): void { + git(dir, "init", ...(opts.initArgs ?? [])); + const gitDir = execFileSync("git", ["rev-parse", "--absolute-git-dir"], { + cwd: dir, + encoding: "utf8", + }).trim(); + const hooksDir = join(gitDir, "corbits-no-hooks"); + mkdirSync(hooksDir, { recursive: true }); + git(dir, "config", "--local", "core.hooksPath", hooksDir); + git(dir, "config", "--local", "user.email", "t@t.test"); + git(dir, "config", "--local", "user.name", "t"); +} + +function git(cwd: string, ...args: string[]): void { + execFileSync("git", args, { cwd, stdio: "ignore" }); +} diff --git a/tests/integration/git-push-scoped.test.ts b/tests/integration/git-push-scoped.test.ts index 3c3c04a4f..47a589826 100644 --- a/tests/integration/git-push-scoped.test.ts +++ b/tests/integration/git-push-scoped.test.ts @@ -11,6 +11,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "bun:test"; +import { initTemporaryGitRepo } from "../helpers/temporary-git-repo.js"; const SCRIPT = join(import.meta.dir, "../../bin/git-push-scoped"); @@ -39,9 +40,7 @@ import { spawnSync } from "node:child_process"; function initWorkingRepo(name: string, remotePath: string): string { const path = join(root, name); mkdirSync(path); - spawnSync("git", ["init", "-q", "-b", "main", path]); - spawnSync("git", ["-C", path, "config", "user.email", "test@example.com"]); - spawnSync("git", ["-C", path, "config", "user.name", "Test"]); + initTemporaryGitRepo(path, { initArgs: ["-q", "-b", "main"] }); writeFileSync(join(path, "file.txt"), name); spawnSync("git", ["-C", path, "add", "file.txt"]); spawnSync("git", ["-C", path, "commit", "-q", "-m", "initial commit"]); diff --git a/tests/unit/prepare-homebrew-tap-release.test.ts b/tests/unit/prepare-homebrew-tap-release.test.ts index fe1c9ccbc..11e04d45b 100644 --- a/tests/unit/prepare-homebrew-tap-release.test.ts +++ b/tests/unit/prepare-homebrew-tap-release.test.ts @@ -5,6 +5,8 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { promisify } from "node:util"; +import { initTemporaryGitRepo } from "../helpers/temporary-git-repo.js"; + const execFileAsync = promisify(execFile); const script = join(import.meta.dir, "../../scripts/prepare-homebrew-tap-release.sh"); @@ -16,10 +18,10 @@ describe("prepare-homebrew-tap-release", () => { root = await mkdtemp(join(tmpdir(), "corbits-release-tap-")); const origin = join(root, "origin.git"); tapDir = join(root, "tap"); - await execFileAsync("git", ["init", "--bare", "--initial-branch=main", origin]); + await mkdir(origin); + initTemporaryGitRepo(origin, { initArgs: ["--bare", "--initial-branch=main"] }); await execFileAsync("git", ["clone", origin, tapDir]); - await execFileAsync("git", ["-C", tapDir, "config", "user.name", "Release Test"]); - await execFileAsync("git", ["-C", tapDir, "config", "user.email", "release@example.test"]); + initTemporaryGitRepo(tapDir); await mkdir(join(tapDir, "Formula")); await writeFile(join(tapDir, "Formula/corbits-code.rb"), "version one\n"); diff --git a/tests/unit/tui/at-mention-resolution.test.ts b/tests/unit/tui/at-mention-resolution.test.ts index aefc17076..de18e4748 100644 --- a/tests/unit/tui/at-mention-resolution.test.ts +++ b/tests/unit/tui/at-mention-resolution.test.ts @@ -5,6 +5,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { promisify } from "node:util"; import { resolveAtMentions } from "../../../src/tui/mention-resolution.js"; +import { initTemporaryGitRepo } from "../../helpers/temporary-git-repo.js"; const execFileAsync = promisify(execFile); @@ -224,9 +225,7 @@ describe("resolveAtMentions", () => { const worktree = await mkdtemp(join(tmpdir(), "at-mention-resolution-worktree-")); await rm(worktree, { recursive: true, force: true }); try { - await execFileAsync("git", ["init"], { cwd: repo }); - await execFileAsync("git", ["config", "user.email", "test@example.com"], { cwd: repo }); - await execFileAsync("git", ["config", "user.name", "Test"], { cwd: repo }); + initTemporaryGitRepo(repo); await writeFile(join(repo, "README.md"), "root\n"); await execFileAsync("git", ["add", "README.md"], { cwd: repo }); await execFileAsync("git", ["commit", "-m", "initial"], { cwd: repo }); diff --git a/tests/unit/verify-corbits-only-scope.test.ts b/tests/unit/verify-corbits-only-scope.test.ts index 92b39f742..1cd9c6dd8 100644 --- a/tests/unit/verify-corbits-only-scope.test.ts +++ b/tests/unit/verify-corbits-only-scope.test.ts @@ -3,6 +3,8 @@ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { tmpdir } from "node:os"; +import { initTemporaryGitRepo } from "../helpers/temporary-git-repo.js"; + const repoRoot = join(import.meta.dirname, "../.."); const scopeScript = join(repoRoot, "scripts/verify-corbits-only-scope.sh"); @@ -29,9 +31,7 @@ async function initGitRepo(dir: string): Promise { if (code !== 0) throw new Error(`git ${args.join(" ")} failed with ${code}`); }, ); - await run(["init"]); - await run(["config", "user.email", "scope-test@example.com"]); - await run(["config", "user.name", "scope-test"]); + initTemporaryGitRepo(dir); await writeFile(join(dir, "README.md"), "ok\n"); await run(["add", "README.md"]); await run(["commit", "-m", "init"]); From 423c8838f8320c952f55a629232a261cf55445d9 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Mon, 31 Aug 2026 07:28:13 -0700 Subject: [PATCH 2/2] Inline the temporary Git repo helper at remaining call sites --- src/session/project-key.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/session/project-key.test.ts b/src/session/project-key.test.ts index 49f1fec88..6e8e9c87a 100644 --- a/src/session/project-key.test.ts +++ b/src/session/project-key.test.ts @@ -19,10 +19,6 @@ afterEach(async () => { await rm(root, { recursive: true, force: true }); }); -function initGitRepo(dir: string): void { - initTemporaryGitRepo(dir); -} - async function commitReadme(dir: string): Promise { await writeFile(join(dir, "README"), "x"); execFileSync("git", ["add", "README"], { cwd: dir, stdio: "ignore" }); @@ -37,7 +33,7 @@ test("projectKeyFor is stable across calls for the same path", () => { }); test("projectKeyFor shares nested dirs under the same git toplevel", async () => { - initGitRepo(root); + initTemporaryGitRepo(root); await commitReadme(root); const nested = join(root, "nested", "deep"); @@ -48,7 +44,7 @@ test("projectKeyFor shares nested dirs under the same git toplevel", async () => }); test("linked worktrees have distinct project roots and keys from main and each other", async () => { - initGitRepo(root); + initTemporaryGitRepo(root); await commitReadme(root); const wtA = join(root, "..", `wt-a-${Date.now()}-${Math.random().toString(16).slice(2)}`);