Skip to content

Keep the managed npm tree root-owned so plugin installs load - #19

Closed
lundog wants to merge 1 commit into
Start9-Community:masterfrom
lundog:chown-refactor
Closed

Keep the managed npm tree root-owned so plugin installs load#19
lundog wants to merge 1 commit into
Start9-Community:masterfrom
lundog:chown-refactor

Conversation

@lundog

@lundog lundog commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Problem

The chown oneshot in startos/main.ts runs chown -R node:node /data on every boot. This image runs OpenClaw as root — there's no USER in the Dockerfile, and the gateway daemon and oneshots set no user — and OpenClaw's install policy refuses to load plugin code owned by a lower-privilege uid than the loading process:

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

openclaw plugins install writes the plugin tree root-owned, so the recursive node-chown of /data is what flips the freshly installed plugin files to node:node and gets them blocked on the next gateway load.

This affects any runtime plugin install on the image (surfaced while installing the SimpleX channel plugin from a package action).

Fix

Keep /data node-owned so the gateway can write its state, but re-assert root ownership on the managed npm tree (/data/.openclaw/npm):

  • node-chown all of /data (unchanged intent);
  • mkdir -p /data/.openclaw/npm so the chown target exists on a fresh box before the first install;
  • chown -R root:root /data/.openclaw/npm after the node-chown.

This is exactly OpenClaw's documented remediation for intentional root deployments — see Blocked plugin path ownership: "If you intentionally run OpenClaw as root, repair the managed plugin root to root ownership instead: sudo chown -R root:root /path/to/openclaw-config/npm."

Because the oneshot runs before the gateway on every boot (primary already requires: ['... chown']), it also self-heals: a box whose plugin tree a previous boot left node:node is repaired to root:root before the gateway loads plugins, so existing broken installs recover without a manual doctor/registry --refresh.

Verification

  • tsc --noEmit clean; ncc build startos/index.ts succeeds.
  • Mechanism confirmed by manual install on 0.4.0-beta.9 hardware: openclaw plugins install @dangoldbj/openclaw-simplex@1.8.0 --force (as root, HOME=/data) writes the plugin tree root-owned whether the npm/projects parents are root- or node-owned — npm does not de-escalate to the directory owner, so the blanket node-chown was the sole cause of the node ownership.

The chown oneshot handed all of /data to node:node on every boot. But this
image runs OpenClaw as root (no USER in the Dockerfile, no user set on the
daemon/oneshots), and OpenClaw's install policy refuses to load plugin code
owned by a lower-privilege uid than the loading process:

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

`openclaw plugins install` writes the plugin tree root-owned, so the recursive
node-chown of /data is what flipped it to node-owned and got it blocked on the
next gateway load.

Keep /data node-owned for the gateway's state, but re-assert root ownership on
the managed npm tree (/data/.openclaw/npm) after the node-chown (mkdir first so
it exists before the first install). This matches OpenClaw's documented
remediation for intentional root deployments, and re-running on every boot
self-heals a tree a previous boot left node-owned.

Docs: https://docs.openclaw.ai/tools/plugin#blocked-plugin-path-ownership
@lundog

lundog commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

Closing, superseded!

@lundog lundog closed this Jul 25, 2026
helix-nine added a commit to lundog/openclaw-startos that referenced this pull request Jul 25, 2026
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 (Start9-Community#19, and the earlier Start9-Community#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>
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.

1 participant