openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
244 lines (243 loc) • 10.9 kB
JavaScript
import { r as getSessionEntry } from "./store-Qsgtu-0y.js";
import { n as resolveSandboxRuntimeStatus } from "./runtime-status-DNNoBvYA.js";
import "./sandbox-tF_guAJk.js";
import "./session-store-runtime-rvUx2Fil.js";
//#region extensions/codex/src/app-server/native-execution-policy.ts
const DEFAULT_AGENT_ID = "main";
const VALID_AGENT_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
const INVALID_AGENT_ID_CHARS_PATTERN = /[^a-z0-9_-]+/g;
const LEADING_DASH_PATTERN = /^-+/;
const TRAILING_DASH_PATTERN = /-+$/;
/** Resolves node/gateway/sandbox execution ownership from overrides, session, agent, and config. */
function resolveCodexNativeExecutionPolicy(params) {
const config = params.config ?? {};
const sessionKey = params.sessionKey?.trim() || params.sessionId?.trim() || void 0;
const sessionEntry = params.sessionEntry ?? (params.readRuntimeSessionEntry && sessionKey ? readRuntimeSessionEntryBestEffort(sessionKey) : void 0);
const sandboxAvailable = params.sandboxAvailable ?? (sessionKey ? resolveSandboxRuntimeStatus({
cfg: config,
sessionKey
}).sandboxed : false);
const agentExec = resolvePolicyAgentExec({
config,
agentId: resolvePolicyAgentId({
config,
sessionKey,
agentId: params.agentId
})
});
const globalExec = config.tools?.exec;
const requestedExecHost = normalizeExecTarget(params.execOverrides?.host) ?? normalizeExecTarget(sessionEntry?.execHost) ?? normalizeExecTarget(agentExec?.host) ?? normalizeExecTarget(globalExec?.host) ?? "auto";
const effectiveExecHost = resolveEffectiveExecHost({
requestedExecHost,
sandboxAvailable
});
const node = params.execOverrides?.node ?? sessionEntry?.execNode ?? agentExec?.node ?? globalExec?.node;
if (effectiveExecHost !== "node") return {
nativeToolSurfaceAllowed: true,
requestedExecHost,
effectiveExecHost,
node
};
return {
nativeToolSurfaceAllowed: false,
requestedExecHost,
effectiveExecHost,
node,
blockReason: "OpenClaw exec host=node is active for this session. Codex app-server native execution cannot route shell, filesystem, MCP, or app-backed work through the selected OpenClaw node."
};
}
/** Formats the user-facing explanation shown when native tools are blocked by exec host=node. */
function formatCodexNativeNodeExecBlock(params) {
return [
`Codex-native ${params.surface} is unavailable because OpenClaw exec host=node is active for this session.`,
params.reason ?? "Codex app-server native execution cannot route execution through the selected OpenClaw node.",
"Use a normal Codex harness turn so OpenClaw exec/process tools run on the node, or switch exec host to gateway for native Codex app-server execution."
].join(" ");
}
function resolvePolicyAgentId(params) {
const explicitAgentId = normalizeAgentIdOrDefault(params.agentId);
if (explicitAgentId) return explicitAgentId;
const sessionAgentId = parseAgentIdFromSessionKey(params.sessionKey);
if (sessionAgentId) return sessionAgentId;
const agents = listAgentEntries(params.config);
return normalizeAgentId((agents.find((entry) => entry?.default) ?? agents[0])?.id);
}
function resolvePolicyAgentExec(params) {
return listAgentEntries(params.config).find((entry) => normalizeAgentId(entry?.id) === params.agentId)?.tools?.exec;
}
function listAgentEntries(config) {
return (config.agents?.list ?? []).filter((entry) => entry !== null && typeof entry === "object");
}
function parseAgentIdFromSessionKey(sessionKey) {
const raw = sessionKey?.trim();
if (!raw) return;
const parts = raw.toLowerCase().split(":").filter(Boolean);
if (parts.length < 3 || parts[0] !== "agent" || !parts[2]) return;
return normalizeAgentIdOrDefault(parts[1]);
}
function normalizeAgentIdOrDefault(value) {
const normalized = normalizeAgentId(value);
return normalized === DEFAULT_AGENT_ID && !(value ?? "").trim() ? void 0 : normalized;
}
function normalizeAgentId(value) {
const trimmed = (value ?? "").trim();
if (!trimmed) return DEFAULT_AGENT_ID;
const normalized = trimmed.toLowerCase();
if (VALID_AGENT_ID_PATTERN.test(trimmed)) return normalized;
return normalized.replace(INVALID_AGENT_ID_CHARS_PATTERN, "-").replace(LEADING_DASH_PATTERN, "").replace(TRAILING_DASH_PATTERN, "").slice(0, 64) || DEFAULT_AGENT_ID;
}
function normalizeExecTarget(value) {
const normalized = value?.trim().toLowerCase();
if (normalized === "auto" || normalized === "sandbox" || normalized === "gateway" || normalized === "node") return normalized;
}
function resolveEffectiveExecHost(params) {
if (params.requestedExecHost === "auto") return params.sandboxAvailable ? "sandbox" : "gateway";
return params.requestedExecHost;
}
function readRuntimeSessionEntryBestEffort(sessionKey) {
try {
return getSessionEntry({
sessionKey,
hydrateSkillPromptRefs: false
});
} catch {
return;
}
}
//#endregion
//#region extensions/codex/src/app-server/sandbox-guard.ts
const DIRECT_METHOD_POLICIES = new Map([
["account/rateLimits/read", "allowed-control-plane"],
["account/read", "allowed-control-plane"],
["app/list", "allowed-control-plane"],
["config/mcpServer/reload", "allowed-control-plane"],
["environment/add", "allowed-control-plane"],
["experimentalFeature/enablement/set", "allowed-control-plane"],
["feedback/upload", "allowed-control-plane"],
["hooks/list", "allowed-control-plane"],
["initialize", "allowed-control-plane"],
["marketplace/add", "allowed-control-plane"],
["mcpServerStatus/list", "allowed-control-plane"],
["model/list", "allowed-control-plane"],
["plugin/install", "allowed-control-plane"],
["plugin/list", "allowed-control-plane"],
["plugin/read", "allowed-control-plane"],
["skills/list", "allowed-control-plane"],
["thread/archive", "allowed-control-plane"],
["thread/inject_items", "allowed-control-plane"],
["thread/list", "allowed-control-plane"],
["thread/metadata/update", "allowed-control-plane"],
["thread/name/update", "allowed-control-plane"],
["thread/read", "allowed-control-plane"],
["thread/rollback", "allowed-control-plane"],
["thread/start", "requires-openclaw-environment"],
["thread/unarchive", "allowed-control-plane"],
["thread/unsubscribe", "allowed-control-plane"],
["turn/interrupt", "allowed-control-plane"],
["turn/steer", "allowed-control-plane"],
["command/exec", "blocked-native-bypass"],
["command/resize", "blocked-native-bypass"],
["command/terminate", "blocked-native-bypass"],
["command/write", "blocked-native-bypass"],
["fuzzyFileSearch", "blocked-native-bypass"],
["mcpServer/resource/read", "blocked-native-bypass"],
["mcpServer/tool/call", "blocked-native-bypass"],
["process/kill", "blocked-native-bypass"],
["process/resizePty", "blocked-native-bypass"],
["process/spawn", "blocked-native-bypass"],
["process/writeStdin", "blocked-native-bypass"],
["review/start", "blocked-native-bypass"],
["thread/compact/start", "blocked-native-bypass"],
["thread/fork", "blocked-native-bypass"],
["thread/resume", "blocked-native-bypass"],
["thread/shellCommand", "blocked-native-bypass"],
["turn/start", "blocked-native-bypass"]
]);
const BLOCKED_DIRECT_METHOD_PREFIXES = [
"command/",
"fs/",
"windowsSandbox/"
];
const NODE_EXEC_BLOCKED_CONTROL_PLANE_METHODS = new Set(["config/mcpServer/reload"]);
/** Returns a block message when a direct app-server method would bypass OpenClaw execution policy. */
function resolveCodexAppServerDirectSandboxBypassBlock(params) {
const policy = resolveDirectMethodPolicy(params.method);
if (NODE_EXEC_BLOCKED_CONTROL_PLANE_METHODS.has(params.method)) {
const nodeExecBlock = resolveCodexNativeNodeExecBlock({
config: params.config,
sessionKey: params.sessionKey,
sessionId: params.sessionId,
surface: `app-server method \`${params.method}\``
});
if (nodeExecBlock) return nodeExecBlock;
}
if (policy === "allowed-control-plane") return;
const nodeExecBlock = resolveCodexNativeNodeExecBlock({
config: params.config,
sessionKey: params.sessionKey,
sessionId: params.sessionId,
surface: `app-server method \`${params.method}\``
});
if (nodeExecBlock) return nodeExecBlock;
const sessionKey = params.sessionKey?.trim() || params.sessionId?.trim();
if (!sessionKey) return;
const sandboxBlock = resolveCodexNativeSandboxBlock({
config: params.config,
sessionKey,
surface: `app-server method \`${params.method}\``
});
if (!sandboxBlock) return;
if (policy === "requires-openclaw-environment" && hasOpenClawSandboxEnvironmentSelection(params.requestParams)) return;
return sandboxBlock;
}
/** Resolves the generic native-execution block for sandboxed or node-hosted sessions. */
function resolveCodexNativeExecutionBlock(params) {
return resolveCodexNativeSandboxBlock(params) ?? resolveCodexNativeNodeExecBlock(params);
}
/** Returns a block message when native Codex execution cannot honor active sandboxing. */
function resolveCodexNativeSandboxBlock(params) {
const sessionKey = params.sessionKey?.trim() || params.sessionId?.trim();
if (!sessionKey) return;
if (!resolveSandboxRuntimeStatus({
cfg: params.config,
sessionKey
}).sandboxed) return;
return formatCodexNativeSandboxBlock({ surface: params.surface });
}
function resolveDirectMethodPolicy(method) {
const exact = DIRECT_METHOD_POLICIES.get(method);
if (exact) return exact;
if (BLOCKED_DIRECT_METHOD_PREFIXES.some((prefix) => method.startsWith(prefix))) return "blocked-native-bypass";
return "blocked-native-bypass";
}
function hasOpenClawSandboxEnvironmentSelection(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
const environments = value.environments;
return Array.isArray(environments) && environments.length > 0 && environments.every((entry) => {
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
const environment = entry;
return typeof environment.environmentId === "string" && environment.environmentId.startsWith("openclaw-sandbox-") && typeof environment.cwd === "string" && environment.cwd.trim().length > 0;
});
}
function formatCodexNativeSandboxBlock(params) {
return [
`Codex-native ${params.surface} is unavailable because OpenClaw sandboxing is active for this session.`,
"This mode cannot route execution through the OpenClaw sandbox backend.",
"Use a normal Codex harness turn, or run an intentionally unsandboxed session."
].join(" ");
}
function resolveCodexNativeNodeExecBlock(params) {
const sessionKey = params.sessionKey?.trim() || params.sessionId?.trim();
const policy = resolveCodexNativeExecutionPolicy({
config: params.config,
sessionKey,
readRuntimeSessionEntry: Boolean(sessionKey)
});
if (policy.nativeToolSurfaceAllowed) return;
return formatCodexNativeNodeExecBlock({
surface: params.surface,
reason: policy.blockReason
});
}
//#endregion
export { resolveCodexNativeExecutionPolicy as i, resolveCodexNativeExecutionBlock as n, resolveCodexNativeSandboxBlock as r, resolveCodexAppServerDirectSandboxBypassBlock as t };