Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
f3b0dbe
chore: upgrade OpenClaw from 2026.4.9 to 2026.4.24
ericksoa Apr 25, 2026
c1fe5f4
Merge branch 'main' into upgrade/openclaw-2026.4.24
ericksoa Apr 25, 2026
5dcb0a9
fix: update Patch 4 for OpenClaw 2026.4.24 replaceConfigFile restructure
ericksoa Apr 25, 2026
2aacc51
test: add diagnostics to TC-SBX-02 for openclaw agent failure mode
ericksoa Apr 26, 2026
e1f1be8
fix: symlink plugin-runtime-deps to writable .openclaw-data tree
ericksoa Apr 26, 2026
1e512b1
test: bump TC-SBX-02 SSH timeout to 240s for OpenClaw 2026.4.24 lazy …
ericksoa Apr 26, 2026
935a9b4
revert: undo test/e2e/test-sandbox-operations.sh timeout + diagnostics
ericksoa Apr 26, 2026
521c599
fix: give gateway user write access to plugin-runtime-deps cache
ericksoa Apr 26, 2026
e685857
Revert "fix: give gateway user write access to plugin-runtime-deps ca…
ericksoa Apr 26, 2026
c18575f
fix: gate sandbox-safety-net to gateway processes only
ericksoa Apr 26, 2026
457e631
diag: mirror gateway log to PID 1 stderr + capture docker logs on fai…
ericksoa Apr 26, 2026
4407930
diag: continuously stream docker container logs to host files
ericksoa Apr 26, 2026
706f0d0
diag: stream k3s pod logs via openshell-cluster container exec
ericksoa Apr 26, 2026
c17c05d
diag: capture gateway log via nemoclaw <sandbox> logs --follow
ericksoa Apr 26, 2026
c511559
diag: switch gateway log capture from --follow to bounded snapshots
ericksoa Apr 26, 2026
5d89d25
diag: read sandbox names from registry json instead of parsing list
ericksoa Apr 27, 2026
03b0046
diag: ssh-tail /tmp/gateway.log directly to capture full event stream
ericksoa Apr 27, 2026
62642ee
diag: fix ssh config race in gateway log streamer
ericksoa Apr 27, 2026
4dbe32c
diag: remove apostrophes from streamer comments
ericksoa Apr 27, 2026
a66beed
diag: drop head -c cap on streamer, add post-run 5MB tail-trim
ericksoa Apr 27, 2026
a72aa93
diag: also tail openclaw structured log file, not just gateway.log
ericksoa Apr 27, 2026
ef47d2f
fix: disable bonjour mDNS plugin in sandbox openclaw.json
ericksoa Apr 27, 2026
92debb3
fix: remove sandbox-safety-net Node preload entirely
ericksoa Apr 27, 2026
23d10c5
Revert "fix: remove sandbox-safety-net Node preload entirely"
ericksoa Apr 27, 2026
9d79443
fix: rewrite sandbox-safety-net as selective handler with documented …
ericksoa Apr 27, 2026
3999886
fix: gate ciao guard uncaughtException listener to gateway processes
ericksoa Apr 27, 2026
5f1325c
diag: snapshot all openclaw log dirs before artifact upload
ericksoa Apr 27, 2026
6b17d4b
fix: disable unused bundled channels in sandbox openclaw.json
ericksoa Apr 27, 2026
f4c6c8b
fix: disable qqbot at plugin level instead of channel level
ericksoa Apr 27, 2026
37f8818
ci: bump sandbox-operations test timeout from 30m to 45m
ericksoa Apr 27, 2026
0ccad30
Merge remote-tracking branch 'origin/main' into upgrade/openclaw-2026…
ericksoa Apr 27, 2026
be9e275
fix(sandbox): stage generate-openclaw-config.py in build context
ericksoa Apr 27, 2026
d85766d
diag: use nemoclaw logs for final snapshot, add debug echoes
ericksoa Apr 27, 2026
32d3a30
diag: re-select openshell gateway + ssh fallback in final snapshot
ericksoa Apr 27, 2026
8223bfa
diag: capture nemoclaw exit code before piping to tail
ericksoa Apr 28, 2026
15cae08
Merge remote-tracking branch 'origin/main' into upgrade/openclaw-2026…
ericksoa Apr 28, 2026
0d88db4
diag: persist gateway log under .openclaw-data so it survives pod res…
ericksoa Apr 28, 2026
1ecb86c
diag: snapshot reads /sandbox/.openclaw-data persistent log directly …
ericksoa Apr 28, 2026
81d2189
diag: drop set -e in stop-streamer step so partial failures don't abort
ericksoa Apr 28, 2026
8b67681
diag: switch streamer from raw ssh to openshell sandbox exec
ericksoa Apr 28, 2026
5ba8b3d
fix(diag): apostrophe in comment closed outer bash -c block
ericksoa Apr 28, 2026
ffaf3e1
diag: bypass openshell client, use docker exec + kubectl in cluster
ericksoa Apr 28, 2026
0ba3006
diag: streamer uses docker exec + kubectl bypass, snapshots not tail-F
ericksoa Apr 28, 2026
64a2835
fix(start): make auto-pair exit on non-browser pairing convergence
ericksoa Apr 28, 2026
9fe905b
fix(openclaw-patch): bump WS handshake timeout 10s -> 60s
ericksoa Apr 28, 2026
634909c
fix: pre-install @zed-industries/codex-acp at build time
ericksoa Apr 28, 2026
a2bf48b
Merge branch 'main' into upgrade/openclaw-2026.4.24
ericksoa Apr 28, 2026
441f223
fix: set npm prefer-offline=true so codex-acp runtime uses cached ins…
ericksoa Apr 28, 2026
13fcbd4
fix(start): re-apply auto-pair quiet-exit fix lost in main merge
ericksoa Apr 28, 2026
7443996
fix(ci): restore selective dispatch for new e2e jobs
ericksoa Apr 28, 2026
0699bb3
fix(sandbox): use preinstalled codex-acp for acpx
ericksoa Apr 28, 2026
ff14e77
style(start): apply shell formatter
ericksoa Apr 28, 2026
b6cb3a6
test(e2e): reset config recovery artifacts in sandbox fixture
ericksoa Apr 28, 2026
c7c7553
fix(sandbox): isolate codex-acp runtime state
ericksoa Apr 28, 2026
f09eb36
fix(sandbox): skip interactive OpenClaw bootstrap
ericksoa Apr 28, 2026
4de3c67
test(e2e): resume sandbox onboard after import reset
ericksoa Apr 28, 2026
aa6fecc
fix(sandbox): disable inferred thinking for smoke agent
ericksoa Apr 28, 2026
0df3c91
test(e2e): retry sandbox onboard resume resets
ericksoa Apr 28, 2026
2843fde
style(e2e): apply sandbox operations shell format
ericksoa Apr 28, 2026
2cb8064
fix(sandbox): trim staged OpenClaw runtime deps
ericksoa Apr 28, 2026
14278b8
Merge remote-tracking branch 'origin/main' into upgrade/openclaw-2026…
ericksoa Apr 29, 2026
3363b22
Merge branch 'main' into upgrade/openclaw-2026.4.24
ericksoa Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -172,15 +172,18 @@ RUN set -eu; \
sed -i 's/baseLstat\.isSymbolicLink()/false \/* nemoclaw: symlink check disabled, realpath guards containment *\//' "$ipd_file"; \
if grep -q 'fs\.lstat(params\.installBaseDir)' "$ipd_file"; then echo "ERROR: Patch 3b (install-package-dir) left lstat in assertInstallBaseStable" >&2; exit 1; fi; \
# --- Patch 4: graceful EACCES in replaceConfigFile for sandbox (#2254) --- \
# Plugin install persists metadata to openclaw.json via replaceConfigFile. \
# In the sandbox, openclaw.json is immutable (444 root:root in a 755 \
# root:root directory) by design. The write fails with EACCES. This \
# patch wraps the writeConfigFile call inside replaceConfigFile to catch \
# EACCES when OPENSHELL_SANDBOX=1 and emit a warning instead of crashing. \
# Plugins still load via auto-discovery from the extensions directory. \
# Plugin install persists metadata via replaceConfigFile. In the sandbox, \
# openclaw.json is immutable (444 root:root) by design. OpenClaw 2026.4.24 \
# restructured config writes: replaceConfigFile now first attempts a \
# single-key include-file mutation (tryWriteSingleTopLevelIncludeMutation), \
# falling back to writeConfigFile for the full config. Both paths can hit \
# EACCES in the read-only sandbox tree. This patch wraps the entire \
# write block in a try/catch that catches EACCES when OPENSHELL_SANDBOX=1 \
# and emits a warning instead of crashing. Plugins still load via \
# auto-discovery from the extensions directory. \
rcf_file="$(grep -RIlE --include='*.js' 'async function replaceConfigFile\(params\)' "$OC_DIST" | head -n 1)"; \
test -n "$rcf_file" || { echo "ERROR: replaceConfigFile function not found in OpenClaw dist" >&2; exit 1; }; \
python3 -c "import sys; p=sys.argv[1]; f=open(p); src=f.read(); f.close(); old='\tawait writeConfigFile(params.nextConfig, {\n\t\t...writeOptions,\n\t\t...params.writeOptions\n\t});'; new='\ttry { await writeConfigFile(params.nextConfig, {\n\t\t...writeOptions,\n\t\t...params.writeOptions\n\t}); } catch(_rcfErr) { if (process.env.OPENSHELL_SANDBOX === \"1\" && _rcfErr.code === \"EACCES\") { console.error(\"[nemoclaw] Config is read-only in sandbox \\u2014 plugin metadata not persisted (plugins auto-load from extensions/)\"); } else { throw _rcfErr; } }'; assert old in src, 'writeConfigFile(params.nextConfig) pattern not found'; f=open(p,'w'); f.write(src.replace(old,new,1)); f.close()" "$rcf_file"; \
python3 -c "import sys; p=sys.argv[1]; f=open(p); src=f.read(); f.close(); old='\tif (!await tryWriteSingleTopLevelIncludeMutation({\n\t\tsnapshot,\n\t\tnextConfig: params.nextConfig\n\t})) await writeConfigFile(params.nextConfig, {\n\t\tbaseSnapshot: snapshot,\n\t\t...writeOptions,\n\t\t...params.writeOptions\n\t});'; new='\ttry { if (!await tryWriteSingleTopLevelIncludeMutation({\n\t\tsnapshot,\n\t\tnextConfig: params.nextConfig\n\t})) await writeConfigFile(params.nextConfig, {\n\t\tbaseSnapshot: snapshot,\n\t\t...writeOptions,\n\t\t...params.writeOptions\n\t}); } catch(_rcfErr) { if (process.env.OPENSHELL_SANDBOX === \"1\" && _rcfErr.code === \"EACCES\") { console.error(\"[nemoclaw] Config is read-only in sandbox \\u2014 plugin metadata not persisted (plugins auto-load from extensions/)\"); } else { throw _rcfErr; } }'; assert old in src, 'tryWriteSingleTopLevelIncludeMutation/writeConfigFile pattern not found in replaceConfigFile'; f=open(p,'w'); f.write(src.replace(old,new,1)); f.close()" "$rcf_file"; \
grep -REq --include='*.js' 'OPENSHELL_SANDBOX.*EACCES' "$rcf_file" || { echo "ERROR: Patch 4 (replaceConfigFile EACCES) not applied" >&2; exit 1; }

# Set up blueprint for local resolution.
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ RUN printf '%s\n' \
# OpenClaw version: change the OPENCLAW_VERSION ARG default so CI rebuilds
# the base image on push to main, or use workflow_dispatch on base-image.yaml
# with the openclaw_version input for a one-off build without editing this file.
ARG OPENCLAW_VERSION=2026.4.9
ARG OPENCLAW_VERSION=2026.4.24

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

Expand Down
2 changes: 1 addition & 1 deletion agents/openclaw/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ homepage: "https://openclaw.ai"
install_method: npm # npm install -g openclaw@<version>
binary_path: /usr/local/bin/openclaw
version_command: "openclaw --version"
expected_version: "2026.4.9"
expected_version: "2026.4.24"
gateway_command: "openclaw gateway run"

# ── Health probe ────────────────────────────────────────────────
Expand Down
2 changes: 1 addition & 1 deletion nemoclaw-blueprint/blueprint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
version: "0.1.0"
min_openshell_version: "0.0.32"
max_openshell_version: "0.0.36"
min_openclaw_version: "2026.4.9"
min_openclaw_version: "2026.4.24"
# Mirrors the components.sandbox.image manifest digest below. Lets a
# downstream consumer (or release tooling) verify the blueprint declares
# a specific sandbox image without parsing the components tree, and
Expand Down
22 changes: 11 additions & 11 deletions src/lib/sandbox-version.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ vi.mock("./agent-defs.js", () => ({
name,
displayName: name === "openclaw" ? "OpenClaw" : "Hermes Agent",
versionCommand: name === "openclaw" ? "openclaw --version" : "hermes --version",
expectedVersion: name === "openclaw" ? "2026.4.9" : "2026.4.9",
expectedVersion: name === "openclaw" ? "2026.4.24" : "2026.4.24",
stateDirs: [],
configPaths: { writableDir: "/sandbox/.openclaw-data" },
})),
Expand Down Expand Up @@ -76,12 +76,12 @@ describe("checkAgentVersion", () => {
registry.registerSandbox({
name: "test-sb",
agent: null,
agentVersion: "2026.4.9",
agentVersion: "2026.4.24",
});

const result = checkAgentVersion("test-sb");
expect(result.detectionMethod).toBe("registry");
expect(result.sandboxVersion).toBe("2026.4.9");
expect(result.sandboxVersion).toBe("2026.4.24");
expect(result.isStale).toBe(false);
});

Expand All @@ -102,7 +102,7 @@ describe("checkAgentVersion", () => {
registry.registerSandbox({
name: "test-sb",
agent: null,
agentVersion: "2026.4.9",
agentVersion: "2026.4.24",
});

const result = checkAgentVersion("test-sb");
Expand All @@ -119,7 +119,7 @@ describe("checkAgentVersion", () => {

vi.mocked(spawnSync).mockReturnValue({
status: 0,
stdout: "OpenClaw 2026.4.9 (abc123)\n",
stdout: "OpenClaw 2026.4.24 (abc123)\n",
stderr: "",
pid: 1234,
output: [],
Expand All @@ -128,12 +128,12 @@ describe("checkAgentVersion", () => {

const result = checkAgentVersion("test-sb");
expect(result.detectionMethod).toBe("ssh-exec");
expect(result.sandboxVersion).toBe("2026.4.9");
expect(result.sandboxVersion).toBe("2026.4.24");
expect(result.isStale).toBe(false);

// Should have cached the version in registry
const updated = registry.getSandbox("test-sb");
expect(updated?.agentVersion).toBe("2026.4.9");
expect(updated?.agentVersion).toBe("2026.4.24");
});

it("returns unavailable when SSH config fails", () => {
Expand Down Expand Up @@ -163,7 +163,7 @@ describe("checkAgentVersion", () => {

vi.mocked(spawnSync).mockReturnValue({
status: 0,
stdout: "OpenClaw 2026.4.9 (abc123)\n",
stdout: "OpenClaw 2026.4.24 (abc123)\n",
stderr: "",
pid: 1234,
output: [],
Expand All @@ -172,7 +172,7 @@ describe("checkAgentVersion", () => {

const result = checkAgentVersion("test-sb", { forceProbe: true });
expect(result.detectionMethod).toBe("ssh-exec");
expect(result.sandboxVersion).toBe("2026.4.9");
expect(result.sandboxVersion).toBe("2026.4.24");
});
});

Expand All @@ -199,14 +199,14 @@ describe("formatStalenessWarning", () => {
it("includes sandbox name, versions, and rebuild hint", () => {
const lines = formatStalenessWarning("my-sb", {
sandboxVersion: "2026.3.11",
expectedVersion: "2026.4.9",
expectedVersion: "2026.4.24",
isStale: true,
detectionMethod: "registry",
});
const joined = lines.join("\n");
expect(joined).toContain("my-sb");
expect(joined).toContain("2026.3.11");
expect(joined).toContain("2026.4.9");
expect(joined).toContain("2026.4.24");
expect(joined).toContain("rebuild");
});
});
Loading