fix(sandbox/recover): enforce Hermes env-file secret boundary on probe path - #5530
Conversation
…e path Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
📝 WalkthroughWalkthroughFixes a security regression where ChangesHermes Secret-Boundary Enforcement on Recover
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
E2E Advisor RecommendationRequired E2E: Dispatch hint: Auto-dispatched E2E: Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
Dispatch hint
|
Vitest E2E Scenario RecommendationRequired Vitest E2E scenarios: Dispatch required Vitest E2E scenarios:
Full Vitest E2E advisor summaryVitest E2E Scenario AdvisorBase: Required Vitest E2E scenarios
Optional Vitest E2E scenarios
Relevant changed files
|
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in the Show a code coverage summary of the most covered files.
TypeScript / code-coverage/cliThe overall coverage in the Show a code coverage summary of the most covered files.
Updated |
|
🌿 Preview your docs: https://nvidia-preview-pr-5530.docs.buildwithfern.com/nemoclaw |
PR Review AdvisorFindings: 0 needs attention, 3 worth checking, 1 nice ideas Review findings🛠️ Needs attention
🔎 Worth checking
🌱 Nice ideas
Consider writing more tests for
Since last review detailsCurrent findings:
This is an automated advisory review. A human maintainer must make the final merge decision. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/process-recovery.ts`:
- Around line 523-538: The stderr output from the validator is being suppressed
when quiet mode is enabled, but security diagnostics should always be surfaced
regardless of the quiet flag. In the block checking for
SECRET_BOUNDARY_REFUSED_MARKER or non-zero status, move the stderr logging
section (which iterates through result.stderr and logs each line) outside of or
separate from the main if (!quiet) condition so that validator error diagnostics
are always displayed to help the caller understand which secret-shaped values
need to be replaced, even when called with quiet: true.
🪄 Autofix (Beta)
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: 0cda9f0a-deb4-4ed5-b935-03c51274c78d
📒 Files selected for processing (7)
docs/reference/commands-nemohermes.mdxdocs/reference/commands.mdxsrc/lib/actions/sandbox/connect.tssrc/lib/actions/sandbox/process-recovery.tssrc/lib/agent/hermes-recovery-boundary.tssrc/lib/agent/runtime-hermes-secret-boundary-behavioural.test.tstest/process-recovery.test.ts
…clusive secret-boundary check Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Selective E2E Results — ✅ All requested jobs passedRun: 27677577987
|
…r probe refusal at the command boundary Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Selective E2E Results — ✅ All requested jobs passedRun: 27679202263
|
…c and stop the non-probe connect path on refusal Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Selective E2E Results — ✅ All requested jobs passedRun: 27681289046
|
…5590) ## Summary Fixes the framed-output cause of San's Hermes recover/connect regression from #5530 without reverting the running-gateway secret-boundary enforcement. This intentionally retains the #5525 security contract: a running Hermes gateway still refuses when the validator reports raw secret-shaped values; the accepted healthy path is framed `SECRET_BOUNDARY_OK`, not ignoring the env-file boundary. The sandbox exec path now tolerates OpenShell stdout framing such as `stdout: ...`, avoids multiline payloads for the Hermes validator probe, and falls back to local Docker root exec when the OpenShell exec transport does not produce the startup marker, so healthy sandboxes can read `SECRET_BOUNDARY_OK` instead of failing closed as inconclusive. ## Related Issue Related to #5589 Addresses #5525 ## Changes - Normalize stdout-framed `openshell sandbox exec` output after the NemoClaw startup marker in `process-recovery.ts`. - Reuse the robust marker extraction for both synchronous recovery checks and async status probes. - Encode Hermes validator payloads before passing them through `sh -c` so OpenShell does not receive multiline exec payloads. - Fall back to local Docker root exec for Docker-backed sandboxes when OpenShell exec output does not include the startup marker. - Add regression coverage for framed root-exec output, newline-free Hermes validator payloads, Docker root-exec fallback, and the Hermes running-gateway boundary success/refusal paths with framed markers. ## Type of Change - [x] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [ ] Doc only (prose changes, no code sample modifications) - [ ] Doc only (includes code sample changes) ## Verification - [x] PR description includes the DCO sign-off declaration and every commit appears as `Verified` in GitHub - [x] Git hooks passed during commit and push, or `npx prek run --from-ref main --to-ref HEAD` passes - [x] Targeted tests pass for changed behavior - [ ] Full `npm test` passes (broad runtime changes only) - [x] Tests added or updated for new or changed behavior - [x] No secrets, API keys, or credentials committed - [ ] Docs updated for user-facing behavior changes - [ ] `npm run docs` builds without warnings (doc changes only) - [ ] Doc pages follow the [style guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md) (doc changes only) - [ ] New doc pages include SPDX header and frontmatter (new pages only) --- <!-- DCO sign-off is required in this PR description, and every commit must appear as Verified in GitHub. Run: git config user.name && git config user.email --> Signed-off-by: Carlos Villela <cvillela@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved sandbox stdout handling to correctly ignore optional line framing (for example, `stdout:`/`[stdout]`) and extract output only after the startup marker. * Updated sandbox exec status handling to return `null` when the marker is missing or extraction isn’t reliable. * **Tests** * Added unit tests covering correct stdout extraction and the failure scenario when the marker appears outside the expected format. * Updated recovery test mocks to match the new framed marker output and added coverage for the “falls through” recovery path. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Carlos Villela <cvillela@nvidia.com> Co-authored-by: San Dang <sdang@nvidia.com>
Summary
nemohermes <name> recoverdid not re-evaluate the documented Hermes secret boundary when the gateway was already running.recover→connect --probe-only→checkAndRecoverSandboxProcessestook theif (running)branch and returned after refreshing the port-forward, never invokingbuildHermesEnvFileBoundaryGuard()(only the relaunch path embeds it). A rawTELEGRAM_BOT_TOKENinjected into/sandbox/.hermes/.envsurvived recovery and the gateway kept serving. The probe path now executes a standalone secret-boundary check via the rootopenshell sandbox execchannel (so the kill snippet has authority over the gateway-user process), brings the gateway down on refusal, and surfaces a non-zero exit onrecover.Related Issue
Fixes #5525
Changes
hermes-recovery-boundary.tsexportsbuildHermesEnvFileBoundaryStandaloneCheck()plusSECRET_BOUNDARY_{OK,REFUSED,VALIDATOR_MISSING}_MARKERconstants. The standalone snippet runs the existing validator on/sandbox/.hermes/.env, kills any running Hermes gateway/dashboard on refusal, and emits a single stdout marker.process-recovery.tsaddsenforceHermesSecretBoundaryOnRunningGateway, invoked fromcheckAndRecoverSandboxProcessesbefore theif (running)early-return when the active agent is Hermes. Refusal short-circuits the function withsecretBoundaryRefused: trueand skips the forward-refresh path.connect.tsrunSandboxConnectProbesurfaces a refusal as exit 1 with a clear remediation line pointing at theopenshell:resolve:env:<name>placeholder.docs/reference/commands.mdxdocuments the Hermes-only secret-boundary re-evaluation onrecover; the nemohermes variant is regenerated.process-recovery.test.ts(refused / passed / validator-missing / OpenClaw no-op); 3 inruntime-hermes-secret-boundary-behavioural.test.tsexercising the standalone snippet against real bash with stubbedpython3/pkill.Type of Change
Verification
Verifiedin GitHubnpx prek run --from-ref main --to-ref HEADpassesnpm testpasses (broad runtime changes only)npm run docsbuilds without warnings (doc changes only)Signed-off-by: Tinson Lai tinsonl@nvidia.com
Summary by CodeRabbit
Documentation
recovercommand documentation to describe secret boundary re-evaluation behavior.New Features
Bug Fixes
Tests