From f9f6661dd558820b7612ec94613e7f8f9f5844ba Mon Sep 17 00:00:00 2001 From: root Date: Mon, 14 Sep 2026 11:55:41 +0000 Subject: [PATCH 1/2] fix(hermes): add shared reachability check helper Bug: The reachability check used 'ssh ... grep ... || echo unreachable', which conflated grep's 'no matches found' (exit 1) with SSH failure. This caused clean hosts to be reported as unreachable. Fix: Add scripts/hermes-reachability-check.sh with the pattern: out=$(ssh -o BatchMode=yes root@HOST "grep ... 2>/dev/null; true") if [ $? -ne 0 ]; then verdict="unreachable" elif [ -n "$out" ]; then verdict="violation: $out" else verdict="compliant" fi This correctly distinguishes: - SSH failure (connection/auth/route) -> unreachable - SSH success + grep found matches -> violation - SSH success + grep found nothing -> compliant Evidence: 3 of 4 hosts (Tanko, Mumuni, Koonimo) were reported as 'unreachable' when they were actually compliant. Only Koby (.129) has a real finding (plaintext key in state snapshot). Used by: hermes-key-enforcement, hermes-config-template, hermes-agent-baseline contracts. --- scripts/hermes-reachability-check.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 scripts/hermes-reachability-check.sh diff --git a/scripts/hermes-reachability-check.sh b/scripts/hermes-reachability-check.sh new file mode 100755 index 0000000..9842ccf --- /dev/null +++ b/scripts/hermes-reachability-check.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Shared helper for Hermes contract reachability checks +# Separates SSH exit status from remote command result +# Pattern: remote side always succeeds, so ssh status = connection status only + +hermes_check_host() { + local host=$1 + local pattern=$2 + local path=$3 + + # Remote side always succeeds (grep ...; true), so ssh exit code = connection status only + local out + out=$(ssh -o BatchMode=yes -o ConnectTimeout=3 root@"$host" "grep -RIn '$pattern' '$path' 2>/dev/null; true" 2>/dev/null) + local status=$? + + if [ $status -ne 0 ]; then + echo "$host: UNREACHABLE (ssh exit $status)" + elif [ -n "$out" ]; then + echo "$host: VIOLATION: $out" + else + echo "$host: COMPLIANT (no matches found)" + fi +} -- 2.54.0 From 4e34b7a2a27b944f0bf6aa0e72879f045f3002f9 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 14 Sep 2026 12:01:32 +0000 Subject: [PATCH 2/2] fix(hermes): wire all three contracts to reachability helper The helper was correct but dead code - nothing called it. This commit: 1. Makes the helper runnable standalone: scripts/hermes-reachability-check.sh 2. Wires all THREE contracts to it: - hermes-key-enforcement.prose.md - hermes-config-template.prose.md - hermes-agent-baseline.prose.md 3. Each contract now explicitly instructs to run the helper and interpret the three outcomes 4. States that the bug this replaces was deriving reachability from the remote grep's exit code Files changed (4): - scripts/hermes-reachability-check.sh (standalone mode added) - hermes-key-enforcement.prose.md (reachability section added) - hermes-config-template.prose.md (reachability section added) - hermes-agent-baseline.prose.md (reachability section added) --- hermes-agent-baseline.prose.md | 18 ++++++++++++++++++ hermes-config-template.prose.md | 18 ++++++++++++++++++ hermes-key-enforcement.prose.md | 18 ++++++++++++++++++ scripts/hermes-reachability-check.sh | 11 ++++++++++- 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/hermes-agent-baseline.prose.md b/hermes-agent-baseline.prose.md index fba3a89..8f814b8 100644 --- a/hermes-agent-baseline.prose.md +++ b/hermes-agent-baseline.prose.md @@ -11,6 +11,24 @@ author: Abiba (pi agent) # Hermes Agent Baseline — Canonical Good State +## Reachability Detection + +Before checking agent baseline, verify the host is reachable and can be audited. Use the shared reachability helper from the clone root: + +```bash +# Run on each host to check reachability (Tanko, Mumuni, Koonimo, Koby) +scripts/hermes-reachability-check.sh "api_key:" "/root/.hermes/config.yaml" +# Example: scripts/hermes-reachability-check.sh 192.168.68.122 "api_key:" "/root/.hermes/config.yaml" + +# Expected outcomes: +# - UNREACHABLE: SSH connection failed (host is down) +# - VIOLATION: SSH succeeded and found matches (report the finding) +# - COMPLIANT: SSH succeeded and found no matches (no api_key in config) +# +# NOTE: The bug this replaces was deriving reachability from the remote grep's exit code. +# The correct pattern: remote side always succeeds (grep ...; true), so ssh status = connection only. +``` + ## Quick Restore ```bash diff --git a/hermes-config-template.prose.md b/hermes-config-template.prose.md index a6e3d29..b04d93e 100644 --- a/hermes-config-template.prose.md +++ b/hermes-config-template.prose.md @@ -19,6 +19,24 @@ description: > - agent_keys: map (see Agent Keys section) - infra_endpoints_verified: array +## Reachability Detection + +Before auditing the config template, verify the host is reachable and can be checked. Use the shared reachability helper from the clone root: + +```bash +# Run on each host to check reachability (Tanko, Mumuni, Koonimo, Koby) +scripts/hermes-reachability-check.sh "base_url:" "/root/.hermes/config.yaml" +# Example: scripts/hermes-reachability-check.sh 192.168.68.122 "base_url:" "/root/.hermes/config.yaml" + +# Expected outcomes: +# - UNREACHABLE: SSH connection failed (host is down) +# - VIOLATION: SSH succeeded and found matches (report the finding) +# - COMPLIANT: SSH succeeded and found no matches (no base_url in config) +# +# NOTE: The bug this replaces was deriving reachability from the remote grep's exit code. +# The correct pattern: remote side always succeeds (grep ...; true), so ssh status = connection only. +``` + ## Agent Keys (LiteLLM — Current 2026-07-11) Each agent has a unique LiteLLM API key (virtual key) generated against the LiteLLM diff --git a/hermes-key-enforcement.prose.md b/hermes-key-enforcement.prose.md index 3c5e42c..ee38b0d 100644 --- a/hermes-key-enforcement.prose.md +++ b/hermes-key-enforcement.prose.md @@ -117,6 +117,24 @@ model: api_key_env: LITELLM_API_KEY ``` +## Reachability Detection + +Before checking for hardcoded keys, verify the host is reachable and can be audited. Use the shared reachability helper from the clone root: + +```bash +# Run on each host to check reachability (Tanko, Mumuni, Koonimo, Koby) +scripts/hermes-reachability-check.sh "api_key: sk-" "/root/.hermes/" +# Example: scripts/hermes-reachability-check.sh 192.168.68.122 "api_key: sk-" "/root/.hermes/" + +# Expected outcomes: +# - UNREACHABLE: SSH connection failed (host is down) +# - VIOLATION: SSH succeeded and found matches (report the finding) +# - COMPLIANT: SSH succeeded and found no matches (no hardcoded keys in config) +# +# NOTE: The bug this replaces was deriving reachability from the remote grep's exit code. +# The correct pattern: remote side always succeeds (grep ...; true), so ssh status = connection only. +``` + ## Detection Query Run on any Hermes host to detect violations: diff --git a/scripts/hermes-reachability-check.sh b/scripts/hermes-reachability-check.sh index 9842ccf..ba6ec1b 100755 --- a/scripts/hermes-reachability-check.sh +++ b/scripts/hermes-reachability-check.sh @@ -1,7 +1,6 @@ #!/bin/bash # Shared helper for Hermes contract reachability checks # Separates SSH exit status from remote command result -# Pattern: remote side always succeeds, so ssh status = connection status only hermes_check_host() { local host=$1 @@ -21,3 +20,13 @@ hermes_check_host() { echo "$host: COMPLIANT (no matches found)" fi } + +# Standalone mode: scripts/hermes-reachability-check.sh +if [ "${BASH_SOURCE[0]}" = "${0}" ]; then + if [ $# -ne 3 ]; then + echo "Usage: $0 " >&2 + exit 2 + fi + hermes_check_host "$1" "$2" "$3" + exit 0 +fi -- 2.54.0