From d7079b5578833bfbe51da3927f02f17e4114fe58 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Feb 2026 13:10:07 +0000 Subject: [PATCH] refactor(security): share sandbox tool policy picker --- src/security/audit-extra.async.ts | 35 +++---------------------------- src/security/audit-extra.sync.ts | 35 +++---------------------------- src/security/audit-tool-policy.ts | 31 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 64 deletions(-) create mode 100644 src/security/audit-tool-policy.ts diff --git a/src/security/audit-extra.async.ts b/src/security/audit-extra.async.ts index 3c75966f760..e2bd4d0bbba 100644 --- a/src/security/audit-extra.async.ts +++ b/src/security/audit-extra.async.ts @@ -31,6 +31,7 @@ import { inspectPathPermissions, safeStat, } from "./audit-fs.js"; +import { pickSandboxToolPolicy } from "./audit-tool-policy.js"; import { extensionUsesSkippedScannerPath, isPathInside } from "./scan-paths.js"; import * as skillScanner from "./skill-scanner.js"; @@ -108,36 +109,6 @@ function formatCodeSafetyDetails(findings: SkillScanFinding[], rootDir: string): .join("\n"); } -function unionAllow(base?: string[], extra?: string[]): string[] | undefined { - if (!Array.isArray(extra) || extra.length === 0) { - return base; - } - if (!Array.isArray(base) || base.length === 0) { - return Array.from(new Set(["*", ...extra])); - } - return Array.from(new Set([...base, ...extra])); -} - -function pickToolPolicy(config?: { - allow?: string[]; - alsoAllow?: string[]; - deny?: string[]; -}): SandboxToolPolicy | undefined { - if (!config) { - return undefined; - } - const allow = Array.isArray(config.allow) - ? unionAllow(config.allow, config.alsoAllow) - : Array.isArray(config.alsoAllow) && config.alsoAllow.length > 0 - ? unionAllow(undefined, config.alsoAllow) - : undefined; - const deny = Array.isArray(config.deny) ? config.deny : undefined; - if (!allow && !deny) { - return undefined; - } - return { allow, deny }; -} - function resolveToolPolicies(params: { cfg: OpenClawConfig; agentTools?: AgentToolsConfig; @@ -148,8 +119,8 @@ function resolveToolPolicies(params: { const profilePolicy = resolveToolProfilePolicy(profile); const policies: Array = [ profilePolicy, - pickToolPolicy(params.cfg.tools ?? undefined), - pickToolPolicy(params.agentTools), + pickSandboxToolPolicy(params.cfg.tools ?? undefined), + pickSandboxToolPolicy(params.agentTools), ]; if (params.sandboxMode === "all") { policies.push(resolveSandboxToolPolicyForAgent(params.cfg, params.agentId ?? undefined)); diff --git a/src/security/audit-extra.sync.ts b/src/security/audit-extra.sync.ts index 895776249ea..1ccc45d99c5 100644 --- a/src/security/audit-extra.sync.ts +++ b/src/security/audit-extra.sync.ts @@ -17,6 +17,7 @@ import { formatCliCommand } from "../cli/command-format.js"; import { resolveGatewayAuth } from "../gateway/auth.js"; import { resolveNodeCommandAllowlist } from "../gateway/node-command-policy.js"; import { inferParamBFromIdOrName } from "../shared/model-param-b.js"; +import { pickSandboxToolPolicy } from "./audit-tool-policy.js"; export type SecurityAuditFinding = { checkId: string; @@ -167,36 +168,6 @@ function extractAgentIdFromSource(source: string): string | null { return match?.[1] ?? null; } -function unionAllow(base?: string[], extra?: string[]): string[] | undefined { - if (!Array.isArray(extra) || extra.length === 0) { - return base; - } - if (!Array.isArray(base) || base.length === 0) { - return Array.from(new Set(["*", ...extra])); - } - return Array.from(new Set([...base, ...extra])); -} - -function pickToolPolicy(config?: { - allow?: string[]; - alsoAllow?: string[]; - deny?: string[]; -}): SandboxToolPolicy | null { - if (!config) { - return null; - } - const allow = Array.isArray(config.allow) - ? unionAllow(config.allow, config.alsoAllow) - : Array.isArray(config.alsoAllow) && config.alsoAllow.length > 0 - ? unionAllow(undefined, config.alsoAllow) - : undefined; - const deny = Array.isArray(config.deny) ? config.deny : undefined; - if (!allow && !deny) { - return null; - } - return { allow, deny }; -} - function hasConfiguredDockerConfig( docker: Record | undefined | null, ): docker is Record { @@ -265,12 +236,12 @@ function resolveToolPolicies(params: { policies.push(profilePolicy); } - const globalPolicy = pickToolPolicy(params.cfg.tools ?? undefined); + const globalPolicy = pickSandboxToolPolicy(params.cfg.tools ?? undefined); if (globalPolicy) { policies.push(globalPolicy); } - const agentPolicy = pickToolPolicy(params.agentTools); + const agentPolicy = pickSandboxToolPolicy(params.agentTools); if (agentPolicy) { policies.push(agentPolicy); } diff --git a/src/security/audit-tool-policy.ts b/src/security/audit-tool-policy.ts new file mode 100644 index 00000000000..478ac30c0d4 --- /dev/null +++ b/src/security/audit-tool-policy.ts @@ -0,0 +1,31 @@ +import type { SandboxToolPolicy } from "../agents/sandbox/types.js"; + +function unionAllow(base?: string[], extra?: string[]): string[] | undefined { + if (!Array.isArray(extra) || extra.length === 0) { + return base; + } + if (!Array.isArray(base) || base.length === 0) { + return Array.from(new Set(["*", ...extra])); + } + return Array.from(new Set([...base, ...extra])); +} + +export function pickSandboxToolPolicy(config?: { + allow?: string[]; + alsoAllow?: string[]; + deny?: string[]; +}): SandboxToolPolicy | undefined { + if (!config) { + return undefined; + } + const allow = Array.isArray(config.allow) + ? unionAllow(config.allow, config.alsoAllow) + : Array.isArray(config.alsoAllow) && config.alsoAllow.length > 0 + ? unionAllow(undefined, config.alsoAllow) + : undefined; + const deny = Array.isArray(config.deny) ? config.deny : undefined; + if (!allow && !deny) { + return undefined; + } + return { allow, deny }; +}