Skip to content

feat(onboard): declare runtime host mount support - #8368

Open
ericksoa wants to merge 28 commits into
mainfrom
feat/runtime-host-mount-capability-8343
Open

feat(onboard): declare runtime host mount support#8368
ericksoa wants to merge 28 commits into
mainfrom
feat/runtime-host-mount-capability-8343

Conversation

@ericksoa

@ericksoa ericksoa commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Declare read-only host-mount support through the selected runtime-provider contract and reject unsupported providers or host platforms before onboarding mutates durable session state. Docker remains supported on Linux and WSL, while Kubernetes, Podman, and OpenShell MXC fail closed with provider-specific reasons. This is a stacked follow-up to #8280.

Related Issue

Part of #8343. Depends on #8280.

Changes

  • Require every runtime-provider bundle to declare read-only host-mount support or an explicit unsupported reason, including qualified host platforms for supported providers.
  • Resolve and enforce that capability for CLI requests and persisted resume state before session mutation.
  • Declare the merged base branch's dormant Podman provider unsupported and reject host mounts for both portable-profile selection paths before session or runtime mutation.
  • Document the current Docker, Kubernetes, Podman, and MXC support matrix plus the qualification checklist for future provider implementations.
  • Keep the abstraction because onboarding has multiple runtime providers and a direct Docker-only platform check cannot protect persisted mounts when runtime selection changes. Runtime-provider contract tests protect registration and the support matrix; command and session-bootstrap tests protect requested and persisted fail-closed paths.

Type of Change

  • 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)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • 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: Maintainer security-code review completed below; no remaining findings.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Security Review

  • Input validation and untrusted input: pass. Provider declarations are validated as a strict supported/unsupported union; supported platform lists must be non-empty, unique, and valid Node.js host platforms.
  • Runtime trust boundaries: pass. Runtime selection is resolved before accepting requested or persisted mounts, including fail-closed portable-profile handling for Podman.
  • Filesystem safety and TOCTOU: pass. This change preserves absolute-path, no-symlink, directory, target-containment, duplicate, and final source-identity revalidation protections.
  • Command and configuration injection: pass. No new shell/process execution or string-built command path is introduced.
  • Authorization and capability enforcement: pass. Unsupported providers and unqualified host platforms throw before durable state or runtime mutation; no provider fallback is allowed.
  • Secrets and logging: pass. Capability diagnostics contain only provider/platform reasons and do not expose mount contents or credentials.
  • Network exposure: not applicable. No listener, route, policy, or network-permission change is introduced.
  • State ordering and rollback: pass. Fresh and resumed session paths enforce support before clear, save, update, or recovery operations.
  • Dependencies and supply chain: not applicable. No dependency or lockfile changes are introduced.

Documentation Writer Review

  • Documentation writer subagent reviewed the completed changes
  • Result: docs-updated
  • Evidence: docs/manage-sandboxes/workspace-files.mdx; independent final review found no findings and passed 202 focused tests; npm run docs passed with 0 errors and 2 pre-existing hidden-page warnings.
  • Agent: Codex Desktop

DGX Station Hardware Evidence

  • Tested on DGX Station
  • Tested commit:
  • Station profile/scenario:
  • Result:
  • Supporting evidence:

Verification

  • PR description includes a Signed-off-by: line and every pushed commit appears as Verified in GitHub
  • npm run validate:pr passed after refreshing origin/main
  • npm run build:cli and npm run typecheck:cli passed
  • 239 targeted tests passed across runtime-provider, Podman, host-mount, command, session-bootstrap, checkpoint-resume, create-plan, registration, and Station Express suites
  • npm run test-conditionals:scan -- --top 25 passed
  • Applicable broad gate passed — targeted tests plus npm run validate:pr were used because this change is limited to the runtime-provider capability and onboarding guard paths
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only) — 0 errors; 2 pre-existing hidden-page warnings remain
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Aaron Erickson aerickson@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added runtime capability checks for read-only host mounts during onboarding and session resume.
    • Docker on Linux and WSL2 is supported; unsupported providers and platforms now show clear rejection reasons.
    • Host-mount validation includes platform qualification and revalidation requirements.
  • Documentation

    • Expanded host-mount guidance with supported platforms, provider limitations, capability checks, and configuration requirements.
  • Bug Fixes

    • Improved compatibility when resuming legacy sessions with missing or invalid machine state.
    • Removed outdated SSH dashboard access guidance from sandbox status information.

ericksoa and others added 15 commits August 4, 2026 18:28
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@ericksoa ericksoa added area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery area: security Security controls, permissions, secrets, or hardening feature PR adds or expands user-visible functionality platform: container Affects Docker, containerd, Podman, or images platform: k8s Affects Kubernetes deployments platform: wsl Affects Windows Subsystem for Linux area: architecture Architecture, design debt, major refactors, or maintainability v0.0.103 release-target labels Aug 5, 2026
@ericksoa ericksoa self-assigned this Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: 2c31b48e-b925-4bc5-9cd2-af55fa771094

📥 Commits

Reviewing files that changed from the base of the PR and between 0a8a6d0 and 8415b24.

📒 Files selected for processing (31)
  • docs/manage-sandboxes/workspace-files.mdx
  • src/lib/actions/sandbox/status-flow.test.ts
  • src/lib/actions/sandbox/status-snapshot.ts
  • src/lib/actions/sandbox/status-text.ts
  • src/lib/actions/sandbox/status.test.ts
  • src/lib/onboard/checkpoint-resume-guard.test.ts
  • src/lib/onboard/command.ts
  • src/lib/onboard/docker-driver-gateway-config.ts
  • src/lib/onboard/docker-driver-gateway-env.ts
  • src/lib/onboard/docker-driver-gateway-launch.test.ts
  • src/lib/onboard/host-mount/host-mount.test.ts
  • src/lib/onboard/host-mount/index.ts
  • src/lib/onboard/managed-workload-rebuild-transaction.test.ts
  • src/lib/onboard/resume-config.ts
  • src/lib/onboard/runtime-provider/access.ts
  • src/lib/onboard/runtime-provider/contract.ts
  • src/lib/onboard/runtime-provider/docker.ts
  • src/lib/onboard/runtime-provider/mxc.test.ts
  • src/lib/onboard/runtime-provider/mxc.ts
  • src/lib/onboard/runtime-provider/podman.test.ts
  • src/lib/onboard/runtime-provider/podman.ts
  • src/lib/onboard/runtime-provider/registry.ts
  • src/lib/onboard/runtime-provider/runtime-provider-contract.test.ts
  • src/lib/onboard/session-bootstrap.test.ts
  • src/lib/onboard/session-bootstrap.ts
  • src/lib/state/onboard-session-station-express.test.ts
  • src/lib/state/onboard-session.test.ts
  • src/lib/state/onboard-session.ts
  • src/lib/state/registry.ts
  • test/helpers/runtime-provider-bundle.ts
  • test/support/status-flow-test-harness.ts
💤 Files with no reviewable changes (2)
  • src/lib/state/onboard-session.ts
  • src/lib/onboard/docker-driver-gateway-env.ts
🚧 Files skipped from review as they are similar to previous changes (27)
  • test/helpers/runtime-provider-bundle.ts
  • src/lib/onboard/runtime-provider/docker.ts
  • src/lib/onboard/managed-workload-rebuild-transaction.test.ts
  • src/lib/onboard/runtime-provider/mxc.ts
  • src/lib/actions/sandbox/status.test.ts
  • src/lib/onboard/session-bootstrap.test.ts
  • src/lib/onboard/docker-driver-gateway-config.ts
  • src/lib/onboard/resume-config.ts
  • src/lib/actions/sandbox/status-text.ts
  • src/lib/onboard/checkpoint-resume-guard.test.ts
  • src/lib/onboard/runtime-provider/registry.ts
  • src/lib/actions/sandbox/status-flow.test.ts
  • src/lib/onboard/host-mount/host-mount.test.ts
  • docs/manage-sandboxes/workspace-files.mdx
  • src/lib/onboard/runtime-provider/access.ts
  • test/support/status-flow-test-harness.ts
  • src/lib/onboard/host-mount/index.ts
  • src/lib/actions/sandbox/status-snapshot.ts
  • src/lib/onboard/docker-driver-gateway-launch.test.ts
  • src/lib/onboard/session-bootstrap.ts
  • src/lib/state/onboard-session-station-express.test.ts
  • src/lib/onboard/runtime-provider/podman.ts
  • src/lib/onboard/runtime-provider/contract.ts
  • src/lib/onboard/runtime-provider/podman.test.ts
  • src/lib/onboard/runtime-provider/mxc.test.ts
  • src/lib/state/registry.ts
  • src/lib/onboard/runtime-provider/runtime-provider-contract.test.ts

📝 Walkthrough

Walkthrough

The change adds runtime-provider capability checks for read-only host mounts, validates them during onboarding and session preparation, simplifies sandbox state handling, removes obsolete gateway and remote-access behavior, and updates related tests and documentation.

Changes

Sandbox runtime and state changes

Layer / File(s) Summary
Runtime-provider host-mount capability contract
src/lib/onboard/runtime-provider/..., test/helpers/runtime-provider-bundle.ts
Runtime providers now declare read-only host-mount support, supported platforms, or rejection reasons. Registry validation and provider tests cover these capabilities.
Onboarding host-mount validation
docs/manage-sandboxes/workspace-files.mdx, src/lib/onboard/host-mount/..., src/lib/onboard/command.ts, src/lib/onboard/session-bootstrap.ts, src/lib/onboard/*test.ts
Onboarding and session preparation validate host mounts against the selected runtime provider before state changes. Portable profiles and unsupported providers are rejected.
Session and registry state simplification
src/lib/onboard/resume-config.ts, src/lib/state/onboard-session.ts, src/lib/state/onboard-session.test.ts, src/lib/state/registry.ts
Sandbox recovery uses completed session state and default-agent rules. CUA readiness mutation and step-rejection handling are removed. Legacy session normalization tests are added.
Status and gateway cleanup
src/lib/actions/sandbox/..., src/lib/onboard/docker-driver-gateway-*.ts, test/support/status-flow-test-harness.ts
Status output uses persisted host-mount normalization and no longer generates dashboard remote-access guidance. Gateway namespace and Podman socket handling are removed.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to 8415b

Portable host-mount requests may receive a generic Docker-driver error instead of the documented provider-specific diagnostic. The request is still rejected safely, so the PR is mergeable with owner awareness or follow-up to make the delegated validator the sole failure path.

Possibly related PRs

  • NVIDIA/NemoClaw#8920: Both PRs modify Docker gateway configuration and onboarding behavior.
  • NVIDIA/NemoClaw#9010: Both PRs modify runtime-provider admission and host-mount support validation.
  • NVIDIA/NemoClaw#9011: Both PRs cover host-mount onboarding support and Linux/WSL2 validation documentation.

Suggested labels: area: providers, platform: ubuntu

Suggested reviewers: cv, senthilr-nv

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OnboardCommand
  participant SessionBootstrap
  participant RuntimeProviderRegistry
  participant RuntimeProvider
  User->>OnboardCommand: start onboarding with host mounts
  OnboardCommand->>SessionBootstrap: prepare fresh or resumed session
  SessionBootstrap->>RuntimeProviderRegistry: resolve provider capability
  RuntimeProviderRegistry->>RuntimeProvider: check readOnlyHostMounts and host platform
  RuntimeProvider-->>SessionBootstrap: capability or selection error
  SessionBootstrap-->>OnboardCommand: create or reject session
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.59% 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 clearly and concisely describes the main change: declaring runtime support for host mounts during onboarding.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/runtime-host-mount-capability-8343

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

@github-code-quality

github-code-quality Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in commit 905b4e6 in the feat/runtime-host-mo... branch remains at 96%, unchanged from commit 0d33997 in the feat/read-only-host-... branch.

TypeScript / code-coverage/cli

The overall coverage in commit 905b4e6 in the feat/runtime-host-mo... branch remains at 81%, unchanged from commit 0d33997 in the feat/read-only-host-... branch.

Show a code coverage summary of the most impacted files.
File feat/read-only-host-... 0d33997 feat/runtime-host-mo... 905b4e6 +/-
src/lib/adapter...teway-server.ts 0% 79% +79%
src/lib/voice-g...nclaw-client.ts 0% 83% +83%
src/lib/state/r...y/host-mount.ts 0% 88% +88%
src/lib/voice-g...dential-file.ts 0% 88% +88%
src/lib/actions...ateway/serve.ts 0% 91% +91%
src/lib/voice-g...sion-service.ts 0% 93% +93%
src/lib/hermes-...anaged-route.ts 0% 94% +94%
src/lib/inferen...test-support.ts 0% 98% +98%
src/lib/adapter...nd-transport.ts 0% 100% +100%
src/lib/onboard...-mount/index.ts 0% 100% +100%

Updated August 06, 2026 23:54 UTC

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Preserve the provider capability guard alongside the base branch's portable-profile changes.

Declare Podman unsupported and fail closed before session mutation.

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
@github-actions github-actions Bot added v0.0.105 and removed v0.0.104 labels Aug 7, 2026

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This stacked capability declaration cannot be approved before parent PR #8280 resolves its host-mount canonicalization defect and passes review. Restack after the parent changes, then fix the failing exact all-agent activation and advisor checks and rerun the complete required set. Confirm that persisted resume rejection still occurs before durable session or runtime mutation on the final parent head.

@github-actions github-actions Bot added v0.0.106 and removed v0.0.105 labels Aug 8, 2026
Base automatically changed from feat/read-only-host-mounts-8274 to main August 12, 2026 05:37
@copy-pr-bot

copy-pr-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/lib/actions/sandbox/status-text.ts (2)

207-214: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Both status renderers now propagate a throw from the shared host-mount normalizer. normalizePersistedSandboxHostMounts throws when persisted state holds an invalid mount. Both call sites invoke it without a guard, so one corrupt registry row breaks the status command that the user runs to diagnose that corruption.

  • src/lib/actions/sandbox/status-text.ts#L207-L214: printSandboxHostMounts throws mid-render, so printSandboxDetails stops after the GPU section and never prints OpenShell, policies, or agent status. Catch the error and print a repair hint in place of the mount list.
  • src/lib/actions/sandbox/status-snapshot.ts#L54-L56: the wrapper is called at line 650 during buildSandboxStatusReport, so --json status produces no document. Catch the error and report it as a field, or confirm the fail-closed behavior is intended.
🤖 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/actions/sandbox/status-text.ts` around lines 207 - 214, Guard both
call sites of normalizePersistedSandboxHostMounts: update printSandboxHostMounts
in src/lib/actions/sandbox/status-text.ts (lines 207-214) to catch invalid
persisted mounts and print an in-place repair hint so printSandboxDetails
continues rendering; update the wrapper in
src/lib/actions/sandbox/status-snapshot.ts (lines 54-56), used by
buildSandboxStatusReport, to catch the error and expose it as a status field so
JSON output remains valid.

392-410: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update stale status-output documentation

docs/deployment/deploy-to-headless-server.mdx:242-243 and docs/changelog/2026-08-07.mdx:30-32 still state that status prints SSH dashboard guidance. Update them to reference dashboard-url; retain the valid SSH hint for that command.

🤖 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/actions/sandbox/status-text.ts` around lines 392 - 410, Update the
stale status-output references in the deployment documentation and changelog to
describe the dashboard-url guidance instead of SSH dashboard guidance, while
preserving the valid SSH hint associated with the dashboard-url command.

Source: Coding guidelines

src/lib/actions/sandbox/status-snapshot.ts (1)

565-578: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Restore a bounded post-recovery inference probe retry.

waitForRecoveredSandboxGateway proves gateway health, not https://inference.local/v1/models readiness. A single immediate probe can mark the route unprobed and set status exit code 1 while the route starts. Existing tests still require a 2-second retry and up to three probes. Restore this retry or add an equivalent route-readiness guarantee.

🤖 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/actions/sandbox/status-snapshot.ts` around lines 565 - 578, Update
the inference probe flow around waitForRecoveredSandboxGateway and
buildSandboxInferenceRouteHealth to restore bounded readiness retries after
gateway recovery: perform up to three probes with a 2-second delay between
attempts, stopping early when the inference endpoint is healthy. Preserve
fail-closed behavior and report unexpected probe errors through
reportInferenceProbeError.
src/lib/onboard/resume-config.ts (1)

15-24: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Align src/lib/onboard/resume-config.test.ts with the resume-conflict implementation. The test passes checkpoint.sandboxIdentity for a pending sandbox and expects a conflict, but getResumeSandboxConflict ignores checkpoint identity and requires a completed sandbox step.

🤖 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/onboard/resume-config.ts` around lines 15 - 24, Update
resume-config.test.ts fixtures for getResumeSandboxConflict to represent a
pending sandbox through checkpoint.steps.sandbox.status with a completed status,
rather than checkpoint.sandboxIdentity. Keep the assertion expecting a resume
conflict and align the test input with ResumeSessionLike’s steps shape.
src/lib/state/registry.ts (1)

272-283: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Preserve CUA readiness invalidation in updateSandbox. CUA readers still consume cuaRuntimeReadiness, and persistence retains valid records when qualification is enabled. Object.assign also accepts caller-supplied readiness and writes explicit undefined values. Restrict readiness writes to the canonical recorder, invalidate readiness when inference or runtime authority changes, and discard opaque records when qualification is disabled.

🤖 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/state/registry.ts` around lines 272 - 283, Update updateSandbox to
prevent caller-supplied cuaRuntimeReadiness, including explicit undefined, from
being persisted; only the canonical readiness recorder may write it. Invalidate
the stored readiness whenever inference or runtime authority changes, and remove
opaque readiness records when qualification is disabled. Preserve the existing
name validation, locking, and successful update behavior.
🧹 Nitpick comments (1)
test/support/status-flow-test-harness.ts (1)

206-206: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the running gateway status branch.

createStatusFlowHarness always mocks isSandboxGatewayRunningForStatus to return false, so the status-flow suite does not assert the OpenClaw: running output. Add one test that returns true, or document this coverage gap as intentional.

🤖 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/support/status-flow-test-harness.ts` at line 206, Update
createStatusFlowHarness and its status-flow tests to cover the true result from
statusProcessRecovery.isSandboxGatewayRunningForStatus, asserting the expected
“OpenClaw: running” output; preserve the existing false-result coverage.
🤖 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/actions/sandbox/status.test.ts`:
- Around line 96-105: Strengthen the assertions in the getSandboxStatusReport
test so they verify each returned host mount is a distinct object from the
corresponding entry in hostMounts, not just that report.hostMounts is a new
array. Preserve the existing value-equality assertion while adding element-level
identity checks that exercise the cloning behavior in
normalizePersistedSandboxHostMounts and the status snapshot wrapper.
- Around line 96-105: Expand regression coverage for invalid persisted host
mounts: in src/lib/onboard/host-mount/host-mount.test.ts, test non-array values
and terminal-control characters in source or target, asserting
normalizePersistedSandboxHostMounts throws rather than omitting unsafe mounts.
In src/lib/actions/sandbox/status.test.ts and
src/lib/actions/sandbox/status-flow.test.ts, add status-boundary cases asserting
the intended rejection behavior. In src/lib/state/onboard-session.test.ts, add
terminal-control metadata coverage and verify hasInvalidSessionHostMounts
preserves its fail-closed marker.

In `@src/lib/onboard/command.ts`:
- Around line 200-203: Remove the earlier portable-profile-specific failure
branch so portable --host-mount requests reach
requireReadOnlyHostMountRuntimeSupport() in the shown try/catch. Preserve the
validator’s error handling through fail(), making its declared capability
diagnostic the sole failure message for unsupported portable profiles.

In `@src/lib/onboard/docker-driver-gateway-config.ts`:
- Around line 59-64: The gateway ID derivation must retain its documented
per-user state-directory contract while restoring coverage for the active
sandbox namespace behavior. In src/lib/onboard/docker-driver-gateway-config.ts
lines 59-64, document that the state directory is always per-user and explain
why the process UID is intentionally excluded from the digest; in
src/lib/onboard/docker-driver-gateway-launch.test.ts lines 233-242, restore
public-entrypoint assertions that buildDockerDriverGatewayConfigToml emits
sandbox_namespace for Docker and that direct host launches set
NEMOCLAW_OPENSHELL_SANDBOX_NAMESPACE_ENV, without restoring the deleted
hasStateScopedSandboxNamespace path.
- Around line 87-92: Restore and export hasStateScopedSandboxNamespace, then
retain its existing callers in host-gateway-process.ts and uninstall run-plan.ts
so TypeScript compilation succeeds and scoped gateway shutdown remains
fail-closed. Do not alter the Docker-only supervisor_bin handling; Podman must
continue omitting that field.

In `@src/lib/onboard/session-bootstrap.ts`:
- Line 46: Update the race test around checkpointSandboxName to use a
synchronous updateSession mutator that returns the session or void, preventing
Promise values from being stored as mock session state. Assert
checkpointSandboxName’s immediate persistence, or remove the obsolete race test
if it no longer applies.

---

Outside diff comments:
In `@src/lib/actions/sandbox/status-snapshot.ts`:
- Around line 565-578: Update the inference probe flow around
waitForRecoveredSandboxGateway and buildSandboxInferenceRouteHealth to restore
bounded readiness retries after gateway recovery: perform up to three probes
with a 2-second delay between attempts, stopping early when the inference
endpoint is healthy. Preserve fail-closed behavior and report unexpected probe
errors through reportInferenceProbeError.

In `@src/lib/actions/sandbox/status-text.ts`:
- Around line 207-214: Guard both call sites of
normalizePersistedSandboxHostMounts: update printSandboxHostMounts in
src/lib/actions/sandbox/status-text.ts (lines 207-214) to catch invalid
persisted mounts and print an in-place repair hint so printSandboxDetails
continues rendering; update the wrapper in
src/lib/actions/sandbox/status-snapshot.ts (lines 54-56), used by
buildSandboxStatusReport, to catch the error and expose it as a status field so
JSON output remains valid.
- Around line 392-410: Update the stale status-output references in the
deployment documentation and changelog to describe the dashboard-url guidance
instead of SSH dashboard guidance, while preserving the valid SSH hint
associated with the dashboard-url command.

In `@src/lib/onboard/resume-config.ts`:
- Around line 15-24: Update resume-config.test.ts fixtures for
getResumeSandboxConflict to represent a pending sandbox through
checkpoint.steps.sandbox.status with a completed status, rather than
checkpoint.sandboxIdentity. Keep the assertion expecting a resume conflict and
align the test input with ResumeSessionLike’s steps shape.

In `@src/lib/state/registry.ts`:
- Around line 272-283: Update updateSandbox to prevent caller-supplied
cuaRuntimeReadiness, including explicit undefined, from being persisted; only
the canonical readiness recorder may write it. Invalidate the stored readiness
whenever inference or runtime authority changes, and remove opaque readiness
records when qualification is disabled. Preserve the existing name validation,
locking, and successful update behavior.

---

Nitpick comments:
In `@test/support/status-flow-test-harness.ts`:
- Line 206: Update createStatusFlowHarness and its status-flow tests to cover
the true result from statusProcessRecovery.isSandboxGatewayRunningForStatus,
asserting the expected “OpenClaw: running” output; preserve the existing
false-result coverage.
🪄 Autofix

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: f83b3a59-860e-49bd-b3d8-7f6cce16a108

📥 Commits

Reviewing files that changed from the base of the PR and between 6174550 and f832717.

📒 Files selected for processing (32)
  • docs/manage-sandboxes/workspace-files.mdx
  • src/lib/actions/sandbox/status-flow.test.ts
  • src/lib/actions/sandbox/status-snapshot.ts
  • src/lib/actions/sandbox/status-text.ts
  • src/lib/actions/sandbox/status.test.ts
  • src/lib/onboard/checkpoint-resume-guard.test.ts
  • src/lib/onboard/command.test.ts
  • src/lib/onboard/command.ts
  • src/lib/onboard/docker-driver-gateway-config.ts
  • src/lib/onboard/docker-driver-gateway-env.ts
  • src/lib/onboard/docker-driver-gateway-launch.test.ts
  • src/lib/onboard/host-mount/host-mount.test.ts
  • src/lib/onboard/host-mount/index.ts
  • src/lib/onboard/managed-workload-rebuild-transaction.test.ts
  • src/lib/onboard/resume-config.ts
  • src/lib/onboard/runtime-provider/access.ts
  • src/lib/onboard/runtime-provider/contract.ts
  • src/lib/onboard/runtime-provider/docker.ts
  • src/lib/onboard/runtime-provider/mxc.test.ts
  • src/lib/onboard/runtime-provider/mxc.ts
  • src/lib/onboard/runtime-provider/podman.test.ts
  • src/lib/onboard/runtime-provider/podman.ts
  • src/lib/onboard/runtime-provider/registry.ts
  • src/lib/onboard/runtime-provider/runtime-provider-contract.test.ts
  • src/lib/onboard/session-bootstrap.test.ts
  • src/lib/onboard/session-bootstrap.ts
  • src/lib/state/onboard-session-station-express.test.ts
  • src/lib/state/onboard-session.test.ts
  • src/lib/state/onboard-session.ts
  • src/lib/state/registry.ts
  • test/helpers/runtime-provider-bundle.ts
  • test/support/status-flow-test-harness.ts
💤 Files with no reviewable changes (2)
  • src/lib/onboard/docker-driver-gateway-env.ts
  • src/lib/state/onboard-session.ts

Comment on lines +96 to +105
const hostMounts = [
{ source: "/srv/project", target: "/sandbox/project", readOnly: true as const },
];
const report = await getSandboxStatusReport("alpha", {
getSandbox: () => ({ name: "alpha", hostMounts }) as never,
reconcile: async () => ({ state: "missing" as const, output: "not found" }),
});

await expect(reportFor("not-an-array")).rejects.toThrow(
"Persisted host mount state must be an array",
);
await expect(
reportFor([
{
source: "/srv/project\u202e",
target: "/sandbox/project",
readOnly: true,
},
]),
).rejects.toThrow("unsafe terminal control characters");
expect(report.hostMounts).toEqual(hostMounts);
expect(report.hostMounts).not.toBe(hostMounts);

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the element-level defensive copy.

not.toBe(hostMounts) only proves that the report holds a new array. normalizePersistedSandboxHostMounts already returns a new array, so this assertion passes even if the wrapper at src/lib/actions/sandbox/status-snapshot.ts lines 54-56 stops cloning each mount. Assert the element identity to lock in the claim.

💚 Proposed assertion
     expect(report.hostMounts).toEqual(hostMounts);
     expect(report.hostMounts).not.toBe(hostMounts);
+    expect(report.hostMounts[0]).not.toBe(hostMounts[0]);

As per path instructions: "Flag copied production algorithms, broad mocks that bypass the behavior under test, and conditionals that make a test pass without exercising its claim."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const hostMounts = [
{ source: "/srv/project", target: "/sandbox/project", readOnly: true as const },
];
const report = await getSandboxStatusReport("alpha", {
getSandbox: () => ({ name: "alpha", hostMounts }) as never,
reconcile: async () => ({ state: "missing" as const, output: "not found" }),
});
await expect(reportFor("not-an-array")).rejects.toThrow(
"Persisted host mount state must be an array",
);
await expect(
reportFor([
{
source: "/srv/project\u202e",
target: "/sandbox/project",
readOnly: true,
},
]),
).rejects.toThrow("unsafe terminal control characters");
expect(report.hostMounts).toEqual(hostMounts);
expect(report.hostMounts).not.toBe(hostMounts);
const hostMounts = [
{ source: "/srv/project", target: "/sandbox/project", readOnly: true as const },
];
const report = await getSandboxStatusReport("alpha", {
getSandbox: () => ({ name: "alpha", hostMounts }) as never,
reconcile: async () => ({ state: "missing" as const, output: "not found" }),
});
expect(report.hostMounts).toEqual(hostMounts);
expect(report.hostMounts).not.toBe(hostMounts);
expect(report.hostMounts[0]).not.toBe(hostMounts[0]);
🤖 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/actions/sandbox/status.test.ts` around lines 96 - 105, Strengthen the
assertions in the getSandboxStatusReport test so they verify each returned host
mount is a distinct object from the corresponding entry in hostMounts, not just
that report.hostMounts is a new array. Preserve the existing value-equality
assertion while adding element-level identity checks that exercise the cloning
behavior in normalizePersistedSandboxHostMounts and the status snapshot wrapper.

Source: Path instructions


🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Locate remaining coverage for unsafe host-mount rejection.
fd 'host-mount' --type f
rg -nP --type=ts -C4 'hasUnsafeHostMountTerminalText|terminal control|\\u001b|x1b'
rg -nP --type=ts -C4 'normalizePersistedSandboxHostMounts' -g '**/*.test.ts'

Repository: NVIDIA/NemoClaw

Length of output: 236


🏁 Script executed:

#!/bin/bash
set -u

echo '=== candidate files ==='
fd -t f -e ts -e tsx | rg '(^|/)(host-mount|status(-flow)?|onboard-session|registry)([^/]*)?\.test\.tsx?$|src/lib/state/registry/host-mount\.ts|src/lib/state/registry\.ts|src/lib/actions/sandbox/status-(snapshot|text)\.ts'

echo '=== AST outlines ==='
for f in \
  src/lib/state/registry/host-mount.ts \
  src/lib/onboard/host-mount/host-mount.test.ts \
  src/lib/actions/sandbox/status-snapshot.ts \
  src/lib/actions/sandbox/status-text.ts \
  src/lib/actions/sandbox/status.test.ts \
  src/lib/actions/sandbox/status-flow.test.ts \
  src/lib/state/onboard-session.test.ts
do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    ast-grep outline "$f" 2>/dev/null | head -120
  fi
done

echo '=== normalizer and validator references ==='
rg -n -C5 'normalizePersistedSandboxHostMounts|hasUnsafeHostMountTerminalText|hostMounts' \
  src/lib/state/registry/host-mount.ts \
  src/lib/onboard/host-mount/host-mount.test.ts \
  src/lib/actions/sandbox/status-snapshot.ts \
  src/lib/actions/sandbox/status-text.ts \
  src/lib/actions/sandbox/status.test.ts \
  src/lib/actions/sandbox/status-flow.test.ts \
  src/lib/state/onboard-session.test.ts \
  src/lib/state/registry.ts 2>/dev/null || true

echo '=== focused current diff ==='
git diff --stat -- \
  src/lib/state/registry/host-mount.ts \
  src/lib/onboard/host-mount/host-mount.test.ts \
  src/lib/actions/sandbox/status-snapshot.ts \
  src/lib/actions/sandbox/status-text.ts \
  src/lib/actions/sandbox/status.test.ts \
  src/lib/actions/sandbox/status-flow.test.ts \
  src/lib/state/onboard-session.test.ts \
  src/lib/state/registry.ts
git diff -- \
  src/lib/state/registry/host-mount.ts \
  src/lib/onboard/host-mount/host-mount.test.ts \
  src/lib/actions/sandbox/status-snapshot.ts \
  src/lib/actions/sandbox/status-text.ts \
  src/lib/actions/sandbox/status.test.ts \
  src/lib/actions/sandbox/status-flow.test.ts \
  src/lib/state/onboard-session.test.ts \
  src/lib/state/registry.ts | sed -n '1,1200p'

Repository: NVIDIA/NemoClaw

Length of output: 32872


🏁 Script executed:

#!/bin/bash
set -u

echo '=== host-mount normalizer ==='
cat -n src/lib/state/registry/host-mount.ts | sed -n '1,190p'

echo '=== owner host-mount tests ==='
cat -n src/lib/onboard/host-mount/host-mount.test.ts | sed -n '1,180p'

echo '=== session normalization implementation and relevant tests ==='
rg -n -C8 'normalizeSession|hasInvalidSessionHostMounts|metadata\.hostMounts|hostMounts' \
  src/lib/state/onboard-session.ts \
  src/lib/state/onboard-session.test.ts \
  src/lib/state/onboard-session-normalization.test.ts \
  src/lib/state/onboard-session-redaction.test.ts 2>/dev/null || true

echo '=== status flow harness and host-mount behavior ==='
rg -n -C12 'createStatusFlowHarness|showSandboxStatus|printSandboxDetails|printSandboxHostMounts|hostMounts' \
  src/lib/actions/sandbox/status-flow.test.ts \
  src/lib/actions/sandbox/status-lookup-rendering.test.ts \
  src/lib/actions/sandbox/status-snapshot*.test.ts \
  src/lib/actions/sandbox/status-text.ts \
  src/lib/actions/sandbox/status-snapshot.ts 2>/dev/null || true

echo '=== full test-tree searches ==='
rg -n -i -C3 \
  'terminal control|control characters|unsafe.*host.?mount|host.?mount.*unsafe|hasUnsafeHostMountTerminalText|normalizePersistedSandboxHostMounts|hasInvalidSessionHostMounts' \
  --glob '**/*.{test,spec}.{ts,tsx,js,jsx,mts,mjs,cts,cjs}' . 2>/dev/null || true

echo '=== control-character literals ==='
rg -n -P -C3 '\\\\x1b|\\\\u001b|\\\\u000[0-9a-f]|\\x1b|\\u001b' \
  --glob '**/*.{test,spec}.{ts,tsx,js,jsx,mts,mjs,cts,cjs}' . 2>/dev/null || true

Repository: NVIDIA/NemoClaw

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -u

echo '=== normalizer source ==='
sed -n '1,132p' src/lib/state/registry/host-mount.ts

echo '=== session source: host-mount normalization ==='
rg -n -C10 'hasInvalidSessionHostMounts|hostMounts|normalize.*Session|metadata' src/lib/state/onboard-session.ts | head -260

echo '=== session tests: relevant sections ==='
sed -n '1015,1060p' src/lib/state/onboard-session.test.ts
sed -n '320,420p' src/lib/state/onboard-session.test.ts

echo '=== status text source ==='
sed -n '195,220p' src/lib/actions/sandbox/status-text.ts
sed -n '340,390p' src/lib/actions/sandbox/status-text.ts

echo '=== status-flow harness declaration and implementation references ==='
rg -n -m30 -C8 'function createStatusFlowHarness|const createStatusFlowHarness|showSandboxStatus\s*=|showSandboxStatus\(' \
  src/lib/actions/sandbox/status-flow.test.ts \
  src/lib/actions/sandbox/*.ts

echo '=== focused status tests ==='
sed -n '90,112p' src/lib/actions/sandbox/status.test.ts
sed -n '155,178p' src/lib/actions/sandbox/status-flow.test.ts

echo '=== owner-test assertions only ==='
rg -n -C4 'normalizePersistedSandboxHostMounts|parseReadOnlyHostMount|terminal|control|malformed|invalid' \
  src/lib/onboard/host-mount/host-mount.test.ts

Repository: NVIDIA/NemoClaw

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -u

node - <<'JS'
const unsafeTerminalText = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;
const cases = [
  ["/srv/project", false],
  ["/srv/proj\u001b[31mect", true],
  ["/srv/proj\nect", true],
  ["/srv/project\u200b", true],
];
for (const [value, expected] of cases) {
  const actual = unsafeTerminalText.test(value);
  console.log(JSON.stringify({ value, actual, expected, pass: actual === expected }));
}
JS

Repository: NVIDIA/NemoClaw

Length of output: 436


🏁 Script executed:

#!/bin/bash
set -u

echo '=== session normalization flow ==='
sed -n '784,925p' src/lib/state/onboard-session.ts
rg -n -C12 'function loadSession|export function loadSession|normalizeSession\(' src/lib/state/onboard-session.ts

echo '=== status flow implementation ==='
sed -n '68,155p' src/lib/actions/sandbox/status.ts

echo '=== owner test full focused range ==='
sed -n '1,125p' src/lib/onboard/host-mount/host-mount.test.ts

echo '=== exact relevant assertions across tests ==='
rg -n -C3 'hasInvalidSessionHostMounts|Persisted state contains an invalid read-only host mount|terminal control|Host mounts:' \
  src/lib --glob '**/*.test.ts' --glob '**/*.test.tsx' | head -240

Repository: NVIDIA/NemoClaw

Length of output: 22733


🏁 Script executed:

#!/bin/bash
set -u

node - <<'JS'
const unsafe = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u;

function parseDeclaration(value) {
  if (unsafe.test(value)) {
    throw new Error("paths must not contain terminal control characters");
  }
  const separator = value.lastIndexOf(":/sandbox/");
  if (separator <= 0) throw new Error("invalid host-mount syntax");
  return value;
}

function normalize(value) {
  if (value === undefined) return [];
  if (!Array.isArray(value)) throw new Error("Persisted host mount state must be an array");
  const declarations = value.map((candidate) => {
    if (
      typeof candidate !== "object" ||
      candidate === null ||
      typeof candidate.source !== "string" ||
      typeof candidate.target !== "string" ||
      candidate.readOnly !== true
    ) {
      throw new Error("invalid read-only host mount");
    }
    return `${candidate.source}:${candidate.target}`;
  });
  return declarations.map(parseDeclaration);
}

const cases = [
  ["malformed array", { source: "/srv/project", target: "/sandbox/project", readOnly: true }, false],
  ["unsafe source", [{ source: "/srv/\u001b[31mproject", target: "/sandbox/project", readOnly: true }], true],
  ["unsafe target", [{ source: "/srv/project", target: "/sandbox/\u001bproject", readOnly: true }], true],
  ["non-read-only", [{ source: "/srv/project", target: "/sandbox/project", readOnly: false }], true],
];

for (const [name, value, shouldThrow] of cases) {
  let threw = false;
  try {
    normalize(value);
  } catch {
    threw = true;
  }
  console.log(JSON.stringify({ name, threw, shouldThrow, pass: threw === shouldThrow }));
}
JS

Repository: NVIDIA/NemoClaw

Length of output: 433


Add regression coverage for invalid host-mount state. normalizePersistedSandboxHostMounts lacks tests for non-array values and terminal-control text in source or target. Add these cases to src/lib/onboard/host-mount/host-mount.test.ts.

  • Add status-boundary tests that assert the intended rejection behavior. The normalizer throws; it does not silently omit unsafe mounts.
  • Add session coverage for terminal-control metadata if hasInvalidSessionHostMounts must preserve its fail-closed marker. The existing test covers only readOnly: false.
📍 Affects 3 files
  • src/lib/actions/sandbox/status.test.ts#L96-L105 (this comment)
  • src/lib/actions/sandbox/status-flow.test.ts#L162-L174
  • src/lib/state/onboard-session.test.ts#L332-L407
🤖 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/actions/sandbox/status.test.ts` around lines 96 - 105, Expand
regression coverage for invalid persisted host mounts: in
src/lib/onboard/host-mount/host-mount.test.ts, test non-array values and
terminal-control characters in source or target, asserting
normalizePersistedSandboxHostMounts throws rather than omitting unsafe mounts.
In src/lib/actions/sandbox/status.test.ts and
src/lib/actions/sandbox/status-flow.test.ts, add status-boundary cases asserting
the intended rejection behavior. In src/lib/state/onboard-session.test.ts, add
terminal-control metadata coverage and verify hasInvalidSessionHostMounts
preserves its fail-closed marker.

Comment thread src/lib/onboard/command.ts
Comment thread src/lib/onboard/docker-driver-gateway-config.ts
Comment on lines 87 to 92
["network_name", gatewayEnv.OPENSHELL_DOCKER_NETWORK_NAME],
["supervisor_image", gatewayEnv.OPENSHELL_DOCKER_SUPERVISOR_IMAGE],
// OpenShell 0.0.99 accepts supervisor_bin only for the Docker driver.
// OpenShell 0.0.85 accepts supervisor_bin only for the Docker driver.
// The Podman schema rejects the entire driver table when this Docker-only
// field is present, so portable onboarding must rely on supervisor_image.
["supervisor_bin", driver === "docker" ? (sandboxBin ?? undefined) : undefined],

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check for remaining callers of the removed validator and the declared OpenShell version.
rg -nP --type=ts -C3 'hasStateScopedSandboxNamespace'
rg -nP -C2 'OPENSHELL_VERSION|openshell.*0\.0\.[0-9]+' -g '!**/node_modules/**' | head -40
rg -nP -C3 'socket_path' -g '!**/node_modules/**'

Repository: NVIDIA/NemoClaw

Length of output: 153


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(docker-driver-gateway-config|onboard|openshell|gateway|sandbox|README)' | head -120

printf '%s\n' '--- validator and related identifiers ---'
rg -n -C3 'hasStateScopedSandboxNamespace|state.?scoped|sandbox.?namespace|supervisor_bin|supervisor_image|OPENSHELL_VERSION|0\.0\.(85|99)' \
  src test tests .github README.md package.json 2>/dev/null | head -240 || true

printf '%s\n' '--- relevant source outline and file size ---'
if command -v ast-grep >/dev/null 2>&1; then
  ast-grep outline src/lib/onboard/docker-driver-gateway-config.ts --view compact || true
fi
wc -l src/lib/onboard/docker-driver-gateway-config.ts
printf '%s\n' '--- gateway config source ---'
cat -n src/lib/onboard/docker-driver-gateway-config.ts

Repository: NVIDIA/NemoClaw

Length of output: 31969


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- gateway config consumers and writers ---'
rg -n -C4 'OPENSHELL_GATEWAY_CONFIG|openshell-gateway\.toml|writeDockerDriverGatewayConfig|prepareDockerDriverGatewayConfigEnv|NEMOCLAW_OPENSHELL_SANDBOX_NAMESPACE_ENV' \
  src scripts nemoclaw test docs .github 2>/dev/null | head -320 || true

printf '%s\n' '--- state directory and gateway environment setup ---'
rg -n -C4 'stateDir|OPENSHELL_STATE|OPENSHELL_HOME|gatewayEnv|mkdirSync|chmodSync|lstatSync|realpathSync|readlinkSync' \
  src/lib/onboard src/lib/state src/commands/onboard.ts src/lib/actions/onboard.ts scripts 2>/dev/null | head -360 || true

printf '%s\n' '--- version migration records ---'
for f in docs/security/openshell-0.0.85-migration-review.md docs/security/openshell-0.0.99-migration-review.md docs/security/openshell-0.0.72-compatibility-review.mdx; do
  if [ -f "$f" ]; then
    printf '\n--- %s ---\n' "$f"
    rg -n -C4 'supervisor_bin|supervisor_image|driver|Docker|Podman|version|schema|namespace|config' "$f" | head -260 || true
  fi
done

printf '%s\n' '--- focused tests ---'
rg -n -C5 'docker-driver-gateway-config|supervisor_bin|supervisor_image|gateway config|gateway-config|0o600|sandbox namespace' \
  test src --glob '*test.ts' 2>/dev/null | head -320 || true

Repository: NVIDIA/NemoClaw

Length of output: 50372


🌐 Web query:

Official OpenShell documentation or source for the gateway driver configuration schema: determine the first release that accepts supervisor_bin for the Docker driver and whether the Podman driver rejects that field.

💡 Result:

In NVIDIA OpenShell, the supervisor_bin configuration field for the Docker driver was introduced as part of the transition to the TOML-based configuration schema defined in RFC 0003 [1][2]. This configuration format was implemented and merged in the OpenShell gateway, making supervisor_bin available for use in the [openshell.drivers.docker] table from release v0.0.83 onward [3]. Regarding the Podman driver, the field supervisor_bin is not a supported configuration key. The Podman driver schema is separate from the Docker driver's and does not include supervisor_bin [4][5]. Consequently, providing supervisor_bin within the [openshell.drivers.podman] table will cause the gateway to reject the configuration, as the driver's deserialization logic enforces strict field validation (e.g., deny_unknown_fields) [5][6]. Users attempting to use this field with the Podman driver will encounter preflight errors [6].

Citations:


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- relevant gateway launch code ---'
cat -n src/lib/onboard/docker-driver-gateway-launch.ts | sed -n '90,205p'

printf '%s\n' '--- gateway config validation symbols ---'
rg -n -C5 'function assertDockerDriverGateway|export function assertDockerDriverGateway|readFileSync|OPENSHELL_GATEWAY_CONFIG' \
  src/lib/onboard --glob 'docker-driver-gateway-env-config-validation.ts' \
  --glob 'docker-driver-gateway-env-config-validation.test.ts' \
  --glob 'docker-driver-gateway-jwt-bundle.ts' \
  --glob 'docker-driver-gateway-jwt-bundle.test.ts' 2>/dev/null || true

printf '%s\n' '--- state directory creation and gateway state paths ---'
rg -n -C5 'openshell-docker-gateway|gatewayStateDir|stateDir.*mkdir|mkdir.*stateDir|ensure.*State|chmod.*0o700|mode: 0o700|mode: 0o600|realpath|lstat|readlink' \
  src/lib src/commands scripts test --glob '*.ts' --glob '*.mts' --glob '*.sh' 2>/dev/null | head -300 || true

printf '%s\n' '--- current diff for the reviewed file ---'
git status --short
git diff --unified=25 -- src/lib/onboard/docker-driver-gateway-config.ts | head -260

printf '%s\n' '--- migration-document security claims ---'
sed -n '680,755p' docs/security/openshell-0.0.85-migration-review.md
rg -n -C6 'mode-0600|ownership|symlink|link count|namespace|supervisor_bin|0\.0\.85|0\.0\.99' \
  docs/security/openshell-0.0.99-migration-review.md docs/security/openshell-0.0.85-migration-review.md | head -260 || true

Repository: NVIDIA/NemoClaw

Length of output: 50371


🏁 Script executed:

#!/bin/bash
python3 - <<'PY'
from pathlib import Path
import re

root = Path(".")
config = root / "src/lib/onboard/docker-driver-gateway-config.ts"
launch = root / "src/lib/onboard/docker-driver-gateway-launch.ts"

text = config.read_text()
launch_text = launch.read_text()

print("--- static config trust-path facts ---")
print("atomic writer:", "writeRestrictedFileAtomic(" in text)
print("final mode argument:", re.search(r"writeRestrictedFileAtomic\(\s*configPath,.*?0o600", text, re.S) is not None)
print("parent mkdir mode:", re.search(r"mkdirSync\(dir, \{ recursive: true, mode: 0o700 \}\)", text) is not None)
print("rename replaces destination:", "fs.renameSync(tmpPath, filePath)" in text)
print("config path from stateDir:", 'path.join(stateDir, DOCKER_DRIVER_GATEWAY_CONFIG_NAME)' in text)
print("config exported through env:", "gatewayEnv.OPENSHELL_GATEWAY_CONFIG = writeDockerDriverGatewayConfig" in text)
print("namespace validator reference count:", len(re.findall(r"hasStateScopedSandboxNamespace", "\n".join(p.read_text(errors="ignore") for p in root.rglob("*.ts")))))
print("--- launch path assignments ---")
for i, line in enumerate(launch_text.splitlines(), 1):
    if "prepareDockerDriverGatewayConfigEnv" in line or "OPENSHELL_GATEWAY_CONFIG" in line:
        print(f"{launch}:{i}:{line.strip()}")
PY

Repository: NVIDIA/NemoClaw

Length of output: 690


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- every namespace-validator reference ---'
rg -n -C8 'hasStateScopedSandboxNamespace' . --glob '!**/node_modules/**' --glob '!**/.git/**' || true

printf '%s\n' '--- auth validator implementation ---'
fd -i 'docker-driver-gateway-env-config-validation' src/lib/onboard --type f --exec sh -c 'for f do echo "--- $f"; cat -n "$f"; done' sh

printf '%s\n' '--- JWT bundle implementation ---'
cat -n src/lib/onboard/docker-driver-gateway-jwt-bundle.ts | sed -n '1,240p'

printf '%s\n' '--- gateway state path definitions ---'
rg -n -C8 'openshell-docker-gateway|resolve.*StateDir|gateway.*state|state.*gateway|GATEWAY_STATE' \
  src/lib --glob '*.ts' --glob '*.mts' | head -260 || true

printf '%s\n' '--- exact diff/status ---'
git status --short
git diff --numstat -- src/lib/onboard/docker-driver-gateway-config.ts
git diff --unified=8 -- src/lib/onboard/docker-driver-gateway-config.ts | sed -n '1,220p'

Repository: NVIDIA/NemoClaw

Length of output: 44037


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- host gateway namespace validation call sites ---'
cat -n src/lib/onboard/host-gateway-process.ts | sed -n '1,35p;245,315p'

printf '%s\n' '--- uninstall namespace validation call site ---'
cat -n src/lib/actions/uninstall/run-plan.ts | sed -n '45,72p;1005,1045p'

printf '%s\n' '--- config exports and symbol definitions ---'
rg -n '^(export )?(function|const|type|interface)|hasStateScopedSandboxNamespace|processUsesStateScopedSandboxNamespace' \
  src/lib/onboard/docker-driver-gateway-config.ts src/lib/onboard/host-gateway-process.ts

printf '%s\n' '--- TypeScript configuration and scripts ---'
cat package.json | sed -n '1,180p'
fd -i 'tsconfig' . --type f --max-depth 3 --exec sh -c 'for f do echo "--- $f"; sed -n "1,140p" "$f"; done' sh

Repository: NVIDIA/NemoClaw

Length of output: 28291


🏁 Script executed:

#!/bin/bash
python3 - <<'PY'
from pathlib import Path
import re

config = Path("src/lib/onboard/docker-driver-gateway-config.ts").read_text()
host = Path("src/lib/onboard/host-gateway-process.ts").read_text()
uninstall = Path("src/lib/actions/uninstall/run-plan.ts").read_text()

symbol = "hasStateScopedSandboxNamespace"
print("config defines symbol:", bool(re.search(rf"\b(?:export\s+)?function\s+{symbol}\b", config)))
print("config exports symbol:", bool(re.search(rf"\bexport\s+(?:function|const)\s+{symbol}\b", config)))
print("host imports symbol:", bool(re.search(rf"\b{symbol}\b", host.split("from \"./docker-driver-gateway-config\"")[0])))
print("host re-exports symbol:", bool(re.search(rf"\bexport\s*\{{[^}}]*\b{symbol}\b", host, re.S)))
print("host call count:", len(re.findall(rf"\b{symbol}\s*\(", host)))
print("uninstall call count:", len(re.findall(rf"\b{symbol}\s*\(", uninstall)))
PY

Repository: NVIDIA/NemoClaw

Length of output: 309


Restore the namespace validator or remove its dependent callers.

hasStateScopedSandboxNamespace is no longer exported, but src/lib/onboard/host-gateway-process.ts and src/lib/actions/uninstall/run-plan.ts still import and call it. This breaks TypeScript compilation and removes the fail-closed guard for scoped gateway shutdown. The 0.0.85 supervisor_bin statement is accurate; Podman must continue to omit this field.

🤖 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/onboard/docker-driver-gateway-config.ts` around lines 87 - 92,
Restore and export hasStateScopedSandboxNamespace, then retain its existing
callers in host-gateway-process.ts and uninstall run-plan.ts so TypeScript
compilation succeeds and scoped gateway shutdown remains fail-closed. Do not
alter the Docker-only supervisor_bin handling; Podman must continue omitting
that field.

Comment thread src/lib/onboard/session-bootstrap.ts
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@prekshivyas prekshivyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed current head 29d0ab3a3e24e306a47f20102d6a109b0d3db6c9.

This PR creates a user-visible runtime-provider host-mount capability contract and canonical support documentation across Docker, Podman, and OpenShell MXC, but it has no linked accepted issue or design decision defining ownership, lifecycle, compatibility, security, and qualification expectations. The repository product-scope gate blocks that supported surface until maintainers establish those decisions.

The effective diff is also stale against current main: it removes unrelated current sandbox-status SSH guidance and associated safety tests while introducing the host-mount changes. Refresh without reverting current behavior. Then either scope the change to an accepted current consumer or record the product decision, and rerun security, behavior, documentation, and required CI review on the resulting exact head.

@github-actions github-actions Bot added v0.0.110 Release target and removed v0.0.109 labels Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: architecture Architecture, design debt, major refactors, or maintainability area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow area: sandbox OpenShell sandbox lifecycle, runtime, config, or recovery area: security Security controls, permissions, secrets, or hardening feature PR adds or expands user-visible functionality platform: container Affects Docker, containerd, Podman, or images platform: k8s Affects Kubernetes deployments platform: wsl Affects Windows Subsystem for Linux release-target v0.0.110 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants