Skip to content

fix(hermes): enforce env secret boundary on sandbox recover#4959

Merged
cv merged 7 commits into
mainfrom
fix/4957-hermes-recover-secret-boundary
Jun 8, 2026
Merged

fix(hermes): enforce env secret boundary on sandbox recover#4959
cv merged 7 commits into
mainfrom
fix/4957-hermes-recover-secret-boundary

Conversation

@laitingsheng

@laitingsheng laitingsheng commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

The documented Hermes secret-boundary validator only ran from start.sh, so sandbox recover / connect --probe-only relaunched the gateway without checking /sandbox/.hermes/.env or the recovery shell's environment for raw secret-shaped values. This PR makes the recover path enforce the same boundary as cold start.

Related Issue

Fixes #4957

Changes

  • Extract both Python validators from agents/hermes/start.sh into a standalone CLI: agents/hermes/validate-env-secret-boundary.py (env-file <path> + runtime-env subcommands). Single source of truth shared between cold start and recover.
  • Bake the script into the Hermes sandbox image at /usr/local/lib/nemoclaw/validate-hermes-env-secret-boundary.py (Dockerfile, chmod 755).
  • start.sh now delegates both validators to the script via _HERMES_BOUNDARY_VALIDATOR (default: install path, dev fallback: script-relative repo path). Cold-start behaviour unchanged.
  • New buildHermesSecretBoundaryGuard() in src/lib/agent/runtime.ts invokes both subcommands at the very start of the recovery script, before the ALREADY_RUNNING health probe. Refuses the relaunch with SECRET_BOUNDARY_REFUSED + exit 1 on any violation. Tolerates a missing validator on older images with a warning so partial upgrades do not break recovery. Wired into both buildRecoveryScript (Hermes branch) and buildHermesDashboardProcessRecoveryScript.
  • The validator-path variable is named _HERMES_BOUNDARY_VALIDATOR (not _HERMES_SECRET_BOUNDARY_VALIDATOR) so the variable name itself does not match the secret-shaped key regex when the runtime-env validator scans os.environ.
  • Test coverage: new Hermes secret-boundary guard on recovery describe block in src/lib/agent/runtime.test.ts asserts the recovery scripts contain the validator invocations, the SECRET_BOUNDARY_REFUSED short-circuit, and the correct order relative to the launch. Existing test/hermes-start.test.ts wrappers updated to point _HERMES_BOUNDARY_VALIDATOR at the repo Python script so the shell-wrapper behavioural tests exercise the extracted validator end-to-end.

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)

Verification

  • `npx prek run --all-files` passes
  • `npm test` passes
  • Tests added or updated for new or changed behavior
  • 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 (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Tinson Lai tinsonl@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added secret boundary validation for Hermes agent environment configuration.
    • Enhanced recovery procedures with additional validation checks before launching critical services.
  • Refactor

    • Optimized environment validation scripts for better modularity and maintainability.
  • Tests

    • Added comprehensive test coverage for recovery and validation workflows.

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: hermes-secret-boundary-e2e, hermes-root-entrypoint-smoke-e2e, hermes-e2e
Optional E2E: hermes-dashboard-e2e, hermes-slack-e2e, hermes-onboard-security-posture-e2e

Dispatch hint: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e,hermes-e2e

Auto-dispatched E2E: hermes-secret-boundary-e2e, hermes-root-entrypoint-smoke-e2e, hermes-e2e via nightly-e2e.yaml at e6a79754ab733fc39e14152cbad0bbbd72ab8e22nightly run

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • hermes-secret-boundary-e2e (medium): Most directly covers this PR: builds the Hermes sandbox image, verifies the image contains no raw secret-shaped .env values, checks managed-tool boundary behavior, and proves Hermes startup rejects poisoned .env/runtime-env values without leaking secret values. It should catch Dockerfile packaging or validator/start.sh integration regressions.
  • hermes-root-entrypoint-smoke-e2e (medium): Required because start.sh and the Hermes image contract changed. This validates the root entrypoint, gateway startup, privilege separation, PID/runtime layout, config protection, and real /health readiness in the built Hermes container.
  • hermes-e2e (high): Required full user-flow confidence for changes that can affect Hermes onboarding, health, gateway launch, and inference through the sandbox. It verifies a clean repo install/onboard with NEMOCLAW_AGENT=hermes still produces a working assistant path after the new boundary guards are present.

Optional E2E

  • hermes-dashboard-e2e (high): Useful adjacent coverage because runtime.ts now also guards the Hermes dashboard-only recovery script. This validates the dashboard user flow still works, though it does not appear to specifically poison recovery state.
  • hermes-slack-e2e (high): Optional confidence for messaging credential placeholder compatibility, especially because the validator allows Slack xoxb/xapp OpenShell resolver aliases and the PR changes runtime-env secret enforcement. Run if messaging risk tolerance is low or Slack paths were implicated in review.
  • hermes-onboard-security-posture-e2e (high): Optional broader security-posture validation for Hermes onboarding after credential-boundary and runtime-launch changes. This is useful but less targeted than hermes-secret-boundary-e2e.

New E2E recommendations

  • Hermes recovery secret-boundary enforcement (high): Existing focused E2E covers cold-start rejection, and new unit tests exercise generated recovery shell snippets, but there is no apparent live E2E that poisons an existing Hermes sandbox, triggers nemoclaw <sandbox> status or connect --probe-only recovery, and asserts recovery refuses with SECRET_BOUNDARY_REFUSED, stops any already-serving poisoned gateway, and persists sanitized [SECURITY] details to /tmp/gateway-recovery.log.
    • Suggested test: Add a Hermes recovery secret-boundary E2E that onboards Hermes, writes a raw secret-shaped value into /sandbox/.hermes/.env or /tmp/nemoclaw-proxy-env.sh, kills/restarts the gateway path via status/connect --probe-only, and asserts refusal, no raw-value leakage, and recovery log contents.
  • Hermes dashboard-only recovery boundary (medium): runtime.ts now gates dashboard-only recovery as well as gateway recovery, but existing dashboard E2E appears to validate dashboard availability rather than a poisoned recovery refusal path.
    • Suggested test: Extend or add a Hermes dashboard recovery E2E that breaks the dashboard process, injects a raw secret-shaped value, triggers dashboard reconnect/recovery, and verifies the validator refuses before relaunch.

Dispatch hint

  • Workflow: .github/workflows/nightly-e2e.yaml
  • jobs input: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e,hermes-e2e

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

E2E Scenario Advisor Recommendation

Required scenario E2E: ubuntu-repo-cloud-hermes
Optional scenario E2E: ubuntu-repo-cloud-hermes-slack, ubuntu-repo-cloud-hermes-discord

Dispatch required scenario E2E:

  • gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required scenario E2E

  • ubuntu-repo-cloud-hermes: Hermes Dockerfile/startup and Hermes host-side recovery logic changed. This scenario is the primary Ubuntu repo-current Hermes onboarding path and exercises the rebuilt Hermes sandbox startup, gateway health, sandbox shell, and Hermes-specific readiness checks.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes

Optional scenario E2E

  • ubuntu-repo-cloud-hermes-slack: Optional adjacent Hermes messaging coverage for the secret-boundary validator changes, especially Slack resolver placeholder handling and no-secret-leak checks.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-slack
  • ubuntu-repo-cloud-hermes-discord: Optional adjacent Hermes messaging coverage for the secret-boundary validator changes against a different messaging provider path and no-secret-leak checks.
    • Dispatch: gh workflow run e2e-scenarios.yaml --ref <pr-head-ref> --field scenarios=ubuntu-repo-cloud-hermes-discord

Relevant changed files

  • agents/hermes/Dockerfile
  • agents/hermes/start.sh
  • agents/hermes/validate-env-secret-boundary.py
  • src/lib/agent/hermes-recovery-boundary.ts
  • src/lib/agent/runtime.ts

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements Hermes secret-boundary validation: a new Python CLI that detects raw secrets in .env files and process environments, delegated from startup bash scripts; host-side recovery guards that enforce fail-closed refusal on boundary violations; runtime integration injecting guards into Hermes recovery and manual recovery flows; and comprehensive tests verifying both guard behavior and recovery-script shapes.

Changes

Hermes Secret-Boundary Validation and Enforcement

Layer / File(s) Summary
Validator CLI implementation
agents/hermes/validate-env-secret-boundary.py
New Python CLI with env-file and runtime-env subcommands enforcing secret-boundary by detecting secret-shaped keys (TOKEN, KEY, etc.) and allowing only placeholder values (openshell:resolve:env:*, resolver markers, empty/[STRIPPED_BY_MIGRATION]); includes defensive file handling with O_NOFOLLOW + fstat, aggregated [SECURITY] stderr output, and exit codes 0/1.
Startup refactor and Docker packaging
agents/hermes/start.sh, agents/hermes/Dockerfile, test/hermes-start.test.ts
start.sh resolves _HERMES_BOUNDARY_VALIDATOR from installed path (fallback to repo-local), delegates validate_hermes_env_secret_boundary and validate_hermes_runtime_env_secret_boundary to the CLI via python3 subcommands; Dockerfile copies and chmodsthe validator; test helpers inject resolved path and add validator-path bootstrap suite.
Host-side recovery guard builders and test fixtures
src/lib/agent/hermes-recovery-boundary.ts, src/lib/agent/hermes-recovery-boundary-fixtures.ts
New module exporting buildHermesEnvFileBoundaryGuard() and buildHermesRuntimeEnvBoundaryGuard() that construct shell snippets running validator, killing Hermes on violation, logging to /tmp/gateway-recovery.log, and warning-skip on missing validator; test fixtures define makeAgent() factory and hermesAgent / minimalAgent constants.
Runtime integration of guard snippets
src/lib/agent/runtime.ts
Imports guard builders and conditionally injects both guards into Hermes dashboard recovery (env-file before proxy-env source, runtime-env after), gateway recovery (env-file before launch, runtime-env after sourcing), and manual recovery command (both guards before gateway relaunch).
Tests: generated-shape and execution harness
src/lib/agent/runtime-hermes-secret-boundary-shape.test.ts, src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts
Shape assertions verify guard ordering relative to gateway/dashboard launch, refusal sentinel presence, pkill patterns, and non-Hermes exclusion; behavioral tests validate guard snippet exit codes, process kills, security log output, and full recovery-script execution against stubbed and real validators.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

security, area: sandbox

Suggested reviewers

  • cv
  • prekshivyas

Poem

🐰 A boundary guard stands watch in the shell,
Python scanner bells when secrets dwell,
Refuses to start if .env looks wrong,
Recovery fails when the values are strong—
Your tokens stay hidden, forever tucked tight! 🔐

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% 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 summarizes the main change: enforcing the Hermes env secret boundary during sandbox recovery, which directly addresses the issue.
Linked Issues check ✅ Passed The pull request fully implements all coding requirements from issue #4957: extracted validator CLI, installed to Dockerfile, integrated into recovery scripts with proper guards, and boundary checks execute before health probes.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the secret-boundary validator and integrating it into recovery flows; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/4957-hermes-recover-secret-boundary

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


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

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27140313358
Target ref: 46588051eb0a1b8bb697999a340d8ae4b7dad593
Workflow ref: main
Requested jobs: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e
Summary: 2 passed, 0 failed, 0 skipped

Job Result
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ✅ success

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 2 needs attention, 6 worth checking, 0 nice ideas
Since last review: 0 prior items resolved, 6 still apply, 0 new items found

Review findings

🛠️ Needs attention

  • Add endpoint-level evidence for the issue's /health refusal clause (src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts:336): Issue NemoHermes gateway starts and serves after raw secret-shaped value injected into .env, no [SECURITY] refusal #4957 explicitly expects that after a raw secret is injected, "`/health` returns `HEALTH_DOWN` (gateway must NOT serve)." The new recovery-shell test is useful because it proves the guard runs before the `curl` health probe, refuses recovery, kills Hermes process patterns, and avoids a launch marker, but it still does not observe an actual Hermes `/health` endpoint after refusal.
    • Recommendation: Add or identify targeted runtime/integration validation that injects `TELEGRAM_BOT_TOKEN=1234567890:AAExample-RawSecretValueHere` into a Hermes `.env`, triggers the recovery path, and asserts `/health` returns `HEALTH_DOWN` or that the gateway is not serving. Keep the evidence in code/tests rather than relying on external job status.
    • Evidence: Linked issue clause: "And `/health` returns `HEALTH_DOWN` (gateway must NOT serve)." Current test `refuses before /health can accept an already-serving poisoned gateway` asserts `curlLog` is absent and `SECRET_BOUNDARY_REFUSED` is emitted, but it does not query a live endpoint or assert `HEALTH_DOWN`.
  • Split or offset the new large behavioural recovery test file (src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts:1): The PR still adds a 475-line behavioural test file that mixes guard-snippet execution, full recovery-script harnessing, stubs, real-validator cases, health-probe ordering, and runtime-env cases. For security-critical sandbox recovery behavior, this size makes future review and regression isolation harder.
    • Recommendation: Split the file into narrower suites, for example guard-snippet behavior, full gateway recovery behavior, real-validator cases, and runtime-env/proxy-env behavior, or otherwise offset the test monolith growth in this PR.
    • Evidence: Deterministic monolith signal flags `src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts` as a new 475-line file; the previous advisor also flagged this test monolith growth.

🔎 Worth checking

  • Source-of-truth review needed: Missing-validator recovery compatibility branch: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `buildHermesValidatorMissingLog()` logs "skipping recovery boundary check" and both guards continue when the validator file is absent.
  • Source-of-truth review needed: Early recovery log tee before no-follow setup: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `buildHermesValidatorInvocation()` pipes stderr through `tee -a '/tmp/gateway-recovery.log'`; `buildGatewayLogSetup()` runs later in the main recovery script.
  • Missing-validator recovery path still fails open (src/lib/agent/hermes-recovery-boundary.ts:62): When an older Hermes sandbox image lacks `/usr/local/lib/nemoclaw/validate-hermes-env-secret-boundary.py`, both recovery guards log a warning and continue. That preserves partial-upgrade compatibility, but it also bypasses the new secret boundary exactly for older images that may be most likely to need migration.
    • Recommendation: Bound the compatibility path with an enforceable image/NemoClaw version cutoff, or fail closed once the minimum supported Hermes image includes the validator. Add a regression test for the cutoff behavior so the fail-open branch cannot persist indefinitely.
    • Evidence: `buildHermesValidatorMissingLog()` emits "skipping recovery boundary check"; `buildHermesEnvFileBoundaryGuard()` and `buildHermesRuntimeEnvBoundaryGuard()` proceed when `[ ! -f validator ]`. The comment documents a future removal condition but no code enforces a cutoff.
  • Recovery validator logging relies on an unenforced non-root caller invariant (src/lib/agent/hermes-recovery-boundary.ts:58): The validator stderr is piped through `tee -a /tmp/gateway-recovery.log` before the normal recovery log setup prepares files with the no-follow helper. The code comment says this is safe because non-OpenClaw recovery currently runs over SSH as the sandbox user, but the guard itself does not enforce that contract and could become unsafe if reused from a root-exec recovery path.
    • Recommendation: Prepare `/tmp/gateway-recovery.log` with an O_NOFOLLOW log helper before invoking `tee`, or add focused regression coverage/caller-contract assertions that Hermes recovery remains on the sandbox-user SSH path and must not move to root exec without no-follow log preparation.
    • Evidence: `buildHermesValidatorInvocation()` emits `2> >(tee -a '/tmp/gateway-recovery.log' >&2)` before `buildGatewayLogSetup`; `process-recovery.ts` currently uses `executeSandboxCommand()` for non-OpenClaw recovery, but that security property is only documented in comments.
  • Dashboard-only and manual Hermes recovery refusal paths are only shape-tested (src/lib/agent/runtime-hermes-secret-boundary-shape.test.ts:82): The main gateway recovery path now has behavioural shell coverage, including real-validator `.env` and runtime-env cases. The dashboard-only recovery script and the manual copy-paste command are only checked for generated string ordering, so their actual refusal behavior, diagnostic persistence, no-launch guarantees, and raw-value redaction remain unproven.
    • Recommendation: Add behavioural generated-shell tests for `buildHermesDashboardProcessRecoveryScript()` and `buildManualRecoveryCommand()` with both a poisoned `.env` and a raw secret-shaped runtime env. Assert `SECRET_BOUNDARY_REFUSED`, persisted `[SECURITY]` diagnostics, no raw value leakage, and no dashboard/gateway launch marker.
    • Evidence: Shape tests assert guard ordering for dashboard-only and manual recovery, while `runtime-hermes-secret-boundary-behavioural.test.ts` executes guard snippets and `buildRecoveryScript()` but not `buildHermesDashboardProcessRecoveryScript()` or `buildManualRecoveryCommand()`.
  • Add cold-start coverage for non-regular Hermes .env paths (test/hermes-start.test.ts:862): The extracted Python validator now rejects non-regular `.env` paths after `O_NOFOLLOW` open and `fstat`, and `start.sh` delegates every existing non-symlink `.env` path to that validator. Existing cold-start tests cover symlinked `.env`, but not directories, FIFOs, or other non-regular paths.
    • Recommendation: Add a cold-start test where `/sandbox/.hermes/.env` is a directory or FIFO and assert startup validation exits non-zero with `[SECURITY] ... is not a regular file`.
    • Evidence: `validate_hermes_env_secret_boundary()` delegates to `python3 "$_HERMES_BOUNDARY_VALIDATOR" env-file "$env_file"`; `validate-env-secret-boundary.py` rejects non-regular files, but `test/hermes-start.test.ts` visibly covers symlink and raw-value cases only.

🌱 Nice ideas

  • None.
Consider writing more tests for
  • **Runtime validation** — Hermes recovery with `TELEGRAM_BOT_TOKEN=1234567890:AAExample-RawSecretValueHere` in `/sandbox/.hermes/.env` leaves real `/health` down or returning `HEALTH_DOWN`.. The changed surfaces include Docker image contents, sandbox startup, secret-boundary parsing, generated recovery shell, process lifecycle, and recovery diagnostics. Unit and generated-shell tests cover the main gateway path well, but endpoint-level runtime behavior and several generated recovery paths remain unproven.
  • **Runtime validation** — Dashboard-only recovery refuses a poisoned `/sandbox/.hermes/.env`, persists `[SECURITY]`, redacts the raw token value, and does not launch `hermes dashboard`.. The changed surfaces include Docker image contents, sandbox startup, secret-boundary parsing, generated recovery shell, process lifecycle, and recovery diagnostics. Unit and generated-shell tests cover the main gateway path well, but endpoint-level runtime behavior and several generated recovery paths remain unproven.
  • **Runtime validation** — Dashboard-only recovery refuses a raw `TELEGRAM_BOT_TOKEN` exported by `/tmp/nemoclaw-proxy-env.sh` after sourcing required `NODE_OPTIONS`.. The changed surfaces include Docker image contents, sandbox startup, secret-boundary parsing, generated recovery shell, process lifecycle, and recovery diagnostics. Unit and generated-shell tests cover the main gateway path well, but endpoint-level runtime behavior and several generated recovery paths remain unproven.
  • **Runtime validation** — Manual Hermes recovery command refuses a poisoned `.env` before `nohup hermes gateway run` and persists `[SECURITY]` diagnostics without raw value leakage.. The changed surfaces include Docker image contents, sandbox startup, secret-boundary parsing, generated recovery shell, process lifecycle, and recovery diagnostics. Unit and generated-shell tests cover the main gateway path well, but endpoint-level runtime behavior and several generated recovery paths remain unproven.
  • **Runtime validation** — Cold start refuses when `/sandbox/.hermes/.env` is a directory or FIFO and logs `[SECURITY] ... is not a regular file`.. The changed surfaces include Docker image contents, sandbox startup, secret-boundary parsing, generated recovery shell, process lifecycle, and recovery diagnostics. Unit and generated-shell tests cover the main gateway path well, but endpoint-level runtime behavior and several generated recovery paths remain unproven.
  • **Split or offset the new large behavioural recovery test file** — Split the file into narrower suites, for example guard-snippet behavior, full gateway recovery behavior, real-validator cases, and runtime-env/proxy-env behavior, or otherwise offset the test monolith growth in this PR.
  • **Dashboard-only and manual Hermes recovery refusal paths are only shape-tested** — Add behavioural generated-shell tests for `buildHermesDashboardProcessRecoveryScript()` and `buildManualRecoveryCommand()` with both a poisoned `.env` and a raw secret-shaped runtime env. Assert `SECRET_BOUNDARY_REFUSED`, persisted `[SECURITY]` diagnostics, no raw value leakage, and no dashboard/gateway launch marker.
  • **Add cold-start coverage for non-regular Hermes .env paths** — Add a cold-start test where `/sandbox/.hermes/.env` is a directory or FIFO and assert startup validation exits non-zero with `[SECURITY] ... is not a regular file`.
Since last review details

Current findings:

  • Source-of-truth review needed: Missing-validator recovery compatibility branch: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `buildHermesValidatorMissingLog()` logs "skipping recovery boundary check" and both guards continue when the validator file is absent.
  • Source-of-truth review needed: Early recovery log tee before no-follow setup: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: `buildHermesValidatorInvocation()` pipes stderr through `tee -a '/tmp/gateway-recovery.log'`; `buildGatewayLogSetup()` runs later in the main recovery script.
  • Add endpoint-level evidence for the issue's /health refusal clause (src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts:336): Issue NemoHermes gateway starts and serves after raw secret-shaped value injected into .env, no [SECURITY] refusal #4957 explicitly expects that after a raw secret is injected, "`/health` returns `HEALTH_DOWN` (gateway must NOT serve)." The new recovery-shell test is useful because it proves the guard runs before the `curl` health probe, refuses recovery, kills Hermes process patterns, and avoids a launch marker, but it still does not observe an actual Hermes `/health` endpoint after refusal.
    • Recommendation: Add or identify targeted runtime/integration validation that injects `TELEGRAM_BOT_TOKEN=1234567890:AAExample-RawSecretValueHere` into a Hermes `.env`, triggers the recovery path, and asserts `/health` returns `HEALTH_DOWN` or that the gateway is not serving. Keep the evidence in code/tests rather than relying on external job status.
    • Evidence: Linked issue clause: "And `/health` returns `HEALTH_DOWN` (gateway must NOT serve)." Current test `refuses before /health can accept an already-serving poisoned gateway` asserts `curlLog` is absent and `SECRET_BOUNDARY_REFUSED` is emitted, but it does not query a live endpoint or assert `HEALTH_DOWN`.
  • Split or offset the new large behavioural recovery test file (src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts:1): The PR still adds a 475-line behavioural test file that mixes guard-snippet execution, full recovery-script harnessing, stubs, real-validator cases, health-probe ordering, and runtime-env cases. For security-critical sandbox recovery behavior, this size makes future review and regression isolation harder.
    • Recommendation: Split the file into narrower suites, for example guard-snippet behavior, full gateway recovery behavior, real-validator cases, and runtime-env/proxy-env behavior, or otherwise offset the test monolith growth in this PR.
    • Evidence: Deterministic monolith signal flags `src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts` as a new 475-line file; the previous advisor also flagged this test monolith growth.
  • Missing-validator recovery path still fails open (src/lib/agent/hermes-recovery-boundary.ts:62): When an older Hermes sandbox image lacks `/usr/local/lib/nemoclaw/validate-hermes-env-secret-boundary.py`, both recovery guards log a warning and continue. That preserves partial-upgrade compatibility, but it also bypasses the new secret boundary exactly for older images that may be most likely to need migration.
    • Recommendation: Bound the compatibility path with an enforceable image/NemoClaw version cutoff, or fail closed once the minimum supported Hermes image includes the validator. Add a regression test for the cutoff behavior so the fail-open branch cannot persist indefinitely.
    • Evidence: `buildHermesValidatorMissingLog()` emits "skipping recovery boundary check"; `buildHermesEnvFileBoundaryGuard()` and `buildHermesRuntimeEnvBoundaryGuard()` proceed when `[ ! -f validator ]`. The comment documents a future removal condition but no code enforces a cutoff.
  • Recovery validator logging relies on an unenforced non-root caller invariant (src/lib/agent/hermes-recovery-boundary.ts:58): The validator stderr is piped through `tee -a /tmp/gateway-recovery.log` before the normal recovery log setup prepares files with the no-follow helper. The code comment says this is safe because non-OpenClaw recovery currently runs over SSH as the sandbox user, but the guard itself does not enforce that contract and could become unsafe if reused from a root-exec recovery path.
    • Recommendation: Prepare `/tmp/gateway-recovery.log` with an O_NOFOLLOW log helper before invoking `tee`, or add focused regression coverage/caller-contract assertions that Hermes recovery remains on the sandbox-user SSH path and must not move to root exec without no-follow log preparation.
    • Evidence: `buildHermesValidatorInvocation()` emits `2> >(tee -a '/tmp/gateway-recovery.log' >&2)` before `buildGatewayLogSetup`; `process-recovery.ts` currently uses `executeSandboxCommand()` for non-OpenClaw recovery, but that security property is only documented in comments.
  • Dashboard-only and manual Hermes recovery refusal paths are only shape-tested (src/lib/agent/runtime-hermes-secret-boundary-shape.test.ts:82): The main gateway recovery path now has behavioural shell coverage, including real-validator `.env` and runtime-env cases. The dashboard-only recovery script and the manual copy-paste command are only checked for generated string ordering, so their actual refusal behavior, diagnostic persistence, no-launch guarantees, and raw-value redaction remain unproven.
    • Recommendation: Add behavioural generated-shell tests for `buildHermesDashboardProcessRecoveryScript()` and `buildManualRecoveryCommand()` with both a poisoned `.env` and a raw secret-shaped runtime env. Assert `SECRET_BOUNDARY_REFUSED`, persisted `[SECURITY]` diagnostics, no raw value leakage, and no dashboard/gateway launch marker.
    • Evidence: Shape tests assert guard ordering for dashboard-only and manual recovery, while `runtime-hermes-secret-boundary-behavioural.test.ts` executes guard snippets and `buildRecoveryScript()` but not `buildHermesDashboardProcessRecoveryScript()` or `buildManualRecoveryCommand()`.
  • Add cold-start coverage for non-regular Hermes .env paths (test/hermes-start.test.ts:862): The extracted Python validator now rejects non-regular `.env` paths after `O_NOFOLLOW` open and `fstat`, and `start.sh` delegates every existing non-symlink `.env` path to that validator. Existing cold-start tests cover symlinked `.env`, but not directories, FIFOs, or other non-regular paths.
    • Recommendation: Add a cold-start test where `/sandbox/.hermes/.env` is a directory or FIFO and assert startup validation exits non-zero with `[SECURITY] ... is not a regular file`.
    • Evidence: `validate_hermes_env_secret_boundary()` delegates to `python3 "$_HERMES_BOUNDARY_VALIDATOR" env-file "$env_file"`; `validate-env-secret-boundary.py` rejects non-regular files, but `test/hermes-start.test.ts` visibly covers symlink and raw-value cases only.

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

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

🧹 Nitpick comments (1)
agents/hermes/validate-env-secret-boundary.py (1)

125-146: 💤 Low value

Unreachable return statement.

Line 142 (return 2) is unreachable because argparse with required=True on subparsers will exit with an error before main() returns when an invalid or missing subcommand is provided.

This is harmless but could be removed or replaced with a defensive assertion.

🤖 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 `@agents/hermes/validate-env-secret-boundary.py` around lines 125 - 146, The
final `return 2` in main() is unreachable because argparse's subparsers were
created with required=True; remove the dead `return 2` or replace it with a
defensive assertion (e.g., assert False, "unreachable") to make intent explicit.
Locate the main() function and the parser/sub = parser.add_subparsers(...) block
and either delete the `return 2` line or swap it for a short defensive assertion
to document that control flow should never reach that point.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@agents/hermes/validate-env-secret-boundary.py`:
- Around line 125-146: The final `return 2` in main() is unreachable because
argparse's subparsers were created with required=True; remove the dead `return
2` or replace it with a defensive assertion (e.g., assert False, "unreachable")
to make intent explicit. Locate the main() function and the parser/sub =
parser.add_subparsers(...) block and either delete the `return 2` line or swap
it for a short defensive assertion to document that control flow should never
reach that point.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a30f636c-86cf-4e85-a343-d9f863af0bb1

📥 Commits

Reviewing files that changed from the base of the PR and between ec408c8 and 4658805.

📒 Files selected for processing (6)
  • agents/hermes/Dockerfile
  • agents/hermes/start.sh
  • agents/hermes/validate-env-secret-boundary.py
  • src/lib/agent/runtime.test.ts
  • src/lib/agent/runtime.ts
  • test/hermes-start.test.ts

… violation

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>

@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: 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/agent/runtime.ts`:
- Around line 180-181: The current shell snippet in runtime.ts kills the process
if the validator script is missing; change the first check that tests for the
presence of `validator` to emit a warning/skip instead of invoking `${kill}` and
`exit 1` so older Hermes images remain recoverable, while leaving the second
check (the actual execution: `python3 ${shellQuote(validator)} env-file
/sandbox/.hermes/.env`) as a hard failure when the validator runs and refuses;
apply the same shape to the corresponding runtime-env helper checks (the other
pair around lines 199-200) and update the related test
`runtime-hermes-secret-boundary.test.ts` to expect a warning/skip for the
missing-validator case rather than a process kill.
🪄 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: 8fb5183e-8ddf-4bbe-ae36-73a55113be74

📥 Commits

Reviewing files that changed from the base of the PR and between 4658805 and d270573.

📒 Files selected for processing (3)
  • agents/hermes/start.sh
  • src/lib/agent/runtime-hermes-secret-boundary.test.ts
  • src/lib/agent/runtime.ts

Comment thread src/lib/agent/runtime.ts Outdated
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27142275082
Target ref: d27057377b76f230c3bf276b7e5e57c9d99e29e2
Workflow ref: main
Requested jobs: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e,hermes-e2e,hermes-dashboard-e2e
Summary: 4 passed, 0 failed, 0 skipped

Job Result
hermes-dashboard-e2e ✅ success
hermes-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ✅ success

….env on recover

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27143622706
Target ref: bc7d372ca1b3c145ec89bf0245a354fc75120201
Workflow ref: main
Requested jobs: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e,hermes-e2e
Summary: 3 passed, 0 failed, 0 skipped

Job Result
hermes-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ✅ success

@wscurran wscurran added area: security Security controls, permissions, secrets, or hardening bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior provider: nvidia NVIDIA inference endpoint, NIM, or NVIDIA provider behavior labels Jun 8, 2026
@wscurran

wscurran commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

…pand tests

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
Comment thread agents/hermes/validate-env-secret-boundary.py Fixed
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27145242873
Target ref: 288f5403c420d8aeca78128b7126cfbc8fe461c0
Workflow ref: main
Requested jobs: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e,hermes-e2e
Summary: 3 passed, 0 failed, 0 skipped

Job Result
hermes-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ✅ success

@cv cv added the v0.0.61 Release target label Jun 8, 2026
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

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

🧹 Nitpick comments (1)
agents/hermes/validate-env-secret-boundary.py (1)

116-121: 💤 Low value

Add an explanatory comment for the empty except clause.

The CodeQL warning is valid — silent except: pass blocks are a code smell. In this context the intent is correct (nothing useful can be done if close() fails on cleanup), but an inline comment makes the intent explicit and silences the static analysis warning.

Proposed fix
     finally:
         if fd != -1:
             try:
                 os.close(fd)
             except OSError:
-                pass
+                pass  # Best-effort cleanup; nothing to do if close fails
🤖 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 `@agents/hermes/validate-env-secret-boundary.py` around lines 116 - 121, The
except OSError: pass is currently silent; update the finally block that closes
fd (the os.close(fd) call) to include a brief explanatory comment explaining
that failures during cleanup are intentionally ignored (e.g., "Ignore errors
closing fd during cleanup — nothing useful can be done here") so the intent is
explicit and static analysis warnings are silenced; keep the except handling
as-is (no re-raise) but add the comment directly above or inside the except
block referencing fd/os.close to make the rationale clear.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@agents/hermes/validate-env-secret-boundary.py`:
- Around line 116-121: The except OSError: pass is currently silent; update the
finally block that closes fd (the os.close(fd) call) to include a brief
explanatory comment explaining that failures during cleanup are intentionally
ignored (e.g., "Ignore errors closing fd during cleanup — nothing useful can be
done here") so the intent is explicit and static analysis warnings are silenced;
keep the except handling as-is (no re-raise) but add the comment directly above
or inside the except block referencing fd/os.close to make the rationale clear.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ea08bdc2-9564-4254-a826-7545fc5dfe1a

📥 Commits

Reviewing files that changed from the base of the PR and between bc7d372 and 288f540.

📒 Files selected for processing (5)
  • agents/hermes/validate-env-secret-boundary.py
  • src/lib/agent/hermes-recovery-boundary.ts
  • src/lib/agent/runtime-hermes-secret-boundary.test.ts
  • src/lib/agent/runtime.ts
  • test/hermes-start.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/hermes-start.test.ts

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27145988310
Target ref: 07517a9e1b16f38de1009f28090d5d6c08083f86
Workflow ref: main
Requested jobs: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e,hermes-e2e
Summary: 2 passed, 1 failed, 0 skipped

Job Result
hermes-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ❌ failure

Failed jobs: hermes-secret-boundary-e2e. Check run artifacts for logs.

… .env to validator

Signed-off-by: Tinson Lai <tinsonl@nvidia.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 27146629162
Target ref: 3e1dbd98beee57738a5c138acde5f5eefc7f4de9
Workflow ref: main
Requested jobs: hermes-secret-boundary-e2e,hermes-e2e
Summary: 1 passed, 1 failed, 0 skipped

Job Result
hermes-e2e ✅ success
hermes-secret-boundary-e2e ❌ failure

Failed jobs: hermes-secret-boundary-e2e. Check run artifacts for logs.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 27147381522
Target ref: e6a79754ab733fc39e14152cbad0bbbd72ab8e22
Workflow ref: main
Requested jobs: hermes-secret-boundary-e2e,hermes-root-entrypoint-smoke-e2e,hermes-e2e
Summary: 3 passed, 0 failed, 0 skipped

Job Result
hermes-e2e ✅ success
hermes-root-entrypoint-smoke-e2e ✅ success
hermes-secret-boundary-e2e ✅ success

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

🧹 Nitpick comments (1)
src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts (1)

85-87: ⚡ Quick win

Prefer replaceAll over RegExp for literal string replacement.

The file path HERMES_SECRET_BOUNDARY_VALIDATOR_PATH contains . characters that are regex metacharacters. While not a true ReDoS risk (the path is controlled by the codebase), using String.prototype.replaceAll() is clearer and avoids the metacharacter issue entirely.

♻️ Proposed fix using replaceAll
-    const guardWithStubs = opts.guard
-      .replace(new RegExp(HERMES_SECRET_BOUNDARY_VALIDATOR_PATH, "g"), validatorPath)
-      .replace(/\/tmp\/gateway-recovery\.log/g, recoveryLogPath);
+    const guardWithStubs = opts.guard
+      .replaceAll(HERMES_SECRET_BOUNDARY_VALIDATOR_PATH, validatorPath)
+      .replaceAll("/tmp/gateway-recovery.log", recoveryLogPath);

Apply the same fix at lines 222-234 and 396-397.

🤖 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/agent/runtime-hermes-secret-boundary-behavioural.test.ts` around
lines 85 - 87, The current replacement uses .replace(new
RegExp(HERMES_SECRET_BOUNDARY_VALIDATOR_PATH, "g"), validatorPath) which treats
dots as regex metacharacters; change these to use String.prototype.replaceAll
for literal replacements (e.g. call
opts.guard.replaceAll(HERMES_SECRET_BOUNDARY_VALIDATOR_PATH,
validatorPath).replaceAll("/tmp/gateway-recovery.log", recoveryLogPath)) so both
HERMES_SECRET_BOUNDARY_VALIDATOR_PATH and the recovery log path are replaced
literally; apply the same replaceAll change for the other occurrences referenced
in the file (the blocks around the current guardWithStubs usage and the
occurrences at the later locations noted).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts`:
- Around line 85-87: The current replacement uses .replace(new
RegExp(HERMES_SECRET_BOUNDARY_VALIDATOR_PATH, "g"), validatorPath) which treats
dots as regex metacharacters; change these to use String.prototype.replaceAll
for literal replacements (e.g. call
opts.guard.replaceAll(HERMES_SECRET_BOUNDARY_VALIDATOR_PATH,
validatorPath).replaceAll("/tmp/gateway-recovery.log", recoveryLogPath)) so both
HERMES_SECRET_BOUNDARY_VALIDATOR_PATH and the recovery log path are replaced
literally; apply the same replaceAll change for the other occurrences referenced
in the file (the blocks around the current guardWithStubs usage and the
occurrences at the later locations noted).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b1f6e7f1-cd4c-4a9a-8c44-93d43efa892a

📥 Commits

Reviewing files that changed from the base of the PR and between 288f540 and e6a7975.

📒 Files selected for processing (6)
  • agents/hermes/start.sh
  • agents/hermes/validate-env-secret-boundary.py
  • src/lib/agent/hermes-recovery-boundary-fixtures.ts
  • src/lib/agent/hermes-recovery-boundary.ts
  • src/lib/agent/runtime-hermes-secret-boundary-behavioural.test.ts
  • src/lib/agent/runtime-hermes-secret-boundary-shape.test.ts
💤 Files with no reviewable changes (1)
  • agents/hermes/start.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/agent/hermes-recovery-boundary.ts
  • agents/hermes/validate-env-secret-boundary.py

@cv cv merged commit 396eb34 into main Jun 8, 2026
38 checks passed
@cv cv deleted the fix/4957-hermes-recover-secret-boundary branch June 8, 2026 16:04
miyoungc added a commit that referenced this pull request Jun 8, 2026
## Summary
- Add the v0.0.61 release notes from the GitHub dev announcement.
- Document managed vLLM recovery after host reboot and Slack
denied-mention feedback.
- Refresh generated `nemoclaw-user-*` skills from the source docs.

## Source summary
- #4983 -> `docs/about/release-notes.mdx`: Added the v0.0.61 release
summary from the dev announcement and linked behavior groups to deeper
docs.
- #4904 -> `docs/inference/use-local-inference.mdx`: Documented that
managed vLLM restarts the `nemoclaw-vllm` container after host reboot
during recovery.
- #4933 -> `docs/manage-sandboxes/messaging-channels.mdx`: Documented
Slack sender feedback for denied channel `@mention` events.
- #4879, #4915, #4935, #4759, #4164, #4888, #4897, #4944, #4959 ->
`.agents/skills/`: Refreshed generated user skills from the current
source docs for release prep.

## Verification
- `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix
nemoclaw-user --doc-platform fern-mdx`
- `npm run docs` (passed outside the tool sandbox after `tsx` IPC pipe
creation was blocked in the sandbox)
- `npm run build:cli` (refreshed local `dist/` for the pre-push
TypeScript hook)
- Commit and pre-push hooks passed, including docs-to-skills
verification, markdownlint, gitleaks, skills YAML tests, and CLI
TypeScript.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
  * Updated sandbox security documentation with file descriptor limits.
  * Changed default inference model for DGX Station profile.
  * Enhanced agent policy and backup/restore documentation.
  * Improved command reference examples with clearer formatting.
  * Clarified Slack messaging denial notice behavior.
  * Added automatic vLLM container recovery during host reboot.
  * Updated release notes for v0.0.61.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: security Security controls, permissions, secrets, or hardening bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior provider: nvidia NVIDIA inference endpoint, NIM, or NVIDIA provider behavior v0.0.61 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NemoHermes gateway starts and serves after raw secret-shaped value injected into .env, no [SECURITY] refusal

4 participants