Skip to content

fix: run OpenClaw as node so installed plugins load - #21

Merged
helix-nine merged 1 commit into
masterfrom
run-as-node
Jul 25, 2026
Merged

fix: run OpenClaw as node so installed plugins load#21
helix-nine merged 1 commit into
masterfrom
run-as-node

Conversation

@helix-nine

Copy link
Copy Markdown
Contributor

Problem

openclaw plugins install writes the plugin tree root-owned, but the boot-time chown -R node:node /data oneshot flips it to node before the gateway loads — and the gateway runs as root (no USER in the Dockerfile, no user on the daemon; the SDK defaults exec to root). OpenClaw's plugin loader then blocks the node-owned tree:

blocked plugin candidate: suspicious ownership (uid=1000, expected uid=0 or root)

This is a root/node hybrid. /data being node-owned is correct — OpenClaw's official image runs as node (uid 1000) and its loader only accepts plugins owned by the gateway's own uid (its documented Docker remediation is literally chown -R 1000:1000). The mistake is running the gateway as root against that node-owned tree. OpenClaw does not de-escalate ("plugins and tools execute within the same process context"), so a root gateway demands root-owned plugins while the node-chown guarantees node-owned ones. It surfaced installing the SimpleX plugin, but hit any runtime plugin install (e.g. Codex, see #7).

Fix

Align to OpenClaw's actual model — run as node — rather than patch the symptom:

  • The primary gateway and every openclaw / start-cli exec that touches /data (plugin install/list/uninstall, auth login, check-login, state snapshot, whatsapp login) now run as node.
  • Root stays only where genuinely required: the chown oneshot (only root can chown), update-ca-certificates (system trust store), init seeding (a fresh /data is root-owned before main's chown ever runs), and the revoke-access cookie rm (a security action must always succeed at deleting).

Plugin installs now write node-owned trees, the node gateway loads them, and file-exchange files OpenClaw writes come out node-owned too.

Relationship to the other open PRs

Self-heal: existing boxes with a blocked (node-owned) plugin tree recover on upgrade — the node-owned tree now matches the node gateway, so no re-install is needed.

Version

Deliberately not bumped (still 2026.7.1:2) to avoid minting a second :3 alongside #20. Coordinate the release: fold into #20's :3, or land this first as :3 and rebase #20 to :4.

Test plan

  1. Build and install this branch's .s9pk. Complete first-run: Set Password, Configure AI Provider, Login to StartOS.
  2. Confirm the gateway runs as node: start-cli package attach openclaw -n openclaw-sub -- iduid=1000(node). Web UI health goes green.
  3. Install SimpleX Websocket Bridge, then run Configure SimpleX → Enabled.
  4. Restart the service (the ownership block only surfaces on a reload). Confirm the gateway logs show no blocked plugin candidate: suspicious ownership, and the SimpleX channel comes up. Verify ownership: start-cli package attach openclaw -n openclaw-sub -- ls -la /data/.openclaw/npm/node_modules → plugin dirs owned node node.
  5. Confirm start-cli host administration still works as node: start-cli package attach openclaw -n openclaw-sub -- tail /data/.openclaw/workspace/MEMORY.md shows the startup server-state snapshot, and the agent can list packages.
  6. With Wire SimpleX file exchange (openclaw-simplex 1.8.0) and release 2026.7.1:3 #20's file-exchange wired: send and receive a file over SimpleX; confirm OpenClaw's outbound files are node-owned and the bridge consumes them.
  7. Run Revoke StartOS Access → the stored cookie is removed and start-cli auth session list fails.

🤖 Generated with Claude Code

The gateway ran as root against a node-owned /data. OpenClaw's image is
designed to run as `node` (uid 1000) and its plugin loader only accepts
plugins owned by the gateway's own uid. `openclaw plugins install` wrote the
tree root-owned, then the boot-time `chown -R node:node /data` flipped it to
node, so the root gateway blocked it ("suspicious ownership, expected uid=0").
This surfaced installing the SimpleX channel plugin, but hit any runtime
plugin install (e.g. Codex).

Align to OpenClaw's model: run the gateway and every openclaw/start-cli exec
(plugin install/list/uninstall, auth login, check-login, state snapshot,
whatsapp login) as node. Keep root only where genuinely required — the chown
oneshot (only root can chown), update-ca-certificates (system trust store),
init seeding (fresh /data is root-owned before main's chown), and the
revoke-access cookie rm (a security action must always delete).

Supersedes the npm-subtree carve-out approach (#19, and the earlier #7).
Existing blocked installs self-heal on upgrade: the node-owned tree now
matches the node gateway, so no re-install is needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lundog

lundog commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

I’m happy to remove the version tag from my PR branch if you’d like to handle the release part.

@helix-nine
helix-nine merged commit 0d6b494 into master Jul 25, 2026
3 checks passed
@helix-nine
helix-nine deleted the run-as-node branch July 25, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants