fix(install): ensure .openclaw-data ownership for sandbox user (fixes #692)#1089
fix(install): ensure .openclaw-data ownership for sandbox user (fixes #692)#1089kagura-agent wants to merge 4 commits intoNVIDIA:mainfrom
Conversation
…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).
📝 WalkthroughWalkthroughAdds a non-root-only local function Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 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, thelncommand 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
📒 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.
There was a problem hiding this comment.
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
📒 Files selected for processing (1)
scripts/nemoclaw-start.sh
scripts/nemoclaw-start.sh
Outdated
| 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" |
There was a problem hiding this comment.
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.
| 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
There was a problem hiding this comment.
🧹 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 -snfcalls on lines 327 and 331 use|| truebut still unconditionally echo success messages. Iflnfails (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
📒 Files selected for processing (1)
scripts/nemoclaw-start.sh
|
✨ 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. |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
scripts/nemoclaw-start.sh (1)
334-336:⚠️ Potential issue | 🟠 MajorRemediate existing non-symlink
~/.openclaw/identityinstead 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
📒 Files selected for processing (1)
scripts/nemoclaw-start.sh
Resubmitted as requested by @mnsami (original: #698).
Problem
When NemoClaw is installed via the curl installer on Linux,
.openclaw-datadirectories may be created with root ownership. When openclaw runs as thesandboxuser, it getsEACCES: permission deniedtrying to writedevice-auth.json.Fix
Add a startup ownership check to
nemoclaw-start.sh(non-root path) that: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.jsare unrelated (Node.js version detection message mismatch).Fixes #692
Summary by CodeRabbit