hermes-agent/tests/gateway/relay
Ben Barclay 2c6e266e88
fix(relay): trigger self-provision on relay-config + NAS token, not is_managed() (#48724)
self_provision_if_managed() gated on is_managed(), but is_managed() means
"NixOS/package-manager-managed" (it keys on HERMES_MANAGED or a ~/.hermes/.managed
marker) — NOT "NAS-hosted". A NAS-provisioned Fly agent sets NEITHER, so the gate
was always False and relay self-provision SILENTLY no-oped on exactly the hosted
agents it was built for. Caught live: a staging agent with GATEWAY_RELAY_URL
correctly stamped logged "No messaging platforms enabled" and never dialed the
connector; HERMES_MANAGED was unset on the machine. The unit tests had mocked
is_managed()->True, so they passed while the real trigger never fired (mocked-
trigger blind spot).

Fix: drop the is_managed() gate and rename self_provision_if_managed ->
self_provision_relay. The real trigger is now "relay_url() set + no pinned secret
+ a resolvable NAS token", which is both NAS-independent and self-guarding:
  - NAS-hosted agent: GATEWAY_RELAY_URL + no pinned secret + bootstrapped NAS
    token -> self-provisions.
  - Self-hosted + `hermes gateway enroll`: pinned GATEWAY_RELAY_SECRET -> skipped
    (existing secret-present guard).
  - Self-hosted, unenrolled, no NAS identity: resolve_nous_access_token() fails
    -> graceful no-op (existing fail-soft path).

Security: unchanged trust model. The connector still derives tenant from the
validated NAS token; this only broadens WHEN the provision attempt fires, and
every broadened case is still guarded by token-resolution + pinned-secret-skip.

Tests: replaced the (wrong) "skips when not managed" test with a regression test
proving a NAS host where is_managed()==False STILL provisions; renamed all call
sites; added a "no NAS token -> non-fatal skip" test for the self-hosted branch.
88 relay tests pass.

Relay-adapter lane. EXPERIMENTAL.
2026-06-19 01:01:24 +00:00
..
__init__.py feat(relay): experimental CapabilityDescriptor schema 2026-06-17 16:37:45 -07:00
stub_connector.py feat(relay): WS-only inbound on the gateway adapter (Phase 3) (#48294) 2026-06-19 09:33:15 +10:00
test_auth.py feat(relay): connector⇄gateway channel auth + signed-HTTP inbound receiver + enroll CLI (#48147) 2026-06-18 12:01:54 +10:00
test_contract_doc_conformance.py test(gateway): enforce relay contract-doc ⟷ Python conformance 2026-06-17 16:37:45 -07:00
test_descriptor.py feat(relay): experimental CapabilityDescriptor schema 2026-06-17 16:37:45 -07:00
test_descriptor_from_entry.py feat(relay): derive descriptor from PlatformEntry 2026-06-17 16:37:45 -07:00
test_no_stub_leak.py test(relay): assert connector stub never leaks into production paths 2026-06-17 16:37:45 -07:00
test_relay_adapter.py feat(relay): generic RelayAdapter advertising negotiated capabilities 2026-06-17 16:37:45 -07:00
test_relay_follow_up.py feat(gateway): token-less follow_up outbound op (A2 capability action) 2026-06-17 16:37:45 -07:00
test_relay_interrupt.py feat(relay): WS-only inbound on the gateway adapter (Phase 3) (#48294) 2026-06-19 09:33:15 +10:00
test_relay_registration.py test(gateway): live ws-transport round-trip + config-driven registration 2026-06-17 16:37:45 -07:00
test_relay_roundtrip.py feat(relay): transport protocol + test-only stub connector 2026-06-17 16:37:45 -07:00
test_relay_roundtrip_telegram.py test(gateway): Telegram relay round-trip (Phase 1 generalization proof) 2026-06-17 16:37:45 -07:00
test_relay_sheds_crypto.py feat(relay): WS-only inbound on the gateway adapter (Phase 3) (#48294) 2026-06-19 09:33:15 +10:00
test_self_provision.py fix(relay): trigger self-provision on relay-config + NAS token, not is_managed() (#48724) 2026-06-19 01:01:24 +00:00
test_ws_transport.py test(gateway): live ws-transport round-trip + config-driven registration 2026-06-17 16:37:45 -07:00