fix(cloud): give a cloud box's agent its workspace, and stop three AppleDouble leaks - #370
fix(cloud): give a cloud box's agent its workspace, and stop three AppleDouble leaks#370madarco wants to merge 3 commits into
Conversation
A hetzner OpenClaw box had the user's files in /workspace and the gateway pointed at ~/.openclaw/workspace — the headline "your project dir is the agent's workspace" behaviour, broken off docker. `spec.boxRunEnv` was built and passed to `provision` correctly, then dropped twice: hetzner's `cloudInitBoxEnv` keeps only `AGENTBOX_`-prefixed keys (rightly — `req.env` also carries forwarded API keys and box.env is 0644), and `kickCloudBootstrap` rewrites box.env with `tee` anyway on every create AND resume. The bootstrap is the last writer and the shared cloud path, so it is the one place to fix. The run-env now rides both surfaces it already maintains: `env`, which the daemon inherits and hands to every task — that is what fixes onboard — and `boxEnvFile`, because a cloud login shell does NOT inherit the daemon's env, so a hand-run `openclaw` would otherwise disagree with the service unit. Docker needs only the one surface because `docker run -e` serves both. Takes `buildCloudBoxRunEnv`, not `buildForwardedEnv`: only what a registry row declares, never the provider API keys that would then land in a world-readable file. Claude-Session: https://claude.ai/code/session_01ChpFVKPMobDd3xk3uwG6gj
`tar` on macOS emits `._*` resource-fork stubs unless COPYFILE_DISABLE is set, and they land wherever the archive is unpacked. Three creating call sites still lacked it: - the NO-GIT cloud seed, which is what an OpenClaw workspace usually is — a real hetzner box came up with ._agentbox.yaml, ._AGENTS.md, ._skills in /workspace; - and both --with-env file packers, docker's and the generic concern's. This is the fifth time this class has been fixed, because the rule lived only in the comments of the sites that already had it. A source scan now asserts it: every tar that CREATES an archive passes COPYFILE_DISABLE. Extractions are exempt — the variable means nothing when unpacking. Claude-Session: https://claude.ai/code/session_01ChpFVKPMobDd3xk3uwG6gj
The cloud workspace-env and AppleDouble blockers are verified fixed on a fresh hetzner box. Testing it surfaced a new one: a brand-new box refuses any openclaw CLI command touching exec approvals until `doctor --fix` has run. Claude-Session: https://claude.ai/code/session_01ChpFVKPMobDd3xk3uwG6gj
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 32c257c. Configure here.
| webProxyPort: webPort, | ||
| // Re-sent on every kick: the kick REWRITES box.env with `tee`, so a value | ||
| // it omits is gone for the rest of the box's life, not merely stale. | ||
| agentRunEnv: buildCloudBoxRunEnv(box.agents ?? []), |
There was a problem hiding this comment.
Resume drops cloud agent run-env
Medium Severity
Resume builds agentRunEnv from box.agents ?? [], so a missing agents field becomes no run-env. Create uses agentVolumes.agents, which means every agent when the caller omitted a selection, and the kick then rewrites box.env with tee. A later start therefore strips OPENCLAW_WORKSPACE_DIR (and other declared run-env) for generic and pre-selection boxes, undoing the workspace fix this change just applied.
Reviewed by Cursor Bugbot for commit 32c257c. Configure here.


Blockers 1 and 4 of
docs/plans/service-boxes-plan.md. Two independent fixes,one commit each.
A cloud box's agent never saw its workspace
Measured on a Hetzner OpenClaw box: the user's files were in
/workspaceandthe gateway was pointed at
~/.openclaw/workspace. The headline "your projectdir is the agent's workspace" behaviour, broken on every VPS provider.
spec.boxRunEnvwas built and handed toprovisioncorrectly, then droppedtwice:
cloudInitBoxEnvkeeps onlyAGENTBOX_-prefixed keys — rightly,since
req.envalso carries forwarded provider API keys and cloud-init writesbox.env
0644;kickCloudBootstraprewrites box.env withteeanyway, on every createand resume, so anything cloud-init wrote is gone a step later.
The bootstrap is the last writer and the shared cloud path, so it is the one
place to fix. The run-env now rides both surfaces it already maintains:
env— exported beforeagentbox-ctl bootstrap; the daemon is spawnedwith
env: process.envand hands each task{ ...process.env }. This is whatactually fixes
openclaw-onboard.boxEnvFile— because a cloud login shell does not inherit thedaemon's env, so a hand-run
openclawwould otherwise disagree with theservice unit. Docker needs only one surface because
docker run -eservesboth; a VPS has no equivalent store.
It takes
buildCloudBoxRunEnv, notbuildForwardedEnv— only what aregistry row declares, never the API keys that would then land in a
world-readable file.
Three more tars leaking AppleDouble stubs
taron macOS emits._*resource-fork stubs withoutCOPYFILE_DISABLE, andthey land wherever the archive is unpacked. Three creating call sites still
lacked it: the no-git cloud seed (what an OpenClaw workspace usually is — a
real box came up holding
._agentbox.yaml,._AGENTS.md,._skills), and both--with-envfile packers.This is the fifth time this class has been fixed, because the rule lived only
in the comments of the sites that already had it. A source scan now asserts it:
every tar that CREATES an archive passes
COPYFILE_DISABLE; extractions areexempt. It names the offending file:line when it fails.
Verified on a fresh Hetzner box
and the gateway's own
agents.defaults.workspacereports/workspace, with/workspace/skills/summarise-thread.mdsitting where it now looks. Boxdestroyed; the Hetzner API shows only the pre-existing box.
Both behavioural fixes are mutation-checked.
build,typecheck,testandlintgreen.Found while verifying, not fixed: a brand-new box refuses any openclaw CLI
command that touches exec approvals until
openclaw doctor --fixruns(
ExecApprovalsMigrationRequiredError, on a box where nothing legacy can exist).The gateway itself is unaffected; whether the runtime approvals path is too is
unknown. Recorded in the backlog and added to the plan's blocker list.
https://claude.ai/code/session_01ChpFVKPMobDd3xk3uwG6gj
Note
Medium Risk
Changes cloud bootstrap env wiring and multiple host-side tar paths used for workspace seeding and sync; incorrect quoting or env filtering could break onboard or leak secrets, though only declared agent run-env is written to world-readable box.env.
Overview
Cloud VPS boxes were onboarding OpenClaw against
~/.openclaw/workspacewhile project files lived in/workspacebecause declaredspec.boxRunEnvnever reached ctl tasks or login shells after bootstrap rewrote/etc/agentbox/box.env.buildBootstrapEnvnow acceptsagentRunEnvfrombuildCloudBoxRunEnv(non-secret registry vars only) and writes each key to both the exported bootstrapenvandboxEnvFile, withcloud-providerpassing it on create and every resume kick.macOS archive creation no longer leaks
._*AppleDouble stubs into boxes:COPYFILE_DISABLE=1was added to the no-git cloud seed tar, shared env-file packing insandbox-core, and docker host export packing. A newtar-copyfile-disable.test.tssource scan fails CI if any archive-creatingexeca('tar', …)omits that guard.Planning docs mark the workspace-env and AppleDouble blockers done and record a separate follow-up: fresh boxes may need
openclaw doctor --fixbefore exec-approval CLI commands work.Reviewed by Cursor Bugbot for commit 32c257c. Configure here.