fix(shields): preserve managed MCP policies - #8141
Conversation
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in commit 1803956 in the TypeScript / code-coverage/cliThe overall coverage in commit 1803956 in the Show a code coverage summary of the most impacted files.
Updated |
PR Review Advisor — No blocking findings reportedAdvisor assessment: No blocking advisor findings reported Model lanes
8 terminology differences from the second opinionAdvisory only. These are normalized differences from the primary terminology receipt.
Second-opinion terminology and E2E selections are advisory. They do not change the primary assessment or E2E / PR Gate. 3 semantic terminology decisionsTerminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.
E2E guidanceAdvisory only. E2E / PR Gate selects and runs jobs independently. Recommended E2E: This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge. |
apurvvkumaria
left a comment
There was a problem hiding this comment.
Reviewed exact head 1803956 against its current stacked base. Exact policy ownership proof, canonical generated-policy validation, reserved-key stripping, fail-closed drift handling, and deadline restoration are sound and well covered. I found no blocking defect; exact-head CI and E2E are green. Re-review affected areas if the stacked base changes materially.
0f6d801
into
codex/shields-deadline-safety-7952
<!-- markdownlint-disable MD041 --> ## Summary Shields down previously replaced the complete live OpenShell policy, which removed NemoClaw-generated MCP entries and made a surviving Hermes MCP server unreachable. This change reconciles only exact, independently proven NemoClaw-managed MCP entries so server A stays reachable while a removed server B stays removed. This is the focused MCP-policy change built on the lifecycle and deadline prerequisite merged in #8130. It replaces the focused behavior from the closed historical work in #7980 and #8141. ## Related Issue Fixes #7952 ## Changes - Prove managed MCP ownership from the registry, generated-policy record, and live gateway policy before preserving an entry. - Save the managed-key manifest with the Shields snapshot, remove snapshot-time managed entries during restoration, and overlay only the current exact entries. - Fail closed for ambiguous, malformed, or manually edited ownership; deadline restoration omits unproven entries and records the omission count. - Preserve exact current managed entries in the permissive Shields policy without copying unrelated live egress. - Sanitize untrusted registry and policy identifiers before including them in operator diagnostics. - Clean staged policy files across success and failure paths. - Reuse the validated unchanged snapshot when both saved and current managed MCP sets are empty, so deadline restoration does not depend on temporary staging. - Update the Hermes MCP regression so it calls A immediately after Shields down and again after B removal, before the later explicit `mcp restart A` coverage. - Document managed MCP policy behavior during Shields transitions. ### Why this appeared during the Hermes upgrade The original live journey contained a hidden lifecycle between the first successful call to A and the later B lifecycle: 1. Raise Shields. 2. Restart the Hermes gateway. 3. Lower Shields. 4. Exercise config rollback. 5. Add and remove B. 6. Call A. A remained healthy through Shields up and the gateway restart. It became unusable immediately after Shields down, which dropped A's generated MCP policy. The later failure after B removal was only where the test detected the damage; B removal was a misleading correlation. This surfaced alongside the Hermes upgrade because coverage and upgrade fixes landed close together: - #7761 added the helper containing Shields up, gateway restart, Shields down, and rollback, but did not run the complete live E2E. - #7771 upgraded Hermes, while its selected E2E did not include the MCP bridge target. - #7849 fixed Hermes 0.19 migrations and the `mcp__fake__*` tool naming, allowing the journey to progress far enough to expose the later failure. - #7866 moved an explicit restart of A before the post-removal call, which reapplied A's policy and masked the defect. The whole-policy Shields replacement predates those changes. This is a latent NemoClaw Shields policy-composition bug exposed by expanded Hermes upgrade regression coverage, not evidence of a Hermes regression. ### Corrected live regression order 1. Raise Shields and restart the Hermes gateway. 2. Lower Shields and call A immediately. 3. Exercise config rollback. 4. Add B, prove DNS-rebinding access is denied, remove B, and verify A's policy is unchanged while B is gone. 5. Call A before the later explicit restart. 6. Capture authenticated rediscovery state, restart A without resupplying its secret, and call A again. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [x] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Quality Gates - [x] Tests added or updated for changed behavior - [ ] Existing tests cover changed behavior — justification: - [ ] Tests not applicable — justification: - [x] Docs updated for user-facing behavior changes - [ ] Docs not applicable — justification: - [x] Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging) - [x] Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: Independent maintainer security review of commit `5d46d4a2ee924edf743ac36d04807948eec01c96` passed all nine categories. The review covered managed-policy ownership, diagnostic sanitization, deadline restoration, empty-MCP staging failure, and current-main integration. - [ ] Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue: ## Documentation Writer Review - [x] Documentation writer subagent reviewed the completed changes - Result: `docs-updated` - Evidence: Reviewed the complete PR change at commit `5d46d4a2ee924edf743ac36d04807948eec01c96` against current main, including generated OpenClaw and Hermes variants, operator-facing assertions, test titles, and the empty-MCP deadline-restore regression. The current-main merge was mechanical, contributor attribution remains intact, and the existing documentation remains accurate. Normal hooks passed; GitHub CI is the current validation authority. - Agent: Codex Desktop <!-- docs-review-head-sha: 5d46d4a --> <!-- docs-review-agents-blob-sha: 3dd7c24 --> ## DGX Station Hardware Evidence - [ ] Tested on DGX Station - Tested commit: Not applicable; `scripts/prepare-dgx-station-host.sh` is unchanged. - Station profile/scenario: Not applicable. - Result: Not applicable. - Supporting evidence: Not applicable. ## Verification - [x] PR description includes a `Signed-off-by:` line and every commit appears as `Verified` in GitHub - [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or `npm run validate:pr` passed after refreshing `origin/main` when hooks were skipped or unavailable - [ ] Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: GitHub CI is running for commit `5d46d4a2ee924edf743ac36d04807948eec01c96`. - [ ] Applicable broad gate passed — `npm test` for broad runtime/test-harness changes; `npm run check` for repo-wide validation/coverage changes — command/result: GitHub CI is running for commit `5d46d4a2ee924edf743ac36d04807948eec01c96`. - [x] Quality Gates section completed with required justifications or waivers - [x] No secrets, API keys, or credentials committed - [ ] `npm run docs` builds without warnings (doc changes only) — GitHub CI is running for commit `5d46d4a2ee924edf743ac36d04807948eec01c96`. - [x] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [x] New doc pages include SPDX header and frontmatter (new pages only) — no new pages --- Signed-off-by: Julie Yaunches <jyaunches@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Shields transitions now securely track and reconcile managed MCP policies. * Existing MCP servers retain verified endpoints and address pins during unlock and restoration. * Removed MCP servers remain removed instead of being unintentionally restored. * Automatic restoration omits policies that cannot be independently verified and records clear warnings. * **Bug Fixes** * Improved fail-closed behavior for malformed, mismatched, incomplete, or unavailable policy data. * **Documentation** * Expanded guidance on MCP policy handling during manual and automatic Shields transitions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Julie Yaunches <jyaunches@nvidia.com> Signed-off-by: Carlos Villela <cvillela@nvidia.com> Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Summary
nemoclaw shields downreplaced the complete live OpenShell policy and dropped generated policy entries for registered Model Context Protocol (MCP) servers. This change reconciles only exact NemoClaw-managed MCP entries during Shields transitions, so a surviving server remains reachable while removed servers stay removed.Stacked on prerequisite #8130, which makes Shields deadline recovery serialize with lifecycle mutations without signaling the lock owner, this focused fix supersedes the MCP portion of #7980.
Related Issue
Fixes #7952
Changes
Failure Timing and Hermes Upgrade Context
The original journey had a hidden Shields lifecycle between the first successful call to server A and the later lifecycle for server B:
shields up.shields down.Boundary instrumentation recorded in #7952 showed that A remained healthy through Shields up and the gateway restart. It became unusable immediately after Shields down, which dropped A's generated MCP policy. The later failure after B was removed was only where the test noticed the already-broken route; B removal was a misleading correlation.
This surfaced during the Hermes upgrade work because new coverage and upgrade repairs landed nearly back-to-back:
mcp-bridgetarget.mcp restart Abefore the first post-removal call. Restart reapplied A's generated policy and masked the missing-policy state.The corrected regression order is:
shields up.shields down.mcp restart Awithout resupplying the secret.Whole-policy Shields replacement and the filesystem-only runtime merge predate the Hermes upgrade. This is a latent NemoClaw Shields policy-composition defect detected by expanded Hermes regression coverage, not a Hermes upgrade regression.
Type of Change
Quality Gates
18039569796d6ac7604de032edb7abf84f2c73c4; no findings.Documentation Writer Review
docs-updateddocs/manage-sandboxes/runtime-controls.mdxanddocs/reference/commands.mdx, all rendered guide variants, changed operator-facing text, comments, test titles, and the Hermes E2E chronology. Verified claims against source, issue Shields down drops registered MCP policies from the effective gateway policy #7952, and PRs test(hermes): cover MCP integrity through restart #7761, chore(hermes): upgrade Hermes Agent to v2026.7.20 #7771, fix(hermes): repair v0.19 runtime migrations #7849, and test(e2e): restart Hermes before MCP rediscovery #7866.npm run docscompleted with 0 errors and 2 existing Fern warnings.DGX Station Hardware Evidence
scripts/prepare-dgx-station-host.shis unchanged.Verification
Signed-off-by:line and every commit appears asVerifiedin GitHubpre-commit,commit-msg, andpre-pushhooks passed, ornpm run validate:prpassed after refreshingorigin/mainwhen hooks were skipped or unavailablenpm run typecheck:cli,npm run checks:repository, test-size guardrail, E2E semantic phase plans, and serialnpm run test:changed674/674 passed.npm testfor broad runtime/test-harness changes;npm run checkfor repo-wide validation/coverage changes — command/result: Standard PR CI run 30824992396 passed. One inherited 50 ms lifecycle-lock assertion timing flake passed on the failed-job rerun without a code change.npm run docsbuilds without warnings (doc changes only)npm run docspassed with 0 errors and 2 existing Fern warnings, so the warning-free checkbox remains unchecked. No new documentation pages were added.Trusted E2E run 30826792180 passed all 10 selected checks: cloud inference, cloud onboard, security posture, inference routing, MCP bridge, MCP bridge dev, network policy, onboard repair, onboard resume, and OpenShell credential-generation window. The primary review advisor reported no findings. Nemotron completed after retrying a protocol-only failure; its one test warning requested the exact transition/state ownership-mismatch deadline regression already present in
src/lib/shields/policy-transition.test.ts, which passed.Signed-off-by: Julie Yaunches jyaunches@nvidia.com