fix(sandbox): protect DCode managed login probes - #8670
Conversation
The terminal smoke runner executed every agent's smoke commands through `sh -lc`, so a sandbox-user `.bash_profile` or `.profile` ran before the managed command. For Deep Agents Code that startup file can emit output into the connect probe's evidence and create persistent side effects, which is the state the managed boundary is meant to bypass. Deep Agents Code smoke commands now run through the image-baked dcode-managed-exec launcher with BASH_ENV and ENV cleared and no login shell, matching how the managed inference route probe already invokes that launcher. Every other terminal agent keeps `sh -lc`. Their smoke commands depend on profile-provided PATH entries, and this defect is reported only against the Deep Agents Code managed boundary. Refs #8624 Signed-off-by: Dongni Yang <dongniy@nvidia.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughTerminal smoke execution now selects shell arguments by agent. Deep Agents Code uses the managed launcher with cleared startup-environment variables and a non-login shell. Other agents retain login-shell execution. Tests cover argument construction, command invocation, and exit-marker validation. ChangesTerminal smoke execution
Estimated code review effort: 2 (Simple) | ~10 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 d701f60 in the TypeScript / code-coverage/cliThe overall coverage in commit d701f60 in the Show a code coverage summary of the most impacted files.
Updated |
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 for the commit under review. Recommended E2E: Manual-only E2E: This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge. |
The CLI dispatch stub for terminal agents extracted the smoke command from a fixed argv position, so it stopped matching once the Deep Agents Code smoke invocation gained its launcher and environment flags. The stub then produced no smoke output and the probe reported failure. The smoke command is always the final argument, so read it from the end. The stub no longer depends on how many flags precede it. Refs #8624 Signed-off-by: Dongni Yang <dongniy@nvidia.com>
|
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. |
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Security review — BLOCKED\n\nThe updated wording now describes the local hardening accurately: NemoClaw removes two nested login-shell layers, while the OpenShell transport still runs a sandbox-user startup profile before the managed launcher.\n\nOne unresolved trust-boundary blocker remains:\n\n- src/lib/agent/terminal-smoke.ts accepts the first NEMOCLAW_AGENT_SMOKE_EXIT marker found anywhere in captured output.\n- NVIDIA/OpenShell#2668 means a sandbox-user startup profile runs before the requested launcher.\n- That profile can print NEMOCLAW_AGENT_SMOKE_EXIT:0 and exit successfully before the real smoke command starts. The current parser can then report a successful smoke check without evidence that the repository-defined command ran.\n- Removing NemoClaw's nested shells reduces repeated profile execution, but it does not remove this earlier output source or the profile's side effects.\n\nA local fail-closed change could stop Deep Agents Code connect from falling back to smoke when the managed route result is indeterminate. That would change compatibility for older images and other unavailable-probe cases. The alternative is to wait for an upstream non-login exec contract and validate the managed boundary against it. This choice needs an explicit architecture and compatibility decision.\n\nI did not find a secret disclosure, dependency, cryptography, or privilege-escalation defect in the changed argv construction. The focused source tests pass 44/44, the compiled-CLI dispatch test passes, and CLI build, type checking, pre-commit, and pre-push checks pass. PR #8670 must remain unmerged until the trust-evidence decision above is resolved. |
prekshivyas
left a comment
There was a problem hiding this comment.
Blocking security finding on latest PR commit a19233fb5.
getSmokeExitCode accepts the first NEMOCLAW_AGENT_SMOKE_EXIT marker in combined OpenShell output. The transport login shell runs before the managed launcher, so sandbox-user startup output can forge an earlier :0 marker and make a later failed smoke command report success.
Bind the accepted evidence to a marker only the smoke runner can produce, or reject any pre-runner marker before parsing the runner result. Add a regression with a preamble NEMOCLAW_AGENT_SMOKE_EXIT:0 followed by the runner's nonzero marker and assert runAgentSmokeCommands returns failure.
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Addressed by d5039af: duplicate/forged smoke markers are rejected; focused terminal/onboard smoke tests and the exact-head pre-push typecheck passed.
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Readiness updateThe branch now includes the current Validation on the refreshed branch:
The prior gateway-shard failures were inherited from the older base and are covered by the current |
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
cv
left a comment
There was a problem hiding this comment.
src/lib/agent/terminal-smoke.ts:26-34 treats one static NEMOCLAW_AGENT_SMOKE_BEGIN followed by one NEMOCLAW_AGENT_SMOKE_EXIT:0 as managed-runner evidence, while lines 65-70 rely on openshell sandbox exec --env HOME=... to prevent the transport login shell from reading /sandbox/.bash_profile. OpenShell v0.0.101, which this commit pins, serializes request environment entries as assignments inside the command passed to /bin/bash -lc; Bash reads its login profile before those assignments. A sandbox-user profile can therefore print exactly the accepted marker pair and exit before dcode-managed-exec; NemoClaw then reports smoke success although no smoke command ran. test/e2e/e2e-cloud-experimental/checks/04-deepagents-code-fresh-reonboard.sh:206-230 does not cover this regression: its profile forges only the legacy EXIT marker, and its inspection and cleanup commands repeat the ineffective HOME override. Keep this marker diagnostic-only until OpenShell provides a pre-start environment or non-login contract, or bind success at a trust boundary that startup files cannot forge. Add a regression that emits exactly one ordered BEGIN/EXIT:0 pair and terminates before the managed runner, then verifies that connect fails and that cleanup uses an authority not subject to the hostile profile.
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
|
🌿 Preview your docs: https://nvidia-preview-pr-8670.docs.buildwithfern.com/nemoclaw |
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
|
CI classification update The all-agent managed activation failed in the unchanged OpenClaw path: the sandbox launched, but the gateway never answered and its dashboard forward refused the connection. The direct managed startup checks for OpenClaw, Hermes, and Deep Agents Code all passed, as did staging QA. This PR changes the Deep Agents Code smoke route and does not change OpenClaw startup. The managed-image workflow is already on attempt two, so the single transient retry is exhausted. I will not rerun it again. A fresh repository-owned run or runtime-infrastructure intervention is required before this gate can pass. This CI classification does not resolve or waive the separate human security-review state. |
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Dismissed as stale at 5e6bedb. Smoke success now depends on the protected root-owned login profile instead of sandbox-user marker output, and the hostile-profile regression verifies fail-closed behavior and cleanup authority.
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
cv
left a comment
There was a problem hiding this comment.
Approved at reviewed commit d701f60812787554500b204809d3a12e47ae6e46. The login-profile probe now uses the trusted root-owned shell path, the hostile-profile regression covers the original failure boundary, and the managed-image staging source matches the required libssh2 package revision. All review threads are resolved, and the published advisor assessment reports no findings requiring follow-up.
prekshivyas
left a comment
There was a problem hiding this comment.
Approved based on code-diff review. Required GitHub checks must pass before merge.
Summary
Managed Deep Agents Code images now reserve
/sandbox/.bash_profileas a root-owned first-match Bash login profile. This prevents sandbox-user startup code from running before NemoClaw-managed DCode route and terminal probes, even though the current OpenShell transport still starts command-bearing sessions withbash -lc.The image keeps
/sandboxwritable for normal work with a sticky root-owned directory, repairs and verifies the managed profile before dropping from root to the sandbox user, and fails closed when a sandbox-user startup cannot verify that boundary. Ordinary login commands retain the existing credential-free runtime environment, while managed probes skip it and clearBASH_ENVandENV.The earlier defense-in-depth work remains: DCode smoke commands avoid nested login shells, use the image-baked managed launcher, require one ordered diagnostic marker pair, and honor the structured OpenShell process status during both connect and onboarding so forged success output cannot hide a failed transport. String-only DCode smoke evidence is rejected.
Related Issue
Closes #8624
Changes
/sandbox/.bash_profileasroot:rootmode0444beneath/sandboxasroot:sandboxmode1775.setprivto run the established entrypoint assandbox./tmp/nemoclaw-proxy-env.shonly for commands containing the fixed/usr/local/lib/nemoclaw/dcode-managed-execboundary; preserve it for ordinary login commands and leave interactive.bashrcbehavior unchanged.dcode-managed-execand non-loginsh -c, while preserving legacy login-shell behavior for other terminal agents.Root Cause and Remaining OpenShell Work
OpenShell v0.0.101 serializes a sandbox exec request into a shell command and starts both pipe and PTY command paths with
/bin/bash -lc. Requested--envvalues are applied inside that command, after Bash has selected its login profile. Changing the requestedHOME,BASH_ENV, orENVtherefore cannot prevent the first profile read.NemoClaw can close the reported DCode path because it owns the DCode image: the first profile is now immutable to the sandbox user and deliberately excludes sandbox startup state from managed probes. This resolves #8624 for new or rebuilt managed DCode sandboxes.
OpenShell#2668 remains desirable as a platform-wide improvement: an explicit non-login/raw exec mode should preserve argv boundaries, install requested environment before process startup, retain OpenShell policy/CA/provider injection, and work consistently for both pipe and PTY paths. NemoClaw does not require that upstream change for this DCode-specific fix, and this PR makes no OpenShell changes.
Type of Change
Quality Gates
8556876a5fa431549fce06bb7d7c5abb6db6c923against all nine repository security categories. The protected profile source and installed copy are root-owned, non-symlink, fixed-path artifacts;/sandboxuses sticky root ownership; startup repairs before immediately dropping privileges; the sandbox-user path fails closed; managed commands do not source sandbox-owned convenience state; and DCode connect plus onboarding require a structured zero transport status. Hostile fallback,BASH_ENV, exact-marker forgery, string-only capture, overwrite, transport-status, initial-start, and respawn-adjacent probe paths are covered. No credential, dependency, cryptographic, network-policy, authorization, logging, or privilege-expansion issue was found.Documentation Writer Review
no-docs-neededDGX Station Hardware Evidence
Verification
Signed-off-by:line and every new commit is signed for GitHub verificationpiplacks--dry-run8556876a5fa431549fce06bb7d7c5abb6db6c923npm run docsbuilds without errorsSigned-off-by: Dongni Yang dongniy@nvidia.com
Signed-off-by: Apurv Kumaria akumaria@nvidia.com