Skip to content

fix(hermes): symlink .hermes_history to writable data dir#2473

Open
octo-patch wants to merge 2 commits intoNVIDIA:mainfrom
octo-patch:fix/issue-2432-hermes-history-permission
Open

fix(hermes): symlink .hermes_history to writable data dir#2473
octo-patch wants to merge 2 commits intoNVIDIA:mainfrom
octo-patch:fix/issue-2432-hermes-history-permission

Conversation

@octo-patch
Copy link
Copy Markdown

@octo-patch octo-patch commented Apr 25, 2026

Fixes #2432

Problem

Hermes TUI (prompt_toolkit) writes command history to
/sandbox/.hermes/.hermes_history. Because /sandbox/.hermes is
intentionally locked to root:root at image build time (to prevent
config tampering), the sandbox user cannot write to this path — every
interaction triggers a traceback and Press ENTER to continue...
prompt, blocking /exit.

Solution

Create a symlink /sandbox/.hermes/.hermes_history
/sandbox/.hermes-data/.hermes_history before the DAC hardening step
in the Dockerfile. This follows the same pattern already used for
SOUL.md (line 92).

After the chown -h root:root pass, the symlink itself becomes
root-owned, but the target path lives under /sandbox/.hermes-data/
which is owned by the sandbox user. When prompt_toolkit opens
/sandbox/.hermes/.hermes_history in append mode it follows the
symlink transparently and creates/writes the file in the writable
directory.

Testing

  • Added a regression test in test/hermes-plugin-handlers.test.ts
    asserting the Dockerfile contains the symlink and that it appears
    before the chown root:root /sandbox/.hermes step.
  • Logic verified: path.isAbsolute of the symlink target resolves
    correctly through the writable dir at container runtime.

Summary by CodeRabbit

  • Bug Fixes

    • Hermes TUI command history now persists correctly, resolving permission-related failures.
  • Tests

    • Added regression tests to ensure command history persistence behavior remains correct.

…IA#2432)

Hermes TUI (prompt_toolkit) attempts to write command history to
/sandbox/.hermes/.hermes_history at runtime. /sandbox/.hermes is
intentionally locked root:root during image build to prevent config
tampering, making the history path unwritable for the sandbox user.

Create a symlink /sandbox/.hermes/.hermes_history →
/sandbox/.hermes-data/.hermes_history before the DAC hardening step.
The symlink itself becomes root-owned (chown -h root:root) but the
target path lives under the sandbox-user-writable .hermes-data dir,
so prompt_toolkit can create and append to the history file at runtime.

Also add a regression test asserting the symlink is present in the
Dockerfile and appears before the chown step that locks the directory.
@copy-pr-bot
Copy link
Copy Markdown

copy-pr-bot Bot commented Apr 25, 2026

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: df9c3f8f-d620-4daa-aeaa-3d150415f7e2

📥 Commits

Reviewing files that changed from the base of the PR and between 4633408 and ad5bfd9.

📒 Files selected for processing (1)
  • test/hermes-plugin-handlers.test.ts

📝 Walkthrough

Walkthrough

The Dockerfile adds a build-time symlink redirecting Hermes TUI history from /sandbox/.hermes/.hermes_history to /sandbox/.hermes-data/.hermes_history before /sandbox/.hermes is locked to root. A regression test verifies the symlink and enforces that it appears before the chown in the Dockerfile.

Changes

Cohort / File(s) Summary
Dockerfile Symlink Fix
agents/hermes/Dockerfile
Adds creation of a symlink from /sandbox/.hermes/.hermes_history to /sandbox/.hermes-data/.hermes_history and then locks /sandbox/.hermes ownership to root, ensuring the history file is writable at runtime by the sandbox user.
Regression Test
test/hermes-plugin-handlers.test.ts
New test that loads the Dockerfile, strips comments, and asserts presence and ordering of the symlink ln -s .../.hermes_history .../.hermes/.hermes_history command and the RUN chown root:root /sandbox/.hermes command.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A locked-up file no longer bleak,
I dug a tunnel, sly and sleek.
History hops to a friendly ground,
No more permission bugged-around.
/exit now leaves without the squeak.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and concisely describes the primary change: creating a symlink for .hermes_history to a writable directory to resolve permission issues.
Linked Issues check ✅ Passed The PR fully implements the required fix from issue #2432: creates symlink from /sandbox/.hermes/.hermes_history to /sandbox/.hermes-data/.hermes_history before the chown step, allowing sandbox user to write history, and includes regression test validating the solution.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the Hermes history permission issue: Dockerfile symlink creation and regression test. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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 `@test/hermes-plugin-handlers.test.ts`:
- Around line 93-104: The test currently searches raw src for substrings which
can appear in comments and yield false positives; update the test in
hermes-plugin-handlers.test.ts to only inspect executable Dockerfile RUN
commands by splitting src into lines, filtering out comment lines (lines
starting with '#' or '//') or extracting lines beginning with 'RUN', then
perform the contains/indexOf checks against that filtered/run-only string (use
the existing src variable, then compute a runOnlySrc or filteredSrc and use
symlinkIdx/chownIdx comparisons against that instead).
🪄 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: 802544c0-4fd7-4ac0-a687-14f25dc2aa1a

📥 Commits

Reviewing files that changed from the base of the PR and between 9c5a42a and 4633408.

📒 Files selected for processing (2)
  • agents/hermes/Dockerfile
  • test/hermes-plugin-handlers.test.ts

Comment thread test/hermes-plugin-handlers.test.ts Outdated
Filter out comment lines and use regex matching against `RUN ln -s ...`
and `RUN chown root:root ...` so the regression assertion can no longer
pass on doc comments alone. Addresses CodeRabbit review feedback.

Co-Authored-By: Octopus <liyuan851277048@icloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[station][Agent&Skills] Hermes TUI spams "Permission denied: /sandbox/.hermes/.hermes_history" on every interaction, blocking /exit

1 participant