fix(git): isolate catalog commands from parent hook environment
CI / check (push) Successful in 1m48s
CI / deploy (push) Successful in 1m26s
CI / e2e (push) Successful in 27s

This commit is contained in:
Simo committed 2026-09-05 19:57:19 +02:00
1 parent 816e3875c2
commit 98b0009206
4 files changed
+51 -2

No files matched your search

+6 -1
View File
@@ -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");
+6 -1
View File
@@ -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();
};
@@ -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");
});
@@ -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;
}