From e28803503d9e01c6f3d5e05025f5e3ad9399f40b Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 25 Feb 2026 02:09:22 +0000 Subject: [PATCH] fix: add sandbox bind-override regression coverage (#25410) (thanks @skyer-jian) --- CHANGELOG.md | 1 + src/config/config.sandbox-docker.test.ts | 41 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f01eed45f..ea31fe236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Docs: https://docs.openclaw.ai - Matrix/Read receipts: send read receipts as soon as Matrix messages arrive (before handler pipeline work), so clients no longer show long-lived unread/sent states while replies are processing. (#25841, #25840) Thanks @joshjhall. - Sandbox/FS bridge: build canonical-path shell scripts with newline separators (not `; ` joins) to avoid POSIX `sh` `do;` syntax errors that broke sandbox file/image read-write operations. (#25737, #25824, #25868) Thanks @DennisGoldfinger and @peteragility. - Sandbox/FS bridge tests: add regression coverage for dash-leading basenames to confirm sandbox file reads resolve to absolute container paths (and avoid shell-option misdiagnosis for dashed filenames). (#25891) Thanks @albertlieyingadrian. +- Sandbox/Config: preserve `dangerouslyAllowReservedContainerTargets` and `dangerouslyAllowExternalBindSources` during sandbox docker config resolution so explicit bind-mount break-glass overrides reach runtime validation. (#25410) Thanks @skyer-jian. - Routing/Session isolation: harden followup routing so explicit cross-channel origin replies never fall back to the active dispatcher on route failure, preserve queued overflow summary routing metadata (`channel`/`to`/`thread`) across followup drain, and prefer originating channel context over internal provider tags for embedded followup runs. This prevents webchat/control-ui context from hijacking Discord-targeted replies in shared sessions. (#25864) Thanks @Gamedesigner. - Messaging tool dedupe: treat originating channel metadata as authoritative for same-target `message.send` suppression in proactive runs (heartbeat/cron/exec-event), including synthetic-provider contexts, so `delivery-mirror` transcript entries no longer cause duplicate Telegram sends. (#25835) Thanks @jadeathena84-arch. - Cron/Heartbeat delivery: stop inheriting cached session `lastThreadId` for heartbeat-mode target resolution unless a thread/topic is explicitly requested, so announce-mode cron and heartbeat deliveries stay on top-level destinations instead of leaking into active conversation threads. (#25730) Thanks @markshields-tl. diff --git a/src/config/config.sandbox-docker.test.ts b/src/config/config.sandbox-docker.test.ts index 71b24af01..1124eca5f 100644 --- a/src/config/config.sandbox-docker.test.ts +++ b/src/config/config.sandbox-docker.test.ts @@ -103,6 +103,47 @@ describe("sandbox docker config", () => { expect(overridden.dangerouslyAllowContainerNamespaceJoin).toBe(false); }); + it("uses agent override precedence for bind-mount dangerous overrides", () => { + const inherited = resolveSandboxDockerConfig({ + scope: "agent", + globalDocker: { + dangerouslyAllowReservedContainerTargets: true, + dangerouslyAllowExternalBindSources: true, + }, + agentDocker: {}, + }); + expect(inherited.dangerouslyAllowReservedContainerTargets).toBe(true); + expect(inherited.dangerouslyAllowExternalBindSources).toBe(true); + + const overridden = resolveSandboxDockerConfig({ + scope: "agent", + globalDocker: { + dangerouslyAllowReservedContainerTargets: true, + dangerouslyAllowExternalBindSources: true, + }, + agentDocker: { + dangerouslyAllowReservedContainerTargets: false, + dangerouslyAllowExternalBindSources: false, + }, + }); + expect(overridden.dangerouslyAllowReservedContainerTargets).toBe(false); + expect(overridden.dangerouslyAllowExternalBindSources).toBe(false); + + const sharedScope = resolveSandboxDockerConfig({ + scope: "shared", + globalDocker: { + dangerouslyAllowReservedContainerTargets: true, + dangerouslyAllowExternalBindSources: true, + }, + agentDocker: { + dangerouslyAllowReservedContainerTargets: false, + dangerouslyAllowExternalBindSources: false, + }, + }); + expect(sharedScope.dangerouslyAllowReservedContainerTargets).toBe(true); + expect(sharedScope.dangerouslyAllowExternalBindSources).toBe(true); + }); + it("rejects seccomp unconfined via Zod schema validation", () => { const res = validateConfigObject({ agents: {