mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(agents): preserve sandbox scope in container names (#115571)
This commit is contained in:
@@ -53,7 +53,7 @@ import {
|
||||
issueNoVncObserverToken,
|
||||
} from "./novnc-auth.js";
|
||||
import { readBrowserRegistry, updateBrowserRegistry } from "./registry.js";
|
||||
import { resolveSandboxAgentId, slugifySessionKey } from "./shared.js";
|
||||
import { buildSandboxContainerName, resolveSandboxAgentId, slugifySessionKey } from "./shared.js";
|
||||
import { isToolAllowed } from "./tool-policy.js";
|
||||
import type { SandboxBrowserContext, SandboxConfig } from "./types.js";
|
||||
import { validateNetworkMode } from "./validate-sandbox-security.js";
|
||||
@@ -242,8 +242,7 @@ export async function ensureSandboxBrowser(params: {
|
||||
}
|
||||
|
||||
const slug = params.cfg.scope === "shared" ? "shared" : slugifySessionKey(params.scopeKey);
|
||||
const name = `${params.cfg.browser.containerPrefix}${slug}`;
|
||||
const containerName = name.slice(0, 63);
|
||||
const containerName = buildSandboxContainerName(params.cfg.browser.containerPrefix, slug);
|
||||
let existing = BROWSER_BRIDGES.get(params.scopeKey);
|
||||
const stopExistingForContainer = async () => {
|
||||
await stopCachedBrowserBridgesForContainer(containerName);
|
||||
|
||||
@@ -95,7 +95,7 @@ import {
|
||||
} from "./constants.js";
|
||||
import { handleHotSandboxConfigMismatch } from "./current-config.js";
|
||||
import { readRegistryEntry, updateRegistry } from "./registry.js";
|
||||
import { resolveSandboxScopeKey, slugifySessionKey } from "./shared.js";
|
||||
import { buildSandboxContainerName, resolveSandboxScopeKey, slugifySessionKey } from "./shared.js";
|
||||
import type { SandboxConfig, SandboxDockerConfig, SandboxWorkspaceAccess } from "./types.js";
|
||||
import { validateSandboxSecurity } from "./validate-sandbox-security.js";
|
||||
import {
|
||||
@@ -503,8 +503,7 @@ export async function ensureSandboxContainer(params: {
|
||||
}) {
|
||||
const scopeKey = resolveSandboxScopeKey(params.cfg.scope, params.sessionKey);
|
||||
const slug = params.cfg.scope === "shared" ? "shared" : slugifySessionKey(scopeKey);
|
||||
const name = `${params.cfg.docker.containerPrefix}${slug}`;
|
||||
const containerName = name.slice(0, 63);
|
||||
const containerName = buildSandboxContainerName(params.cfg.docker.containerPrefix, slug);
|
||||
const readOnlyWorkspaceSkillMounts = resolveReadOnlyWorkspaceSkillMounts({
|
||||
workspaceDir: params.workspaceDir,
|
||||
agentWorkspaceDir: params.agentWorkspaceDir,
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildSandboxContainerName, slugifySessionKey } from "./shared.js";
|
||||
|
||||
describe("buildSandboxContainerName", () => {
|
||||
it("preserves scope identity when a custom prefix exceeds the Docker name limit", () => {
|
||||
const commonPrefix = "custom-prefix-".repeat(6);
|
||||
const first = buildSandboxContainerName(
|
||||
`${commonPrefix}first`,
|
||||
slugifySessionKey("session:first"),
|
||||
);
|
||||
const second = buildSandboxContainerName(
|
||||
`${commonPrefix}second`,
|
||||
slugifySessionKey("session:second"),
|
||||
);
|
||||
const sameScopeDifferentPrefix = buildSandboxContainerName(
|
||||
`${commonPrefix}second`,
|
||||
slugifySessionKey("session:first"),
|
||||
);
|
||||
const oversizedSlug = buildSandboxContainerName(
|
||||
commonPrefix,
|
||||
slugifySessionKey("session:".concat("x".repeat(200))),
|
||||
);
|
||||
|
||||
expect(first).not.toBe(second);
|
||||
expect(first).not.toBe(sameScopeDifferentPrefix);
|
||||
expect(first).toHaveLength(63);
|
||||
expect(second).toHaveLength(63);
|
||||
expect(oversizedSlug).toHaveLength(63);
|
||||
expect(first).toMatch(/-[0-9a-f]{12}$/);
|
||||
expect(second).toMatch(/-[0-9a-f]{12}$/);
|
||||
expect(oversizedSlug).toMatch(/-[0-9a-f]{12}$/);
|
||||
});
|
||||
});
|
||||
@@ -25,6 +25,17 @@ export function slugifySessionKey(value: string) {
|
||||
return `${base}-${hash}`;
|
||||
}
|
||||
|
||||
/** Builds a bounded Docker name without truncating the scope-identity slug. */
|
||||
export function buildSandboxContainerName(prefix: string, slug: string): string {
|
||||
const maxLength = 63;
|
||||
const fullName = `${prefix}${slug}`;
|
||||
if (fullName.length <= maxLength) {
|
||||
return fullName;
|
||||
}
|
||||
const identitySuffix = `-${hashTextSha256(fullName).slice(0, 12)}`;
|
||||
return `${fullName.slice(0, maxLength - identitySuffix.length)}${identitySuffix}`;
|
||||
}
|
||||
|
||||
/** Resolves the per-session sandbox workspace directory under the configured sandbox root. */
|
||||
function resolveSandboxWorkspaceDir(root: string, sessionKey: string) {
|
||||
const resolvedRoot = resolveUserPath(root);
|
||||
|
||||
Reference in New Issue
Block a user