fix(cli): fail closed on a malformed sandbox registry file - #8443
Conversation
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
📝 WalkthroughWalkthroughThe configuration reader now reports malformed JSON instead of using a fallback. Registry operations preserve corrupted files and fail explicitly. Tests cover corruption, concurrency, recovery, symlinks, and path handling. Documentation describes backup, removal, retry, and re-onboarding steps. ChangesMalformed registry handling
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in commit 02a8035 in the TypeScript / code-coverage/cliThe overall coverage in commit 02a8035 in the Show a code coverage summary of the most impacted files.
Updated |
|
🌿 Preview your docs: https://nvidia-preview-pr-8443.docs.buildwithfern.com/nemoclaw |
PR Review Advisor — No blocking findings reportedAdvisor assessment: No blocking advisor findings reported Model lanes
Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests. 2 semantic terminology decisionsTerminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.
E2E guidanceAdvisory only. A maintainer can dispatch the default E2E suite against this exact revision. Recommended E2E: This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge. |
Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
|
Addressed PRA-1 on the current branch revision (342fc07).
Fresh CI and automated review are now running. The PR still needs the required independent approval before merge. |
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
|
Post-review refresh completed.
Fresh required checks are queued or running. Independent approval is still required before merge. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
test/registry.test.ts (1)
1428-1428: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse an ESM import for
child_process.Line 1428 uses CommonJS
require()in a root-level test. ImportspawnSyncfromnode:child_processat module scope and remove this localrequire().As per coding guidelines, root-level tests must use ESM imports.
🤖 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 `@test/registry.test.ts` at line 1428, Replace the local CommonJS require in the root-level test with a module-scope ESM import of spawnSync from node:child_process, and remove the require declaration from the test body.Source: Coding guidelines
🤖 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.
Nitpick comments:
In `@test/registry.test.ts`:
- Line 1428: Replace the local CommonJS require in the root-level test with a
module-scope ESM import of spawnSync from node:child_process, and remove the
require declaration from the test body.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 0f2fbb34-acae-4875-93be-b3b2bb68982b
📒 Files selected for processing (1)
test/registry.test.ts
<!-- markdownlint-disable MD041 --> ## Summary Adds the canonical dated changelog entry required before cutting `v0.0.104`. The entry reconciles user-facing changes merged from `v0.0.103` through `8d2b86aaf44968b4f7bc3b714222a73bd28e0403` while excluding hidden and experimental product surfaces. ## Changes - Added `docs/changelog/2026-08-06.mdx` with the exact `## v0.0.104` heading and release themes for local inference, private endpoints, network policy, state authority, lifecycle recovery, uninstall, Hermes, MCP diagnostics, credential safety, and installation guidance. - Source summary links: - [#8399](#8399) -> `docs/changelog/2026-08-06.mdx`: fixed DGX Spark local serving profiles. - [#8418](#8418) -> `docs/changelog/2026-08-06.mdx`: durable llama.cpp lifecycle management. - [#8422](#8422) -> `docs/changelog/2026-08-06.mdx`: recoverable llama.cpp receipt publication. - [#8402](#8402) -> `docs/changelog/2026-08-06.mdx`: remediable DGX Spark storage admission. - [#8391](#8391) -> `docs/changelog/2026-08-06.mdx`: host-local serving recipe contracts. - [#8401](#8401) -> `docs/changelog/2026-08-06.mdx`: serving profile lifecycle provenance. - [#8322](#8322) -> `docs/changelog/2026-08-06.mdx`: guarded llama.cpp route compatibility. - [#8272](#8272) -> `docs/changelog/2026-08-06.mdx`: explicitly trusted private endpoints with stable policy pins and CA trust. - [#8431](#8431) -> `docs/changelog/2026-08-06.mdx`: Personal onboarding policy tier and its trust boundary. - [#8143](#8143) -> `docs/changelog/2026-08-06.mdx`: manifest-derived state authority. - [#7859](#7859) -> `docs/changelog/2026-08-06.mdx`: side-effect-free lifecycle lock timeouts. - [#8262](#8262) -> `docs/changelog/2026-08-06.mdx`: managed gateway lease waiting. - [#8339](#8339) -> `docs/changelog/2026-08-06.mdx`: continued journaled rebuild recreation. - [#8373](#8373) -> `docs/changelog/2026-08-06.mdx`: restore readiness after compatibility decisions. - [#8443](#8443) -> `docs/changelog/2026-08-06.mdx`: fail-closed malformed registry handling. - [#8419](#8419) -> `docs/changelog/2026-08-06.mdx`: bounded recovery for a gateway that never served. - [#8486](#8486) -> `docs/changelog/2026-08-06.mdx`: target-scoped registry recovery. - [#8259](#8259) -> `docs/changelog/2026-08-06.mdx`: scoped uninstall ordering and retry safety. - [#8457](#8457) -> `docs/changelog/2026-08-06.mdx`: desktop metadata exclusion during uninstall. - [#8026](#8026) -> `docs/changelog/2026-08-06.mdx`: typed Hermes configuration policy. - [#8242](#8242) -> `docs/changelog/2026-08-06.mdx`: Hermes WhatsApp session diagnostics. - [#8344](#8344) -> `docs/changelog/2026-08-06.mdx`: patched Hermes image and dependency checks. - [#8491](#8491) -> `docs/changelog/2026-08-06.mdx`: bounded MCP discovery timeout. - [#8490](#8490) -> `docs/changelog/2026-08-06.mdx`: MCP shadow diagnostics. - [#7619](#7619) -> `docs/changelog/2026-08-06.mdx`: web-search credential isolation. - [#8476](#8476) -> `docs/changelog/2026-08-06.mdx`: stable preflight advisory identifiers. - [#8452](#8452) -> `docs/changelog/2026-08-06.mdx`: user-local CLI resolution. - [#8481](#8481) -> `docs/changelog/2026-08-06.mdx`: remote network-policy terminal guidance. - Product-scope exclusions: [#8429](#8429) remains experimental; [#8261](#8261) remains feature-gated; and portable-profile changes [#8408](#8408), [#8415](#8415), [#8446](#8446), [#8458](#8458), [#8462](#8462), and [#8506](#8506) are not promoted as supported product surfaces. ## 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 6/6 and validates dated changelog structure and published links. - [ ] 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 - [x] Documentation writer subagent reviewed the completed changes - Result: `docs-updated` - Evidence: `docs/changelog/2026-08-06.mdx`; release-range scope, writing rules, documentation style, skip terms, exact names, threat-boundary wording, and published routes reviewed; changelog tests and docs build passed. - Agent: Codex Desktop <!-- docs-review-head-sha: 02b51ae --> <!-- docs-review-agents-blob-sha: c69aad4 --> ## DGX Station Hardware Evidence - [ ] Tested on DGX Station - Tested commit: Not applicable; no DGX Station host preparation script changed. - 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 — command/result or justification: `npx vitest run test/changelog-docs.test.ts` passed 6/6. - [ ] Applicable broad gate passed — `npm test` for broad runtime/test-harness changes; `npm run check` for repo-wide validation/coverage changes — command/result: Not applicable to a single changelog entry. - [x] Quality Gates section completed with required justifications or waivers - [x] No secrets, API keys, or credentials committed - [x] `npm run docs` builds without warnings (doc changes only) - [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 new dated changelog file includes the required parser-safe SPDX header and intentionally has no frontmatter, matching the changelog contract and existing entries. --- 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.104. * Documented fixes for local model runtimes, private endpoints, network policies, state recovery, uninstall behavior, safety updates, MCP diagnostics, credential isolation, and installation guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
A
sandboxes.jsonfile that was present but held invalid JSON was read as an empty registry, so the next registry mutation atomically rewrote the file and dropped every recorded sandbox without reporting an error. Reading a malformed configuration file now fails with the file path and recovery commands, and the file on disk is left exactly as it was found. A missing file still returns the first-run fallback.Related Issue
Fixes #8420
Changes
readConfigFileinsrc/lib/state/config-io.tsnow separates the read from the parse. Permission failures still raiseConfigPermissionError,ENOENTalone returns the caller's fallback, any other read failure propagates, and a parse failure raises the newConfigCorruptError(ECONFIGCORRUPT).ConfigCorruptErrorcarries the file path and a remediation block that copies the file aside and removes it. It drops theJSON.parseerror instead of keeping it ascause, because Node can quote the offending input and configuration files hold state that must stay out of diagnostics.registry.load()is the only caller ofreadConfigFile, so registry mutations such asregisterSandboxnow fail inside the registry lock beforesave()runs.test/registry.test.tscovers the reported reproduction: the read reports the damage,registerSandboxrefuses and leaves the file byte-identical with no lock directory or temp file behind, four separate reader processes all exit withECONFIGCORRUPTwhile the file stays unchanged, and a repaired file registers normally again. The existinghandles corrupt registry file gracefullytest encoded the old behavior and was replaced.src/lib/state/config-io.test.tscovers the parse-failure contract directly: repeated reads keep failing with the file and its directory untouched, the error names the path and the recovery commands while a planted secret value never reaches the serialized error, a malformed file behind a symlinked final component fails without touching link or target, and a present path that is not a readable file throws.docs/reference/host-files-and-state.mdxaddsMalformed Registry Filewith the recovery steps and the non-default gateway-port path;docs/reference/troubleshooting.mdxadds the matching symptom entry.Some read-only display paths keep their own
catcharound the registry, such assafeListRegistryEntriesinsrc/lib/status-command-deps.tsand the sandbox-name probe insrc/lib/diagnostics/debug.ts. Those still degrade to an empty list or a gateway probe. They persist nothing, so they cannot cause the reported data loss, and this change leaves them as they are.Type of Change
Quality Gates
Documentation Writer Review
docs-updateddocs/reference/host-files-and-state.mdx,docs/reference/troubleshooting.mdx. The review ran against the completed diff and the writing rules indocs/AGENTS.md,WRITING.md, and the controlled word list. Its findings were applied: the claim about affected commands was narrowed to the registry readers and writers that actually stop, the unsupportedrebuild-backups/recovery route was removed, the data-loss warning was moved ahead of thermcommand, the shell fence language was corrected, one term (malformed) is now used for the concept, the frontmatter routing fields and thesandboxes.jsontable row were updated, a troubleshooting symptom entry was added, and the error and remediation strings were reworded. The independent current-branch review also corrected the optional messaging health fallback wording in both pages. A post-refresh review remained PASS after the conflict-free main merge.DGX Station Hardware Evidence
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 unavailablenpx vitest run --project cli src/lib/state526/526 pass;npx vitest run --project cli src/lib/state/config-io.test.ts22/22 pass after the rebase;npx vitest run --project integration test/registry.test.ts test/registry-default-selection-revision.test.ts84/84 pass, andtest/registry.test.ts74/74 pass again after the rebase; after the main refresh,src/lib/state/config-io.test.tspassed 22/22 andtest/registry.test.tspassed 77/77.npm testfor broad runtime/test-harness changes;npm run checkfor repo-wide validation/coverage changes — command/result:npm run docspasses with 0 errors; 2 existing warnings remain (doc changes only)Signed-off-by: Tinson Lai tinsonl@nvidia.com
Summary by CodeRabbit
Bug Fixes
Documentation