Stop leaking real GitHub tool paths to dispatch turns
This commit is contained in:
parent
01bc5558af
commit
45dd81f968
6 changed files with 64 additions and 54 deletions
|
|
@ -443,7 +443,6 @@ exit /b 0
|
|||
["BIFROST_ENFORCE_GITHUB_GATE"] = "true",
|
||||
["BIFROST_GIT_EXECUTABLE"] = Path.Combine(gatePath, "git.cmd"),
|
||||
["BIFROST_GH_EXECUTABLE"] = Path.Combine(gatePath, "gh.cmd"),
|
||||
["BIFROST_REAL_GIT"] = ResolveRealGitExecutable(),
|
||||
["BIFROST_NODE_EXECUTABLE"] = ResolveExecutable("node"),
|
||||
["GIT_CONFIG_COUNT"] = "1",
|
||||
["GIT_CONFIG_KEY_0"] = "core.hooksPath",
|
||||
|
|
@ -455,8 +454,6 @@ exit /b 0
|
|||
|
||||
private static Dictionary<string, string?> BuildDispatchedGitGateEnv() => BuildDispatchedGitHookEnv();
|
||||
|
||||
private static string ResolveRealGitExecutable() => ResolveExecutable("git");
|
||||
|
||||
private static string ResolveExecutable(string command)
|
||||
{
|
||||
using var process = new Process
|
||||
|
|
|
|||
|
|
@ -569,8 +569,6 @@ function buildBridgeContextEnv(request) {
|
|||
BIFROST_ENFORCE_GITHUB_GATE: "true",
|
||||
BIFROST_GIT_EXECUTABLE: resolve(gitGatePath, "git.cmd"),
|
||||
BIFROST_GH_EXECUTABLE: resolve(gitGatePath, "gh.cmd"),
|
||||
BIFROST_REAL_GIT: resolveRealGitExecutable(),
|
||||
...buildRealGitHubCliEnv(),
|
||||
BIFROST_NODE_EXECUTABLE: process.execPath,
|
||||
...buildGitHooksConfigEnv(hooksPath),
|
||||
...buildPathPrependEnv(gitGatePath),
|
||||
|
|
@ -603,41 +601,6 @@ function buildPathPrependEnv(directory) {
|
|||
};
|
||||
}
|
||||
|
||||
function buildRealGitHubCliEnv() {
|
||||
const realGh = tryResolveExecutable("gh");
|
||||
return realGh ? { BIFROST_REAL_GH: realGh } : {};
|
||||
}
|
||||
|
||||
function resolveRealGitExecutable() {
|
||||
const resolved = tryResolveExecutable("git");
|
||||
if (!resolved) {
|
||||
throw new Error("Could not resolve the real git executable for dispatched turn gating.");
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
function tryResolveExecutable(command) {
|
||||
const locator = process.platform === "win32" ? "where.exe" : "which";
|
||||
const result = spawnSync(locator, [command], {
|
||||
cwd: bifrostRoot,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const matches = `${result.stdout ?? ""}`
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
return matches[0] ?? "";
|
||||
}
|
||||
|
||||
class CodexAppServerClient {
|
||||
constructor({ command, env, logPath }) {
|
||||
this.command = command;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
#!/usr/bin/env node
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const realGh = process.env.BIFROST_REAL_GH;
|
||||
const wrapperDir = dirname(fileURLToPath(import.meta.url));
|
||||
const realGh = process.env.BIFROST_REAL_GH || resolveExecutable("gh", wrapperDir);
|
||||
const realGhArgs = splitCommandArgs(process.env.BIFROST_REAL_GH_ARGS ?? "");
|
||||
const mutatingCommands = new Set([
|
||||
"gist create",
|
||||
|
|
@ -73,6 +76,34 @@ if (result.error) {
|
|||
|
||||
process.exit(result.status ?? 1);
|
||||
|
||||
function resolveExecutable(command, excludedDir) {
|
||||
const locator = process.platform === "win32" ? "where.exe" : "which";
|
||||
const result = spawnSync(locator, [command], {
|
||||
cwd: excludedDir,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const matches = `${result.stdout ?? ""}`
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.filter((line) => !isWithinExcludedDir(line, excludedDir));
|
||||
|
||||
return matches[0] ?? "";
|
||||
}
|
||||
|
||||
function isWithinExcludedDir(candidate, excludedDir) {
|
||||
const normalizedCandidate = resolve(candidate).toLowerCase();
|
||||
const normalizedExcludedDir = `${resolve(excludedDir).toLowerCase()}\\`;
|
||||
return normalizedCandidate.startsWith(normalizedExcludedDir);
|
||||
}
|
||||
|
||||
function isWindowsCommandScript(command) {
|
||||
return /\.cmd$/i.test(command) || /\.bat$/i.test(command);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
@echo off
|
||||
setlocal
|
||||
|
||||
set "REAL_GH=%BIFROST_REAL_GH%"
|
||||
if not defined REAL_GH (
|
||||
echo Bifrost GitHub gate has no real GitHub CLI executable configured.>&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set "NODE_EXE=%BIFROST_NODE_EXECUTABLE%"
|
||||
if not defined NODE_EXE (
|
||||
echo Bifrost GitHub gate has no Node executable configured.>&2
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
#!/usr/bin/env node
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const realGit = process.env.BIFROST_REAL_GIT;
|
||||
const wrapperDir = dirname(fileURLToPath(import.meta.url));
|
||||
const realGit = process.env.BIFROST_REAL_GIT || resolveExecutable("git", wrapperDir);
|
||||
|
||||
if (!realGit) {
|
||||
process.stderr.write("Bifrost Git gate has no real git executable configured.\n");
|
||||
|
|
@ -33,6 +36,34 @@ if (result.error) {
|
|||
|
||||
process.exit(result.status ?? 1);
|
||||
|
||||
function resolveExecutable(command, excludedDir) {
|
||||
const locator = process.platform === "win32" ? "where.exe" : "which";
|
||||
const result = spawnSync(locator, [command], {
|
||||
cwd: excludedDir,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const matches = `${result.stdout ?? ""}`
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.filter((line) => !isWithinExcludedDir(line, excludedDir));
|
||||
|
||||
return matches[0] ?? "";
|
||||
}
|
||||
|
||||
function isWithinExcludedDir(candidate, excludedDir) {
|
||||
const normalizedCandidate = resolve(candidate).toLowerCase();
|
||||
const normalizedExcludedDir = `${resolve(excludedDir).toLowerCase()}\\`;
|
||||
return normalizedCandidate.startsWith(normalizedExcludedDir);
|
||||
}
|
||||
|
||||
function findGitSubcommand(input) {
|
||||
const optionsWithSeparateValues = new Set([
|
||||
"-C",
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
@echo off
|
||||
setlocal
|
||||
|
||||
set "REAL_GIT=%BIFROST_REAL_GIT%"
|
||||
if not defined REAL_GIT (
|
||||
echo Bifrost Git gate has no real git executable configured.>&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set "NODE_EXE=%BIFROST_NODE_EXECUTABLE%"
|
||||
if not defined NODE_EXE (
|
||||
echo Bifrost Git gate has no Node executable configured.>&2
|
||||
|
|
|
|||
Loading…
Reference in a new issue