Skip to content

fix(install): prevent nvm/login shell from resetting PATH in subshells#651

Open
cv wants to merge 6 commits intoNVIDIA:mainfrom
cv:fix/install-subshell-helpers
Open

fix(install): prevent nvm/login shell from resetting PATH in subshells#651
cv wants to merge 6 commits intoNVIDIA:mainfrom
cv:fix/install-subshell-helpers

Conversation

@cv
Copy link
Contributor

@cv cv commented Mar 22, 2026

Summary

  • bash -lcbash -c in install_nemoclaw() subshells. The login shell flag sourced /etc/profile which runs path_helper on macOS, resetting PATH to system defaults and hiding the caller's binaries.
  • Skip nvm.sh sourcing when node is already on PATH. ensure_nvm_loaded() unconditionally sourced nvm.sh, which also resets PATH — breaking test stubs and unnecessarily mutating the environment.
  • Export info/warn helpers via declare -f so pre_extract_openclaw can use them in the subshell.
  • Fix SC2206 shellcheck warning in version_gte() — use read -ra instead of unquoted word splitting.
  • Add .shellcheckrc to suppress SC2059 (printf format string with color vars) and SC1091 (dynamically sourced files).
  • Fix pyright CI failures — drop stray . arg from pyright invocations in Makefile and pre-commit hook (overrides pyproject.toml include/exclude, scanning .venv), and exclude test_*.py files from strict type-checking since they import pytest which is a dev-only dependency.

Why these tests failed locally but passed in CI

CI runs on ubuntu-latest with a minimal shell profile — no nvm, no path_helper. On macOS with nvm installed, both bash -l (via /etc/profile) and ensure_nvm_loaded (via nvm.sh) reset PATH, causing the fake node/npm/git stubs in install-preflight.test.js to be overridden by real system binaries.

Test plan

  • npx vitest run — all 27 test files pass (303 tests)
  • npx shellcheck install.sh scripts/install.sh — clean
  • CI green: lint, test-unit, test-e2e-sandbox, commit-lint

🤖 Generated with Claude Code

Two issues caused install_nemoclaw() subshells to lose the caller's
PATH, making install-preflight tests fail on macOS while passing in CI:

1. `bash -lc` sourced /etc/profile which runs path_helper on macOS,
   resetting PATH to system defaults and hiding the caller's binaries.
   Fix: replace `bash -lc` with `bash -c` — the parent shell already
   has the correct PATH, so a login shell is unnecessary.

2. `ensure_nvm_loaded()` unconditionally sourced nvm.sh, which also
   resets PATH. Fix: skip sourcing when node is already on PATH.

Also export `info` and `warn` helpers via `declare -f` so
pre_extract_openclaw can use them in the subshell.

Additionally:
- Fix SC2206 shellcheck warning in version_gte() by using `read -ra`
  instead of unquoted word splitting into arrays.
- Add .shellcheckrc to suppress SC2059 (printf format string with color
  vars) and SC1091 (dynamically sourced files) across the project.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ffb1d687-6976-4028-8cb8-7beaa5557c6e

📥 Commits

Reviewing files that changed from the base of the PR and between 350cba0 and e2b955b.

📒 Files selected for processing (1)
  • nemoclaw-blueprint/Makefile
✅ Files skipped from review due to trivial changes (1)
  • nemoclaw-blueprint/Makefile

📝 Walkthrough

Walkthrough

Added a ShellCheck config and small stylistic/control-flow changes across shell scripts and CI hooks: short-circuited nvm sourcing when node is on PATH, adjusted semver parsing/read usage, replaced some bash -lc with bash -c, and tweaked pre-commit/pyright invocations.

Changes

Cohort / File(s) Summary
ShellCheck configuration
./.shellcheckrc
New file disabling SC2059 and SC1091 with inline comments about intentional printf format vars and dynamically sourced scripts.
Top-level installer
install.sh
Formatting and control-flow tightening: expanded single-line functions, adjusted spinner/tmp handling, refactored version_gte() to use read -ra, changed some bash -lcbash -c, and strengthened a failure handler block.
Scripts installer
scripts/install.sh
ensure_nvm_loaded() now returns early if node is found on PATH; added comment about sourcing nvm.sh side-effects.
OpenShell installer
scripts/install-openshell.sh
Minor change to version_gte() here-string spacing/read usage (stylistic).
Backup tooling
scripts/backup-workspace.sh
Converted fail() to multi-line and normalized indentation/formatting across functions; no behavioral changes.
Pre-push hook
./.pre-commit-config.yaml
Removed trailing . from the pyright pre-push hook invocation (changes target/path behavior).
Pyright config
nemoclaw-blueprint/pyproject.toml
Added exclude = ["**/test_*.py"] under [tool.pyright] to omit test files from analysis.
Makefile check target
nemoclaw-blueprint/Makefile
Removed trailing . from the Pyright invocation in the check target.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through scripts at dawn's first light,
Trimmed a space, kept behavior tight.
NVM now nods when node's in sight,
ShellCheck listens, banners polite.
A tiny carrot, and tests sleep tight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: preventing nvm/login shell from resetting PATH in subshells, which aligns with the core objectives of replacing bash -lc with bash -c and modifying ensure_nvm_loaded().

✏️ 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

@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)
.shellcheckrc (1)

9-9: Scope ShellCheck suppressions more narrowly.

Line 9 disables SC2059 and SC1091 repo-wide, which can mask future issues outside installer helpers. Prefer keeping global config minimal and using local # shellcheck disable=... at intentional callsites.

Example tightening
-disable=SC2059,SC1091
+disable=SC1091
# In files with intentional colorized printf format strings:
# shellcheck disable=SC2059
info() { printf "${C_CYAN}[INFO]${C_RESET}  %s\n" "$*"; }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.shellcheckrc at line 9, Remove the repo‑wide suppression of SC2059 and
SC1091 from .shellcheckrc and instead scope those disables to specific call
sites that intentionally require them (for example the colorized printf helper
like info() and any installer helper that sources generated files), by adding
local comments such as "# shellcheck disable=SC2059" or "# shellcheck
disable=SC1091" directly above the offending function or source statement; keep
the global .shellcheckrc minimal so other files still get checked.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.shellcheckrc:
- Line 9: Remove the repo‑wide suppression of SC2059 and SC1091 from
.shellcheckrc and instead scope those disables to specific call sites that
intentionally require them (for example the colorized printf helper like info()
and any installer helper that sources generated files), by adding local comments
such as "# shellcheck disable=SC2059" or "# shellcheck disable=SC1091" directly
above the offending function or source statement; keep the global .shellcheckrc
minimal so other files still get checked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dee031f5-e9f3-4ee0-b586-67c22701b172

📥 Commits

Reviewing files that changed from the base of the PR and between 2ce2905 and 8c79539.

📒 Files selected for processing (3)
  • .shellcheckrc
  • install.sh
  • scripts/install.sh

cv and others added 4 commits March 22, 2026 20:12
Passing '.' to pyright overrides the include/exclude paths in
pyproject.toml, causing it to scan .venv and test files. Without the
argument, pyright respects the configured include paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Auto-formatted by shfmt via pre-commit hooks after merging
upstream/main.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The test_endpoint_validation.py file imports pytest which is only
available as a dev dependency. Pyright in strict mode cannot resolve it,
breaking the pre-push hook. Exclude test files from pyright's include
paths since they have their own type discipline via pytest.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

@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: 1

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

Inline comments:
In `@install.sh`:
- Around line 572-579: Update the script's usage output (the usage function) to
document the new -h short alias alongside --help and --version/-v; specifically,
modify the displayed options so the help text lists both `-h, --help` (and where
applicable `-v, --version`) to match the case in the option parsing block that
now accepts `-h` in addition to `--help`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9587cdde-3ef8-4e1b-89f2-dd36b75ac933

📥 Commits

Reviewing files that changed from the base of the PR and between 8c79539 and 350cba0.

📒 Files selected for processing (5)
  • .pre-commit-config.yaml
  • install.sh
  • nemoclaw-blueprint/pyproject.toml
  • scripts/backup-workspace.sh
  • scripts/install-openshell.sh
✅ Files skipped from review due to trivial changes (2)
  • nemoclaw-blueprint/pyproject.toml
  • scripts/backup-workspace.sh

Comment on lines +572 to +579
--version | -v)
printf "nemoclaw-installer v%s\n" "$NEMOCLAW_VERSION"
exit 0
;;
--help | -h)
usage
exit 0
;;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Document the new -h alias in usage output.

Line 576 adds -h, but the displayed help text still lists only --help, which can confuse users.

Suggested patch
-  printf "    --help               Show this help message and exit\n\n"
+  printf "    --help, -h           Show this help message and exit\n\n"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install.sh` around lines 572 - 579, Update the script's usage output (the
usage function) to document the new -h short alias alongside --help and
--version/-v; specifically, modify the displayed options so the help text lists
both `-h, --help` (and where applicable `-v, --version`) to match the case in
the option parsing block that now accepts `-h` in addition to `--help`.

Same issue as the pre-commit hook fix — passing '.' to pyright
overrides the include/exclude paths in pyproject.toml, causing it to
scan .venv and site-packages (17k+ errors in CI).

Co-Authored-By: Claude Opus 4.6 (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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant