Skip to content

feat(policy): add policy-remove command to remove applied presets#1822

Merged
cv merged 6 commits intoNVIDIA:mainfrom
cr7258:policy-remove
Apr 15, 2026
Merged

feat(policy): add policy-remove command to remove applied presets#1822
cv merged 6 commits intoNVIDIA:mainfrom
cr7258:policy-remove

Conversation

@cr7258
Copy link
Copy Markdown
Contributor

@cr7258 cr7258 commented Apr 13, 2026

Summary

Add nemoclaw <name> policy-remove to remove previously applied network policy presets from a sandbox.

node bin/nemoclaw.js my-assistant policy-remove

  Applied presets:
    1) npm — npm and Yarn registry access
    2) pypi — Python Package Index (PyPI) access

  Choose preset to remove: 2
  Endpoints that would be removed: pypi.org, files.pythonhosted.org
  Remove 'pypi' from sandbox 'my-assistant'? [Y/n]: 
  Narrowing sandbox egress — removing: pypi.org, files.pythonhosted.org

✓ Policy version 5 submitted (hash: 440e75a56b48)
✓ Policy version 5 loaded (active version: 5)
  Removed preset: pypi

Also fix onboard TUI checkbox so unchecking an applied preset actually removes it.

    [8/8] Policy presets
  ──────────────────────────────────────────────────

  Available policy presets:
     [ ] brave          — Brave Search API access
     [ ] brew           — Homebrew (Linuxbrew) package manager access
     [ ] discord        — Discord API, gateway, and CDN access
     [ ] github         — GitHub.com and GitHub API access (git, gh)
     [ ] huggingface    — Hugging Face Hub, LFS, and Inference API access
     [ ] jira           — Jira and Atlassian Cloud access
     [✓] npm            — npm and Yarn registry access
     [ ] outlook        — Microsoft Outlook and Graph API access
   > [ ] pypi           — Python Package Index (PyPI) access      <--- uncheck pypi
     [ ] slack          — Slack API, Socket Mode, and webhooks access
     [ ] telegram       — Telegram Bot API access

  ↑/↓ j/k  move    Space  toggle    a  all/none    Enter  confirm

  Narrowing sandbox egress — removing: pypi.org, files.pythonhosted.org
✓ Policy version 7 submitted (hash: 440e75a56b48)
✓ Policy version 7 loaded (active version: 7)
  Removed preset: pypi

Related Issue

Fixes #1727

Changes

Changes

  • added nemoclaw <name> policy-remove command that reads the sandbox's current policy, strips the selected preset's network_policies entries, and writes it back via openshell policy set
  • added interactive picker that only lists applied presets for removal, with --dry-run to preview which endpoints would be narrowed
  • fixed onboard TUI checkbox to actually remove presets the user unchecks — previously deselecting an applied preset was silently ignored
  • removed 6 dead Unimplemented gRPC error handlers that became unreachable after minimum OpenShell version was raised to 0.0.24
  • added 12 new tests covering YAML removal logic, interactive selection edge cases, and CLI integration for policy-remove

Type of Change

  • Code change for a new feature, bug fix, or refactor.
  • Code change with doc updates.
  • Doc only. Prose changes without code sample modifications.
  • Doc only. Includes code sample changes.

Testing

  • npx prek run --all-files passes (or equivalently make check).
  • npm test passes.
  • make docs builds without warnings. (for doc-only changes)

Checklist

General

Code Changes

  • Formatters applied — npx prek run --all-files auto-fixes formatting (or make format for targeted runs).
  • Tests added or updated for new or changed behavior.
  • No secrets, API keys, or credentials committed.
  • Doc pages updated for any user-facing behavior changes (new commands, changed defaults, new features, bug fixes that contradict existing docs).

Doc Changes

  • Follows the style guide. Try running the nemoclaw-contributor-update-docs agent skill to draft changes while complying with the style guide. For example, prompt your agent with "/nemoclaw-contributor-update-docs catch up the docs for the new changes I made in this PR."
  • New pages include SPDX license header and frontmatter, if creating a new page.
  • Cross-references and links verified.

Signed-off-by: Seven Cheng sevenc@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added a sandbox command to remove applied policy presets with interactive selection, confirmation prompt, and a --dry-run preview.
  • Improvements

    • Automatic removal reconciliation of deselected presets when updating sandbox policies.
    • More consistent retry and error handling for policy apply/remove operations with clearer failure messages.
  • Tests

    • Added comprehensive tests for preset removal logic, interactive selection behavior, dry-run previews, and confirmation flows.

@cr7258 cr7258 requested a review from cv April 13, 2026 08:40
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Onboard now revokes deselected policy presets with retry handling; new policy-removal primitives modify YAML at the network_policies key and apply updates; CLI gained a sandbox-scoped policy-remove command with preview/confirmation/--dry-run; interactive selection and unit/CLI tests were added.

Changes

Cohort / File(s) Summary
Policy Removal Core
src/lib/policies.ts
Added removePresetFromPolicy to parse/modify policy YAML (removes preset network_policies keys, preserves legacy array form), removePreset to validate sandbox name, compute updated YAML, write temp file, run policy-set, update registry, and selectForRemoval interactive helper. Exports updated.
Onboarding logic
src/lib/onboard.ts
Removed "Unimplemented" special-case handling from retry loops. setupPoliciesWithSelection now computes deselected presets and calls policies.removePreset(...) for each, with retry only on "sandbox not found", and throws on falsy removePreset results.
CLI integration
src/nemoclaw.ts
Added sandboxPolicyRemove command handler wired to nemoclaw <name> policy-remove; lists presets, computes applied presets, uses selectForRemoval, previews endpoints, supports --dry-run, prompts for confirmation, and invokes policies.removePreset on confirmation. Help and valid-actions updated.
Tests
test/policies.test.ts
Added unit tests for removePresetFromPolicy (key removal, edge cases, legacy array preservation), tests for selectForRemoval interactive flows (no-applied, invalid, empty, valid selection), and CLI integration tests for policy-remove confirmation and --dry-run behavior (with stubs).

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as "nemoclaw (policy-remove)"
    participant SelectUI as "selectForRemoval"
    participant Policies as "policies (removePreset / removePresetFromPolicy)"
    participant Sandbox as "Sandbox (policy store)"
    participant Registry as "Sandbox Registry"

    User->>CLI: run "nemoclaw <sandbox> policy-remove [--dry-run]"
    CLI->>Policies: list presets, compute appliedPresets
    CLI->>SelectUI: selectForRemoval(appliedPresets)
    SelectUI->>User: prompt choose preset
    User-->>SelectUI: choose preset / cancel
    SelectUI-->>CLI: return presetName or null
    CLI->>Policies: load presetEntries (preview endpoints)
    CLI->>User: show preview
    alt dry-run
        CLI->>User: announce no changes and exit
    else
        CLI->>User: prompt confirmation
        User-->>CLI: confirm
        CLI->>Policies: removePreset(sandboxName, presetName)
        Policies->>Sandbox: fetch current policy YAML
        Policies->>Policies: removePresetFromPolicy(currentYAML, presetEntries)
        Policies->>Sandbox: apply updated YAML (policy-set via temp file)
        Policies->>Registry: remove presetName from sandbox.policies
        Policies-->>CLI: return success/failure
        CLI->>User: final status
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I nibble keys from YAML vines tonight,
Deselected leaves drift out of sight.
A prompt, a preview, a gentle tug —
The sandbox sheds what no longer fits the rug.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main feature: adding a policy-remove command to remove applied presets from sandboxes.
Linked Issues check ✅ Passed The PR implementation addresses issue #1727: removes stale presets via TUI deselection in setupPoliciesWithSelection and adds a new policy-remove CLI command with dry-run support.
Out of Scope Changes check ✅ Passed All changes are scoped to issue #1727: removal of dead Unimplemented error handlers, TUI checkbox deselection fixes, new policy-remove command, and supporting tests.

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

Actionable comments posted: 3

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

Inline comments:
In `@src/lib/onboard.ts`:
- Around line 4147-4160: The retry loop over deselected presets currently only
retries on thrown errors from policies.removePreset(sandboxName, name) but
ignores a false return; update the loop so that after calling
removePreset(sandboxName, name) you treat a falsey return as a failure (throw a
new Error or re-use a descriptive error) to trigger the retry logic, preserving
the existing handling for the specific "sandbox not found" message and the
3-attempt/backoff behavior; reference the variables and functions involved:
deselected, sandboxName, policies.removePreset, and the attempt/retry block so
the false return path does not silently mark a preset as removed.

In `@src/lib/policies.ts`:
- Around line 311-342: remove reporting and registry updates when
removePresetFromPolicy made no changes: after calling parseCurrentPolicy and
removePresetFromPolicy (symbols: parseCurrentPolicy, removePresetFromPolicy),
compare the returned updated string to the original currentPolicy; if they are
identical, skip creating the temp file, avoid calling
run(buildPolicySetCommand(...)) and console.log("Removed preset..."), and do not
modify the sandbox via registry.updateSandbox — instead log/return early
indicating nothing changed. This ensures we only write, apply, and unregister
the preset when at least one policy entry was actually removed.

In `@src/nemoclaw.ts`:
- Around line 1256-1259: The call to policies.removePreset(sandboxName, answer)
ignores its boolean return so failures are treated as success; update the code
that follows the confirmation prompt to check the return value of
removePreset(sandboxName, answer) and, if it returns false, propagate the
failure by exiting with a non-zero status (e.g., process.exit(1) or return a
non-zero command result) and log an error message; reference the confirm logic
around askPrompt(...) and the policies.removePreset(...) invocation and ensure
the failure path does not fall through to a successful exit.
🪄 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: 53aa80f1-41f0-4c67-9701-417e500e6ab4

📥 Commits

Reviewing files that changed from the base of the PR and between d4aac4c and 3ae5ba9.

📒 Files selected for processing (4)
  • src/lib/onboard.ts
  • src/lib/policies.ts
  • src/nemoclaw.ts
  • test/policies.test.ts

Comment thread src/lib/onboard.ts
Comment thread src/lib/policies.ts
Comment thread src/nemoclaw.ts Outdated
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/onboard.ts (1)

4138-4162: ⚠️ Potential issue | 🟠 Major

Resume can preserve a preset the user already deselected.

onSelection(interactiveChoice) persists the new target set before the removal loop succeeds. If removePreset() exhausts retries here, the session now records the preset as deselected even though it is still live. On resume, the selectedPresets fast-path only reapplies missing presets and never retries that removal, so the sandbox can stay permanently out of sync with the saved selection. Please make the resume path reconcile removals too, or only persist the new selection after both loops complete successfully.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard.ts` around lines 4138 - 4162, The bug is that
onSelection(interactiveChoice) persists the new selection before removals
complete, so failed removePreset(sandboxName, name) leaves the session out of
sync; fix by deferring persistence until after both the deselection loop (which
calls policies.removePreset) and the addition loop complete successfully — move
the onSelection(interactiveChoice) call so it runs only after the removal
retries and any addition logic finish, or alternatively enhance the
resume/selectedPresets fast-path to reconcile removals by checking applied vs
interactiveChoice and invoking policies.removePreset for any names that should
be removed; target functions/variables: onSelection, interactiveChoice, applied,
policies.removePreset, selectedPresets fast-path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/policies.ts`:
- Around line 311-317: Currently we call parseCurrentPolicy(rawPolicy) and then
removePresetFromPolicy(...) which can convert a failed parse (parseCurrentPolicy
returning an empty string) into a fresh policy skeleton and proceed to write it;
instead detect parse failure and fail closed: after computing currentPolicy (the
return value of parseCurrentPolicy), if currentPolicy is an empty string or
otherwise indicates a parse error, log an error mentioning presetName and the
read failure and return false immediately (do not call removePresetFromPolicy);
keep the existing updated === currentPolicy equality check only for legitimate
parsed policies.

---

Outside diff comments:
In `@src/lib/onboard.ts`:
- Around line 4138-4162: The bug is that onSelection(interactiveChoice) persists
the new selection before removals complete, so failed removePreset(sandboxName,
name) leaves the session out of sync; fix by deferring persistence until after
both the deselection loop (which calls policies.removePreset) and the addition
loop complete successfully — move the onSelection(interactiveChoice) call so it
runs only after the removal retries and any addition logic finish, or
alternatively enhance the resume/selectedPresets fast-path to reconcile removals
by checking applied vs interactiveChoice and invoking policies.removePreset for
any names that should be removed; target functions/variables: onSelection,
interactiveChoice, applied, policies.removePreset, selectedPresets fast-path.
🪄 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: 92377f6e-0c78-435b-8c13-320412d3f623

📥 Commits

Reviewing files that changed from the base of the PR and between 3ae5ba9 and d63c919.

📒 Files selected for processing (4)
  • src/lib/onboard.ts
  • src/lib/policies.ts
  • src/nemoclaw.ts
  • test/policies.test.ts
✅ Files skipped from review due to trivial changes (2)
  • src/nemoclaw.ts
  • test/policies.test.ts

Comment thread src/lib/policies.ts
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)
src/lib/policies.ts (1)

272-277: ⚠️ Potential issue | 🟠 Major

Detect semantic no-op before serializing policy.

removePresetFromPolicy() re-serializes even when no preset keys actually exist. That can change formatting only, so Line 319 no-op detection may be bypassed and still report success/update registry without real removal.

💡 Proposed fix
-  for (const key of presetKeys) {
-    delete existingNp[key];
-  }
-
-  current.network_policies = existingNp;
-  return YAML.stringify(current);
+  let removed = false;
+  for (const key of presetKeys) {
+    if (Object.prototype.hasOwnProperty.call(existingNp, key)) {
+      delete existingNp[key];
+      removed = true;
+    }
+  }
+
+  if (!removed) return normalizedCurrentPolicy;
+
+  current.network_policies = existingNp;
+  return YAML.stringify(current);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/policies.ts` around lines 272 - 277, In removePresetFromPolicy(),
avoid re-serializing when nothing is changed: before calling
YAML.stringify(current), check whether any of the presetKeys were
present/deleted from existingNp (e.g., track a deleted flag while iterating or
compute intersection of presetKeys and Object.keys(existingNp)); if no keys were
removed, return the original YAML string (or a no-op indicator) instead of
re-serializing current to prevent formatting-only changes; references:
presetKeys, existingNp, current, YAML.stringify.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/lib/policies.ts`:
- Around line 272-277: In removePresetFromPolicy(), avoid re-serializing when
nothing is changed: before calling YAML.stringify(current), check whether any of
the presetKeys were present/deleted from existingNp (e.g., track a deleted flag
while iterating or compute intersection of presetKeys and
Object.keys(existingNp)); if no keys were removed, return the original YAML
string (or a no-op indicator) instead of re-serializing current to prevent
formatting-only changes; references: presetKeys, existingNp, current,
YAML.stringify.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 18757cba-7a94-4363-81af-68be2cf17a20

📥 Commits

Reviewing files that changed from the base of the PR and between d63c919 and bc3f444.

📒 Files selected for processing (1)
  • src/lib/policies.ts

@wscurran wscurran added enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). labels Apr 13, 2026
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)
src/lib/onboard.ts (1)

4214-4246: Extract shared retry logic for preset mutations to reduce branching.

The remove/apply loops now duplicate the same retry/error pattern. A small local helper will keep this path easier to maintain and reduce complexity drift.

♻️ Proposed refactor
+  const mutatePresetWithRetry = (action, name, fn) => {
+    for (let attempt = 0; attempt < 3; attempt += 1) {
+      try {
+        if (!fn()) {
+          throw new Error(`Failed to ${action} preset '${name}'.`);
+        }
+        return;
+      } catch (err) {
+        const message = err && err.message ? err.message : String(err);
+        if (!message.includes("sandbox not found") || attempt === 2) {
+          throw err;
+        }
+        sleep(2);
+      }
+    }
+  };
+
   for (const name of deselected) {
-    for (let attempt = 0; attempt < 3; attempt += 1) {
-      try {
-        if (!policies.removePreset(sandboxName, name)) {
-          throw new Error(`Failed to remove preset '${name}'.`);
-        }
-        break;
-      } catch (err) {
-        const message = err && err.message ? err.message : String(err);
-        if (!message.includes("sandbox not found") || attempt === 2) {
-          throw err;
-        }
-        sleep(2);
-      }
-    }
+    mutatePresetWithRetry("remove", name, () => policies.removePreset(sandboxName, name));
   }

   for (const name of newlySelected) {
-    for (let attempt = 0; attempt < 3; attempt += 1) {
-      try {
-        if (!policies.applyPreset(sandboxName, name)) {
-          throw new Error(`Failed to apply preset '${name}'.`);
-        }
-        break;
-      } catch (err) {
-        const message = err && err.message ? err.message : String(err);
-        if (!message.includes("sandbox not found") || attempt === 2) {
-          throw err;
-        }
-        sleep(2);
-      }
-    }
+    mutatePresetWithRetry("apply", name, () => policies.applyPreset(sandboxName, name));
   }

As per coding guidelines, "Limit cyclomatic complexity to 20 in JavaScript/TypeScript files, with target of 15".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard.ts` around lines 4214 - 4246, Extract the duplicated retry
pattern into a small local helper (e.g., retryPresetMutation) that accepts an
async mutation function and preset name and handles the 3-attempt loop, error
message inspection for "sandbox not found", sleep(2) backoff, and final throw;
then replace both loops that call policies.removePreset(sandboxName, name) and
policies.applyPreset(sandboxName, name) (iterating over deselected and
newlySelected) with calls to this helper, preserving the same error messages
(e.g., "Failed to remove preset '...'" / "Failed to apply preset '...'") and
using sandboxName and sleep as before.
🤖 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/onboard.ts`:
- Around line 4214-4246: Extract the duplicated retry pattern into a small local
helper (e.g., retryPresetMutation) that accepts an async mutation function and
preset name and handles the 3-attempt loop, error message inspection for
"sandbox not found", sleep(2) backoff, and final throw; then replace both loops
that call policies.removePreset(sandboxName, name) and
policies.applyPreset(sandboxName, name) (iterating over deselected and
newlySelected) with calls to this helper, preserving the same error messages
(e.g., "Failed to remove preset '...'" / "Failed to apply preset '...'") and
using sandboxName and sleep as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d7da51dc-bb80-45e9-a77e-d2264ba780f4

📥 Commits

Reviewing files that changed from the base of the PR and between bc3f444 and c15542c.

📒 Files selected for processing (2)
  • src/lib/onboard.ts
  • src/nemoclaw.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/nemoclaw.ts

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)
src/lib/policies.ts (1)

273-278: ⚠️ Potential issue | 🟠 Major

Return the original YAML when nothing was actually deleted.

If none of presetKeys exist in network_policies, this still reserializes the document. That can make updated !== currentPolicy on formatting alone, so removePreset() may call policy set and drop the preset from the registry even though the live policy rules were unchanged. A regression case where the preset key is already absent would be worth adding too.

🛠️ Proposed fix
-  for (const key of presetKeys) {
-    delete existingNp[key];
-  }
+  let removed = false;
+  for (const key of presetKeys) {
+    if (Object.prototype.hasOwnProperty.call(existingNp, key)) {
+      delete existingNp[key];
+      removed = true;
+    }
+  }
+
+  if (!removed) return normalizedCurrentPolicy;
 
   current.network_policies = existingNp;
   return YAML.stringify(current);

Also applies to: 320-323

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/policies.ts` around lines 273 - 278, The code always reserializes and
returns YAML.stringify(current) even when none of the keys in presetKeys were
present, causing no-op changes; update the removePreset logic to detect whether
any deletion actually occurred (track a boolean like "deleted" while iterating
presetKeys against existingNp) and only overwrite current.network_policies /
return a new YAML when at least one key was removed; if no keys were removed,
return the original YAML string (or originalPolicy variable) unchanged. Apply
the same change to the analogous block around the other occurrence (the block at
the indicated second location).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/lib/policies.ts`:
- Around line 273-278: The code always reserializes and returns
YAML.stringify(current) even when none of the keys in presetKeys were present,
causing no-op changes; update the removePreset logic to detect whether any
deletion actually occurred (track a boolean like "deleted" while iterating
presetKeys against existingNp) and only overwrite current.network_policies /
return a new YAML when at least one key was removed; if no keys were removed,
return the original YAML string (or originalPolicy variable) unchanged. Apply
the same change to the analogous block around the other occurrence (the block at
the indicated second location).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e08388d-025a-4b05-ad07-e38525e069e1

📥 Commits

Reviewing files that changed from the base of the PR and between c15542c and 906bba6.

📒 Files selected for processing (4)
  • src/lib/onboard.ts
  • src/lib/policies.ts
  • src/nemoclaw.ts
  • test/policies.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/nemoclaw.ts

@cv cv merged commit 0f3216c into NVIDIA:main Apr 15, 2026
11 checks passed
cv pushed a commit that referenced this pull request Apr 15, 2026
## Summary
- Document `nemoclaw <name> snapshot create/list/restore` commands (from
#1892)
- Document `nemoclaw <name> policy-remove` command (from #1822)
- Document `nemoclaw <name> rebuild` command with version staleness
detection (from #1870)
- Document `nemoclaw backup-all` command (from #1870)
- Update `status` to mention live enforced policy display (from #1896)
- Update `connect` and `status` to mention version staleness warnings
(from #1870)
- Update `destroy` to reference snapshots and rebuild as alternatives
- Add snapshot commands section to backup-restore page
- Add `policy-remove` to customize-network-policy page
- Add "Sandbox is running an outdated agent version" troubleshooting
entry
- Bump doc version switcher through 0.0.16
- 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**
* Added documentation for policy preset removal command with selection
flow
* Documented new rebuild command for sandbox upgrades while preserving
workspace state
* Introduced snapshot commands for creating, listing, and restoring
workspace backups
  * Added bulk backup capability for multiple sandboxes
* Enhanced agent version warnings in connect and status commands with
remediation guidance
* Expanded troubleshooting guide with outdated agent version resolution
steps

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

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

enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[All Platform] Re-onboard preset deselection does not revoke previously applied policy presets

3 participants