[BUG] SSH backend fails when remote login shell is fish

Author: danclaw93Created Sep 3, 2026Updated Sep 3, 2026

Summary

Hermes One's SSH backend assumes the remote account uses a POSIX-compatible login shell. When the remote user's login shell is fish, SSH authentication and port forwarding succeed, but connection setup fails when Hermes One sends shell fragments containing POSIX assignments such as tmp=....

Observed error:

fish: Unsupported use of '='. In fish, please use 'set tmp ...'

This prevents SSH mode from provisioning its dashboard session token and blocks connection setup.

Environment

  • Client: Linux (Arch), current Hermes One release
  • Remote: Linux, OpenSSH 10.5
  • Remote login shell: /usr/bin/fish
  • SSH authentication: public key, BatchMode=yes
  • Remote Hermes gateway: loopback-bound and otherwise healthy
  • Current upstream main inspected at 9756351e2398af6efbd3294541e23041b497324b is still affected

Reproduction

  1. Configure a remote SSH host whose user's login shell is fish.
  2. Confirm ordinary SSH and forwarding work.
  3. Configure Hermes One SSH Tunnel mode and connect.
  4. Hermes One reaches sshEnsureDashboardToken() and sends a command containing:
bash
tmp=~/.hermes/.env.tmp.$$
  1. OpenSSH executes the supplied command through fish -c; fish rejects the POSIX assignment before execution.

Root cause

sshExec() passes command strings directly as the SSH remote command. OpenSSH evaluates those strings using the remote user's configured login shell, but many call sites construct POSIX shell syntax.

Examples in src/main/ssh-remote.ts include:

  • sshEnsureDashboardToken() (tmp=..., $tmp, || true)
  • sshPersistDashboardPort() (same pattern)
  • sshResolveDashboardRoot() (built=""; buildable=""; for ...; do ...)
  • Other call sites using [ ... ], variable assignments, and POSIX control flow

Changing only the two failing assignments to fish syntax would not be sufficient because it would break POSIX-shell users and more downstream commands have the same assumption.

Expected behavior

SSH mode should work independently of the remote user's interactive login shell, provided a POSIX shell such as /bin/sh exists on the remote.

Suggested fix

Centralize remote command execution through an explicitly selected POSIX shell rather than handing POSIX fragments to the user's login shell. For example, safely quote the complete command and execute it through /bin/sh -c, while preserving stdin behavior used by sshPython() and file operations.

Please add coverage using a test SSH endpoint/account whose login shell is fish. The test should verify at least:

  • dashboard token provisioning
  • dashboard-port persistence
  • dashboard-root probing
  • gateway/API health checks
  • commands that consume stdin

The error should also retain SSH stderr instead of collapsing to a generic connection failure where possible.

Related issue

The same token/port writers are discussed in #920 for a separate atomicity and credential-file corruption risk. A shell-compatibility fix should avoid perpetuating that read-modify-write pattern; ideally both concerns are addressed together.

No credentials or session-token values are included in this report.