Skip to content

fix(hermes): scope prebaked dependencies to supported integrations#2846

Merged
cv merged 8 commits into
mainfrom
review/pr-2834-hermes-deps-on-main-0501
May 1, 2026
Merged

fix(hermes): scope prebaked dependencies to supported integrations#2846
cv merged 8 commits into
mainfrom
review/pr-2834-hermes-deps-on-main-0501

Conversation

@ericksoa
Copy link
Copy Markdown
Contributor

@ericksoa ericksoa commented May 1, 2026

This is a maintainer experiment that builds on Ben Barclay's PR #2834. Ben identified the right install gap: the Hermes image needs the dependencies required for supported runtime integrations, otherwise users hit missing-package failures after onboarding.

This branch keeps that direction while narrowing the dependency surface for NemoClaw:

  • targets the selected Hermes release v2026.4.23 / 0.11.0
  • verifies the GitHub release tarball by SHA256 before extraction
  • installs Hermes with uv sync --frozen --no-dev --extra messaging --extra web by default instead of [all]
  • preserves the /usr/local/bin/hermes final-image contract used by policy and e2e checks
  • grants the Hermes gateway group write access to runtime state directories while keeping config files non-group-writable
  • opens /tmp/gateway.log from inside the gateway user context so capability-dropping does not block startup
  • updates the Hermes manifest expected version to 2026.4.23
  • leaves OpenClaw dependency handling unchanged

The intent is to prebake the Hermes dependencies that map to NemoClaw-supported onboarding integrations today: Telegram, Discord, Slack, and the API/health runtime. Larger or unsupported integrations should stay out of the base image and be installed by the agent workflow when enabled.

Local validation completed:

  • docker build --progress=plain -f agents/hermes/Dockerfile.base -t nemoclaw-hermes-base-experiment .
  • docker build --progress=plain -f agents/hermes/Dockerfile.base --build-arg HERMES_VERSION=v2026.4.13 --build-arg HERMES_TARBALL_SHA256=5e4529b8cb6e4821eb916b81517e48125109b1764d6d1e68a204a9f0ddf2d98c --build-arg HERMES_UV_EXTRAS=messaging -t nemoclaw-hermes-old-base-e2e-rebuild-test .
  • docker build --progress=plain -f agents/hermes/Dockerfile --build-arg BASE_IMAGE=nemoclaw-hermes-base-experiment -t nemoclaw-hermes-final-experiment .
  • final image resolves hermes to /usr/local/bin/hermes and reports Hermes Agent v0.11.0 (2026.4.23)
  • imports present: telegram, discord, slack_bolt, fastapi, uvicorn
  • imports absent: faster_whisper, mautrix, boto3, dingtalk_stream, lark_oapi
  • entrypoint gateway health check returns {"status":"ok","platform":"hermes-agent"} through port 8642
  • npm test -- test/sandbox-provisioning.test.ts src/lib/agent-defs.test.ts src/lib/sandbox-version.test.ts
  • npm run validate:configs
  • npm run typecheck:cli
  • npx prek run --all-files --stage pre-push

Focused e2e passed on this branch: https://github.com/NVIDIA/NemoClaw/actions/runs/25222726016

Earlier focused e2e on this experiment found four useful issues that this branch now addresses: first the image contract expected /usr/local/bin/hermes, then the gateway needed writable Hermes runtime state under /sandbox/.hermes, then the entrypoint opened /tmp/gateway.log before switching to the gateway user. The rebuild e2e also needed its old-version fixture pinned to the matching tarball checksum and extras profile. The final OpenShell-specific blocker was that the Hermes executable is a symlink into /opt/hermes, so the Hermes policy now grants read-only access to that venv path.

Related context:

Summary by CodeRabbit

  • New Features

    • Enhanced startup logging with improved diagnostics for troubleshooting sandbox initialization issues
    • Added runtime diagnostics to capture system state and logs when errors occur
  • Chores

    • Updated Hermes agent to v2026.4.23
    • Improved build pipeline with better dependency verification and deterministic installation

benbarclay and others added 2 commits May 1, 2026 07:38
This change introduces UV to sync the .[all] target for all python dependencies. This was introduced due to missing dependencies such as `discord.py` in the logs.

Additionally runs npm install to get the JS dependencies for the TUI and web dashboards.

(cherry picked from commit 2a1a9d7)
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented May 1, 2026

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 1, 2026

📝 Walkthrough

Walkthrough

Hermes agent is updated from v2026.4.8/v2026.4.13 to v2026.4.23 with a new deterministic build pipeline using uv and sha256 verification instead of direct pip3 install. Filesystem structure is reorganized with a dedicated /sandbox/.hermes/runtime directory, adjusted permissions, and symlinked state files. Startup logging is enhanced to capture restricted logs and forward gateway output, while test diagnostics are expanded to verify provisioning and troubleshoot failures.

Changes

Cohort / File(s) Summary
Hermes Build Pipeline
agents/hermes/Dockerfile.base
Updated Hermes version to v2026.4.23, switched from direct pip3 install to deterministic uv pipeline with sha256 verification of GitHub tarball, exposed venv executables via symlinks, tightened directory permissions and ownership.
Hermes Runtime Directory
agents/hermes/Dockerfile
Added /sandbox/.hermes/runtime directory with gateway:sandbox ownership and 770 permissions; replaced state files under /sandbox/.hermes with symlinks into runtime/ subdirectory; adjusted config file ownership and group permissions.
Hermes Configuration & Policies
agents/hermes/manifest.yaml, agents/hermes/policy-additions.yaml, agents/hermes/policy-permissive.yaml
Updated manifest to reflect Hermes v2026.4.23 and clarified dashboard documentation; added /opt/hermes to read-only filesystem policy in both policy variants.
Hermes Startup & Logging
agents/hermes/start.sh
Introduced prepare_restricted_log() for early startup log capture and start_gateway_log_stream() to continuously tail and prefix gateway logs; wrapped gateway launch in gosu gateway shell; tracked log tail PID for coordinated cleanup.
E2E Test Diagnostics
test/e2e/test-hermes-e2e.sh, test/e2e/test-rebuild-hermes.sh
Added dump_hermes_diagnostics() and dump_hermes_sandbox_logs() helpers to gather logs, process info, and sandbox state on test failure; updated base version variable to v2026.4.13 with fixed tarball SHA256 and HERMES_UV_EXTRAS.
Hermes Provisioning Tests
test/sandbox-provisioning.test.ts
Expanded regression checks to verify Hermes base image group membership, start script runtime directory setup, diagnostic log capture with tee-ing and gateway prefixing, and OpenShell policy read-only access to /opt/hermes.
Runtime Override Test
test/e2e/test-runtime-overrides.sh
Minor formatting improvement: added trailing newline to run_override output; enhanced CORS test failure message to include current allowedOrigins value.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A hermes rabbit hops with glee,
New pipelines built with uv so free,
Runtime dirs with symlinks tight,
Gateway logs now in flight,
Tests diagnose with rabbit might! 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 accurately summarizes the main change: scoping Hermes dependencies to supported integrations (messaging and web extras) rather than installing all dependencies.
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.

✏️ 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 review/pr-2834-hermes-deps-on-main-0501

Review rate limit: 8/10 reviews remaining, refill in 6 minutes and 8 seconds.

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ❌ Some jobs failed

Run: 25219741538
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: hermes-e2e,rebuild-hermes-e2e
Summary: 0 passed, 2 failed, 19 skipped

Job Result
cloud-e2e ⏭️ skipped
cloud-inference-e2e ⏭️ skipped
cloud-onboard-e2e ⏭️ skipped
deployment-services-e2e ⏭️ skipped
diagnostics-e2e ⏭️ skipped
docs-validation-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
hermes-e2e ❌ failure
inference-routing-e2e ⏭️ skipped
messaging-providers-e2e ⏭️ skipped
network-policy-e2e ⏭️ skipped
overlayfs-autofix-e2e ⏭️ skipped
rebuild-hermes-e2e ❌ failure
rebuild-openclaw-e2e ⏭️ skipped
sandbox-operations-e2e ⏭️ skipped
sandbox-survival-e2e ⏭️ skipped
shields-config-e2e ⏭️ skipped
skill-agent-e2e ⏭️ skipped
snapshot-commands-e2e ⏭️ skipped
token-rotation-e2e ⏭️ skipped
upgrade-stale-sandbox-e2e ⏭️ skipped

Failed jobs: hermes-e2e, rebuild-hermes-e2e. Check run artifacts for logs.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ❌ Some jobs failed

Run: 25220440120
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: hermes-e2e,rebuild-hermes-e2e
Summary: 0 passed, 2 failed, 19 skipped

Job Result
cloud-e2e ⏭️ skipped
cloud-inference-e2e ⏭️ skipped
cloud-onboard-e2e ⏭️ skipped
deployment-services-e2e ⏭️ skipped
diagnostics-e2e ⏭️ skipped
docs-validation-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
hermes-e2e ❌ failure
inference-routing-e2e ⏭️ skipped
messaging-providers-e2e ⏭️ skipped
network-policy-e2e ⏭️ skipped
overlayfs-autofix-e2e ⏭️ skipped
rebuild-hermes-e2e ❌ failure
rebuild-openclaw-e2e ⏭️ skipped
sandbox-operations-e2e ⏭️ skipped
sandbox-survival-e2e ⏭️ skipped
shields-config-e2e ⏭️ skipped
skill-agent-e2e ⏭️ skipped
snapshot-commands-e2e ⏭️ skipped
token-rotation-e2e ⏭️ skipped
upgrade-stale-sandbox-e2e ⏭️ skipped

Failed jobs: hermes-e2e, rebuild-hermes-e2e. Check run artifacts for logs.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ❌ Some jobs failed

Run: 25221059901
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: hermes-e2e,rebuild-hermes-e2e
Summary: 0 passed, 2 failed, 19 skipped

Job Result
cloud-e2e ⏭️ skipped
cloud-inference-e2e ⏭️ skipped
cloud-onboard-e2e ⏭️ skipped
deployment-services-e2e ⏭️ skipped
diagnostics-e2e ⏭️ skipped
docs-validation-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
hermes-e2e ❌ failure
inference-routing-e2e ⏭️ skipped
messaging-providers-e2e ⏭️ skipped
network-policy-e2e ⏭️ skipped
overlayfs-autofix-e2e ⏭️ skipped
rebuild-hermes-e2e ❌ failure
rebuild-openclaw-e2e ⏭️ skipped
sandbox-operations-e2e ⏭️ skipped
sandbox-survival-e2e ⏭️ skipped
shields-config-e2e ⏭️ skipped
skill-agent-e2e ⏭️ skipped
snapshot-commands-e2e ⏭️ skipped
token-rotation-e2e ⏭️ skipped
upgrade-stale-sandbox-e2e ⏭️ skipped

Failed jobs: hermes-e2e, rebuild-hermes-e2e. Check run artifacts for logs.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ❌ Some jobs failed

Run: 25221685089
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: hermes-e2e,rebuild-hermes-e2e
Summary: 0 passed, 2 failed, 19 skipped

Job Result
cloud-e2e ⏭️ skipped
cloud-inference-e2e ⏭️ skipped
cloud-onboard-e2e ⏭️ skipped
deployment-services-e2e ⏭️ skipped
diagnostics-e2e ⏭️ skipped
docs-validation-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
hermes-e2e ❌ failure
inference-routing-e2e ⏭️ skipped
messaging-providers-e2e ⏭️ skipped
network-policy-e2e ⏭️ skipped
overlayfs-autofix-e2e ⏭️ skipped
rebuild-hermes-e2e ❌ failure
rebuild-openclaw-e2e ⏭️ skipped
sandbox-operations-e2e ⏭️ skipped
sandbox-survival-e2e ⏭️ skipped
shields-config-e2e ⏭️ skipped
skill-agent-e2e ⏭️ skipped
snapshot-commands-e2e ⏭️ skipped
token-rotation-e2e ⏭️ skipped
upgrade-stale-sandbox-e2e ⏭️ skipped

Failed jobs: hermes-e2e, rebuild-hermes-e2e. Check run artifacts for logs.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ❌ Some jobs failed

Run: 25222192970
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: hermes-e2e,rebuild-hermes-e2e
Summary: 0 passed, 2 failed, 19 skipped

Job Result
cloud-e2e ⏭️ skipped
cloud-inference-e2e ⏭️ skipped
cloud-onboard-e2e ⏭️ skipped
deployment-services-e2e ⏭️ skipped
diagnostics-e2e ⏭️ skipped
docs-validation-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
hermes-e2e ❌ failure
inference-routing-e2e ⏭️ skipped
messaging-providers-e2e ⏭️ skipped
network-policy-e2e ⏭️ skipped
overlayfs-autofix-e2e ⏭️ skipped
rebuild-hermes-e2e ❌ failure
rebuild-openclaw-e2e ⏭️ skipped
sandbox-operations-e2e ⏭️ skipped
sandbox-survival-e2e ⏭️ skipped
shields-config-e2e ⏭️ skipped
skill-agent-e2e ⏭️ skipped
snapshot-commands-e2e ⏭️ skipped
token-rotation-e2e ⏭️ skipped
upgrade-stale-sandbox-e2e ⏭️ skipped

Failed jobs: hermes-e2e, rebuild-hermes-e2e. Check run artifacts for logs.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ✅ All requested jobs passed

Run: 25222726016
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: hermes-e2e,rebuild-hermes-e2e
Summary: 2 passed, 0 failed, 19 skipped

Job Result
cloud-e2e ⏭️ skipped
cloud-inference-e2e ⏭️ skipped
cloud-onboard-e2e ⏭️ skipped
deployment-services-e2e ⏭️ skipped
diagnostics-e2e ⏭️ skipped
docs-validation-e2e ⏭️ skipped
gpu-e2e ⏭️ skipped
hermes-e2e ✅ success
inference-routing-e2e ⏭️ skipped
messaging-providers-e2e ⏭️ skipped
network-policy-e2e ⏭️ skipped
overlayfs-autofix-e2e ⏭️ skipped
rebuild-hermes-e2e ✅ success
rebuild-openclaw-e2e ⏭️ skipped
sandbox-operations-e2e ⏭️ skipped
sandbox-survival-e2e ⏭️ skipped
shields-config-e2e ⏭️ skipped
skill-agent-e2e ⏭️ skipped
snapshot-commands-e2e ⏭️ skipped
token-rotation-e2e ⏭️ skipped
upgrade-stale-sandbox-e2e ⏭️ skipped

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@agents/hermes/Dockerfile`:
- Around line 214-228: The Dockerfile currently makes /sandbox/.hermes
group-writable with the chmod 770 line; change that to keep the config root
non-group-writable (chmod 750) so /sandbox/.hermes remains 750 sandbox:sandbox
while leaving config.yaml and .env as 640; additionally, create and chown
dedicated writable subdirectories for gateway runtime state (e.g., pid, logs,
socket or state dirs like /sandbox/.hermes/pid or /sandbox/.hermes/runtime) and
grant those gateway-writable permissions (chown to gateway and chmod 770/750 as
appropriate) so gateway can write runtime files without giving group write on
the config root.

In `@agents/hermes/start.sh`:
- Around line 42-54: The current _START_LOG creation (variable _START_LOG and
the block that truncates and chowns it before the exec redirection/tee) risks
following attacker-controlled symlinks; change to an atomic safe-create pattern:
open a new temporary file in the same directory (e.g., create a unique tmp
name), set ownership and permissions on that temp file, then atomically rename
it to the final _START_LOG path (or call the planned restricted-log helper)
before running exec > >(tee -a "$_START_LOG") 2> >(tee -a "$_START_LOG" >&2);
ensure the logic for both root and non-root branches uses the same
safe-create/rename flow and avoid using shell truncation (:) on the final path
so symlinks cannot be followed.

In `@test/e2e/test-rebuild-hermes.sh`:
- Around line 33-35: The test seeds an old hermes version using
OLD_HERMES_VERSION but the final assertion still checks a hardcoded version;
introduce a single constant (e.g., OLD_HERMES_REGISTRY_VERSION) to hold the
seeded registry version and use it both where the fixture is set (replacing
OLD_HERMES_VERSION usage if needed) and in the final REGISTRY_VERSION assertion
to compare against the same value; update any other occurrences (notably the
other two spots mentioned) to reference OLD_HERMES_REGISTRY_VERSION so the seed
and the final guard come from the same source of truth.
🪄 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: 766247a0-11e5-4977-922b-3bad7a378121

📥 Commits

Reviewing files that changed from the base of the PR and between f9d21af and 91e8273.

📒 Files selected for processing (9)
  • agents/hermes/Dockerfile
  • agents/hermes/Dockerfile.base
  • agents/hermes/manifest.yaml
  • agents/hermes/policy-additions.yaml
  • agents/hermes/policy-permissive.yaml
  • agents/hermes/start.sh
  • test/e2e/test-hermes-e2e.sh
  • test/e2e/test-rebuild-hermes.sh
  • test/sandbox-provisioning.test.ts

Comment thread agents/hermes/Dockerfile Outdated
Comment thread agents/hermes/start.sh
Comment thread test/e2e/test-rebuild-hermes.sh
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ✅ All requested jobs passed

Run: 25223575974
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: all (no filter)
Summary: 20 passed, 0 failed, 1 skipped

Job Result
cloud-e2e ✅ success
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
deployment-services-e2e ✅ success
diagnostics-e2e ✅ success
docs-validation-e2e ✅ success
gpu-e2e ⏭️ skipped
hermes-e2e ✅ success
inference-routing-e2e ✅ success
messaging-providers-e2e ✅ success
network-policy-e2e ✅ success
overlayfs-autofix-e2e ✅ success
rebuild-hermes-e2e ✅ success
rebuild-openclaw-e2e ✅ success
sandbox-operations-e2e ✅ success
sandbox-survival-e2e ✅ success
shields-config-e2e ✅ success
skill-agent-e2e ✅ success
snapshot-commands-e2e ✅ success
token-rotation-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success

@ericksoa ericksoa marked this pull request as ready for review May 1, 2026 18:20
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@agents/hermes/start.sh`:
- Around line 66-67: The mv invocation in agents/hermes/start.sh currently uses
mv -f "$tmp" "$path" which will follow a destination symlink-to-directory and
can be exploited; change the publish step to use mv -T (atomic replace of
destination) so the temp file replaces the target path rather than being moved
into a symlinked directory — update the mv command that handles the "$tmp" ->
"$path" replacement to use mv -T (and keep the existing -f behavior) and ensure
the cleanup branch still removes "$tmp" on failure.
🪄 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: 6904c474-9a14-46b7-8df2-3297ba037477

📥 Commits

Reviewing files that changed from the base of the PR and between 91e8273 and 2e5fddb.

📒 Files selected for processing (6)
  • agents/hermes/Dockerfile
  • agents/hermes/Dockerfile.base
  • agents/hermes/start.sh
  • test/e2e/test-rebuild-hermes.sh
  • test/e2e/test-runtime-overrides.sh
  • test/sandbox-provisioning.test.ts
✅ Files skipped from review due to trivial changes (2)
  • test/e2e/test-runtime-overrides.sh
  • agents/hermes/Dockerfile.base
🚧 Files skipped from review as they are similar to previous changes (2)
  • agents/hermes/Dockerfile
  • test/e2e/test-rebuild-hermes.sh

Comment thread agents/hermes/start.sh
Comment on lines +66 to +67
if ! mv -f "$tmp" "$path"; then
rm -f "$tmp"
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, examine the actual file to see the context
head -80 agents/hermes/start.sh | tail -40

Repository: NVIDIA/NemoClaw

Length of output: 1102


🏁 Script executed:

# Check if the file has SPDX headers
head -5 agents/hermes/start.sh

Repository: NVIDIA/NemoClaw

Length of output: 266


🏁 Script executed:

# Get more context around the function in question
sed -n '45,80p' agents/hermes/start.sh

Repository: NVIDIA/NemoClaw

Length of output: 898


🌐 Web query:

GNU coreutils mv -T flag symlink directory behavior

💡 Result:

The GNU coreutils mv command with the -T (or --no-target-directory) flag does not treat the destination operand specially if it is a directory or a symbolic link to a directory. Normally, without -T, if the destination is a directory or symlink to a directory, mv moves the source into that directory (e.g., mv source dest becomes mv source dest/source). With -T, mv treats the destination as a normal file path, attempting to rename or move the source directly to that exact path, even if dest exists as a directory or symlink to one. This enables overwriting or replacing a directory symlink atomically with another file or symlink. This behavior holds regardless of whether the destination is a symlink to a directory; the check for special treatment explicitly includes "a directory or a symbolic link to a directory". The mv source code confirms that when no_target_directory is set, it skips the directory detection logic for the last operand and performs a direct rename operation. Note that symlink handling also depends on trailing slashes (use --strip-trailing-slashes if needed) and the underlying rename(2) syscall behavior, which varies by OS/kernel (e.g., modern Linux fails with ENOTDIR for symlink-to-dir sources with trailing slash, while others may dereference).

Citations:


🏁 Script executed:

# Check for Dockerfile or system requirements to understand target environment
find . -name "Dockerfile*" -o -name "*.dockerfile" | head -5

Repository: NVIDIA/NemoClaw

Length of output: 175


🏁 Script executed:

# Check if other shell scripts use GNU-specific mv flags
rg "mv\s+-[a-zA-Z]*T" --type sh

Repository: NVIDIA/NemoClaw

Length of output: 41


🏁 Script executed:

# Check for any POSIX compatibility notes or system requirements
rg "POSIX|portability|compatibility" README.md 2>/dev/null | head -20

Repository: NVIDIA/NemoClaw

Length of output: 41


🏁 Script executed:

# See if there are any CI/build configs that indicate target platform
find . -name ".github" -type d -exec find {} -name "*.yml" -o -name "*.yaml" \; | head -5

Repository: NVIDIA/NemoClaw

Length of output: 354


🏁 Script executed:

# Check the Hermes Dockerfile to see base image
cat agents/hermes/Dockerfile | head -20

Repository: NVIDIA/NemoClaw

Length of output: 908


🏁 Script executed:

# Also check the base image
cat agents/hermes/Dockerfile.base | head -20

Repository: NVIDIA/NemoClaw

Length of output: 1042


🏁 Script executed:

# Check where prepare_restricted_log is called (should be 2+ times)
rg "prepare_restricted_log" agents/hermes/start.sh -n

Repository: NVIDIA/NemoClaw

Length of output: 311


🏁 Script executed:

# Verify the second usage for gateway.log
sed -n '500,570p' agents/hermes/start.sh

Repository: NVIDIA/NemoClaw

Length of output: 3064


Use mv -T when publishing the restricted log file.

On line 66, mv -f treats a destination symlink-to-directory as a directory, so a pre-planted /tmp/nemoclaw-start.log or /tmp/gateway.log link can redirect the temp file into an attacker-chosen directory instead of replacing the log path. Because this helper is reused for both restricted logs, the /tmp hardening is incomplete.

🔒 Proposed hardening
-  if ! mv -f "$tmp" "$path"; then
+  if ! mv -fT "$tmp" "$path"; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agents/hermes/start.sh` around lines 66 - 67, The mv invocation in
agents/hermes/start.sh currently uses mv -f "$tmp" "$path" which will follow a
destination symlink-to-directory and can be exploited; change the publish step
to use mv -T (atomic replace of destination) so the temp file replaces the
target path rather than being moved into a symlinked directory — update the mv
command that handles the "$tmp" -> "$path" replacement to use mv -T (and keep
the existing -f behavior) and ensure the cleanup branch still removes "$tmp" on
failure.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Selective E2E Results — ✅ All requested jobs passed

Run: 25227294718
Branch: review/pr-2834-hermes-deps-on-main-0501
Requested jobs: all (no filter)
Summary: 20 passed, 0 failed, 1 skipped

Job Result
cloud-e2e ✅ success
cloud-inference-e2e ✅ success
cloud-onboard-e2e ✅ success
deployment-services-e2e ✅ success
diagnostics-e2e ✅ success
docs-validation-e2e ✅ success
gpu-e2e ⏭️ skipped
hermes-e2e ✅ success
inference-routing-e2e ✅ success
messaging-providers-e2e ✅ success
network-policy-e2e ✅ success
overlayfs-autofix-e2e ✅ success
rebuild-hermes-e2e ✅ success
rebuild-openclaw-e2e ✅ success
sandbox-operations-e2e ✅ success
sandbox-survival-e2e ✅ success
shields-config-e2e ✅ success
skill-agent-e2e ✅ success
snapshot-commands-e2e ✅ success
token-rotation-e2e ✅ success
upgrade-stale-sandbox-e2e ✅ success

@ericksoa ericksoa self-assigned this May 1, 2026
@ericksoa ericksoa added enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. Integration: Hermes v0.0.33 labels May 1, 2026
@ericksoa ericksoa requested a review from cv May 1, 2026 19:17
@cv cv merged commit 0968dfd into main May 1, 2026
52 checks passed
cv pushed a commit that referenced this pull request May 2, 2026
## Summary
Daily release-prep documentation refresh for merged PRs from the past 24
hours.
This updates user-facing docs for Telegram mention-only mode, in-sandbox
messaging shutdown, Hermes onboarding/runtime behavior, and
compatible-endpoint smoke validation, then bumps the docs metadata to
0.0.33 after tag v0.0.32.

## Related Issue
None.

## Changes
- #2417 / c7e49ad: Document `TELEGRAM_REQUIRE_MENTION` for Telegram
group-chat replies in `docs/manage-sandboxes/messaging-channels.md` and
`docs/reference/commands.md`.
- #1977 / 69403e0: Update `nemoclaw tunnel stop` and deprecated
`nemoclaw stop` docs to explain that NemoClaw also attempts to stop the
in-sandbox OpenClaw gateway and messaging polling.
- #2781 / b83ffe2, #2859 / 4df8be6, and #2846 / 0968dfd: Refresh the
Hermes quickstart for the default `my-hermes` sandbox name, cross-agent
same-name guard, agent type visibility in `nemoclaw list`, Brave prompt
omission, and supported prebaked Hermes integrations.
- #2849 / fd240ff: Document the Telegram plus OpenAI-compatible
endpoint `inference.local` smoke check in inference options and
troubleshooting.
- Bump `docs/versions1.json` and `docs/project.json` from 0.0.32 to
0.0.33 for daily release preparation.

## Type of Change
- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [x] 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
- [x] No secrets, API keys, or credentials committed
- [x] Docs updated for user-facing behavior changes
- [x] `make docs` builds without warnings (doc changes only)
- [x] 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)

Additional checks run:
- `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix
nemoclaw-user --dry-run`
- `git diff --check`
- `make docs` passed with the existing local version-switcher read
message.
- Full `npx prek run --all-files` and `npm test` were skipped for this
doc-only automation run. Commit and pre-push hooks otherwise passed
docs, lint, secret, and conversion checks until the local `Test (skills
YAML)` hook failed because `vitest/config` is not installed in this
fresh worktree.

---
Signed-off-by: Miyoung Choi <miyoungc@nvidia.com>


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

* **Documentation**
* Updated Hermes quickstart: default sandbox name is "hermes"; guidance
to use distinct sandbox names, note same-name reuse is prevented, Hermes
wizard does not request Brave Web Search, and sandbox listings now show
agent type.
* Clarified provider onboarding: bounded in-sandbox smoke check runs
when Telegram messaging is enabled.
* Expanded Telegram docs: added TELEGRAM_REQUIRE_MENTION (DMs still
governed by TELEGRAM_ALLOWED_IDS), onboarding examples,
stop-messaging/tunnel behavior, and troubleshooting.
  * Promoted docs to version 0.0.33.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Miyoung Choi <miyoungc@nvidia.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
cv pushed a commit that referenced this pull request May 4, 2026
<!-- markdownlint-disable MD041 -->
## Summary
Follows up on NousResearch's dependency-bootstrap proposal in #2834 and
the maintainer-side #2846 by carrying the remaining root Node dependency
install into the Hermes base image. The existing `uv sync` step covers
the supported Python integration extras; this adds deterministic `npm
ci` from the Hermes root lockfile so browser tooling such as
`agent-browser` is available in the extracted Hermes tree.

## Credit
Thanks to Ben Barclay and the NousResearch team for the original PR
#2834. They identified the Hermes dependency-bootstrap gap and proposed
the direction this follow-up carries into the current NemoClaw
base-image flow.

## Related Issue
Follow-up to #2834 and #2846.

## Changes
- Install Hermes root Node dependencies with `npm ci --prefer-offline
--no-audit --no-fund` after the existing `uv sync` step.
- Remove transient `/tmp/camoufox-*` installer downloads in the same
Docker layer so large temporary archives do not persist into the image.
- Document why the root Node install belongs in the Hermes base image.

## 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
- [ ] `npx prek run --all-files` passes
- [ ] `npm test` passes
- [ ] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `make 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)

Additional validation:
- `git diff --check`
- `docker build --progress=plain --output=type=cacheonly -f
agents/hermes/Dockerfile.base .`
  - validated the `uv sync` step
  - validated the new `npm ci` step
- validated `/usr/local/bin/hermes --version` reports `Hermes Agent
v0.11.0 (2026.4.23)`

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

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

* **Chores**
* Optimized the container image build by removing temporary build
artifacts to reduce clutter and image size.
* Made tooling dependencies for browser-related features explicit so
tooling is reliably present during build.
* Ensured Node package installation runs deterministically during image
creation to improve build stability and reproducibility.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
Co-authored-by: Ben Barclay <ben@nousresearch.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. Integration: Hermes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants