Skip to content

fix(openclaw): merge restored config with runtime state#5174

Merged
jyaunches merged 2 commits into
mainfrom
hotfix/5101-openclaw-config-merge
Jun 10, 2026
Merged

fix(openclaw): merge restored config with runtime state#5174
jyaunches merged 2 commits into
mainfrom
hotfix/5101-openclaw-config-merge

Conversation

@jyaunches

@jyaunches jyaunches commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Selectively merge restored OpenClaw openclaw.json instead of overwriting fresh rebuild-generated config
  • Preserve runtime-owned gateway and generated managed channel/provider state from the rebuilt sandbox
  • Keep durable user settings from sanitized backups, including MCP servers and custom agents
  • Extend snapshot coverage for the "nemoclaw backup-all" is not backuping any openclaw settings, agents etc. #5027 preservation path and the stale-runtime-config regression

Validation

  • npm test -- --run test/snapshot.test.ts src/lib/security/credential-filter.test.ts src/lib/agent/defs.test.ts
  • npm run build:cli

Notes

Summary by CodeRabbit

  • New Features

    • Selective merge for durable config during sandbox state restore: runtime-owned sections are preserved while durable-only settings are merged when enabled.
    • Safer remote state reads to detect missing or non-fatal state files before restore.
  • Tests

    • New unit tests for the config-merge logic and updated snapshot validating selective restore behavior.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: bdbb8b7b-a375-4d65-ac73-e0ccc7099be6

📥 Commits

Reviewing files that changed from the base of the PR and between efd514d and eb6cdf8.

📒 Files selected for processing (3)
  • src/lib/state/openclaw-config-merge.test.ts
  • src/lib/state/openclaw-config-merge.ts
  • src/lib/state/sandbox.ts

📝 Walkthrough

Walkthrough

Adds ownership-aware merging for openclaw.json during sandbox restore: the code can read the remote file, selectively merge backup + runtime config via mergeOpenClawRestoredConfig, and restore the merged bytes; tests verify non-resurrection and correct precedence.

Changes

OpenClaw Config Restore with Selective Merge

Layer / File(s) Summary
Remote state file reading
src/lib/state/sandbox.ts
New buildStateFileReadCommand, readCurrentStateFile, and shouldMergeOpenClawConfig to fetch a specific remote state file and decide per-file merge applicability.
JSON merge utilities and OpenClaw merge logic
src/lib/state/openclaw-config-merge.ts
Adds OPENCLAW_CONFIG_RESTORE_OWNERSHIP, MANAGED_OPENCLAW_CHANNELS, JSON helpers (isPlainJsonObject, cloneJson, mergeJsonObjects) and ownership-aware merge functions plus exported mergeOpenClawRestoredConfig.
Selective merge integration into restore flow
src/lib/state/sandbox.ts
Adds buildStateFileRestoreInput to produce merged or raw restore input, extends restoreStateFile to accept mergeOpenClawConfig, and updates restoreSandboxState to compute and pass the merge flag per file.
Test validation of selective merge
test/snapshot.test.ts, src/lib/state/openclaw-config-merge.test.ts
Updates snapshot test to overwrite openclaw.json with a rebuilt shape and assert restored fields; adds unit tests asserting merge precedence and non-resurrection of managed channels.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#5101: Related work around making openclaw.json durable in state_files and snapshot test updates.

Suggested labels

integration: openclaw, area: sandbox, bug-fix, area: integrations

Suggested reviewers

  • cv
  • prekshivyas

Poem

🐰 A rabbit in the code-hop light,
Gently blends the old and bright,
Keeps the runtime keys intact,
Skips the channels left abstract,
Hops away — state whole and right.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% 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 'fix(openclaw): merge restored config with runtime state' directly and clearly describes the main change: selective merging of restored OpenClaw configuration with runtime state instead of overwriting it.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hotfix/5101-openclaw-config-merge

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: rebuild-openclaw-e2e, snapshot-commands-e2e, credential-sanitization-e2e, channels-add-remove-e2e
Optional E2E: channels-stop-start-e2e, messaging-providers-e2e, state-backup-restore-e2e, full

Dispatch hint: rebuild-openclaw-e2e,snapshot-commands-e2e,credential-sanitization-e2e,channels-add-remove-e2e

Auto-dispatched E2E: rebuild-openclaw-e2e, snapshot-commands-e2e, credential-sanitization-e2e, channels-add-remove-e2e via nightly-e2e.yaml at eb6cdf83d13186f3fda65dfe4a39b7a8c6bb70a3nightly run

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • rebuild-openclaw-e2e (high): Highest-signal existing E2E for this change: it exercises OpenClaw rebuild, sandbox state backup/restore, gateway token rotation, config hash validity, post-rebuild inference, policy survival, and credential absence in rebuild backups. The changed restore path is directly used here.
  • snapshot-commands-e2e (medium): Covers the user-facing snapshot create/list/restore lifecycle. Since the PR changes restoreStateFile input construction for openclaw.json, this should run to catch regressions in real snapshot restore behavior and no-credential snapshot checks.
  • credential-sanitization-e2e (high): The restore merge handles credential-bearing OpenClaw config after sanitized backups are created. This suite is the existing broad E2E guard for credential stripping, snapshot/migration credential boundaries, and sandbox runtime credential exposure.
  • channels-add-remove-e2e (high): The new merge ownership rules explicitly avoid resurrecting NemoClaw-managed channel blocks and preserve current generated channel placeholders. This existing E2E exercises channel add/remove lifecycle plus rebuild-related gateway credential reuse, making it relevant to the managed-channel restore behavior.

Optional E2E

  • channels-stop-start-e2e (very high): Additional confidence for managed-channel enable/disable state across telegram, discord, wechat, slack, and whatsapp. Useful because the merge code controls whether backed-up managed channels can overwrite or resurrect current channel state, but it is broader and slower than the add/remove rebuild guard.
  • messaging-providers-e2e (high): Adjacent confidence for provider placeholders, OpenClaw channel config patching, and L7 proxy token rewriting after config changes. Not merge-blocking unless reviewers are specifically concerned about provider placeholder merge semantics.
  • state-backup-restore-e2e (high): General backup/restore lifecycle confidence for sandbox state. It is less targeted than snapshot-commands/rebuild-openclaw for the openclaw.json selective merge, so keep it optional.
  • full (medium): Clean install/onboard/live inference smoke via E2E / Branch Validation can provide broad end-to-end confidence that the branch still works from source, but it does not specifically target snapshot/rebuild restore merge behavior.

New E2E recommendations

  • OpenClaw selective config restore merge (high): Existing E2Es cover rebuild, snapshot restore, credentials, and channel lifecycle, but none appear to directly assert the new ownership contract end-to-end in a live sandbox: fresh gateway/diagnostics/model/channel/plugin sections win, backup-only custom providers/plugins/mcpServers/customAgents survive, and removed managed channels are not resurrected.
    • Suggested test: Add a targeted live E2E that seeds openclaw.json with stale managed channel/provider/plugin/runtime values plus durable custom sections, performs snapshot restore or rebuild, then asserts current runtime-owned OpenClaw config wins while durable user-owned backup sections survive and sanitized secrets remain stripped.

Dispatch hint

  • Workflow: .github/workflows/nightly-e2e.yaml
  • jobs input: rebuild-openclaw-e2e,snapshot-commands-e2e,credential-sanitization-e2e,channels-add-remove-e2e

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

E2E Scenario Advisor Recommendation

Required scenario E2E: None
Optional scenario E2E: None

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required scenario E2E

  • None. The PR changes OpenClaw snapshot/rebuild restore logic and non-scenario tests, but no live-supported Vitest registry scenario on trusted main exercises snapshot restore. The closest rebuild scenario, ubuntu-rebuild-openclaw, is present in the registry but is not live-supported because its lifecycle profile is not wired for live Vitest execution. Therefore no scenario E2E dispatch is recommended.

Optional scenario E2E

  • None.

Relevant changed files

  • src/lib/state/openclaw-config-merge.ts
  • src/lib/state/sandbox.ts

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 1 needs attention, 5 worth checking, 0 nice ideas
Since last review: 2 prior items resolved, 3 still apply, 1 new item found

Review findings

🛠️ Needs attention

  • Avoid wholesale backup fallback for OpenClaw runtime-owned config (src/lib/state/sandbox.ts:949): The new ownership contract only applies when the freshly rebuilt openclaw.json can be read and both configs parse. If the current read returns null or either JSON parse/merge throws, buildStateFileRestoreInput() restores backupContents as-is. That bypasses the PR's core guarantee to preserve rebuilt gateway/proxy/diagnostics and current managed channel/provider/plugin state, and can resurrect stale sanitized channel placeholders or delete fresh runtime auth/routing state.
    • Recommendation: For OpenClaw openclaw.json, make current-read/parse failures explicit restore failures, or implement a degraded path that never clobbers runtime-owned sections. Add regression tests for current read failure, missing current file, invalid current JSON, and invalid backed-up JSON.
    • Evidence: src/lib/state/sandbox.ts:949 returns backupContents when currentContents is absent; src/lib/state/sandbox.ts:957-962 catches merge/parse errors and restores the sanitized backup as-is. The PR body clause says it preserves runtime-owned gateway and generated managed channel/provider state, but that is only true on the successful merge path.

🔎 Worth checking

  • Source-of-truth review needed: OpenClaw openclaw.json selective restore merge: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: src/lib/state/openclaw-config-merge.ts exports OPENCLAW_CONFIG_RESTORE_OWNERSHIP; agents/openclaw/manifest.yaml only declares openclaw.json as a durable state file.
  • Source-of-truth review needed: Fallback to sanitized backup on current-read or JSON-parse failure: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: src/lib/state/sandbox.ts:949 returns backupContents when currentContents is absent; src/lib/state/sandbox.ts:957-962 catches all merge/parse errors and returns backupContents.
  • Keep the OpenClaw config ownership contract from drifting (src/lib/state/openclaw-config-merge.ts:14): The prior embedded policy has been extracted into OPENCLAW_CONFIG_RESTORE_OWNERSHIP, which is a substantial improvement, but the contract remains a hard-coded TypeScript list rather than a manifest/schema-backed ownership declaration. Provider/plugin behavior is also still broad: every current same-key entry wins, and if current models/plugins sections are absent the backup section is restored wholesale.
    • Recommendation: Either declare key-level ownership near the OpenClaw agent manifest/schema or document why this helper is the source of truth. Add tests for absent current models.providers/plugins.entries and same-key custom provider/plugin cases, and record the condition under which this restore workaround can be removed.
    • Evidence: agents/openclaw/manifest.yaml declares openclaw.json as a durable state file but does not declare key-level ownership. src/lib/state/openclaw-config-merge.ts:14-22 declares runtimeSections, managedChannels, currentGeneratedEntryMaps, and backupDurableSections in code.
  • Add negative and runtime validation for the restore merge (test/snapshot.test.ts:1445): The added tests cover the successful merge path and one managed-channel omission case, but the highest-risk restore paths are not covered: SSH current-read failure, invalid current JSON, invalid backup JSON, absent provider/plugin sections, and actual sandbox rebuild/restore runtime behavior.
    • Recommendation: Add focused unit or fake-SSH tests for the failure and edge paths, plus targeted runtime/integration validation that a rebuilt OpenClaw sandbox remains usable after restore with gateway/proxy/diagnostics, managed channel placeholders, provider routing, MCP servers, and custom agents intact.
    • Evidence: src/lib/state/openclaw-config-merge.test.ts covers the main merge matrix and omitted managed channels. test/snapshot.test.ts covers a fake SSH happy path. No changed test exercises readCurrentStateFile() returning null or buildStateFileRestoreInput() catch fallback.
  • Limit further growth in the sandbox state monolith (src/lib/state/sandbox.ts:889): This PR reduced the previous embedded merge logic by extracting the ownership helper, but src/lib/state/sandbox.ts still grows by 91 lines in an already-large sandbox lifecycle module. The added read/merge/fallback orchestration is security-sensitive restore code and will be hard to maintain if more agent-specific state-file behavior accumulates here.
    • Recommendation: Consider extracting the OpenClaw state-file restore input/read orchestration into a focused module beside openclaw-config-merge.ts, leaving sandbox.ts to select strategies and report restore success/failure.
    • Evidence: Deterministic monolith signal: src/lib/state/sandbox.ts grew from 1642 to 1733 lines (+91). New helpers include buildStateFileReadCommand(), readCurrentStateFile(), shouldMergeOpenClawConfig(), and buildStateFileRestoreInput().

🌱 Nice ideas

  • None.
Consider writing more tests for
  • **Runtime validation** — restoreSandboxState preserves rebuilt gateway/proxy/diagnostics or fails explicitly when current openclaw.json cannot be read. The changed behavior affects sandbox restore lifecycle and OpenClaw runtime configuration reconciliation. Unit/fake-SSH tests cover the happy path, but negative fallback paths and real sandbox runtime behavior need validation.
  • **Runtime validation** — restoreSandboxState does not resurrect managed channels when current openclaw.json read exits nonzero. The changed behavior affects sandbox restore lifecycle and OpenClaw runtime configuration reconciliation. Unit/fake-SSH tests cover the happy path, but negative fallback paths and real sandbox runtime behavior need validation.
  • **Runtime validation** — restoreSandboxState handles invalid current openclaw.json without clobbering fresh runtime-owned sections. The changed behavior affects sandbox restore lifecycle and OpenClaw runtime configuration reconciliation. Unit/fake-SSH tests cover the happy path, but negative fallback paths and real sandbox runtime behavior need validation.
  • **Runtime validation** — restoreSandboxState handles invalid backed-up openclaw.json as a failed file instead of writing stale config. The changed behavior affects sandbox restore lifecycle and OpenClaw runtime configuration reconciliation. Unit/fake-SSH tests cover the happy path, but negative fallback paths and real sandbox runtime behavior need validation.
  • **Runtime validation** — mergeOpenClawRestoredConfig documents and tests provider/plugin behavior when current models.providers or plugins.entries are absent. The changed behavior affects sandbox restore lifecycle and OpenClaw runtime configuration reconciliation. Unit/fake-SSH tests cover the happy path, but negative fallback paths and real sandbox runtime behavior need validation.
  • **Add negative and runtime validation for the restore merge** — Add focused unit or fake-SSH tests for the failure and edge paths, plus targeted runtime/integration validation that a rebuilt OpenClaw sandbox remains usable after restore with gateway/proxy/diagnostics, managed channel placeholders, provider routing, MCP servers, and custom agents intact.
  • **Acceptance clause:** Selectively merge restored OpenClaw openclaw.json instead of overwriting fresh rebuild-generated config — add test evidence or identify existing coverage. shouldMergeOpenClawConfig() gates OpenClaw openclaw.json and buildStateFileRestoreInput() calls mergeOpenClawRestoredConfig() on the normal path. However, current-read absence or JSON parse/merge failure restores the sanitized backup wholesale.
  • **Acceptance clause:** Preserve runtime-owned gateway and generated managed channel/provider state from the rebuilt sandbox — add test evidence or identify existing coverage. OPENCLAW_CONFIG_RESTORE_OWNERSHIP lists gateway/proxy/diagnostics as runtime sections; managed channels are skipped from backup; current provider/plugin entries win by key. Tests assert gateway, Discord placeholder, WhatsApp state, Nvidia provider, and plugin behavior. The fallback path bypasses these guarantees.
Since last review details

Current findings:

  • Source-of-truth review needed: OpenClaw openclaw.json selective restore merge: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: src/lib/state/openclaw-config-merge.ts exports OPENCLAW_CONFIG_RESTORE_OWNERSHIP; agents/openclaw/manifest.yaml only declares openclaw.json as a durable state file.
  • Source-of-truth review needed: Fallback to sanitized backup on current-read or JSON-parse failure: The advisor marked localized patch analysis as missing.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: src/lib/state/sandbox.ts:949 returns backupContents when currentContents is absent; src/lib/state/sandbox.ts:957-962 catches all merge/parse errors and returns backupContents.
  • Avoid wholesale backup fallback for OpenClaw runtime-owned config (src/lib/state/sandbox.ts:949): The new ownership contract only applies when the freshly rebuilt openclaw.json can be read and both configs parse. If the current read returns null or either JSON parse/merge throws, buildStateFileRestoreInput() restores backupContents as-is. That bypasses the PR's core guarantee to preserve rebuilt gateway/proxy/diagnostics and current managed channel/provider/plugin state, and can resurrect stale sanitized channel placeholders or delete fresh runtime auth/routing state.
    • Recommendation: For OpenClaw openclaw.json, make current-read/parse failures explicit restore failures, or implement a degraded path that never clobbers runtime-owned sections. Add regression tests for current read failure, missing current file, invalid current JSON, and invalid backed-up JSON.
    • Evidence: src/lib/state/sandbox.ts:949 returns backupContents when currentContents is absent; src/lib/state/sandbox.ts:957-962 catches merge/parse errors and restores the sanitized backup as-is. The PR body clause says it preserves runtime-owned gateway and generated managed channel/provider state, but that is only true on the successful merge path.
  • Keep the OpenClaw config ownership contract from drifting (src/lib/state/openclaw-config-merge.ts:14): The prior embedded policy has been extracted into OPENCLAW_CONFIG_RESTORE_OWNERSHIP, which is a substantial improvement, but the contract remains a hard-coded TypeScript list rather than a manifest/schema-backed ownership declaration. Provider/plugin behavior is also still broad: every current same-key entry wins, and if current models/plugins sections are absent the backup section is restored wholesale.
    • Recommendation: Either declare key-level ownership near the OpenClaw agent manifest/schema or document why this helper is the source of truth. Add tests for absent current models.providers/plugins.entries and same-key custom provider/plugin cases, and record the condition under which this restore workaround can be removed.
    • Evidence: agents/openclaw/manifest.yaml declares openclaw.json as a durable state file but does not declare key-level ownership. src/lib/state/openclaw-config-merge.ts:14-22 declares runtimeSections, managedChannels, currentGeneratedEntryMaps, and backupDurableSections in code.
  • Add negative and runtime validation for the restore merge (test/snapshot.test.ts:1445): The added tests cover the successful merge path and one managed-channel omission case, but the highest-risk restore paths are not covered: SSH current-read failure, invalid current JSON, invalid backup JSON, absent provider/plugin sections, and actual sandbox rebuild/restore runtime behavior.
    • Recommendation: Add focused unit or fake-SSH tests for the failure and edge paths, plus targeted runtime/integration validation that a rebuilt OpenClaw sandbox remains usable after restore with gateway/proxy/diagnostics, managed channel placeholders, provider routing, MCP servers, and custom agents intact.
    • Evidence: src/lib/state/openclaw-config-merge.test.ts covers the main merge matrix and omitted managed channels. test/snapshot.test.ts covers a fake SSH happy path. No changed test exercises readCurrentStateFile() returning null or buildStateFileRestoreInput() catch fallback.
  • Limit further growth in the sandbox state monolith (src/lib/state/sandbox.ts:889): This PR reduced the previous embedded merge logic by extracting the ownership helper, but src/lib/state/sandbox.ts still grows by 91 lines in an already-large sandbox lifecycle module. The added read/merge/fallback orchestration is security-sensitive restore code and will be hard to maintain if more agent-specific state-file behavior accumulates here.
    • Recommendation: Consider extracting the OpenClaw state-file restore input/read orchestration into a focused module beside openclaw-config-merge.ts, leaving sandbox.ts to select strategies and report restore success/failure.
    • Evidence: Deterministic monolith signal: src/lib/state/sandbox.ts grew from 1642 to 1733 lines (+91). New helpers include buildStateFileReadCommand(), readCurrentStateFile(), shouldMergeOpenClawConfig(), and buildStateFileRestoreInput().

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27303738999
Target ref: efd514d5e470fdf3e4858e61802c687b2ad31be0
Workflow ref: main
Requested jobs: snapshot-commands-e2e,rebuild-openclaw-e2e,credential-sanitization-e2e,channels-add-remove-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
channels-add-remove-e2e ⚠️ cancelled
credential-sanitization-e2e ✅ success
rebuild-openclaw-e2e ⚠️ cancelled
snapshot-commands-e2e ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27304497923
Target ref: eb6cdf83d13186f3fda65dfe4a39b7a8c6bb70a3
Workflow ref: main
Requested jobs: rebuild-openclaw-e2e,snapshot-commands-e2e,credential-sanitization-e2e,channels-add-remove-e2e
Summary: 3 passed, 1 failed, 0 skipped

Job Result
channels-add-remove-e2e ✅ success
credential-sanitization-e2e ✅ success
rebuild-openclaw-e2e ❌ failure
snapshot-commands-e2e ✅ success

Failed jobs: rebuild-openclaw-e2e. Check run artifacts for logs.

@prekshivyas prekshivyas self-assigned this Jun 10, 2026
@cv

cv commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

The regression came from treating openclaw.json as a blind copied durable file even though it has mixed ownership: user durable config plus rebuild/runtime-owned gateway, managed channel placeholders, provider/plugin state, diagnostics, etc. This PR fixes the happy merge path, but the fallback paths are the part I most want pinned down so we do not reintroduce the wholesale overwrite later.

I opened the stacked follow-up with focused unit/fake-SSH coverage and a fail-closed guard here: #5178. It covers the restore boundary cases without adding another expensive E2E.

@jyaunches jyaunches merged commit f3d49cb into main Jun 10, 2026
43 checks passed
@jyaunches jyaunches deleted the hotfix/5101-openclaw-config-merge branch June 10, 2026 20:58

@prekshivyas prekshivyas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed (code + 9-cat security) — scrutinized as a real code fix, not just tests. Replaces the wholesale overwrite of the rebuilt openclaw.json during restoreSandboxState with an ownership-aware merge (new openclaw-config-merge.ts): runtime-owned sections (gateway/proxy/diagnostics) + managed channel/provider/plugin state come from the live rebuilt config, while durable user settings (mcpServers, customAgents, agents, custom providers/plugins, non-managed channels) inherit from the sanitized backup.

Approve — fixes the #5101 regression where a sanitized/stale backup clobbered fresh runtime state. Verified: managed channels are never resurrected, current provider/plugin wins by id while backup-only entries survive, arrays replace wholesale, and the snapshot assertion flip (kimi-k2nemotron) correctly reflects the intended behavior.

Security: all 9 pass — the merge writes back to the sandbox while the on-disk backup stays sanitized (no stale real secret reintroduced; placeholders preserved); the new SSH read rejects symlinks (-f && ! -L) and shell-quotes paths; on parse/read error it fails safe to the sanitized backup. Nit: shouldMergeOpenClawConfig matches with .endsWith("/.openclaw") while the sibling guard uses exact === — align for consistency. Non-blocking: no test exercises the parse-error fallback path.

@cv cv restored the hotfix/5101-openclaw-config-merge branch June 10, 2026 21:29
@github-actions

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27306478566
Target ref: main
Requested jobs: rebuild-openclaw-e2e
Summary: 0 passed, 1 failed, 0 skipped

Job Result
rebuild-openclaw-e2e ❌ failure

Failed jobs: rebuild-openclaw-e2e. Check run artifacts for logs.

jyaunches added a commit that referenced this pull request Jun 11, 2026
Follow-up to PR #5174 addressing PR Review Advisor feedback that unsafe
fallback paths could wholesale restore sanitized backup openclaw.json
over fresh runtime-owned config.

Changes:
- fail OpenClaw openclaw.json restore when current rebuilt config is
missing/unreadable or either JSON parse fails
- move restore input/read/source-of-truth policy into a focused helper
module
- keep current provider/plugin entries for matching keys while
preserving backup-only custom entries, including absent current
entry-map coverage
- add regression tests for missing current config, invalid current JSON,
invalid backup JSON, provider/plugin edge cases, and fake-SSH restore
behavior

Validation:
- npm run build:cli
- npx vitest run src/lib/state/openclaw-config-merge.test.ts
src/lib/state/openclaw-config-restore-input.test.ts
- npx vitest run test/snapshot.test.ts -t "backs up and restores
openclaw.json settings|excludes tar-failed" --testTimeout=15000
- npm run checks -- --changed

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Selective-merge for OpenClaw restores: prefers current
runtime-generated config, preserves backup-only entries, and
recomputes/stores sandbox config hash on successful restores.

* **Bug Fixes**
* Prevent stale backup data from overwriting rebuilt/runtime-managed
OpenClaw settings; restore now fails if a safe merge cannot be
constructed.

* **Tests**
* Added extensive tests for merge logic, restore-input generation,
sandbox restore flows, and snapshot/ssh restore scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
miyoungc added a commit that referenced this pull request Jun 11, 2026
## Summary
- Add the v0.0.63 release-note section using the published development
note as source context.
- Update source docs for sandbox recovery, OpenClaw config restore
safety, managed vLLM selection, Slack Socket Mode conflict handling, and
host diagnostics.
- Refresh generated `nemoclaw-user-*` skills from the updated Fern MDX
docs.
- Update the release-doc refresh skill so post-release docs for version
`n` look up the matching announcement discussion and use the `n+1` patch
release label.
- Fix CLI/docs parity by avoiding a `--from <Dockerfile>` flag mention
inside the `upgrade-sandboxes` command section.

## Source summary
- #5034 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document safer stale-sandbox recovery
through `rebuild --yes` before recreating from scratch.
- #5091 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document Docker-driver post-reboot
recovery from OpenShell container labels.
- #5101, #5174, #5177 -> `docs/manage-sandboxes/backup-restore.mdx`,
`docs/about/release-notes.mdx`: Document OpenClaw `openclaw.json`
preservation, merge behavior, and fail-safe restore handling.
- #5102 -> `docs/reference/commands.mdx`,
`docs/reference/commands-nemohermes.mdx`,
`docs/manage-sandboxes/lifecycle.mdx`, `docs/about/release-notes.mdx`:
Document `upgrade-sandboxes` image-fingerprint drift detection.
- #4201 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document the installer diagnostic for
unexpected Docker daemon access outside the `docker` group.
- #5038 -> `docs/inference/inference-options.mdx`,
`docs/inference/use-local-inference.mdx`,
`docs/about/release-notes.mdx`: Document the interactive managed-vLLM
model picker and non-interactive override behavior.
- #5040, #5041 -> `docs/reference/troubleshooting.mdx`,
`docs/about/release-notes.mdx`: Document Ollama auth-proxy recovery and
host DNS preflight diagnostics.
- #4986, #5039 -> `docs/manage-sandboxes/messaging-channels.mdx`,
`docs/about/release-notes.mdx`: Document Slack validation and duplicate
Slack Socket Mode sandbox handling.
- #4981, #5168 -> `docs/about/release-notes.mdx`: Capture Hermes gateway
secret-guard and wrapped-argv startup hardening in the release surface.
- Follow-up ->
`.agents/skills/nemoclaw-contributor-update-docs/SKILL.md`: Record the
post-release docs workflow, discussion-announcement lookup, and
next-patch release label rule.
- Follow-up -> `docs/reference/commands.mdx`,
`docs/reference/commands-nemohermes.mdx`: Reword custom Dockerfile
sandbox text so CLI parity does not treat `--from` as an
`upgrade-sandboxes` flag.

## Verification
- `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix
nemoclaw-user --doc-platform fern-mdx`
- `npm run docs`
- `npm run build:cli`
- `bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-cli`
- Skip-term scan for `docs/.docs-skip` blocked terms across generated
user skills

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Enhanced local inference setup with interactive model selection
prompts and environment variable overrides
* Improved sandbox upgrade detection using build fingerprints and
version checks
* Clarified configuration restore behavior preserving user settings
during rebuild/restore
  * Added gateway authentication as fifth security layer
  * Expanded Slack messaging validation with live credential checking
* Enhanced troubleshooting guidance for Docker access, DNS issues, and
sandbox recovery
* Updated release notes for v0.0.63 featuring sandbox recovery and
inference improvements

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@jyaunches jyaunches deleted the hotfix/5101-openclaw-config-merge branch June 12, 2026 13:54
cv added a commit that referenced this pull request Jun 13, 2026
## Summary
Follow-up to #5174 that pins the risky OpenClaw config restore fallback
cases. The restore now fails closed when selective merging cannot read
or parse the current rebuilt config, or cannot parse the backup, leaving
the fresh runtime config intact instead of writing a stale sanitized
backup wholesale.

## Related Issue
Follow-up to #5174.

## Changes
- Treat OpenClaw config selective-merge failures as state-file restore
failures rather than falling back to the backup contents.
- Add focused fake-SSH coverage for missing/invalid current
`openclaw.json` and invalid backed-up `openclaw.json`.
- Document provider/plugin merge behavior when the rebuilt config lacks
generated maps.
- Update snapshot fake SSH fixtures to model absent `openclaw.json`
state files instead of zero-byte successful reads.

## Type of Change
- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification
- [x] `npx prek run --all-files` passes
- [x] `npm test` passes
- [x] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `npm run docs` builds without warnings (doc changes only)
- [ ] 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)

---
Signed-off-by: Carlos Villela <cvillela@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

**New Features**
- OpenClaw config hash now automatically refreshes after sandbox restore
operations, ensuring configuration consistency

**Tests**
- Added comprehensive test coverage for config restore failure scenarios
- Added tests validating config hash refresh functionality
- Extended regression test coverage for configuration integrity
validation
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Julie Yaunches <jyaunches@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants