/** * Network permission policy for sandbox_run. * * Networking is OFF by default. A network-enabled run requires explicit human * confirmation for that individual run, and fails closed when there is no UI. * * Pure logic, no Docker dependency, unit-testable. */ /** Result of a network policy decision. */ export type NetworkDecision = | { allowed: true } | { allowed: false; reason: string }; /** * Decide whether a network-enabled run may proceed. * * - If networking was not requested, it is always allowed (with no network). * - If networking is requested but there is no interactive UI, it fails closed. * - If networking is requested and there is a UI, the caller must prompt the * human; this function only tells the caller that a prompt is required. */ export function decideNetwork( networkRequested: boolean, hasUI: boolean, approved: boolean, ): NetworkDecision { if (!networkRequested) { return { allowed: true }; } if (!hasUI) { return { allowed: false, reason: "Network access requires interactive approval, which is unavailable here." }; } if (!approved) { return { allowed: false, reason: "Network access was denied by the human." }; } return { allowed: true }; } /** Build the human-readable confirmation message for a network-enabled run. */ export function buildApprovalPrompt(params: { command?: string; executable?: string; args?: string[]; setup?: string[]; projectPath: string; }): string { const lines: string[] = []; lines.push("⚠️ Network access requested for ONE sandbox run."); lines.push(""); lines.push("This sandbox would get internet access. This approval applies to this run only."); lines.push(""); lines.push(`Project mounted read-only: ${params.projectPath}`); lines.push(""); const commandLine = params.command ?? (params.executable ? [params.executable, ...(params.args ?? [])].join(" ") : ""); lines.push(`Command: ${commandLine || "(none)"}`); if (params.setup && params.setup.length > 0) { lines.push(""); lines.push("Setup (runs as root, privileged):"); for (const s of params.setup) lines.push(` ${s}`); } lines.push(""); lines.push("Choose 'Allow once' to grant network for this run only, or 'Deny'."); return lines.join("\n"); }