Updates
This commit is contained in:
+23
-28
@@ -11,49 +11,37 @@ export const BashParams = type({
|
||||
});
|
||||
|
||||
// patterns for sensitive env vars: suffixes (_KEY, _SECRET, _TOKEN) plus AI provider prefixes
|
||||
const SENSITIVE_PATTERNS = [
|
||||
/_KEY$/i,
|
||||
/_SECRET$/i,
|
||||
/_TOKEN$/i,
|
||||
/PASSWORD/i,
|
||||
/CREDENTIAL/i,
|
||||
/AUTH/i,
|
||||
/^ANTHROPIC/i,
|
||||
/^OPENAI/i,
|
||||
/^GEMINI/i,
|
||||
/^GOOGLE/i,
|
||||
/^CLAUDE/i,
|
||||
/^CODEX/i,
|
||||
/^CURSOR/i,
|
||||
/^AWS/i,
|
||||
/^GITHUB_TOKEN$/i,
|
||||
/^GH_TOKEN$/i,
|
||||
];
|
||||
const SENSITIVE_PATTERNS = [/_KEY$/i, /_SECRET$/i, /_TOKEN$/i, /_PASSWORD$/i, /_CREDENTIAL$/i];
|
||||
|
||||
function isSensitive(key: string): boolean {
|
||||
return SENSITIVE_PATTERNS.some((p) => p.test(key));
|
||||
}
|
||||
|
||||
/** filter env vars, removing sensitive values */
|
||||
function filterEnv(): Record<string, string> {
|
||||
/** filter env vars, removing sensitive values (only for public repos) */
|
||||
function filterEnv(isPublicRepo: boolean): Record<string, string> {
|
||||
const filtered: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(process.env)) {
|
||||
if (value !== undefined && !isSensitive(key)) filtered[key] = value;
|
||||
if (value === undefined) continue;
|
||||
// only filter sensitive vars for public repos
|
||||
if (isPublicRepo && isSensitive(key)) continue;
|
||||
filtered[key] = value;
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* spawn command with filtered env. in CI, also use PID namespace isolation
|
||||
* to prevent child from reading /proc/$PPID/environ
|
||||
* to prevent child from reading /proc/$PPID/environ (only for public repos)
|
||||
*/
|
||||
function spawnSandboxed(
|
||||
command: string,
|
||||
options: { env: Record<string, string>; cwd: string }
|
||||
options: { env: Record<string, string>; cwd: string; isPublicRepo: boolean }
|
||||
): ChildProcess {
|
||||
const stdio: ["ignore", "pipe", "pipe"] = ["ignore", "pipe", "pipe"];
|
||||
const spawnOpts = { env: options.env, cwd: options.cwd, stdio, detached: true };
|
||||
return process.env.CI === "true" // requires linux runner or this will fail.
|
||||
// only use PID namespace isolation for public repos in CI
|
||||
const useNamespaceIsolation = process.env.CI === "true" && options.isPublicRepo;
|
||||
return useNamespaceIsolation
|
||||
? spawn("unshare", ["--pid", "--fork", "--mount-proc", "bash", "-c", command], spawnOpts)
|
||||
: spawn("bash", ["-c", command], spawnOpts);
|
||||
}
|
||||
@@ -74,21 +62,28 @@ async function killProcessGroup(proc: ChildProcess): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export function BashTool(_ctx: ToolContext) {
|
||||
export function BashTool(ctx: ToolContext) {
|
||||
const isPublicRepo = !ctx.repo.private;
|
||||
|
||||
return tool({
|
||||
name: "bash",
|
||||
description: `Execute shell commands securely. Environment is filtered to remove API keys and secrets.
|
||||
description: `Execute shell commands securely.${isPublicRepo ? " Environment is filtered to remove API keys and secrets." : ""}
|
||||
|
||||
Use this tool to:
|
||||
- Run shell commands (ls, cat, grep, find, etc.)
|
||||
- Execute build tools (npm, pnpm, cargo, make, etc.)
|
||||
- Run tests and linters
|
||||
- Perform git operations`,
|
||||
- Perform git operations
|
||||
${isPublicRepo ? "\nThe command runs in a bash shell with a filtered environment that excludes sensitive variables like API keys and tokens." : ""}`,
|
||||
parameters: BashParams,
|
||||
execute: execute(async (params) => {
|
||||
const timeout = Math.min(params.timeout ?? 120000, 600000);
|
||||
const cwd = params.working_directory ?? process.cwd();
|
||||
const proc = spawnSandboxed(params.command, { env: filterEnv(), cwd });
|
||||
const proc = spawnSandboxed(params.command, {
|
||||
env: filterEnv(isPublicRepo),
|
||||
cwd,
|
||||
isPublicRepo,
|
||||
});
|
||||
|
||||
let stdout = "",
|
||||
stderr = "",
|
||||
|
||||
Reference in New Issue
Block a user