fix(tor): heal torrc at boot, and report liveness instead of leftovers

Three of five reachable fleet nodes had Tor completely dead — Home said
"Connected" on all of them — and shipping the generator fix alone would
have repaired none of them. Two additions close that loop.

heal_on_boot (wired into the bootstrap repair chain): regenerate torrc
from current config with the fixed generator, and apply-and-restart ONLY
if the live file drifted or Tor is not answering on 9050. A healthy node
is left untouched. Without this, regenerate_torrc runs only from the Tor
RPC handlers and package install, so a node carrying a poisoned torrc
keeps it until someone happens to toggle a Tor setting — and worse, the
still-running OLD binary re-poisons on any such toggle: observed live on
the dev node at 07:20, when the running daemon rewrote torrc with the
unbindable gateway line hours after it had been hand-fixed. The heal
makes the fix self-applying on every restart, i.e. the OTA itself.

ServerInfo gains tor-running, populated by a real connect to
127.0.0.1:9050 each state refresh. tor-address is read from the
hidden-service hostname file, which OUTLIVES a dead daemon — it is a
configuration artifact, and the dashboard treating it as liveness is
precisely why three dead nodes showed "Connected" for days. Liveness now
comes only from the probe; the address stays a separate fact.

The heal reports the truth: it re-probes after restarting and warns if
Tor still is not answering, rather than assuming success.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-09 07:50:39 -04:00
co-authored by Claude Fable 5
parent e5a8fce198
commit aaa0651c8d
5 changed files with 101 additions and 2 deletions
+5
View File
@@ -96,6 +96,11 @@ impl Server {
}
}
data.server_info.tor_address = docker_packages::read_tor_address("archipelago").await;
// Liveness comes from a probe, never from the presence of an onion
// address: read_tor_address reads a hostname file that outlives the
// daemon, which is why the dashboard showed "Connected" on nodes whose
// Tor had been dead for days.
data.server_info.tor_running = crate::api::rpc::tor::check_tor_running().await;
if let Some(ref tor) = data.server_info.tor_address {
data.server_info.node_address = Some(identity.node_address(tor));
}