Skip to content

fix(install): ensure .openclaw-data ownership for sandbox user (fixes #692)#1089

Open
kagura-agent wants to merge 4 commits intoNVIDIA:mainfrom
kagura-agent:fix/692-identity-dir-permissions-v2
Open

fix(install): ensure .openclaw-data ownership for sandbox user (fixes #692)#1089
kagura-agent wants to merge 4 commits intoNVIDIA:mainfrom
kagura-agent:fix/692-identity-dir-permissions-v2

Conversation

@kagura-agent
Copy link
Copy Markdown
Contributor

@kagura-agent kagura-agent commented Mar 30, 2026

Resubmitted as requested by @mnsami (original: #698).

Problem

When NemoClaw is installed via the curl installer on Linux, .openclaw-data directories may be created with root ownership. When openclaw runs as the sandbox user, it gets EACCES: permission denied trying to write device-auth.json.

Fix

Add a startup ownership check to nemoclaw-start.sh (non-root path) that:

  • Creates any missing writable subdirectories (mirrors Dockerfile setup)
  • Fixes ownership if files are not owned by the current user
  • Creates the identity symlink if missing on native installs

The Docker path is unaffected (Dockerfile already sets correct ownership).

Testing

All pre-commit hooks pass (shellcheck, shfmt, gitleaks, etc). 420/422 unit tests pass; 2 pre-existing failures in install-preflight.test.js are unrelated (Node.js version detection message mismatch).

Fixes #692

Summary by CodeRabbit

  • Bug Fixes
    • Improved non-root startup: the launcher now ensures the user data directory and required subfolders exist, attempts to correct ownership where needed (with warnings on failure), and creates or repairs the identity symlink into the data directory. This reduces permission and setup issues and prevents missing or mismatched identity links when running without administrative privileges.

…VIDIA#692)

The native curl installer may create .openclaw-data directories as root,
causing EACCES when openclaw (running as the sandbox user) tries to write
device-auth.json to the identity directory.

Add a startup ownership check to nemoclaw-start.sh that:
- Creates any missing writable subdirectories (mirrors Dockerfile setup)
- Fixes ownership if files are not owned by the current user
- Creates the identity symlink if missing on native installs

The Docker path is unaffected (Dockerfile already sets correct ownership).

Resubmitted as requested by @mnsami (original: NVIDIA#698).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

📝 Walkthrough

Walkthrough

Adds a non-root-only local function fix_openclaw_data_ownership to scripts/nemoclaw-start.sh that ensures ${HOME}/.openclaw-data and required subdirectories exist, repairs ownership where possible via chown -R $(id -u):$(id -g) when mismatched, and ensures ${HOME}/.openclaw/identity is a symlink to the data identity directory before writing the auth profile.

Changes

Cohort / File(s) Summary
Permission Fix Helper
scripts/nemoclaw-start.sh
Add fix_openclaw_data_ownership and invoke it in the non-root branch after verify_config_integrity and before write_auth_profile. The helper creates ${HOME}/.openclaw-data subdirs, checks for ownership mismatches, attempts chown -R $(id -u):$(id -g) (errors suppressed, warnings emitted on failure), and ensures ${HOME}/.openclaw/identity is a symlink to ${HOME}/.openclaw-data/identity, reporting errors if a non-symlink file blocks the path.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through dots and dirs tonight,

I nudged the owners till they were right,
A chown here, a symlink there,
Sandbox identity handled with care,
Hooray — permission troubles take flight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding ownership fix for .openclaw-data to handle sandbox user permissions, which directly addresses the linked issue #692.
Linked Issues check ✅ Passed The code changes fully address issue #692 objectives: creates missing directories, recursively fixes file ownership for current user, ensures identity symlink exists/is repaired, and leaves Docker path unchanged.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing ownership issues in nemoclaw-start.sh for non-root execution; no unrelated modifications to other files or systems present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/nemoclaw-start.sh (1)

317-320: Ensure parent directory exists before symlink creation.

If ${openclaw_dir} (/sandbox/.openclaw) doesn't exist, the ln command will fail silently. While other code assumes this directory exists, adding a guard would make the fix more robust, especially for edge cases in native installs.

Proposed improvement
     if [ ! -e "${openclaw_dir}/identity" ] && [ -d "${data_dir}/identity" ]; then
+      mkdir -p "${openclaw_dir}" 2>/dev/null || true
       ln -sf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
       echo "[setup] created identity symlink"
     fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/nemoclaw-start.sh` around lines 317 - 320, The symlink creation can
fail if the parent directory referenced by openclaw_dir doesn't exist; modify
the block that checks for identity and creates the symlink to first ensure the
openclaw_dir parent exists (e.g., create the directory if missing) before
running ln -sf, while preserving the existing checks using openclaw_dir,
data_dir, and the identity target and keeping the silent-fail behavior (redirect
errors and || true). Ensure the change only creates the directory when necessary
and does not alter the conditional semantics around the identity symlink
creation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/nemoclaw-start.sh`:
- Around line 317-320: The symlink creation can fail if the parent directory
referenced by openclaw_dir doesn't exist; modify the block that checks for
identity and creates the symlink to first ensure the openclaw_dir parent exists
(e.g., create the directory if missing) before running ln -sf, while preserving
the existing checks using openclaw_dir, data_dir, and the identity target and
keeping the silent-fail behavior (redirect errors and || true). Ensure the
change only creates the directory when necessary and does not alter the
conditional semantics around the identity symlink creation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 02d0a39f-e4d3-43c1-9bae-b9dbf25b130f

📥 Commits

Reviewing files that changed from the base of the PR and between f59f58e and 54ec466.

📒 Files selected for processing (1)
  • scripts/nemoclaw-start.sh

Add mkdir -p for openclaw_dir before ln -sf, in case /sandbox/.openclaw
doesn't exist yet (e.g. fresh native installs).

Addresses CodeRabbit review nitpick.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/nemoclaw-start.sh`:
- Around line 313-316: The ownership-check currently uses find with -maxdepth 0
on ${data_dir} and then runs chown -R but always echoes "fixed ownership" even
when chown fails; update the logic so you use find to detect any files/dirs in
${data_dir} not owned by the current uid/gid (e.g. remove -maxdepth 0 and use
-user/! -user/-group), run chown -R and capture its exit status or errors, and
only print "[setup] fixed ownership on ${data_dir}" when chown succeeds; if
chown fails, surface a clear error message (do not suppress with || true) so
unresolved EACCES paths are visible.
- Around line 317-320: The startup script only creates the identity symlink when
"${openclaw_dir}/identity" is missing; modify the logic around openclaw_dir,
data_dir and the identity path to detect and remediate incorrect existing
states: if "${openclaw_dir}/identity" exists but is not a symlink to
"${data_dir}/identity" (including a stale/broken symlink or a regular
directory), remove or rename the existing entry and then create the correct
symlink, preserving any safe backup behavior as needed; use readlink (or test -L
and readlink -f) to compare targets and ensure ln -sf is executed only after the
bad path is removed so permissions/target issues are resolved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8e360189-b61c-4471-a0bf-fe64d047617e

📥 Commits

Reviewing files that changed from the base of the PR and between 54ec466 and 85bcc69.

📒 Files selected for processing (1)
  • scripts/nemoclaw-start.sh

Comment on lines +317 to +320
if [ ! -e "${openclaw_dir}/identity" ] && [ -d "${data_dir}/identity" ]; then
mkdir -p "${openclaw_dir}" 2>/dev/null || true
ln -sf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
echo "[setup] created identity symlink"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Existing invalid ~/.openclaw/identity states are not remediated.

Line 317 only handles the “missing path” case. If ${openclaw_dir}/identity already exists but is wrong (bad symlink target or regular directory), startup leaves it unchanged, so the permission/path issue can persist.

🔧 Proposed fix
-    if [ ! -e "${openclaw_dir}/identity" ] && [ -d "${data_dir}/identity" ]; then
-      mkdir -p "${openclaw_dir}" 2>/dev/null || true
-      ln -sf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
-      echo "[setup] created identity symlink"
-    fi
+    if [ -d "${data_dir}/identity" ]; then
+      mkdir -p "${openclaw_dir}" 2>/dev/null || true
+      if [ -L "${openclaw_dir}/identity" ]; then
+        local current_target expected_target
+        current_target="$(readlink -f "${openclaw_dir}/identity" 2>/dev/null || true)"
+        expected_target="$(readlink -f "${data_dir}/identity" 2>/dev/null || true)"
+        if [ "$current_target" != "$expected_target" ]; then
+          ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
+          echo "[setup] repaired identity symlink"
+        fi
+      elif [ ! -e "${openclaw_dir}/identity" ]; then
+        ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
+        echo "[setup] created identity symlink"
+      else
+        echo "[setup] ${openclaw_dir}/identity exists and is not a symlink; leaving as-is" >&2
+      fi
+    fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ ! -e "${openclaw_dir}/identity" ] && [ -d "${data_dir}/identity" ]; then
mkdir -p "${openclaw_dir}" 2>/dev/null || true
ln -sf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
echo "[setup] created identity symlink"
if [ -d "${data_dir}/identity" ]; then
mkdir -p "${openclaw_dir}" 2>/dev/null || true
if [ -L "${openclaw_dir}/identity" ]; then
local current_target expected_target
current_target="$(readlink -f "${openclaw_dir}/identity" 2>/dev/null || true)"
expected_target="$(readlink -f "${data_dir}/identity" 2>/dev/null || true)"
if [ "$current_target" != "$expected_target" ]; then
ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
echo "[setup] repaired identity symlink"
fi
elif [ ! -e "${openclaw_dir}/identity" ]; then
ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
echo "[setup] created identity symlink"
else
echo "[setup] ${openclaw_dir}/identity exists and is not a symlink; leaving as-is" >&2
fi
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/nemoclaw-start.sh` around lines 317 - 320, The startup script only
creates the identity symlink when "${openclaw_dir}/identity" is missing; modify
the logic around openclaw_dir, data_dir and the identity path to detect and
remediate incorrect existing states: if "${openclaw_dir}/identity" exists but is
not a symlink to "${data_dir}/identity" (including a stale/broken symlink or a
regular directory), remove or rename the existing entry and then create the
correct symlink, preserving any safe backup behavior as needed; use readlink (or
test -L and readlink -f) to compare targets and ensure ln -sf is executed only
after the bad path is removed so permissions/target issues are resolved.

Address CodeRabbit review feedback:

1. Ownership check: remove -maxdepth 0 so find scans all descendants
   for wrong-uid files; surface chown failure instead of suppressing

2. Identity symlink: handle stale/broken symlinks and wrong targets
   by comparing readlink -f; warn if path exists as non-symlink
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/nemoclaw-start.sh (1)

327-332: Symlink operations log success unconditionally, unlike the chown pattern.

The chown block (lines 314-318) correctly checks the exit status before logging success. However, the ln -snf calls on lines 327 and 331 use || true but still unconditionally echo success messages. If ln fails (e.g., permission denied on parent directory), the user sees misleading "[setup] repaired/created identity symlink" output.

For consistency with the ownership fix pattern:

♻️ Proposed fix for consistent error reporting
       if [ "$current_target" != "$expected_target" ]; then
-          ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
-          echo "[setup] repaired identity symlink"
+          if ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null; then
+            echo "[setup] repaired identity symlink"
+          else
+            echo "[setup] could not repair identity symlink" >&2
+          fi
         fi
       elif [ ! -e "${openclaw_dir}/identity" ]; then
-        ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
-        echo "[setup] created identity symlink"
+        if ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null; then
+          echo "[setup] created identity symlink"
+        else
+          echo "[setup] could not create identity symlink" >&2
+        fi
       else
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/nemoclaw-start.sh` around lines 327 - 332, The install script logs
successful identity symlink creation/repair unconditionally even though the ln
-snf calls use "|| true", which can hide failures; change the two ln -snf
"${data_dir}/identity" "${openclaw_dir}/identity" invocations to remove the "||
true" and wrap each in an if/then that checks ln's exit status (e.g. if ln -snf
...; then echo "[setup] created/ repaired identity symlink"; else echo "[setup]
failed to create/repair identity symlink" >&2; fi) so the messages for the
identity symlink mirror the chown pattern and reflect real success/failure for
operations involving ${data_dir}, ${openclaw_dir} and the ln command.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/nemoclaw-start.sh`:
- Around line 327-332: The install script logs successful identity symlink
creation/repair unconditionally even though the ln -snf calls use "|| true",
which can hide failures; change the two ln -snf "${data_dir}/identity"
"${openclaw_dir}/identity" invocations to remove the "|| true" and wrap each in
an if/then that checks ln's exit status (e.g. if ln -snf ...; then echo "[setup]
created/ repaired identity symlink"; else echo "[setup] failed to create/repair
identity symlink" >&2; fi) so the messages for the identity symlink mirror the
chown pattern and reflect real success/failure for operations involving
${data_dir}, ${openclaw_dir} and the ln command.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 137a8d43-b40e-41bb-955c-bcc3dc13783d

📥 Commits

Reviewing files that changed from the base of the PR and between 85bcc69 and 1cc6be5.

📒 Files selected for processing (1)
  • scripts/nemoclaw-start.sh

@wscurran wscurran added bug Something isn't working Getting Started Use this label to identify setup, installation, or onboarding issues. priority: high Important issue that should be resolved in the next release fix labels Mar 30, 2026
@wscurran
Copy link
Copy Markdown
Contributor

✨ Thanks for submitting this PR with a detailed summary, it addresses a bug with the curl installer on Linux and proposes a fix to ensure .openclaw-data ownership for the sandbox user, which could improve the installation process of NemoClaw.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
scripts/nemoclaw-start.sh (1)

334-336: ⚠️ Potential issue | 🟠 Major

Remediate existing non-symlink ~/.openclaw/identity instead of leaving it broken.

Line 335 currently warns and keeps the path unchanged. If that entry is a root-owned directory/file, the startup path remains broken for identity writes.

🔧 Proposed fix
       elif [ ! -e "${openclaw_dir}/identity" ]; then
         ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null || true
         echo "[setup] created identity symlink"
       else
-        echo "[setup] ${openclaw_dir}/identity exists and is not a symlink; leaving as-is" >&2
+        local backup="${openclaw_dir}/identity.bak.$(date +%s)"
+        if mv "${openclaw_dir}/identity" "$backup" 2>/dev/null && \
+           ln -snf "${data_dir}/identity" "${openclaw_dir}/identity" 2>/dev/null; then
+          echo "[setup] replaced non-symlink identity path (backup: ${backup})"
+        else
+          echo "[setup] could not replace ${openclaw_dir}/identity; writes may fail" >&2
+          return 1
+        fi
       fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/nemoclaw-start.sh` around lines 334 - 336, Replace the current branch
that only echoes a warning when "${openclaw_dir}/identity" exists and is not a
symlink: detect the non-symlink, move it aside to a timestamped backup (e.g.
"${openclaw_dir}/identity.bak.$(date +%s)") or otherwise rename it so root-owned
files don't block startup, then create the intended symlink pointing at
"${openclaw_dir}/identity"; ensure the mv and ln -s steps are guarded (check
success and log failures) so the startup can proceed to write identity files.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@scripts/nemoclaw-start.sh`:
- Around line 334-336: Replace the current branch that only echoes a warning
when "${openclaw_dir}/identity" exists and is not a symlink: detect the
non-symlink, move it aside to a timestamped backup (e.g.
"${openclaw_dir}/identity.bak.$(date +%s)") or otherwise rename it so root-owned
files don't block startup, then create the intended symlink pointing at
"${openclaw_dir}/identity"; ensure the mv and ln -s steps are guarded (check
success and log failures) so the startup can proceed to write identity files.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0a2adb4a-cf6f-4d7c-9a2d-8f18ccc051b7

📥 Commits

Reviewing files that changed from the base of the PR and between 1cc6be5 and b33ca5d.

📒 Files selected for processing (1)
  • scripts/nemoclaw-start.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working fix Getting Started Use this label to identify setup, installation, or onboarding issues. priority: high Important issue that should be resolved in the next release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EACCES: permission denied on /sandbox/.openclaw/identity/device-auth.json — curl install on Linux (no sudo in sandbox)

3 participants