Add git-deploy and skip-remote-prep options for fleet E2E harness.

Supports third-party participants deployed via compose pull; includes wormhole prime helper for fresh VPS nodes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
BigBodyCobain
2026-06-14 12:53:36 -06:00
parent 174031479c
commit 96182fe66d
2 changed files with 73 additions and 13 deletions
+49 -13
View File
@@ -4,6 +4,7 @@
Environment:
PETE_SSH / REMOTE_PARTICIPANT_SSH — SSH host for remote participant (default: pete)
E2E_DM_TOR_ONLY=1 — skip disk-inject fallbacks; require Tor replicate-envelope only
E2E_DM_DEPLOY_FROM_GIT=1 — remote participant: git pull + compose (no harness SCP patches)
E2E_DM_FRESH_BACKEND=1 — recreate local lean E2E backend before run
docker-compose.participant.yml — deploy lean participant on any fleet peer
"""
@@ -40,6 +41,16 @@ TOR_ONLY = os.environ.get("E2E_DM_TOR_ONLY", "0").strip().lower() not in {
"false",
"no",
}
DEPLOY_FROM_GIT = os.environ.get("E2E_DM_DEPLOY_FROM_GIT", "0").strip().lower() not in {
"0",
"false",
"no",
}
SKIP_REMOTE_PREP = os.environ.get("E2E_DM_SKIP_REMOTE_PREP", "0").strip().lower() not in {
"0",
"false",
"no",
}
PETE_ONION = os.environ.get("REMOTE_PARTICIPANT_ONION") or os.environ.get(
"PETE_ONION",
"nwbs4ur2usffb7lk3vyffhaqrijry544vmfjkk3qbrhvoh4v26fwxlid.onion:8000",
@@ -1549,6 +1560,28 @@ print(json.dumps({{"ok": True, "drained": drained}}))
def _restart_pete_backend() -> None:
if DEPLOY_FROM_GIT:
remote_cmd = (
"cd /home/ubuntu/Shadowbroker && "
"git fetch origin && git reset --hard origin/main && "
"docker compose -f docker-compose.yml -f docker-compose.participant.yml pull && "
"docker compose -f docker-compose.yml -f docker-compose.participant.yml up -d && "
"sleep 8 && "
"docker exec shadowbroker-backend sh -c "
"'rm -f /app/data/dm_relay.json /app/data/private_outbox/sealed_private_outbox.json "
"/app/data/dm_alias/wormhole_dm_mls.json /app/data/dm_alias_rust/wormhole_dm_mls_rust.bin'"
)
proc = subprocess.run(
["ssh", "-o", "BatchMode=yes", SSH_PETE, remote_cmd],
capture_output=True,
text=True,
timeout=300,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or "remote git deploy failed")
time.sleep(int(os.environ.get("E2E_DM_PETE_BOOTSTRAP_WAIT_S", "90")))
return
repo_root = os.path.dirname(os.path.dirname(__file__))
patch_files = [
("backend/services/mesh/mesh_dm_relay.py", "/tmp/mesh_dm_relay.py"),
@@ -2526,21 +2559,24 @@ def main() -> int:
print("== prep: ensure local lean E2E backend (MESH_ONLY) ==")
_ensure_local_e2e_backend(recreate=FRESH_BACKEND)
print("== prep: restart Pete backend (lean participant, responsive API) ==")
_restart_pete_backend()
if not SKIP_REMOTE_PREP:
print("== prep: restart Pete backend (lean participant, responsive API) ==")
_restart_pete_backend()
print("== prep: prime Pete wormhole/Tor ==")
pete_runtime: dict = {}
for attempt in range(1, 7):
pete_runtime = _prime_pete_dm_wormhole()
print(json.dumps({"attempt": attempt, **pete_runtime}, indent=2))
running = bool((pete_runtime.get("runtime") or {}).get("running"))
tier = str((pete_runtime.get("runtime") or {}).get("transport_tier") or "")
if running and tier != "public_degraded":
break
time.sleep(30)
print("== prep: prime Pete wormhole/Tor ==")
pete_runtime: dict = {}
for attempt in range(1, 7):
pete_runtime = _prime_pete_dm_wormhole()
print(json.dumps({"attempt": attempt, **pete_runtime}, indent=2))
running = bool((pete_runtime.get("runtime") or {}).get("running"))
tier = str((pete_runtime.get("runtime") or {}).get("transport_tier") or "")
if running and tier != "public_degraded":
break
time.sleep(30)
else:
raise RuntimeError(f"Pete wormhole did not become ready: {pete_runtime}")
else:
raise RuntimeError(f"Pete wormhole did not become ready: {pete_runtime}")
print("== prep: skip remote restart (E2E_DM_SKIP_REMOTE_PREP=1) ==")
print("== warmup: prime Tor to Pete ==")
_warmup_tor()
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env python3
"""One-shot wormhole/Tor prime for fleet participant nodes (run inside backend container)."""
import json
from routers.ai_intel import _write_env_value
from services.config import get_settings
from services.tor_hidden_service import tor_service
from services.wormhole_settings import write_wormhole_settings
from services.wormhole_supervisor import connect_wormhole
port = int(get_settings().MESH_ARTI_SOCKS_PORT or 9050)
write_wormhole_settings(
enabled=True,
transport="tor_arti",
socks_proxy=f"socks5h://127.0.0.1:{port}",
socks_dns=True,
anonymous_mode=True,
)
tor = tor_service.start(target_port=8000)
if tor.get("ok"):
_write_env_value("MESH_ARTI_ENABLED", "true")
get_settings.cache_clear()
runtime = connect_wormhole(reason="participant_warmup")
print(json.dumps({"ok": True, "tor": tor, "runtime": runtime}))