fix(docker): ensure agent directory permissions in docker-setup.sh (#28841)

* fix(docker): ensure agent directory permissions in docker-setup.sh

* fix(docker): restrict chown to config-dir mount, not workspace

The previous 'chown -R node:node /home/node/.openclaw' call crossed into
the workspace bind mount on Linux hosts, recursively rewriting ownership
of all user project files in the workspace directory.

Fix: use 'find -xdev' to restrict chown to the config-dir filesystem
only (won't cross bind-mount boundaries). Then separately chown only
the OpenClaw metadata subdirectory (.openclaw/) within the workspace,
leaving the user's project files untouched.

Addresses review comment on PR #28841.
This commit is contained in:
Glucksberg
2026-03-01 22:07:34 -04:00
committed by GitHub
parent a25a73e707
commit a262a3ea08
2 changed files with 44 additions and 2 deletions

View File

@@ -171,6 +171,30 @@ describe("docker-setup.sh", () => {
expect(identityDirStat.isDirectory()).toBe(true);
});
it("precreates agent data dirs to avoid EACCES in container", async () => {
const activeSandbox = requireSandbox(sandbox);
const configDir = join(activeSandbox.rootDir, "config-agent-dirs");
const workspaceDir = join(activeSandbox.rootDir, "workspace-agent-dirs");
const result = runDockerSetup(activeSandbox, {
OPENCLAW_CONFIG_DIR: configDir,
OPENCLAW_WORKSPACE_DIR: workspaceDir,
});
expect(result.status).toBe(0);
const agentDirStat = await stat(join(configDir, "agents", "main", "agent"));
expect(agentDirStat.isDirectory()).toBe(true);
const sessionsDirStat = await stat(join(configDir, "agents", "main", "sessions"));
expect(sessionsDirStat.isDirectory()).toBe(true);
// Verify that a root-user chown step runs before onboarding.
const log = await readFile(activeSandbox.logPath, "utf8");
const chownIdx = log.indexOf("--user root");
const onboardIdx = log.indexOf("onboard");
expect(chownIdx).toBeGreaterThanOrEqual(0);
expect(onboardIdx).toBeGreaterThan(chownIdx);
});
it("reuses existing config token when OPENCLAW_GATEWAY_TOKEN is unset", async () => {
const activeSandbox = requireSandbox(sandbox);
const configDir = join(activeSandbox.rootDir, "config-token-reuse");