UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

160 lines (159 loc) 6.94 kB
import { c as normalizeOptionalLowercaseString } from "./string-coerce-CIXf7egm.js"; import { n as sliceUtf16Safe, r as truncateUtf16Safe } from "./utf16-slice-D_ngcYKd.js"; import { t as formatCliCommand } from "./command-format-C7YfyMTd.js"; import { o as resolveSessionStorePathCore } from "./paths-CXdaYWF_.js"; import { _ as resolveSessionAgentId } from "./agent-scope-DbtJyKUL.js"; import { _ as resolveSessionEntry } from "./session-accessor.sqlite-entry-CWk3jL7s.js"; import { a as sessionCreatorProfileId } from "./session-entry-provenance-jzrCUpdQ.js"; import { n as canonicalizeMainSessionAlias, r as resolveAgentMainSessionKey } from "./main-session-Br0F9dzh.js"; import { r as resolveSandboxToolPolicyForAgent, t as classifyToolAgainstSandboxToolPolicy } from "./tool-policy-WMCUEiT6.js"; import { r as escapeControlCharsVisible, t as auditSandboxToolPolicyBlock } from "./tool-policy-audit-BoqUwCpm.js"; import { i as resolveSandboxConfigForAgent } from "./config-RoLkL_H5.js"; //#region src/agents/sandbox/runtime-status.ts /** * Sandbox runtime status and tool-policy diagnostics. * * Resolves whether a session is sandboxed and explains policy blocks before tool execution. */ function shouldSandboxSession(cfg, sessionKey, mainSessionKey, sandboxRequired) { if (sandboxRequired) return true; if (cfg.mode === "off") return false; if (cfg.mode === "all") return true; return sessionKey.trim() !== mainSessionKey.trim(); } function resolveMainSessionKeyForSandbox(params) { if (params.cfg?.session?.scope === "global") return "global"; return resolveAgentMainSessionKey({ cfg: params.cfg, agentId: params.agentId }); } function resolveComparableSessionKeyForSandbox(params) { return canonicalizeMainSessionAlias({ cfg: params.cfg, agentId: params.agentId, sessionKey: params.sessionKey }); } /** Resolves sandbox mode, effective session scope, and tool policy for a session. */ function resolveSandboxRuntimeStatus(params) { const sessionKey = params.sessionKey?.trim() ?? ""; const agentId = resolveSessionAgentId({ sessionKey, config: params.cfg, agentId: params.agentId }); const classificationSessionKey = params.classificationSessionKey?.trim() || sessionKey; const classificationAgentId = resolveSessionAgentId({ sessionKey: classificationSessionKey, config: params.cfg, agentId: params.classificationAgentId, fallbackAgentId: classificationSessionKey === sessionKey ? agentId : void 0 }); const cfg = params.cfg; const sandboxCfg = resolveSandboxConfigForAgent(cfg, classificationAgentId); const mainSessionKey = resolveMainSessionKeyForSandbox({ cfg, agentId: classificationAgentId }); const comparableSessionKey = resolveComparableSessionKeyForSandbox({ cfg, agentId: classificationAgentId, sessionKey: classificationSessionKey }); const session = classificationSessionKey ? resolveSessionEntry({ agentId: classificationAgentId, clone: false, sessionKey: comparableSessionKey, storePath: resolveSessionStorePathCore(cfg?.session?.store, { agentId: classificationAgentId }) }, { readOnly: true }) : void 0; const sandboxRequired = session?.existing?.sandbox === "required"; const profileId = sessionCreatorProfileId(session?.existing?.createdActor)?.trim(); const isolation = sandboxRequired ? { sandboxRequired: true, createdActor: session.existing?.createdActor, isolationSubject: profileId ? { kind: "profile", profileId } : { kind: "session", sessionKey: session.normalizedKey }, workspaceAccess: sandboxCfg.workspaceAccess === "rw" ? "ro" : sandboxCfg.workspaceAccess } : { sandboxRequired: false }; const sandboxed = classificationSessionKey ? shouldSandboxSession(sandboxCfg, comparableSessionKey, mainSessionKey, sandboxRequired) : false; return { agentId, sessionKey, classificationAgentId, classificationSessionKey, mainSessionKey, mode: sandboxCfg.mode, ...isolation, sandboxed, toolPolicy: resolveSandboxToolPolicyForAgent(cfg, classificationAgentId) }; } function sanitizeForSingleLineDisplay(value) { return escapeControlCharsVisible(value); } function hasUnsafeControlChars(value) { return Array.from(value).some((char) => { const codePoint = char.codePointAt(0) ?? 0; return codePoint < 32 || codePoint === 127; }); } function redactSessionKey(value) { const trimmed = value.trim(); if (!trimmed) return "(unknown)"; if (trimmed.length <= 12) return "(redacted)"; return `${sanitizeForSingleLineDisplay(truncateUtf16Safe(trimmed, 6))}${sanitizeForSingleLineDisplay(sliceUtf16Safe(trimmed, -6))}`; } function shellEscapeSingleArg(value) { return `'${value.replaceAll("'", `'\\''`)}'`; } /** Formats the user-facing denial message when sandbox tool policy blocks a tool. */ function formatSandboxToolPolicyBlockedMessage(params) { const tool = normalizeOptionalLowercaseString(params.toolName); if (!tool) return; const runtime = resolveSandboxRuntimeStatus({ cfg: params.cfg, sessionKey: params.sessionKey, agentId: params.agentId }); if (!runtime.sandboxed) return; const { blockedByDeny, blockedByAllow } = classifyToolAgainstSandboxToolPolicy(tool, runtime.toolPolicy); if (!blockedByDeny && !blockedByAllow) return; const blockingSource = blockedByDeny ? runtime.toolPolicy.sources.deny : runtime.toolPolicy.sources.allow; if (params.audit === true) auditSandboxToolPolicyBlock({ toolName: tool, ruleType: blockedByDeny ? "deny" : "allow", ruleSource: blockingSource.source, configKey: blockingSource.key, policy: runtime.toolPolicy, mode: runtime.mode }); const reasons = []; const fixes = []; if (blockedByDeny) { reasons.push("deny list"); fixes.push(`Remove "${tool}" from ${runtime.toolPolicy.sources.deny.key}.`); } if (blockedByAllow) { reasons.push("allow list"); fixes.push(`Add "${tool}" to ${runtime.toolPolicy.sources.allow.key} (or set it to [] to allow all).`); } const lines = []; lines.push(`Tool "${tool}" blocked by sandbox tool policy (mode=${runtime.mode}).`); lines.push(`Session: ${redactSessionKey(runtime.sessionKey)}`); lines.push(`Reason: ${reasons.join(" + ")}`); lines.push("Fix:"); lines.push(runtime.sandboxRequired ? "- This session requires a sandbox; create a new session under an authorized role." : "- agents.defaults.sandbox.mode=off (disable sandbox)"); for (const fix of fixes) lines.push(`- ${fix}`); if (runtime.mode === "non-main" && !runtime.sandboxRequired) lines.push("- Use the agent main session instead of a non-main session."); const explainCommand = runtime.sessionKey && !hasUnsafeControlChars(runtime.sessionKey) ? `openclaw sandbox explain --session ${shellEscapeSingleArg(runtime.sessionKey)} --agent ${runtime.agentId}` : `openclaw sandbox explain --agent ${runtime.agentId}`; lines.push(`- See: ${formatCliCommand(explainCommand)}`); return lines.join("\n"); } //#endregion export { resolveSandboxRuntimeStatus as n, formatSandboxToolPolicyBlockedMessage as t };