fix(shields): preserve mutable-default rollback - #7568
Conversation
Signed-off-by: Ho Lim <subhoya@gmail.com>
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe OpenClaw guard now accepts verified mutable posture without rewriting files. Shields-down rollback preserves the initial state, restores mutable-default posture when possible, and reports fail-closed lockdown when restoration cannot be verified. ChangesMutable-default shields-down recovery
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant ShieldsDown
participant OpenClawGuard
participant Rollback
participant StateFile
ShieldsDown->>OpenClawGuard: unlock OpenClaw config
OpenClawGuard-->>ShieldsDown: complete mutable transition or fail
ShieldsDown->>Rollback: pass initial mode and state
Rollback->>OpenClawGuard: restore mutable posture
Rollback->>StateFile: restore shields snapshot
Rollback-->>ShieldsDown: report restored or fail-closed lockdown
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/shields/flow.test.ts`:
- Around line 320-360: The test for fail-closed rollback currently validates
only state and logging, while the stubbed command results do not prove
containment executed. Update createHarness or the test to expose the observed
OpenClaw posture, or perform a post-failure status check, then assert that the
resulting configuration is actually locked after shieldsDown throws. Keep the
existing shieldsDown, shields-open state, and error-log assertions.
🪄 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: Enterprise
Run ID: 182b9e3b-17d3-419d-badc-0cecebaea6ca
📒 Files selected for processing (4)
scripts/openclaw-config-guard.pysrc/lib/shields/flow.test.tssrc/lib/shields/index.tstest/openclaw-config-guard.test.ts
PR Review Advisor — InformationalAdvisor assessment: Informational / low confidence Model lanes
Second-opinion terminology and E2E selections are advisory. They do not change the primary assessment or E2E / PR Gate. 2 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. |
Signed-off-by: Ho Lim <subhoya@gmail.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
…er-followup Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/shields/flow.test.ts`:
- Around line 322-358: Add an assertion in the test case around shieldsDown to
verify the public outcome with harness.getOpenClawPosture(), expecting "mutable"
after rollback. Keep the existing byte-preservation and logging assertions
unchanged.
🪄 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: Enterprise
Run ID: 9e139d55-4d9c-42ab-b44e-50af70c0bf40
📒 Files selected for processing (2)
src/lib/shields/flow.test.tssrc/lib/shields/index.ts
|
Addressed the Advisor rollback-integrity warning in signed, Verified commit Corrupt shields-state snapshots now retain their exact original bytes in memory and restore those bytes verbatim if the mutable-default transition rolls back; persisted runtime markers are still stripped from normal state writes. A regression seeds invalid bytes, forces timer-handoff failure, and verifies byte-for-byte restoration. Local validation: CLI build/typecheck; shields flow and state tests 54/54; all repository hooks and pre-push checks. Documentation-writer review found no docs change required. Fresh exact-head CI/Advisor/E2E remains required before merge readiness. |
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
cv
left a comment
There was a problem hiding this comment.
Security review: FAIL on exact head 3e721d71a01ade1e1c7c4b0888916c2607df4e87.
Three blockers remain:
- Corrupt persisted state is still classified as
mutable_default. If the physical OpenClaw config is actually locked, the transaction can unlock it and the mutable rollback path can leave it mutable. The new commit adds onlyexpect(...).toBe("mutable")to a harness that already starts mutable; it does not exercise corrupt state plus an initially locked posture. Fail before mutation for_isCorrupt, or first establish authoritative physical posture and add a corrupt+locked regression. _rawFileContentsremains a UTF-8string, so invalid bytes are replaced on read/write and restoration is not byte-exact. Failing early for corrupt state removes this path; otherwise preserve aBufferand test non-UTF-8 bytes.- Issue #7538 requires protected live proof of a fresh mutable-default
shields downtransition. The current live test first runsshields up, and the PR risk plan does not selectshields-config, so current E2E cannot prove the reported path.
The focused 69 tests and build/check evidence pass, but they do not cover these security boundaries. Please also add the exact-head documentation-writer receipt after the final change.
Signed-off-by: Ho Lim <subhoya@gmail.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/lib/shields/index.ts (1)
2848-2855: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winReport the actual rollback outcome.
rollbackShieldsDowncan restore mutable-default, but these callers unconditionally describe lockdown/timer authority. That can tell operators the sandbox is locked when it was restored to mutable-default.
src/lib/shields/index.ts#L2848-L2855: return and consume a rollback outcome; do not say the auto-restore timer remains authoritative after mutable-default restoration removes it.src/lib/shields/index.ts#L2874-L2881: select the handoff-failure status from that same outcome rather than always saying lockdown was restored.src/lib/shields/flow.test.ts#L318-L320: assert the stale “lockdown was restored” diagnostic is absent after successful mutable-default restoration.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/shields/index.ts` around lines 2848 - 2855, Update rollback handling around rollbackShieldsDown in src/lib/shields/index.ts:2848-2855 to return and consume its rollback outcome, reporting timer authority only when lockdown remains restored and not after mutable-default restoration removes it. At src/lib/shields/index.ts:2874-2881, derive the handoff-failure status from that same outcome instead of always reporting lockdown restored. In src/lib/shields/flow.test.ts:318-320, assert successful mutable-default restoration does not emit the stale “lockdown was restored” diagnostic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/lib/shields/index.ts`:
- Around line 2848-2855: Update rollback handling around rollbackShieldsDown in
src/lib/shields/index.ts:2848-2855 to return and consume its rollback outcome,
reporting timer authority only when lockdown remains restored and not after
mutable-default restoration removes it. At src/lib/shields/index.ts:2874-2881,
derive the handoff-failure status from that same outcome instead of always
reporting lockdown restored. In src/lib/shields/flow.test.ts:318-320, assert
successful mutable-default restoration does not emit the stale “lockdown was
restored” diagnostic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: ce9c8e10-221b-4b78-85ba-e1801c328e21
📒 Files selected for processing (3)
src/lib/shields/flow.test.tssrc/lib/shields/index.tstest/e2e/live/shields-config.test.ts
Signed-off-by: Ho Lim <subhoya@gmail.com>
|
@cv Current head
I will not sync |
|
Protected E2E completed: https://github.com/NVIDIA/NemoClaw/actions/runs/30860798177 The The branch still merges cleanly with current |
|
Exact-head follow-up for |
|
Exact-head CI follow-up for 3344632: the refreshed branch now fails the required codebase-growth-guardrails check because src/lib/shields/flow.test.ts is 1,617 lines against the 1,500-line budget. This is a branch-owned contract failure, so the test file needs to be split or reduced before the PR is merge-ready. The trusted E2E gate is still in progress; I am not rerunning it. |
Signed-off-by: Ho Lim <subhoya@gmail.com>
Head branch was pushed to by a user without write access
|
Verified new head b0fb1f2: the follow-up mechanically extracts the existing Shields test harness into test/helpers/shields-flow-test-harness.ts, keeps the test call sites and assertions intact, and the required codebase-growth-guardrails check is now green. The refreshed trusted E2E gate is in progress; no rerun or additional branch edit is needed. |
Signed-off-by: Ho Lim <subhoya@gmail.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
<!-- markdownlint-disable MD041 --> ## Summary Add the canonical dated changelog entry for the planned NemoClaw v0.0.103 release. The new `docs/changelog/2026-08-05.mdx` entry uses the exact `## v0.0.103` heading and summarizes supported user-visible changes merged since v0.0.102. ## Changes - Add the parser-safe MDX SPDX header, three-paragraph release summary, and detailed grouped bullets to `docs/changelog/2026-08-05.mdx`. - Link each release-note group to the most specific published OpenClaw, Hermes, or Deep Agents documentation routes. - Exclude dormant MXC and Podman foundations, internal managed-inference adapters, test-only changes, and maintainer tooling from the supported product narrative. ### Source summary - [#8082](#8082) -> `docs/changelog/2026-08-05.mdx`: Document the new one-command agent launch flow. - [#8314](#8314) -> `docs/changelog/2026-08-05.mdx`: Document managed vLLM host capability validation and restart handling. - [#8248](#8248) -> `docs/changelog/2026-08-05.mdx`: Record the DGX Spark Qwen profile MTP default change. - [#8223](#8223) -> `docs/changelog/2026-08-05.mdx`: Record explicit model preservation across provider switches. - [#8209](#8209) -> `docs/changelog/2026-08-05.mdx`: Document corrected Windows WSL provider selection. - [#8316](#8316) -> `docs/changelog/2026-08-05.mdx`: Record clean managed-checkout reuse after installation. - [#8239](#8239) -> `docs/changelog/2026-08-05.mdx`: Record the packaged-service teardown fallback. - [#8247](#8247) -> `docs/changelog/2026-08-05.mdx`: Document uninstall behavior for an already-removed sandbox. - [#7998](#7998) -> `docs/changelog/2026-08-05.mdx`: Record preserved container-start diagnostics. - [#8027](#8027) -> `docs/changelog/2026-08-05.mdx`: Record journal-backed not-ready repair authority. - [#7812](#7812) -> `docs/changelog/2026-08-05.mdx`: Document actionable rebuild preflight diagnostics. - [#8222](#8222) -> `docs/changelog/2026-08-05.mdx`: Record redacted top-level CLI failures. - [#8313](#8313) -> `docs/changelog/2026-08-05.mdx`: Record structured MCP bridge destruction failures. - [#8211](#8211) -> `docs/changelog/2026-08-05.mdx`: Document cleanup of incomplete snapshot captures. - [#8212](#8212) -> `docs/changelog/2026-08-05.mdx`: Document best-effort post-restore policy reconciliation. - [#8245](#8245) -> `docs/changelog/2026-08-05.mdx`: Clarify manifest-defined OpenClaw workspace persistence. - [#8254](#8254) -> `docs/changelog/2026-08-05.mdx`: Include corrected snapshot restore selection guidance. - [#8238](#8238) -> `docs/changelog/2026-08-05.mdx`: Document preservation of managed MCP policy entries. - [#7568](#7568) -> `docs/changelog/2026-08-05.mdx`: Record mutable-default Shields rollback preservation. - [#8200](#8200) -> `docs/changelog/2026-08-05.mdx`: Record truthful Shields state after a rejected transition. - [#7895](#7895) -> `docs/changelog/2026-08-05.mdx`: Record descriptor-bound Shields lock inspection. - [#7892](#7892) -> `docs/changelog/2026-08-05.mdx`: Document the canonical Hermes dashboard profile and migration. - [#7871](#7871) -> `docs/changelog/2026-08-05.mdx`: Document fail-closed Hermes cron restore. - [#7894](#7894) -> `docs/changelog/2026-08-05.mdx`: Record the reset Hermes health budget after recovery. - [#8228](#8228) -> `docs/changelog/2026-08-05.mdx`: Document Hermes build-time corporate CA trust. - [#8206](#8206) -> `docs/changelog/2026-08-05.mdx`: Document bounded Deep Agents Code failure classification. - [#8297](#8297) -> `docs/changelog/2026-08-05.mdx`: Record reuse of the published Deep Agents Code base image. - [#8321](#8321) -> `docs/changelog/2026-08-05.mdx`: Document aligned endpoint SSRF protections and userinfo rejection. - [#8299](#8299) -> `docs/changelog/2026-08-05.mdx`: Document the fail-closed `setpriv` transition in managed images. - [#7603](#7603) -> `docs/changelog/2026-08-05.mdx`: Record corrected confidentiality-root traversal. - [#8334](#8334) -> `docs/changelog/2026-08-05.mdx`: Record removal of the unsupported logs audit example. - [#8256](#8256) -> `docs/changelog/2026-08-05.mdx`: Record reordered network-policy walkthrough prerequisites. - [#7767](#7767) -> `docs/changelog/2026-08-05.mdx`: Record platform runtime shape validation. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [x] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Quality Gates - [ ] Tests added or updated for changed behavior - [x] Existing tests cover changed behavior — justification: `npx vitest run test/changelog-docs.test.ts` passed all 6 tests. - [ ] Tests not applicable — justification: - [x] Docs updated for user-facing behavior changes - [ ] Docs not applicable — justification: - [ ] Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging) - [ ] Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: - [ ] Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue: ## Documentation Writer Review - [ ] Documentation writer subagent reviewed the completed changes - Result: `docs-updated` - Evidence: `docs/changelog/2026-08-05.mdx` follows the release-prep and documentation writing rules. The changelog contract tests passed 6/6, and `npm run docs` completed with 0 errors and the repository's 2 existing Fern warnings. - Agent: Codex Desktop <!-- docs-review-head-sha: 66fcd80 --> <!-- docs-review-agents-blob-sha: 3dd7c24 --> ## DGX Station Hardware Evidence - [ ] Tested on DGX Station - Tested commit: Not applicable. - 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 - [x] Targeted behavior tests pass for the current change set, or tests are marked not applicable above — `npx vitest run test/changelog-docs.test.ts`: 1 file and 6 tests passed. - [ ] Applicable broad gate passed — `npm test` for broad runtime/test-harness changes; `npm run check` for repo-wide validation/coverage changes — command/result: Not run for this doc-only change. - [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) — completed with 0 errors and 2 existing Fern warnings. - [x] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) — the native changelog uses the required parser-safe MDX SPDX comment and does not use page frontmatter. --- Signed-off-by: Charan Jagwani <cjagwani@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added release notes for v0.0.103. * Documented the new `nemoclaw launch` command. * Included updates covering onboarding, inference, installation, recovery, snapshots, security, integrations, endpoint validation, sandbox hardening, and related guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
Preserve a fresh OpenClaw sandbox's mutable-default posture when a Shields-down transaction rolls back. Reject corrupt persisted Shields state before any policy, timer, host-state, or sandbox-config mutation, and retain fail-closed lockdown when rollback cannot revoke timer authority or verify mutable restoration.
Related Issue
Closes #7538
Changes
shields downthrough the canonical protectedshields-configE2E.Type of Change
Quality Gates
ba9cf0395577cdd13e76c34104f24d4cd44ead34with base4cd4d64fe67143b57707f874afa0b9d269dfeff2. All nine security categories passed: secrets and credentials; input validation and data sanitization; authentication and authorization; dependencies; error handling and logging; cryptography and data protection; configuration and security defaults; security testing; and system security. The no-op config path checks the mutable directory and file posture, parses the configuration as JSON5, verifies that the open directory still refers to the same inode, and preserves file bytes and inode identity. Corrupt state or unsuccessful timer-marker removal stops before policy, configuration, or state mutation. Rollback restores mutable posture only after policy restoration and timer-authority revocation; on failure, it locks the configuration again. Current diff SHA-256:a099ea70451abdd9b91604508e2df43891599b5714e7714a5ed0f037a859952f. No findings remain.Documentation Writer Review
docs-updatedba9cf0395577cdd13e76c34104f24d4cd44ead34with base4cd4d64fe67143b57707f874afa0b9d269dfeff2.docs/reference/commands.mdxaccurately describes stale timer-authority cleanup and its failure result; terminology, structure, voice, and code-sample presentation passed review. The page is present in the OpenClaw, Deep Agents, and Hermes guide variants. GitHub Docs / Fern Preview preparation and validation passed: https://github.com/NVIDIA/NemoClaw/actions/runs/30811171284/job/91680561828.DGX Station Hardware Evidence
Verification
Signed-off-by:line and every commit appears asVerifiedin GitHubpre-commit,commit-msg, andpre-pushhooks passed, ornpm run check:diffpassed when hooks were skipped or unavailablenpm testfor broad runtime/test-harness changes;npm run checkfor repo-wide validation/coverage changes — command/result: Not applicable to this scoped Shields rollback and guard fix; targeted tests andnpm run check:diffcover every changed source and test path.npm run docsbuilds without errors (doc changes only; 2 existing suppressed warnings)Review Resolution
Revision
ba9cf03955and all preceding PR commits are GitHub-verified. The change combines cleanly with currentmainat03fbf5ebf; the combined code passes 58 Shields tests and the malformed-JSON5 guard regression. The required static, DCO, commit-lint, and installer-hash gates pass. The protected E2E gate timed out while waiting for approval of the fork run, and the contributor fork still needs an authorized branch update. After synchronization, GitHub CI, protectedshields-configE2E, automated review, documentation review, security review, and maintainer review must all settle successfully before merge.Signed-off-by: Ho Lim subhoya@gmail.com