// Test support: the current user's IDs, a fresh temporary directory, the // inherited environment, and a plain command runner. It imports no source // module, so the repository-level tests in tests/, which reach src/ only // through `#testing`, never touch internals. import { spawn } from "node:child_process"; import { once } from "node:events"; import { mkdtemp } from "node:fs/promises"; import { tmpdir } from "node:os"; import nodePath from "node:path"; import process from "node:process"; import { text } from "node:stream/consumers"; export function currentUid(): number { return process.getuid?.() ?? -1; } export function currentGid(): number { return process.getgid?.() ?? -1; } // The isolation tests switch UIDs, which only root may do. export const IS_ROOT: boolean = currentUid() === 0; // Symlinks and POSIX modes, as these tests use them, need a Unix host. export const IS_WINDOWS: boolean = process.platform === "win32"; export async function makeTempDir(): Promise { const path = await mkdtemp(nodePath.join(tmpdir(), "bot-agents-test-")); return path; } export interface CommandResult { success: boolean; stderr: string; } // This process's environment as a map from variable name to value. export function inheritedEnvironment(): Map { const result = new Map(); for (const [name, value] of Object.entries(process.env)) { if (value !== undefined) { result.set(name, value); } } return result; } // Runs a command with stdin closed and only the given environment, and // collects its stderr. export async function runCommand( command: string, args: string[], env: ReadonlyMap, ): Promise { const child = spawn(command, args, { env: Object.fromEntries(env), stdio: ["ignore", "ignore", "pipe"], }); const [stderr, closed] = await Promise.all([ text(child.stderr), once(child, "close"), ]); const exitCode: unknown = closed[0]; return { success: exitCode === 0, stderr }; }