mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 09:01:22 +00:00
chore: Enable "curly" rule to avoid single-statement if confusion/errors.
This commit is contained in:
@@ -27,7 +27,9 @@ async function waitForSandboxCdp(params: { cdpPort: number; timeoutMs: number })
|
||||
const t = setTimeout(() => ctrl.abort(), 1000);
|
||||
try {
|
||||
const res = await fetch(url, { signal: ctrl.signal });
|
||||
if (res.ok) return true;
|
||||
if (res.ok) {
|
||||
return true;
|
||||
}
|
||||
} finally {
|
||||
clearTimeout(t);
|
||||
}
|
||||
@@ -74,7 +76,9 @@ async function ensureSandboxBrowserImage(image: string) {
|
||||
const result = await execDocker(["image", "inspect", image], {
|
||||
allowFailure: true,
|
||||
});
|
||||
if (result.code === 0) return;
|
||||
if (result.code === 0) {
|
||||
return;
|
||||
}
|
||||
throw new Error(
|
||||
`Sandbox browser image not found: ${image}. Build it with scripts/sandbox-browser-setup.sh.`,
|
||||
);
|
||||
@@ -87,8 +91,12 @@ export async function ensureSandboxBrowser(params: {
|
||||
cfg: SandboxConfig;
|
||||
evaluateEnabled?: boolean;
|
||||
}): Promise<SandboxBrowserContext | null> {
|
||||
if (!params.cfg.browser.enabled) return null;
|
||||
if (!isToolAllowed(params.cfg.tools, "browser")) return null;
|
||||
if (!params.cfg.browser.enabled) {
|
||||
return null;
|
||||
}
|
||||
if (!isToolAllowed(params.cfg.tools, "browser")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const slug = params.cfg.scope === "shared" ? "shared" : slugifySessionKey(params.scopeKey);
|
||||
const name = `${params.cfg.browser.containerPrefix}${slug}`;
|
||||
@@ -152,12 +160,16 @@ export async function ensureSandboxBrowser(params: {
|
||||
}
|
||||
|
||||
const bridge = (() => {
|
||||
if (shouldReuse && existing) return existing.bridge;
|
||||
if (shouldReuse && existing) {
|
||||
return existing.bridge;
|
||||
}
|
||||
return null;
|
||||
})();
|
||||
|
||||
const ensureBridge = async () => {
|
||||
if (bridge) return bridge;
|
||||
if (bridge) {
|
||||
return bridge;
|
||||
}
|
||||
|
||||
const onEnsureAttachTarget = params.cfg.browser.autoStart
|
||||
? async () => {
|
||||
|
||||
@@ -13,7 +13,9 @@ function isPrimitive(value: unknown): value is string | number | boolean | bigin
|
||||
return value === null || (typeof value !== "object" && typeof value !== "function");
|
||||
}
|
||||
function normalizeForHash(value: unknown): unknown {
|
||||
if (value === undefined) return undefined;
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
const normalized = value
|
||||
.map(normalizeForHash)
|
||||
@@ -31,7 +33,9 @@ function normalizeForHash(value: unknown): unknown {
|
||||
const normalized: Record<string, unknown> = {};
|
||||
for (const [key, entryValue] of entries) {
|
||||
const next = normalizeForHash(entryValue);
|
||||
if (next !== undefined) normalized[key] = next;
|
||||
if (next !== undefined) {
|
||||
normalized[key] = next;
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
@@ -39,10 +43,18 @@ function normalizeForHash(value: unknown): unknown {
|
||||
}
|
||||
|
||||
function primitiveToString(value: unknown): string {
|
||||
if (value === null) return "null";
|
||||
if (typeof value === "string") return value;
|
||||
if (typeof value === "number") return String(value);
|
||||
if (typeof value === "boolean") return value ? "true" : "false";
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "number") {
|
||||
return String(value);
|
||||
}
|
||||
if (typeof value === "boolean") {
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@ export function resolveSandboxScope(params: {
|
||||
scope?: SandboxScope;
|
||||
perSession?: boolean;
|
||||
}): SandboxScope {
|
||||
if (params.scope) return params.scope;
|
||||
if (params.scope) {
|
||||
return params.scope;
|
||||
}
|
||||
if (typeof params.perSession === "boolean") {
|
||||
return params.perSession ? "session" : "shared";
|
||||
}
|
||||
|
||||
@@ -21,13 +21,17 @@ export async function resolveSandboxContext(params: {
|
||||
workspaceDir?: string;
|
||||
}): Promise<SandboxContext | null> {
|
||||
const rawSessionKey = params.sessionKey?.trim();
|
||||
if (!rawSessionKey) return null;
|
||||
if (!rawSessionKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const runtime = resolveSandboxRuntimeStatus({
|
||||
cfg: params.config,
|
||||
sessionKey: rawSessionKey,
|
||||
});
|
||||
if (!runtime.sandboxed) return null;
|
||||
if (!runtime.sandboxed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cfg = resolveSandboxConfigForAgent(params.config, runtime.agentId);
|
||||
|
||||
@@ -101,13 +105,17 @@ export async function ensureSandboxWorkspaceForSession(params: {
|
||||
workspaceDir?: string;
|
||||
}): Promise<SandboxWorkspaceInfo | null> {
|
||||
const rawSessionKey = params.sessionKey?.trim();
|
||||
if (!rawSessionKey) return null;
|
||||
if (!rawSessionKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const runtime = resolveSandboxRuntimeStatus({
|
||||
cfg: params.config,
|
||||
sessionKey: rawSessionKey,
|
||||
});
|
||||
if (!runtime.sandboxed) return null;
|
||||
if (!runtime.sandboxed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cfg = resolveSandboxConfigForAgent(params.config, runtime.agentId);
|
||||
|
||||
|
||||
@@ -38,10 +38,14 @@ export async function readDockerPort(containerName: string, port: number) {
|
||||
const result = await execDocker(["port", containerName, `${port}/tcp`], {
|
||||
allowFailure: true,
|
||||
});
|
||||
if (result.code !== 0) return null;
|
||||
if (result.code !== 0) {
|
||||
return null;
|
||||
}
|
||||
const line = result.stdout.trim().split(/\r?\n/)[0] ?? "";
|
||||
const match = line.match(/:(\d+)\s*$/);
|
||||
if (!match) return null;
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const mapped = Number.parseInt(match[1] ?? "", 10);
|
||||
return Number.isFinite(mapped) ? mapped : null;
|
||||
}
|
||||
@@ -50,7 +54,9 @@ async function dockerImageExists(image: string) {
|
||||
const result = await execDocker(["image", "inspect", image], {
|
||||
allowFailure: true,
|
||||
});
|
||||
if (result.code === 0) return true;
|
||||
if (result.code === 0) {
|
||||
return true;
|
||||
}
|
||||
const stderr = result.stderr.trim();
|
||||
if (stderr.includes("No such image")) {
|
||||
return false;
|
||||
@@ -60,7 +66,9 @@ async function dockerImageExists(image: string) {
|
||||
|
||||
export async function ensureDockerImage(image: string) {
|
||||
const exists = await dockerImageExists(image);
|
||||
if (exists) return;
|
||||
if (exists) {
|
||||
return;
|
||||
}
|
||||
if (image === DEFAULT_SANDBOX_IMAGE) {
|
||||
await execDocker(["pull", "debian:bookworm-slim"]);
|
||||
await execDocker(["tag", "debian:bookworm-slim", DEFAULT_SANDBOX_IMAGE]);
|
||||
@@ -73,12 +81,16 @@ export async function dockerContainerState(name: string) {
|
||||
const result = await execDocker(["inspect", "-f", "{{.State.Running}}", name], {
|
||||
allowFailure: true,
|
||||
});
|
||||
if (result.code !== 0) return { exists: false, running: false };
|
||||
if (result.code !== 0) {
|
||||
return { exists: false, running: false };
|
||||
}
|
||||
return { exists: true, running: result.stdout.trim() === "true" };
|
||||
}
|
||||
|
||||
function normalizeDockerLimit(value?: string | number) {
|
||||
if (value === undefined || value === null) return undefined;
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof value === "number") {
|
||||
return Number.isFinite(value) ? String(value) : undefined;
|
||||
}
|
||||
@@ -90,16 +102,24 @@ function formatUlimitValue(
|
||||
name: string,
|
||||
value: string | number | { soft?: number; hard?: number },
|
||||
) {
|
||||
if (!name.trim()) return null;
|
||||
if (!name.trim()) {
|
||||
return null;
|
||||
}
|
||||
if (typeof value === "number" || typeof value === "string") {
|
||||
const raw = String(value).trim();
|
||||
return raw ? `${name}=${raw}` : null;
|
||||
}
|
||||
const soft = typeof value.soft === "number" ? Math.max(0, value.soft) : undefined;
|
||||
const hard = typeof value.hard === "number" ? Math.max(0, value.hard) : undefined;
|
||||
if (soft === undefined && hard === undefined) return null;
|
||||
if (soft === undefined) return `${name}=${hard}`;
|
||||
if (hard === undefined) return `${name}=${soft}`;
|
||||
if (soft === undefined && hard === undefined) {
|
||||
return null;
|
||||
}
|
||||
if (soft === undefined) {
|
||||
return `${name}=${hard}`;
|
||||
}
|
||||
if (hard === undefined) {
|
||||
return `${name}=${soft}`;
|
||||
}
|
||||
return `${name}=${soft}:${hard}`;
|
||||
}
|
||||
|
||||
@@ -120,14 +140,22 @@ export function buildSandboxCreateArgs(params: {
|
||||
args.push("--label", `openclaw.configHash=${params.configHash}`);
|
||||
}
|
||||
for (const [key, value] of Object.entries(params.labels ?? {})) {
|
||||
if (key && value) args.push("--label", `${key}=${value}`);
|
||||
if (key && value) {
|
||||
args.push("--label", `${key}=${value}`);
|
||||
}
|
||||
}
|
||||
if (params.cfg.readOnlyRoot) {
|
||||
args.push("--read-only");
|
||||
}
|
||||
if (params.cfg.readOnlyRoot) args.push("--read-only");
|
||||
for (const entry of params.cfg.tmpfs) {
|
||||
args.push("--tmpfs", entry);
|
||||
}
|
||||
if (params.cfg.network) args.push("--network", params.cfg.network);
|
||||
if (params.cfg.user) args.push("--user", params.cfg.user);
|
||||
if (params.cfg.network) {
|
||||
args.push("--network", params.cfg.network);
|
||||
}
|
||||
if (params.cfg.user) {
|
||||
args.push("--user", params.cfg.user);
|
||||
}
|
||||
for (const cap of params.cfg.capDrop) {
|
||||
args.push("--cap-drop", cap);
|
||||
}
|
||||
@@ -139,18 +167,26 @@ export function buildSandboxCreateArgs(params: {
|
||||
args.push("--security-opt", `apparmor=${params.cfg.apparmorProfile}`);
|
||||
}
|
||||
for (const entry of params.cfg.dns ?? []) {
|
||||
if (entry.trim()) args.push("--dns", entry);
|
||||
if (entry.trim()) {
|
||||
args.push("--dns", entry);
|
||||
}
|
||||
}
|
||||
for (const entry of params.cfg.extraHosts ?? []) {
|
||||
if (entry.trim()) args.push("--add-host", entry);
|
||||
if (entry.trim()) {
|
||||
args.push("--add-host", entry);
|
||||
}
|
||||
}
|
||||
if (typeof params.cfg.pidsLimit === "number" && params.cfg.pidsLimit > 0) {
|
||||
args.push("--pids-limit", String(params.cfg.pidsLimit));
|
||||
}
|
||||
const memory = normalizeDockerLimit(params.cfg.memory);
|
||||
if (memory) args.push("--memory", memory);
|
||||
if (memory) {
|
||||
args.push("--memory", memory);
|
||||
}
|
||||
const memorySwap = normalizeDockerLimit(params.cfg.memorySwap);
|
||||
if (memorySwap) args.push("--memory-swap", memorySwap);
|
||||
if (memorySwap) {
|
||||
args.push("--memory-swap", memorySwap);
|
||||
}
|
||||
if (typeof params.cfg.cpus === "number" && params.cfg.cpus > 0) {
|
||||
args.push("--cpus", String(params.cfg.cpus));
|
||||
}
|
||||
@@ -158,7 +194,9 @@ export function buildSandboxCreateArgs(params: {
|
||||
[string, string | number | { soft?: number; hard?: number }]
|
||||
>) {
|
||||
const formatted = formatUlimitValue(name, value);
|
||||
if (formatted) args.push("--ulimit", formatted);
|
||||
if (formatted) {
|
||||
args.push("--ulimit", formatted);
|
||||
}
|
||||
}
|
||||
if (params.cfg.binds?.length) {
|
||||
for (const bind of params.cfg.binds) {
|
||||
@@ -213,9 +251,13 @@ async function readContainerConfigHash(containerName: string): Promise<string |
|
||||
["inspect", "-f", `{{ index .Config.Labels "${label}" }}`, containerName],
|
||||
{ allowFailure: true },
|
||||
);
|
||||
if (result.code !== 0) return null;
|
||||
if (result.code !== 0) {
|
||||
return null;
|
||||
}
|
||||
const raw = result.stdout.trim();
|
||||
if (!raw || raw === "<no value>") return null;
|
||||
if (!raw || raw === "<no value>") {
|
||||
return null;
|
||||
}
|
||||
return raw;
|
||||
};
|
||||
return await readLabel("openclaw.configHash");
|
||||
|
||||
@@ -16,7 +16,9 @@ async function pruneSandboxContainers(cfg: SandboxConfig) {
|
||||
const now = Date.now();
|
||||
const idleHours = cfg.prune.idleHours;
|
||||
const maxAgeDays = cfg.prune.maxAgeDays;
|
||||
if (idleHours === 0 && maxAgeDays === 0) return;
|
||||
if (idleHours === 0 && maxAgeDays === 0) {
|
||||
return;
|
||||
}
|
||||
const registry = await readRegistry();
|
||||
for (const entry of registry.entries) {
|
||||
const idleMs = now - entry.lastUsedAtMs;
|
||||
@@ -42,7 +44,9 @@ async function pruneSandboxBrowsers(cfg: SandboxConfig) {
|
||||
const now = Date.now();
|
||||
const idleHours = cfg.prune.idleHours;
|
||||
const maxAgeDays = cfg.prune.maxAgeDays;
|
||||
if (idleHours === 0 && maxAgeDays === 0) return;
|
||||
if (idleHours === 0 && maxAgeDays === 0) {
|
||||
return;
|
||||
}
|
||||
const registry = await readBrowserRegistry();
|
||||
for (const entry of registry.entries) {
|
||||
const idleMs = now - entry.lastUsedAtMs;
|
||||
@@ -71,7 +75,9 @@ async function pruneSandboxBrowsers(cfg: SandboxConfig) {
|
||||
|
||||
export async function maybePruneSandboxes(cfg: SandboxConfig) {
|
||||
const now = Date.now();
|
||||
if (now - lastPruneAtMs < 5 * 60 * 1000) return;
|
||||
if (now - lastPruneAtMs < 5 * 60 * 1000) {
|
||||
return;
|
||||
}
|
||||
lastPruneAtMs = now;
|
||||
try {
|
||||
await pruneSandboxContainers(cfg);
|
||||
|
||||
@@ -37,7 +37,9 @@ export async function readRegistry(): Promise<SandboxRegistry> {
|
||||
try {
|
||||
const raw = await fs.readFile(SANDBOX_REGISTRY_PATH, "utf-8");
|
||||
const parsed = JSON.parse(raw) as SandboxRegistry;
|
||||
if (parsed && Array.isArray(parsed.entries)) return parsed;
|
||||
if (parsed && Array.isArray(parsed.entries)) {
|
||||
return parsed;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
@@ -65,7 +67,9 @@ export async function updateRegistry(entry: SandboxRegistryEntry) {
|
||||
export async function removeRegistryEntry(containerName: string) {
|
||||
const registry = await readRegistry();
|
||||
const next = registry.entries.filter((item) => item.containerName !== containerName);
|
||||
if (next.length === registry.entries.length) return;
|
||||
if (next.length === registry.entries.length) {
|
||||
return;
|
||||
}
|
||||
await writeRegistry({ entries: next });
|
||||
}
|
||||
|
||||
@@ -73,7 +77,9 @@ export async function readBrowserRegistry(): Promise<SandboxBrowserRegistry> {
|
||||
try {
|
||||
const raw = await fs.readFile(SANDBOX_BROWSER_REGISTRY_PATH, "utf-8");
|
||||
const parsed = JSON.parse(raw) as SandboxBrowserRegistry;
|
||||
if (parsed && Array.isArray(parsed.entries)) return parsed;
|
||||
if (parsed && Array.isArray(parsed.entries)) {
|
||||
return parsed;
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
@@ -104,6 +110,8 @@ export async function updateBrowserRegistry(entry: SandboxBrowserRegistryEntry)
|
||||
export async function removeBrowserRegistryEntry(containerName: string) {
|
||||
const registry = await readBrowserRegistry();
|
||||
const next = registry.entries.filter((item) => item.containerName !== containerName);
|
||||
if (next.length === registry.entries.length) return;
|
||||
if (next.length === registry.entries.length) {
|
||||
return;
|
||||
}
|
||||
await writeBrowserRegistry({ entries: next });
|
||||
}
|
||||
|
||||
@@ -8,8 +8,12 @@ import { resolveSandboxToolPolicyForAgent } from "./tool-policy.js";
|
||||
import type { SandboxConfig, SandboxToolPolicyResolved } from "./types.js";
|
||||
|
||||
function shouldSandboxSession(cfg: SandboxConfig, sessionKey: string, mainSessionKey: string) {
|
||||
if (cfg.mode === "off") return false;
|
||||
if (cfg.mode === "all") return true;
|
||||
if (cfg.mode === "off") {
|
||||
return false;
|
||||
}
|
||||
if (cfg.mode === "all") {
|
||||
return true;
|
||||
}
|
||||
return sessionKey.trim() !== mainSessionKey.trim();
|
||||
}
|
||||
|
||||
@@ -17,7 +21,9 @@ function resolveMainSessionKeyForSandbox(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
agentId: string;
|
||||
}): string {
|
||||
if (params.cfg?.session?.scope === "global") return "global";
|
||||
if (params.cfg?.session?.scope === "global") {
|
||||
return "global";
|
||||
}
|
||||
return resolveAgentMainSessionKey({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
@@ -78,20 +84,26 @@ export function formatSandboxToolPolicyBlockedMessage(params: {
|
||||
toolName: string;
|
||||
}): string | undefined {
|
||||
const tool = params.toolName.trim().toLowerCase();
|
||||
if (!tool) return undefined;
|
||||
if (!tool) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const runtime = resolveSandboxRuntimeStatus({
|
||||
cfg: params.cfg,
|
||||
sessionKey: params.sessionKey,
|
||||
});
|
||||
if (!runtime.sandboxed) return undefined;
|
||||
if (!runtime.sandboxed) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const deny = new Set(expandToolGroups(runtime.toolPolicy.deny));
|
||||
const allow = expandToolGroups(runtime.toolPolicy.allow);
|
||||
const allowSet = allow.length > 0 ? new Set(allow) : null;
|
||||
const blockedByDeny = deny.has(tool);
|
||||
const blockedByAllow = allowSet ? !allowSet.has(tool) : false;
|
||||
if (!blockedByDeny && !blockedByAllow) return undefined;
|
||||
if (!blockedByDeny && !blockedByAllow) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const reasons: string[] = [];
|
||||
const fixes: string[] = [];
|
||||
@@ -112,7 +124,9 @@ export function formatSandboxToolPolicyBlockedMessage(params: {
|
||||
lines.push(`Reason: ${reasons.join(" + ")}`);
|
||||
lines.push("Fix:");
|
||||
lines.push(`- agents.defaults.sandbox.mode=off (disable sandbox)`);
|
||||
for (const fix of fixes) lines.push(`- ${fix}`);
|
||||
for (const fix of fixes) {
|
||||
lines.push(`- ${fix}`);
|
||||
}
|
||||
if (runtime.mode === "non-main") {
|
||||
lines.push(`- Use main session key (direct): ${runtime.mainSessionKey}`);
|
||||
}
|
||||
|
||||
@@ -24,16 +24,24 @@ export function resolveSandboxWorkspaceDir(root: string, sessionKey: string) {
|
||||
|
||||
export function resolveSandboxScopeKey(scope: "session" | "agent" | "shared", sessionKey: string) {
|
||||
const trimmed = sessionKey.trim() || "main";
|
||||
if (scope === "shared") return "shared";
|
||||
if (scope === "session") return trimmed;
|
||||
if (scope === "shared") {
|
||||
return "shared";
|
||||
}
|
||||
if (scope === "session") {
|
||||
return trimmed;
|
||||
}
|
||||
const agentId = resolveAgentIdFromSessionKey(trimmed);
|
||||
return `agent:${agentId}`;
|
||||
}
|
||||
|
||||
export function resolveSandboxAgentId(scopeKey: string): string | undefined {
|
||||
const trimmed = scopeKey.trim();
|
||||
if (!trimmed || trimmed === "shared") return undefined;
|
||||
if (!trimmed || trimmed === "shared") {
|
||||
return undefined;
|
||||
}
|
||||
const parts = trimmed.split(":").filter(Boolean);
|
||||
if (parts[0] === "agent" && parts[1]) return normalizeAgentId(parts[1]);
|
||||
if (parts[0] === "agent" && parts[1]) {
|
||||
return normalizeAgentId(parts[1]);
|
||||
}
|
||||
return resolveAgentIdFromSessionKey(trimmed);
|
||||
}
|
||||
|
||||
@@ -15,9 +15,15 @@ type CompiledPattern =
|
||||
|
||||
function compilePattern(pattern: string): CompiledPattern {
|
||||
const normalized = pattern.trim().toLowerCase();
|
||||
if (!normalized) return { kind: "exact", value: "" };
|
||||
if (normalized === "*") return { kind: "all" };
|
||||
if (!normalized.includes("*")) return { kind: "exact", value: normalized };
|
||||
if (!normalized) {
|
||||
return { kind: "exact", value: "" };
|
||||
}
|
||||
if (normalized === "*") {
|
||||
return { kind: "all" };
|
||||
}
|
||||
if (!normalized.includes("*")) {
|
||||
return { kind: "exact", value: normalized };
|
||||
}
|
||||
const escaped = normalized.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
return {
|
||||
kind: "regex",
|
||||
@@ -26,7 +32,9 @@ function compilePattern(pattern: string): CompiledPattern {
|
||||
}
|
||||
|
||||
function compilePatterns(patterns?: string[]): CompiledPattern[] {
|
||||
if (!Array.isArray(patterns)) return [];
|
||||
if (!Array.isArray(patterns)) {
|
||||
return [];
|
||||
}
|
||||
return expandToolGroups(patterns)
|
||||
.map(compilePattern)
|
||||
.filter((pattern) => pattern.kind !== "exact" || pattern.value);
|
||||
@@ -34,9 +42,15 @@ function compilePatterns(patterns?: string[]): CompiledPattern[] {
|
||||
|
||||
function matchesAny(name: string, patterns: CompiledPattern[]): boolean {
|
||||
for (const pattern of patterns) {
|
||||
if (pattern.kind === "all") return true;
|
||||
if (pattern.kind === "exact" && name === pattern.value) return true;
|
||||
if (pattern.kind === "regex" && pattern.value.test(name)) return true;
|
||||
if (pattern.kind === "all") {
|
||||
return true;
|
||||
}
|
||||
if (pattern.kind === "exact" && name === pattern.value) {
|
||||
return true;
|
||||
}
|
||||
if (pattern.kind === "regex" && pattern.value.test(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -44,9 +58,13 @@ function matchesAny(name: string, patterns: CompiledPattern[]): boolean {
|
||||
export function isToolAllowed(policy: SandboxToolPolicy, name: string) {
|
||||
const normalized = name.trim().toLowerCase();
|
||||
const deny = compilePatterns(policy.deny);
|
||||
if (matchesAny(normalized, deny)) return false;
|
||||
if (matchesAny(normalized, deny)) {
|
||||
return false;
|
||||
}
|
||||
const allow = compilePatterns(policy.allow);
|
||||
if (allow.length === 0) return true;
|
||||
if (allow.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return matchesAny(normalized, allow);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user