fix(sandbox): avoid nested login shells in Deep Agents Code smoke - #8670
fix(sandbox): avoid nested login shells in Deep Agents Code smoke#8670Dongni-Yang wants to merge 12 commits into
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 |
PR Review Advisor — Blocking findings reportedAdvisor assessment: Blockers require maintainer review Model lanes
Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests. 4 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: Blockers
|
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.
prekshivyas
left a comment
There was a problem hiding this comment.
Blocking smoke-evidence integrity finding on latest PR commit 3656529d6.
src/lib/agent/terminal-smoke.ts:18-24 accepts exactly one static NEMOCLAW_AGENT_SMOKE_EXIT:0 marker. That rejects an extra forged marker, but the OpenShell transport still starts its login shell before the managed runner. A hostile startup file can print exactly one success marker and exit before the requested runner executes; the parser then reports smoke success even though no smoke command ran.
Please bind success to evidence produced by the managed runner/transport rather than a static line that startup output can replace, and add a regression where startup output emits one success marker and terminates before the runner. If a per-invocation identifier is used, its trust boundary must prevent startup code from learning and replaying it before execution.
Security rubric: 1 PASS (no credential flow); 2 FAIL (untrusted transport output can satisfy the parser); 3 PASS (no auth change); 4 PASS (no dependency change); 5 FAIL (early startup failure can become success); 6 PASS (no cryptography change); 7 PASS (no config weakening); 8 FAIL (the exactly-one test misses replacement rather than duplication); 9 FAIL (the evidence is not bound to runner execution). Files reviewed: the complete 5-file diff.
|
Thanks — the finding is correct. A per-invocation identifier cannot meet the bar you setYour constraint — "its trust boundary must prevent startup code from learning and replaying it before execution" — is not satisfiable here, on any delivery channel:
A nonce would raise forgery from "hardcode a constant" to "parse a variable" without moving the boundary — the same class of fix already dismissed once. Proposed instead: remove the pre-runner window, then order the evidence1. No sandbox-writable startup file on the Deep Agents Code path. Add 2. Ordered, runner-produced evidence. The runner emits Against your rubric: 2 a result marker with no preceding begin marker is rejected, and on the dcode path the untrusted producer no longer executes; 5 startup output that prints one marker and exits fails closed, as does a runner killed mid-command (BEGIN, no EXIT); 8 the rule now covers replacement and ordering, not only duplication, on both markers; 9 BEGIN can only be printed after the transport finished sourcing startup files. I reproduced the attack locally (hostile One thing I want your call on before I pushThe other terminal agents keep So I would add a fourth item to the Deep Agents Code entry under Documented Risk Acceptances in |
Refs #8624 Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
The exact-commit audit found that this blocker requires a trusted OpenShell transport guarantee that NemoClaw cannot provide in this PR. The accepted change removes NemoClaw-added login shells and records the remaining boundary. Dismissing this review before a full current-commit review.
Summary
Deep Agents Code terminal smoke commands previously added two nested login shells inside the OpenShell transport. This change keeps both command shells but removes their login mode, routes the smoke through the image-baked managed launcher, and clears
BASH_ENVandENVfor that process.This is defense in depth, not the root fix for #8624. OpenShell still starts the transport through a sandbox-user login shell before any NemoClaw-controlled process runs, so startup files can still execute first. NVIDIA/OpenShell#2668 tracks that upstream behavior.
Related Issue
Refs #8624
Changes
dcode-managed-execand non-loginsh -clayers.PATHentries.BASH_ENVandENVat the managed Deep Agents Code boundary.Root Cause and Remaining Boundary
OpenShell flattens the requested arguments into a command string and starts that string with
/bin/bash -lcin the supervisor. The user's profile therefore runs beforedcode-managed-exec,BASH_ENV=, orENV=can take effect. A per-invocation output marker cannot be hidden from or bound below that earlier shell.This PR removes the two additional login modes that NemoClaw controlled. The issue remains open because a non-login transport and runner-bound execution evidence require the upstream change.
Type of Change
Quality Gates
Documentation Writer Review
no-docs-neededdocs/get-started/quickstart-langchain-deepagents-code.mdxalready describes thedcode --versionsmoke check and launcher environment normalization accurately; nodocs/,fern/, public error, or CLI reference surface changes.DGX Station Hardware Evidence
Verification
Signed-off-by:line and every new commit is signed for GitHub verificationnpm run docsbuilds without warnings (doc changes only)Signed-off-by: Dongni Yang dongniy@nvidia.com
Signed-off-by: Apurv Kumaria akumaria@nvidia.com