feat(openclaw): additive Docker integration with env-driven hardening + doctor cleanup#649
feat(openclaw): additive Docker integration with env-driven hardening + doctor cleanup#649nnnet wants to merge 1 commit into
Conversation
… + doctor cleanup ## Summary Adds an additive OpenClaw gateway integration: a separate `docker-compose-openclaw.yml` that stands up the gateway daemon alongside Mission Control plus a small CLI compatibility shim, env-driven hardening, doctor-banner cleanup, and a brew-enabled sandbox image. The integration is **non-invasive** — when this compose file isn't included, MC keeps working through its direct-dispatch path (PR builderz-labs#648). When it is included, MC discovers the gateway with no extra configuration. ## Headline pieces ### Live-updateable gateway `openclaw-src/` is bind-mounted from the host clone into the gateway container, so `git pull && pnpm build` refreshes the daemon without rebuilding the image. ### CLI compatibility shim (`scripts/openclaw-cli-shim.py`) - Rewrites the legacy CLI shapes MC's source still uses (`gateway sessions_send …`) into the modern RPC call shape (`gateway call sessions_send --params {…}`). MC stays unmodified; openclaw stays read-only. - Projects an env-driven security posture into `~/.openclaw/openclaw.json` on every invocation: `OPENCLAW_SECURITY_WORKSPACE_ONLY`, `OPENCLAW_SECURITY_DENY_AUTOMATION`, `OPENCLAW_SECURITY_DENY_RUNTIME`, `OPENCLAW_SECURITY_DENY_FS`, `OPENCLAW_SECURITY_SANDBOX_ALL`, `TELEGRAM_*`. Reproducible via `.env`, no manual JSON edits. - Filters two `openclaw doctor` output quirks that surface as a warning banner in MC even when nothing is wrong: - The unconditional footer `Run "openclaw doctor --fix" to apply changes.` (printed whenever `--fix` is absent, regardless of whether anything is fixable — see `openclaw-src` `flows/doctor-health-contributions.ts:580-582`). The substring `fix` was tripping MC's `mentionsWarnings` regex. - The Plugins panel's `Errors: 0`. The substring `error` (case-insensitive, no word boundary) was tripping MC's level-`error` escalation regex. Rewritten to `Errs: 0` only when the count is zero; real `Errors: N>0` counts pass through unchanged so genuine plugin errors still raise the banner. ### Path-equivalent state dir Gateway-issued docker bind-mounts now resolve identically inside the gateway container and on the host (so sandbox containers actually see the workspace). ### Auto-pair + Control UI - `scripts/openclaw-auto-pair.py` writes the pairing identity into the gateway's state directory directly, removing a 12-step manual onboarding. - `scripts/openclaw-auto-approve-control-ui.mjs` keeps the local-dev pairing approval flow auto-clicking. - The Control UI runs at `http://127.0.0.1:18791/` behind an nginx that strips loopback-pairing friction and forwards WebSocket upgrades correctly (`docker/openclaw-control-ui.nginx.conf`). ### Brew-enabled gateway and sandbox images - `Dockerfile.openclaw.dockercli` overlays Linuxbrew on `node:24-bookworm` so the `skills.install` RPC can `brew install <formula>` for skills declaring brew dependencies. Also ships the docker CLI so the gateway can spawn sandbox containers via the host docker socket. - `Dockerfile.openclaw.sandbox` overlays brew on top of the upstream `openclaw-sandbox:bookworm-slim` base (kept separate from `openclaw-src/` to preserve the read-only update flow via `make openclaw-update`). ### MC dev container reaches the host docker daemon - `docker.io` added to `Dockerfile.dev` so `openclaw doctor` can verify sandbox readiness without emitting "Sandbox mode is enabled but Docker is not available" to the doctor panel. - `/var/run/docker.sock` bind-mounted; uid 1000 reaches the socket via `group_add` driven by a new `DOCKER_SOCKET_GID` env, auto-detected by the Makefile via `stat -c %g /var/run/docker.sock` (defaults to 994 for stock Debian/Ubuntu hosts; manually overridable on Fedora/Arch/colima/Rancher Desktop where the gid differs). - An empty stub file (`.docker-mask/openclaw-stub.empty`) is bind-mounted over `${HOME}/.openclaw` so openclaw doctor's `findOtherStateDirs()` no longer trips "Multiple state directories detected" against host state visible through the broad `${HOME}:${HOME}` bind. The path becomes a regular file inside the container, so `existsDir()` returns false and the dir is skipped. ## Why this is useful upstream OpenClaw is a macOS-only app today. This makes it usable on any Linux host (cloud VMs, dev sandboxes) without forking either codebase. The shim, env-driven hardening, and doctor-banner filters are **deliberately external** — neither MC nor openclaw-src is modified. Operators can `git clone`, set `.env`, and `make` to bring up an end-to-end MC+gateway stack. ## Test plan 1. `make` → all containers healthy: `mission-control-dev`, `mc-openclaw-gateway`, `mc-openclaw-control-ui`, `mc-openclaw-control-ui-autopair`. 2. `docker exec mission-control-dev docker version` → returns the host docker daemon version. 3. `docker exec mission-control-dev openclaw doctor` → no `Run "openclaw doctor --fix"` footer; `Errors: 0` rendered as `Errs: 0`; no `Multiple state directories detected`. 4. Open `http://127.0.0.1:7012/agents` → no doctor warning banner. 5. Open `http://127.0.0.1:18791/` → Control UI loads; pairing auto-approves. 6. Dispatch a sandboxed task (e.g. weather skill) end-to-end → succeeds. ## Provenance This PR squashes the in-flight history into one cohesive change. Original commits (preserved in our fork at `nnnet/mission-control:experiment/openclaw-integration`): - `cdd75c7 feat(openclaw): additive Docker integration for the OpenClaw gateway` - `e205819 experiment(openclaw): bake openclaw CLI + GATEWAY env into MC dev image` - `c0e71d2 experiment(openclaw): config-only auto-pair flow + agent id binding` - `702eb23 experiment(openclaw): live-updateable bind-mount layout, no docker rebuilds for upgrades` - `beab916 fix(experiment/openclaw): browser WebSocket URL + agent select usability` - `fa28bea fix(experiment/openclaw): rewrite retired CLI shapes via bind-mounted shim` - `73b76e7 fix(experiment/openclaw): silence browser WS retry + fix Command tab Send` - `cc2aa74 Fix prod Mission Control OpenClaw linkage and gateway startup warnings` - `6b1708c fix: harden prod OpenClaw linkage and expose dedicated control UI` - `fd585c1 fix: route OpenClaw control UI through WS-safe proxy` - `6213efe fix(openclaw): bootstrap control UI localhost origin allowlist` - `119ec22 Fix local OpenClaw Control UI pairing flow` - `72d14cf fix(openclaw): stabilize control-ui pairing and telegram allowlist bootstrap` - `c470da4 refactor make/openclaw startup to env-driven runtime config` - `7c83423 fix(openclaw): path-equivalent state dir; stop env_file override in compose` - `b2a75fe`/`2434bad chore(openclaw): harden gateway and add lmstudio/openai models` - `f1c6aed Make OpenClaw tool posture env-driven` - `7a1e819 fix(openclaw): enforce env-driven hardening defaults` - `5f996f1 revert(openclaw): remove doctor info suppression toggle` - `1c24c51 feat(openclaw): make Telegram DM policy env-driven` - `dc2e381 fix(openclaw): project telegram owner policy in MC shim state` - `d0ddc19 chore(openclaw): prebuild dockercli image and run gateway as node` - `b8f7dfe chore: allow auto_backup default via env` - `62daf0a feat(docker): enable docker-in-container + suppress spurious doctor banner` ## Dependencies - Conceptually builds on **builderz-labs#646** (Docker stack) and **builderz-labs#648** (direct multi-provider dispatch), but is independently mergeable: when applied alone on top of `main`, the openclaw-specific files are net-new and the changes to `Dockerfile.dev`/`docker-compose-dev.yml`/`Makefile` are additive. - Reviewers comfortable merging stacked PRs: please consider landing builderz-labs#646 → builderz-labs#648 → this one in that order; this PR will pick up clean rebase deltas afterwards.
0xbrainkid
left a comment
There was a problem hiding this comment.
Summary
- Blocking: the OpenClaw compose integration bakes a host-specific absolute path into the committed compose file, so it will not work on other operator machines.
Strengths
- The doctor unit tests cover several warning-cleanup paths and passed locally.
- The integration is nicely documented and keeps OpenClaw additive rather than forcing MC to depend on it.
Issues
- [BLOCKING]
docker-compose-openclaw.ymlhard-codes/mnt/9/gt/rig_PlatformsAI/mayor/rig/beads/discovered/mission-control/.openclaw-dataintoOPENCLAW_STATE_DIR,OPENCLAW_PLUGIN_STAGE_DIR,OPENCLAW_CONFIG_PATH, and the state volume mount. On any clone outside that exact host path, the gateway will write config/state under a non-existent or wrong host path and sandbox bind mounts will not line up. Please derive this from a configurable env var (for exampleMC_PROJECT_ROOT/OPENCLAW_HOST_STATE_DIR) with a documented default, or avoid the path-equivalence requirement in the committed default.
Questions
- Can the Makefile/bootstrap generate the absolute path into a local ignored override file instead of committing a machine-specific path?
Verification
gh pr checks 649: no checks reported.pnpm vitest run src/lib/__tests__/openclaw-doctor.test.ts: passed (10 tests).docker compose -f docker-compose-openclaw.yml config --quiet: passed syntax/config rendering, but does not catch the portability issue above.
|
Thanks — this is genuinely well-engineered work. Real coverage of an important deployment surface (operator runs MC + OpenClaw stack on a Linux host with sandbox-skill execution), good security-conscious defaults ( But I can't merge it as a single 23-file / 2,924-LoC PR — too large to land safely against the "only merge focused, non-breaking changes" bar I'm using on this triage pass. Three concerns I'd want addressed first: 1. Overlap with #646 and #650
If sequencing: please rebase #649 onto whatever order makes sense and submit as the delta on top of the previous one. Right now 2. Privilege-model documentationThe
That way operators reading the README understand the tradeoff before they enable the flag. 3. Three external-script-fetch patterns at build time
These are well-known projects with canonical install patterns, so it's defensible — but it does mean any future compromise of either CDN injects code into the build. If you'd like to be belt-and-suspenders here, pinning a specific commit/tag of the Homebrew installer ( Path forwardHappy to merge once (1) the relationship with #646/#650 is sorted, and (2) the privilege-model doc section is added. Tagging as |
Summary
Adds an additive OpenClaw gateway integration: a separate
docker-compose-openclaw.ymlthat stands up the gateway daemon alongside Mission Control plus a small CLI compatibility shim, env-driven hardening, doctor-banner cleanup, and a brew-enabled sandbox image. The integration is non-invasive — when this compose file isn't included, MC keeps working through its direct-dispatch path (PR #648). When it is included, MC discovers the gateway with no extra configuration.Headline pieces
Live-updateable gateway
openclaw-src/is bind-mounted from the host clone into the gateway container, sogit pull && pnpm buildrefreshes the daemon without rebuilding the image.CLI compatibility shim (
scripts/openclaw-cli-shim.py)gateway sessions_send …) into the modern RPC call shape (gateway call sessions_send --params {…}). MC stays unmodified; openclaw stays read-only.~/.openclaw/openclaw.jsonon every invocation:OPENCLAW_SECURITY_WORKSPACE_ONLY,OPENCLAW_SECURITY_DENY_AUTOMATION,OPENCLAW_SECURITY_DENY_RUNTIME,OPENCLAW_SECURITY_DENY_FS,OPENCLAW_SECURITY_SANDBOX_ALL,TELEGRAM_*. Reproducible via.env, no manual JSON edits.openclaw doctoroutput quirks that surface as a warning banner in MC even when nothing is wrong:Run "openclaw doctor --fix" to apply changes.(printed whenever--fixis absent, regardless of whether anything is fixable — seeopenclaw-srcflows/doctor-health-contributions.ts:580-582). The substringfixwas tripping MC'smentionsWarningsregex.Errors: 0. The substringerror(case-insensitive, no word boundary) was tripping MC's level-errorescalation regex. Rewritten toErrs: 0only when the count is zero; realErrors: N>0counts pass through unchanged so genuine plugin errors still raise the banner.Path-equivalent state dir
Gateway-issued docker bind-mounts now resolve identically inside the gateway container and on the host (so sandbox containers actually see the workspace).
Auto-pair + Control UI
scripts/openclaw-auto-pair.pywrites the pairing identity into the gateway's state directory directly, removing a 12-step manual onboarding.scripts/openclaw-auto-approve-control-ui.mjskeeps the local-dev pairing approval flow auto-clicking.http://127.0.0.1:18791/behind an nginx that strips loopback-pairing friction and forwards WebSocket upgrades correctly (docker/openclaw-control-ui.nginx.conf).Brew-enabled gateway and sandbox images
Dockerfile.openclaw.dockerclioverlays Linuxbrew onnode:24-bookwormso theskills.installRPC canbrew install <formula>for skills declaring brew dependencies. Also ships the docker CLI so the gateway can spawn sandbox containers via the host docker socket.Dockerfile.openclaw.sandboxoverlays brew on top of the upstreamopenclaw-sandbox:bookworm-slimbase (kept separate fromopenclaw-src/to preserve the read-only update flow viamake openclaw-update).MC dev container reaches the host docker daemon
docker.ioadded toDockerfile.devsoopenclaw doctorcan verify sandbox readiness without emitting "Sandbox mode is enabled but Docker is not available" to the doctor panel./var/run/docker.sockbind-mounted; uid 1000 reaches the socket viagroup_adddriven by a newDOCKER_SOCKET_GIDenv, auto-detected by the Makefile viastat -c %g /var/run/docker.sock(defaults to 994 for stock Debian/Ubuntu hosts; manually overridable on Fedora/Arch/colima/Rancher Desktop where the gid differs)..docker-mask/openclaw-stub.empty) is bind-mounted over${HOME}/.openclawso openclaw doctor'sfindOtherStateDirs()no longer trips "Multiple state directories detected" against host state visible through the broad${HOME}:${HOME}bind. The path becomes a regular file inside the container, soexistsDir()returns false and the dir is skipped.Why this is useful upstream
OpenClaw is a macOS-only app today. This makes it usable on any Linux host (cloud VMs, dev sandboxes) without forking either codebase. The shim, env-driven hardening, and doctor-banner filters are deliberately external — neither MC nor openclaw-src is modified. Operators can
git clone, set.env, andmaketo bring up an end-to-end MC+gateway stack.Test plan
make→ all containers healthy:mission-control-dev,mc-openclaw-gateway,mc-openclaw-control-ui,mc-openclaw-control-ui-autopair.docker exec mission-control-dev docker version→ returns the host docker daemon version.docker exec mission-control-dev openclaw doctor→ noRun "openclaw doctor --fix"footer;Errors: 0rendered asErrs: 0; noMultiple state directories detected.http://127.0.0.1:7012/agents→ no doctor warning banner.http://127.0.0.1:18791/→ Control UI loads; pairing auto-approves.Provenance
This PR squashes the in-flight history into one cohesive change. Original commits (preserved in our fork at
nnnet/mission-control:experiment/openclaw-integration):cdd75c7 feat(openclaw): additive Docker integration for the OpenClaw gatewaye205819 experiment(openclaw): bake openclaw CLI + GATEWAY env into MC dev imagec0e71d2 experiment(openclaw): config-only auto-pair flow + agent id binding702eb23 experiment(openclaw): live-updateable bind-mount layout, no docker rebuilds for upgradesbeab916 fix(experiment/openclaw): browser WebSocket URL + agent select usabilityfa28bea fix(experiment/openclaw): rewrite retired CLI shapes via bind-mounted shim73b76e7 fix(experiment/openclaw): silence browser WS retry + fix Command tab Sendcc2aa74 Fix prod Mission Control OpenClaw linkage and gateway startup warnings6b1708c fix: harden prod OpenClaw linkage and expose dedicated control UIfd585c1 fix: route OpenClaw control UI through WS-safe proxy6213efe fix(openclaw): bootstrap control UI localhost origin allowlist119ec22 Fix local OpenClaw Control UI pairing flow72d14cf fix(openclaw): stabilize control-ui pairing and telegram allowlist bootstrapc470da4 refactor make/openclaw startup to env-driven runtime config7c83423 fix(openclaw): path-equivalent state dir; stop env_file override in composeb2a75fe/2434bad chore(openclaw): harden gateway and add lmstudio/openai modelsf1c6aed Make OpenClaw tool posture env-driven7a1e819 fix(openclaw): enforce env-driven hardening defaults5f996f1 revert(openclaw): remove doctor info suppression toggle1c24c51 feat(openclaw): make Telegram DM policy env-drivendc2e381 fix(openclaw): project telegram owner policy in MC shim stated0ddc19 chore(openclaw): prebuild dockercli image and run gateway as nodeb8f7dfe chore: allow auto_backup default via env62daf0a feat(docker): enable docker-in-container + suppress spurious doctor bannerDependencies
main, the openclaw-specific files are net-new and the changes toDockerfile.dev/docker-compose-dev.yml/Makefileare additive.