From b896aaad5318b8ce1f30b27eda8a3c30acc94036 Mon Sep 17 00:00:00 2001 From: David Young Date: Tue, 27 Oct 2026 10:10:52 -0600 Subject: [PATCH] gateway issues resolved --- sandbox/agent | 4 +++ sandbox/hermes-bridge | 61 +++++++++++++++++++++++++++++++++++++++++ updates.d/72-sandbox.sh | 5 ++-- 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100755 sandbox/hermes-bridge diff --git a/sandbox/agent b/sandbox/agent index 93972b1..d6a4e73 100755 --- a/sandbox/agent +++ b/sandbox/agent @@ -115,5 +115,9 @@ while IFS= read -r path; do case "$path" in "$HOME"/*) mkdir -p "$path" ;; esac done < <(jq -rs "$MERGE | .filesystem.allowWrite[]? | strings" "${ours[@]}") +# Hermes' terminal reaches its gateway, in another sandbox, through a relay +case "$profile" in + hermes) exec "$srt" --settings "$settings" -- bash "$SANDBOX/hermes-bridge" "$real" "$@" ;; +esac exec "$srt" --settings "$settings" -- "$real" "$@" } diff --git a/sandbox/hermes-bridge b/sandbox/hermes-bridge new file mode 100755 index 0000000..7173035 --- /dev/null +++ b/sandbox/hermes-bridge @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Purpose : Run Hermes inside its sandbox (sandbox/agent runs this there) and +# connect its terminal to its gateway. +# +# Hermes' gateway runs the agent; `hermes` in a terminal only talks to it, over +# the gateway's control socket and then a WebSocket on 127.0.0.1:. Each +# sandbox has its own network, so that port can't be reached from another one. +# The gateway's sandbox relays the port to API_SOCKET, and a terminal's sandbox +# listens on the same port and relays to API_SOCKET, so `hermes` reaches the +# gateway as if they shared a network. +# +# Usage: hermes-bridge [arguments] + +real="$1" +shift +HERMES_HOME="${HERMES_HOME:-$HOME/.hermes}" +API_SOCKET="$HERMES_HOME/coredesktop-api.sock" + +# Ask the gateway, through its control socket, where its API listens; prints +# the port, or nothing if no gateway is ready +api_port() { + local control="$HERMES_HOME/gateway.sock" origin + [ -S "$control" ] || control="$(cat "$HERMES_HOME/gateway.sock.path" 2> /dev/null)" + [ -S "$control" ] || return 1 + origin="$(printf '{"protocol":1,"verb":"identify","id":1}\n' \ + | socat -t 5 - "UNIX-CONNECT:$control" 2> /dev/null \ + | jq -r 'select(.result.state == "ready") | .result.api_origin // empty' 2> /dev/null)" + # Only an IPv4 loopback origin is relayed, which is what Hermes uses by default + [[ "$origin" =~ ^http://127\.0\.0\.1:([0-9]+)$ ]] || return 1 + echo "${BASH_REMATCH[1]}" +} + +if [ "$1" = "gateway" ] && [ "$2" = "run" ]; then + # The relay waits for the gateway, which runs in this process once exec'd; + # the sandbox ends both together + ( + for _ in $(seq 120); do + if port="$(api_port)"; then + exec socat "UNIX-LISTEN:$API_SOCKET,unlink-early,mode=600,fork" "TCP:127.0.0.1:$port" + fi + sleep 1 + done + echo "hermes-bridge: the gateway's API didn't come up; terminals can't reach it" >&2 + ) & + exec "$real" "$@" +fi + +# A terminal: relay the gateway's port, if a gateway is running. Without one, +# hermes starts its own gateway inside this sandbox, which needs no relay. +if [ -S "$API_SOCKET" ] && port="$(api_port)"; then + socat "TCP-LISTEN:$port,bind=127.0.0.1,reuseaddr,fork" "UNIX-CONNECT:$API_SOCKET" & + # Wait for the listener (state 0A, LISTEN, in /proc/net/tcp) so hermes' + # first connection doesn't fail + hex="$(printf ':%04X ' "$port")" + for _ in $(seq 50); do + grep -q "$hex.* 0A " /proc/net/tcp && break + sleep 0.05 + done +fi +exec "$real" "$@" diff --git a/updates.d/72-sandbox.sh b/updates.d/72-sandbox.sh index 5d46488..b4a32b0 100644 --- a/updates.d/72-sandbox.sh +++ b/updates.d/72-sandbox.sh @@ -16,10 +16,11 @@ run_update() { fi # The real command, not the sandboxed one in sandbox/bin: updating Hermes - # writes outside what its sandbox allows + # writes outside what its sandbox allows. python-olm, for Matrix, bundles a + # CMake file too old for CMake 4 unless told which policies to use. if [ -x "$HOME/.local/bin/hermes" ]; then echo "Updating Hermes Agent..." - "$HOME/.local/bin/hermes" update < /dev/null || status=1 + CMAKE_POLICY_VERSION_MINIMUM=3.5 "$HOME/.local/bin/hermes" update < /dev/null || status=1 fi if [ "$gateway" = 1 ]; then