fix(snapshot): preflight sandbox liveness and clean restore - #1901
Conversation
restoreSandboxState() returns success immediately when no state dirs are backed up, so a restore against a stopped or missing sandbox could silently report success. Check that the sandbox is live before attempting restore, matching the existing create preflight. Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
📝 WalkthroughWalkthroughThe restore flow now validates the target OpenShell sandbox is present/running before proceeding, and the restore operation performs a remote pre-cleanup over SSH (removing stale writable dirs) prior to extracting the snapshot tar stream. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Nemoclaw as Nemoclaw CLI
participant OpenShell as OpenShell (sandbox list)
participant Local as Local FS / Snapshot
participant Remote as Target Sandbox (SSH)
User->>Nemoclaw: run `sandboxSnapshot restore <sandboxName> ...`
Nemoclaw->>OpenShell: `openshell sandbox list`
OpenShell-->>Nemoclaw: sandbox list (or error)
alt list failed or sandbox not found
Nemoclaw-->>User: exit 1 (abort)
else sandbox present
Nemoclaw->>Local: select snapshot / create tar stream
Nemoclaw->>Remote: SSH run `rm -rf "<writableDir>/<dir>"` for each dir
Remote-->>Nemoclaw: success / non-zero (logged warning)
Local->>Remote: stream `tar -cf -` piped to `tar -xf -` over SSH
Remote-->>Nemoclaw: restore complete
Nemoclaw-->>User: success
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
restoreSandboxState() used tar overlay semantics (tar -xf) which only overwrites files present in the archive. Files added after a snapshot was taken would persist when restoring that earlier snapshot. Remove the target state directories inside the sandbox before extracting the archive so the restored state is an exact replica. Closes #1902 Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/lib/sandbox-state.ts (2)
356-358: Proceeding after cleanup failure is reasonable but may leave inconsistent state.If
rm -rffails partially (e.g., permission denied on some files), the subsequent tar extraction will overwrite matching files but stale files in subdirectories that weren't removed could persist. The warning-only approach is pragmatic since failing the entire restore would be worse, but operators should be aware that a warning here may indicate a partially inconsistent restore.Consider documenting this behavior or surfacing the warning more prominently to the user (not just in verbose logs).
345-358: Shell command construction may be vulnerable to injection from manifest data.Directory names and
writableDirare interpolated directly into the shell command. If the manifest contains values with shell metacharacters ($, backticks,", etc.), this could cause unexpected behavior or command injection. While the double quotes mitigate some risks, they don't fully escape all metacharacters.This follows the existing pattern in
extractCmd(line 360) andbackupSandboxState, so consistency is maintained. Consider sanitizing or using an allow-list of safe characters for paths in a follow-up.🛡️ Safer path handling approach
+function shellEscape(s: string): string { + // Replace each single quote with '\'' and wrap in single quotes + return "'" + s.replace(/'/g, "'\\''") + "'"; +} + // In restoreSandboxState: const rmCmd = localDirs - .map((d) => `rm -rf "${writableDir}/${d}"`) + .map((d) => `rm -rf ${shellEscape(`${writableDir}/${d}`)}`) .join(" && ");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/sandbox-state.ts` around lines 345 - 358, The rm command is built by interpolating writableDir and localDirs into rmCmd and can be injection-prone; add a safe-path validation step (e.g. an isSafePath function that enforces an allow-list regex like /^[A-Za-z0-9._\/-]+$/) and validate writableDir and every entry in localDirs before building rmCmd, throwing/logging an error if any path fails validation; then build rmCmd only from validated values (using proper quoting) and proceed to call spawnSync with sshArgs, referencing the existing symbols rmCmd, localDirs, writableDir, spawnSync, sshArgs, and _log.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/lib/sandbox-state.ts`:
- Around line 345-358: The rm command is built by interpolating writableDir and
localDirs into rmCmd and can be injection-prone; add a safe-path validation step
(e.g. an isSafePath function that enforces an allow-list regex like
/^[A-Za-z0-9._\/-]+$/) and validate writableDir and every entry in localDirs
before building rmCmd, throwing/logging an error if any path fails validation;
then build rmCmd only from validated values (using proper quoting) and proceed
to call spawnSync with sshArgs, referencing the existing symbols rmCmd,
localDirs, writableDir, spawnSync, sshArgs, and _log.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 4bb29625-78ee-4aba-b3ff-593ffe72a470
📒 Files selected for processing (1)
src/lib/sandbox-state.ts
Automated PR review summaryReviewed PR #1901: fix(snapshot): preflight sandbox liveness before restore Recommendation
Installation and setup findings
What was validated
Failing tests and unresolved impact
Passing tests and why they matteredPassing test 1: Live sandbox restore still reaches snapshot lookup
Passing test 2: OpenShell liveness-query failure is surfaced as a hard restore error
Passing test 3: Preflight is ordered before backup inspection for non-live targets
Bottom line
|
## Summary - Add "Ollama network exposure warning during onboard" troubleshooting entry (from #1877) - Document snapshot restore liveness preflight and clean restore behavior (from #1901) - Update Jetson troubleshooting for BSP R39+ support (from #1910) - Document `--from` Dockerfile permission error handling (from #1931) - Bump doc version switcher through 0.0.17 - Regenerate agent skills from updated docs ## Test plan - [x] `make docs` builds without warnings - [x] All pre-commit hooks pass - [ ] Verify rendered pages in docs build output 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Clarified onboarding error when build context contains unreadable files. * Updated snapshot restore: sandbox must be running; restore cleanly replaces state directories and removes files added after the snapshot. * Added Jetson BSP R39 automatic configuration guidance. * Added Ollama network-exposure security guidance for local provider selection during onboarding. * **Documentation (versions)** * Added docs entry for version 0.0.17 and updated project docs version. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Two fixes for
snapshot restore:Preflight sandbox liveness before restore —
restoreSandboxState()returns success immediately when no state dirs are backed up, so a restore against a stopped or missing sandbox could silently report success. Now checks the sandbox is live before attempting restore, matching the existingsnapshot createpreflight.Clean target dirs before extracting to remove stale files —
restoreSandboxState()usedtar -xfoverlay semantics which only overwrites files present in the archive. Files added after a snapshot was taken would persist when restoring that earlier snapshot. Now removes the target state directories inside the sandbox before extracting so the restored state is an exact replica.Closes #1902
Test plan
Signed-off-by: Aaron Erickson aerickson@nvidia.com