From 98b0009206121d6098f361edb794a5186ca3b707 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sat, 5 Sep 2026 19:57:19 +0200 Subject: [PATCH] fix(git): isolate catalog commands from parent hook environment --- src/lib/services/catalog-git-core.test.ts | 7 ++++++- src/lib/services/catalog-git-core.ts | 7 ++++++- .../services/git-process-environment.test.ts | 20 +++++++++++++++++++ src/lib/services/git-process-environment.ts | 19 ++++++++++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 src/lib/services/git-process-environment.test.ts create mode 100644 src/lib/services/git-process-environment.ts diff --git a/src/lib/services/catalog-git-core.test.ts b/src/lib/services/catalog-git-core.test.ts index fc19e119..6f871fa7 100644 --- a/src/lib/services/catalog-git-core.test.ts +++ b/src/lib/services/catalog-git-core.test.ts @@ -9,6 +9,7 @@ import { recoverCatalogQueue, sqlValue, } from "./catalog-git-core"; +import { gitProcessEnvironment } from "./git-process-environment"; describe("catalog export", () => { it("recovers queue entries owned by a terminated local process", async () => { @@ -55,7 +56,11 @@ describe("catalog export", () => { const remote = path.join(root, "remote.git"); const checkout = path.join(root, "checkout"); const git = (cwd: string, ...args: string[]) => - execFileSync("git", args, { cwd, encoding: "utf8" }).trim(); + execFileSync("git", args, { + cwd, + encoding: "utf8", + env: gitProcessEnvironment(), + }).trim(); git(root, "init", "--bare", remote); git(root, "clone", remote, checkout); git(checkout, "checkout", "-b", "Beta-3"); diff --git a/src/lib/services/catalog-git-core.ts b/src/lib/services/catalog-git-core.ts index 9bc755c6..a8e70299 100644 --- a/src/lib/services/catalog-git-core.ts +++ b/src/lib/services/catalog-git-core.ts @@ -4,6 +4,7 @@ import { promises as fs } from "node:fs"; import { hostname } from "node:os"; import path from "node:path"; import { promisify } from "node:util"; +import { gitProcessEnvironment } from "./git-process-environment"; const exec = promisify(execFile); export const CATALOG_REMOTE = @@ -115,7 +116,11 @@ export async function publishCatalogFiles(options: { cwd: checkout, timeout: 120_000, maxBuffer: 16 * 1024 * 1024, - env: { ...process.env, ...options.env, GIT_TERMINAL_PROMPT: "0" }, + env: { + ...gitProcessEnvironment(), + ...options.env, + GIT_TERMINAL_PROMPT: "0", + }, }); return stdout.trim(); }; diff --git a/src/lib/services/git-process-environment.test.ts b/src/lib/services/git-process-environment.test.ts new file mode 100644 index 00000000..32733fe8 --- /dev/null +++ b/src/lib/services/git-process-environment.test.ts @@ -0,0 +1,20 @@ +import { expect, it } from "vitest"; +import { gitProcessEnvironment } from "./git-process-environment"; + +it("does not pass parent repository paths into catalog Git commands", () => { + const env = gitProcessEnvironment({ + NODE_ENV: "test", + PATH: "tools", + GIT_DIR: "parent", + GIT_WORK_TREE: "parent", + GIT_INDEX_FILE: "parent-index", + GIT_COMMON_DIR: "common", + GIT_AUTHOR_NAME: "Catalog", + }); + expect(env.GIT_DIR).toBeUndefined(); + expect(env.GIT_WORK_TREE).toBeUndefined(); + expect(env.GIT_INDEX_FILE).toBeUndefined(); + expect(env.GIT_COMMON_DIR).toBeUndefined(); + expect(env.PATH).toBe("tools"); + expect(env.GIT_AUTHOR_NAME).toBe("Catalog"); +}); diff --git a/src/lib/services/git-process-environment.ts b/src/lib/services/git-process-environment.ts new file mode 100644 index 00000000..3527a837 --- /dev/null +++ b/src/lib/services/git-process-environment.ts @@ -0,0 +1,19 @@ +/** Git hooks export paths belonging to their repository. Never reuse them for a different checkout. */ +export function gitProcessEnvironment( + source: NodeJS.ProcessEnv = process.env, +): NodeJS.ProcessEnv { + const environment = { ...source }; + for (const name of [ + "GIT_DIR", + "GIT_WORK_TREE", + "GIT_INDEX_FILE", + "GIT_COMMON_DIR", + "GIT_OBJECT_DIRECTORY", + "GIT_ALTERNATE_OBJECT_DIRECTORIES", + "GIT_PREFIX", + "GIT_IMPLICIT_WORK_TREE", + "GIT_GRAFT_FILE", + ]) + delete environment[name]; + return environment; +}