You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(state): add key-level restore ownership to agent manifests (#6445)
<!-- markdownlint-disable MD041 -->
## Summary
Agent manifests can now declare key-level restore ownership for
mixed-ownership state files. Managed restore preserves only
manifest-owned user preferences while the current target manifest
remains authoritative for generated configuration. Deep Agents Code is
migrated to this schema, and the restore path now fails closed on unsafe
manifests, paths, TOML, filesystem races, and target/backup mismatches.
## Related Issue
Resolves#6334
## Changes
- Add a strict, discriminated state_files restore schema for
key-allowlist and openclaw-config strategies, including canonical
relative-path validation and rejection of duplicate or
ancestor-overlapping ownership declarations.
- Require the current target manifest to authorize the backup agent,
config directory, state-file path, strategy, and restore ownership
before SSH or filesystem mutation.
- Make managed key-level merge the default. Whole-file restore is
available only through the explicit
allowCustomImageWholeStateFileRestore capability for custom-image
restore.
- Read bounded backup TOML directly from Python stdin, parse with
tomllib, create a private unpredictable O_EXCL stage, traverse parent
directories without following symlinks, and revalidate current/stage
metadata before atomic replacement.
- Preserve all safe leading comments, preserve non-dictionary fresh
ancestors instead of clobbering them, and keep fresh managed tables and
headers authoritative.
- Migrate the Deep Agents Code manifest and remove the agent-specific
restore-policy callback.
- Document managed key-level restore, target-manifest authority, and the
custom-Dockerfile whole-file exception.
## Type of Change
- [x] 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: maintainer-assisted
review of the behavior at dd65850
passed all nine security categories; current head
f9e4537 adds only a formatting-only
blank-line deletion to satisfy the onboard.ts net-growth guardrail.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:
## Verification
- [x] PR description includes the DCO sign-off declaration and every
commit appears as Verified in GitHub
- [x] Normal pre-commit, commit-msg, and pre-push hooks passed, or npm
run check:diff passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — 175 focused CLI assertions plus 71
affected integration assertions passed; the final phase/contract rerun
passed 23/23. npm run typecheck:cli, npm run build:cli, npm run
test-size:check, and git diff --check also passed.
- [ ] Applicable broad gate passed — not applicable locally; targeted
CLI/integration coverage exercised every changed restore path, and
repository CI is running on the exact head.
- [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) — build
passed with 0 errors and 2 pre-existing hidden-page warnings
- [x] Doc pages follow the style guide (doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)
— no new pages
---
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Charan Jagwani <cjagwani@nvidia.com>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added manifest-driven, fine-grained state-file restore rules with
typed user key allowlists and “freshness” requirements.
* Custom Dockerfile sandboxes can restore whole state files during
rebuilds when enabled.
* **Bug Fixes**
* Snapshot restore now fails closed for unknown, unsafe, stale, or
conflicting state data, with stronger atomic replacement safeguards.
* **Documentation**
* Updated sandbox backup/restore guidance to reflect key-level ownership
semantics, allowed preference preservation, and restore failure
behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Charan Jagwani <cjagwani@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Charan Jagwani <cjagwani@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Copy file name to clipboardExpand all lines: docs/manage-sandboxes/backup-restore.mdx
+9-1Lines changed: 9 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -61,6 +61,10 @@ The Hermes database can contain session metadata and message history needed for
61
61
</AgentOnly>
62
62
Snapshots also preserve sandbox registry metadata that affects rebuild behavior, including custom policy presets applied with `policy-add --from-file` or `policy-add --from-dir`.
63
63
When you restore a snapshot, NemoClaw replays those recorded custom presets with their stored YAML content, so you do not need the original preset files on disk for the restored sandbox to keep the same policy state.
64
+
The target sandbox's current agent manifest remains authoritative for state-file restore behavior.
65
+
NemoClaw rejects the restore when the snapshot's agent, config directory, state-file path, or state-file strategy conflicts with that manifest.
66
+
For managed images, NemoClaw applies the current manifest's managed config merge rules by default and does not fall back to whole-file replacement.
67
+
For Deep Agents targets, whole-file config replacement is limited to sandboxes created from a custom Dockerfile.
64
68
65
69
```bash
66
70
$$nemoclaw my-assistant snapshot create
@@ -126,7 +130,11 @@ NemoClaw rejects unsafe symlinks and hard links inside sandbox state during back
126
130
Credential-bearing Deep Agents files such as `.deepagents/.env` and user-authored `.deepagents/.mcp.json` are intentionally excluded from snapshots.
127
131
Deep Agents auth state files such as `.deepagents/.state/auth.json` and `.deepagents/.state/chatgpt-auth.json` are also excluded because the managed launcher refuses to start when upstream credential state is present.
128
132
The managed `.deepagents/.nemoclaw-mcp.json` projection and `hooks.json` are also excluded because NemoClaw reconstructs managed MCP state and disables executable Deep Agents Code hooks in the managed harness.
129
-
NemoClaw recreates generated `config.toml`, managed MCP projection state, and provider credentials from host-side onboarding and OpenShell provider state during rebuild.
133
+
NemoClaw recreates the current inference route headers, `models` and `update` tables, managed MCP projection state, and provider credentials from host-side onboarding and OpenShell provider state during rebuild.
134
+
For a NemoClaw-managed Deep Agents image, it restores only the allowlisted `ui.show_scrollbar`, `ui.show_url_open_toast`, `threads.relative_time`, and `threads.sort_order` preferences from the previous `config.toml` when their values pass validation.
135
+
Unknown, runtime-controlled, executable, and security-sensitive backup keys are dropped instead of replacing freshly generated settings on that managed path.
136
+
A Deep Agents target created from a custom Dockerfile restores `config.toml` as a whole file because the custom image owns its config schema, so review that backup before restoring it.
137
+
On the managed key-level restore path, if either config is malformed, required managed data is missing, or the restore detects an unsafe link or file replacement, NemoClaw marks the restore as failed and does not fall back to copying the backed-up file wholesale.
130
138
Before a Deep Agents rebuild changes the sandbox, NemoClaw verifies the recorded inference route, provider, model, reasoning settings, web search selection, base image, and policy inputs.
131
139
If a late check fails, NemoClaw restores the previous MCP state and keeps the existing sandbox intact.
Copy file name to clipboardExpand all lines: docs/manage-sandboxes/workspace-files.mdx
+8-2Lines changed: 8 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -192,7 +192,13 @@ The Deep Agents manifest declares these durable directories:
192
192
/sandbox/.deepagents/agent/skills/
193
193
```
194
194
195
-
It also declares `/sandbox/.deepagents/config.toml` as a durable top-level state file because the file contains non-secret NemoClaw-generated provider and model configuration.
195
+
It also declares `/sandbox/.deepagents/config.toml` as a durable top-level state file with key-level ownership.
196
+
The target sandbox's current Deep Agents manifest defines this ownership policy, so a snapshot cannot weaken it.
197
+
NemoClaw keeps the newly generated inference route headers and the `models` and `update` tables authoritative during rebuild.
198
+
On a NemoClaw-managed image, only the allowlisted `ui.show_scrollbar`, `ui.show_url_open_toast`, `threads.relative_time`, and `threads.sort_order` preferences can be restored from the previous file.
199
+
Runtime-controlled, unknown, executable, and security-sensitive backup keys are dropped on that managed path.
200
+
A Deep Agents target created from a custom Dockerfile restores `config.toml` as a whole file because the custom image owns its config schema.
201
+
On the managed key-level restore path, if config validation or safe atomic replacement fails, NemoClaw marks the restore as failed instead of falling back to a whole-file copy.
196
202
Credential-bearing files such as `.deepagents/.env` and user-authored `.deepagents/.mcp.json` are intentionally omitted from snapshots.
197
203
Managed MCP state is rebuilt from the host-side NemoClaw registry and OpenShell provider state instead of treated as user-authored durable state.
198
204
Memory files such as `/sandbox/.deepagents/agent/AGENTS.md` and `/sandbox/.deepagents/agent/memories/` are upstream Deep Agents Code files.
@@ -204,7 +210,7 @@ Back up important Deep Agents state before destroying the sandbox.
204
210
## Editing State
205
211
206
212
Prefer NemoClaw host commands for generated configuration such as model, provider, managed MCP, and policy settings.
207
-
Direct edits to `/sandbox/.deepagents/config.toml` can be overwritten by rebuilds because NemoClaw owns the managed inference route.
213
+
Direct edits to NemoClaw-owned or non-allowlisted keys in `/sandbox/.deepagents/config.toml` can be overwritten by rebuilds.
208
214
Use `$$nemoclaw <name> connect` when you need to inspect runtime files interactively, or use `openshell sandbox download` and `openshell sandbox upload` for manual file transfer.
209
215
210
216
Use Deep Agents Code commands for upstream-managed memories and skills.
0 commit comments