Ship DM connect delivery, fleet pubkey lookup, OpenClaw Infonet agent, and relay auto-wormhole.

Auto-relay connect DMs with End Contact severing, signed fleet prekey lookup,
OpenClaw private Infonet channel intents, headless relay Tor bootstrap on redeploy,
and swarm/DM live verification scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
BigBodyCobain
2026-06-12 02:15:56 -06:00
parent d48a0cdace
commit 89d6bb8fb9
52 changed files with 4211 additions and 339 deletions
+5
View File
@@ -0,0 +1,5 @@
import sys
import main
peer = sys.argv[1] if len(sys.argv) > 1 else ""
print(main.compose_wormhole_dm(peer_id=peer, peer_dh_pub="", plaintext="fleet-dm-probe"))
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""Print DM readiness: identities, contacts, peers, transport."""
from __future__ import annotations
import json
def main() -> None:
out: dict = {"ok": True}
try:
from services.wormhole_supervisor import get_wormhole_state, get_transport_tier
out["wormhole"] = get_wormhole_state()
out["transport_tier"] = get_transport_tier()
except Exception as exc:
out["wormhole_error"] = str(exc)
try:
from services.mesh.mesh_wormhole_persona import get_dm_identity
out["dm_identity"] = get_dm_identity()
except Exception as exc:
out["dm_identity_error"] = str(exc)
try:
from services.mesh.mesh_wormhole_contacts import list_wormhole_dm_contacts
contacts = list_wormhole_dm_contacts()
out["dm_contacts"] = {
k: {
"trustLevel": v.get("trustLevel"),
"dmIdentityId": v.get("dmIdentityId"),
"invitePinnedPrekeyLookupHandle": bool(v.get("invitePinnedPrekeyLookupHandle")),
"verifiedFirstContact": v.get("verifiedFirstContact"),
"remotePrekeyLookupMode": v.get("remotePrekeyLookupMode"),
}
for k, v in (contacts or {}).items()
}
out["dm_contact_count"] = len(contacts or {})
except Exception as exc:
out["dm_contacts_error"] = str(exc)
try:
import main as main_mod
out["local_onion"] = main_mod._local_infonet_peer_url()
out["node_enabled"] = main_mod._participant_node_enabled()
out["arti_ready"] = main_mod._check_arti_ready()
out["push_peers"] = main_mod._filter_infonet_peer_urls(
__import__(
"services.mesh.mesh_router", fromlist=["authenticated_push_peer_urls"]
).authenticated_push_peer_urls()
)
except Exception as exc:
out["peer_runtime_error"] = str(exc)
try:
from services.mesh.mesh_private_outbox import private_delivery_outbox
pending = private_delivery_outbox.list_items(exposure="ordinary")
dm_pending = [i for i in pending if str(i.get("lane", "")) == "dm"]
out["dm_outbox_pending"] = len(dm_pending)
out["dm_outbox_samples"] = [
{
"id": i.get("id"),
"release_state": i.get("release_state"),
"status": (i.get("status") or {}).get("code"),
"recipient_id": (i.get("payload") or {}).get("recipient_id"),
}
for i in dm_pending[:5]
]
except Exception as exc:
out["outbox_error"] = str(exc)
try:
from services.mesh.mesh_dm_relay import dm_relay
out["dm_relay_stats"] = dict(dm_relay._stats)
out["dm_mailbox_keys"] = len(dm_relay._mailboxes)
except Exception as exc:
out["relay_error"] = str(exc)
print(json.dumps(out, indent=2, default=str))
if __name__ == "__main__":
main()
+751
View File
@@ -0,0 +1,751 @@
#!/usr/bin/env python3
"""Live E2E: short-address lookup -> contact request -> Pete mailbox."""
from __future__ import annotations
import json
import os
import subprocess
import sys
import textwrap
import time
import urllib.error
import urllib.parse
import urllib.request
API = os.environ.get("SHADOWBROKER_API", "http://127.0.0.1:8000")
MARKER = os.environ.get("E2E_DM_MARKER", f"dm-short-addr-e2e-{int(time.time())}")
REPLY_MARKER = os.environ.get("E2E_DM_REPLY_MARKER", f"{MARKER}-reply")
PETE_HANDLE = os.environ.get("PETE_DM_SHORT_HANDLE", "").strip()
PETE_LOOKUP_PEER_URL = os.environ.get("PETE_DM_LOOKUP_PEER_URL", "").strip()
FRESH_BACKEND = os.environ.get("E2E_DM_FRESH_BACKEND", "1").strip().lower() not in {
"0",
"false",
"no",
}
SSH_PETE = os.environ.get("PETE_SSH", "pete")
PETE_ONION = os.environ.get(
"PETE_ONION",
"nwbs4ur2usffb7lk3vyffhaqrijry544vmfjkk3qbrhvoh4v26fwxlid.onion:8000",
).strip()
def _docker_json(method: str, path: str, body: dict | None = None, *, admin_key: str = "", timeout_s: int = 30) -> dict:
payload = ["docker", "exec", "shadowbroker-backend", "curl", "-s", "--max-time", str(timeout_s)]
if admin_key:
payload.extend(["-H", f"X-Admin-Key: {admin_key}"])
if body is not None:
payload.extend(["-H", "Content-Type: application/json", "-X", method.upper(), "-d", json.dumps(body)])
else:
payload.extend(["-X", method.upper()])
payload.append(f"http://127.0.0.1:8000{path}")
proc = subprocess.run(payload, capture_output=True, text=True, timeout=timeout_s + 15, check=False)
raw = (proc.stdout or "").strip()
if not raw:
raise RuntimeError(proc.stderr.strip() or f"{method} {path} produced no response")
parsed = json.loads(raw)
if isinstance(parsed, dict) and parsed.get("detail") == "private_delivery_item_not_found" and method.upper() == "POST":
return parsed
return parsed if isinstance(parsed, dict) else {"ok": False, "detail": "invalid json response"}
def _json(method: str, path: str, body: dict | None = None, *, admin_key: str = "") -> dict:
data = None
headers = {"Content-Type": "application/json"}
if admin_key:
headers["X-Admin-Key"] = admin_key
if body is not None:
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
req = urllib.request.Request(f"{API}{path}", data=data, headers=headers, method=method.upper())
try:
with urllib.request.urlopen(req, timeout=300) as resp:
return json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as exc:
detail = exc.read().decode("utf-8", errors="replace")
raise RuntimeError(f"{method} {path} -> {exc.code}: {detail}") from exc
def _docker_admin_key() -> str:
proc = subprocess.run(
["docker", "exec", "shadowbroker-backend", "printenv", "ADMIN_KEY"],
capture_output=True,
text=True,
check=True,
)
return proc.stdout.strip()
def _ssh_pete_admin_key() -> str:
proc = subprocess.run(
["ssh", "-o", "BatchMode=yes", SSH_PETE, "docker exec shadowbroker-backend printenv ADMIN_KEY"],
capture_output=True,
text=True,
check=True,
)
return proc.stdout.strip()
def _ensure_pete_invite(pete_admin: str) -> tuple[str, str]:
if PETE_HANDLE:
lookup = PETE_LOOKUP_PEER_URL or (
f"http://{PETE_ONION}" if PETE_ONION else ""
)
return PETE_HANDLE, lookup.rstrip("/")
proc = subprocess.run(
[
"ssh",
"-o",
"BatchMode=yes",
SSH_PETE,
f"curl -s -H 'X-Admin-Key: {pete_admin}' 'http://127.0.0.1:8000/api/wormhole/dm/invite?label=e2e-live'",
],
capture_output=True,
text=True,
check=True,
)
invite = json.loads(proc.stdout)
payload = dict(invite.get("invite", {}).get("payload", {}) or {})
handle = str(payload.get("prekey_lookup_handle", "") or "").strip()
lookup_peer_url = str(payload.get("lookup_peer_url", "") or "").strip().rstrip("/")
if not handle:
raise RuntimeError(f"could not mint Pete short handle: {invite}")
return handle, lookup_peer_url
def _docker_python(code: str) -> dict:
proc = subprocess.run(
["docker", "exec", "shadowbroker-backend", "python", "-c", code],
capture_output=True,
text=True,
timeout=600,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or "docker python failed")
line = proc.stdout.strip().splitlines()[-1]
return json.loads(line)
def _restart_local_backend() -> None:
"""Clear in-memory DM relay state (MESH_DM_PERSIST_SPOOL=false) before a repeat run."""
proc = subprocess.run(
[
"docker",
"compose",
"-f",
"docker-compose.yml",
"-f",
"docker-compose.build.yml",
"restart",
"backend",
],
capture_output=True,
text=True,
timeout=180,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or "backend restart failed")
deadline = time.time() + 120
while time.time() < deadline:
probe = subprocess.run(
[
"docker",
"exec",
"shadowbroker-backend",
"curl",
"-sf",
"--max-time",
"5",
"http://127.0.0.1:8000/api/health",
],
capture_output=True,
text=True,
check=False,
)
if probe.returncode == 0:
print("local backend restarted and healthy")
return
time.sleep(3)
raise RuntimeError("backend did not become healthy after restart")
def _wait_hidden_transport_ready(*, timeout_s: int = 120) -> dict:
code = (
"import json, time\n"
"from services.mesh.mesh_private_dispatcher import _anonymous_dm_hidden_transport_enforced\n"
f"deadline = time.time() + {int(timeout_s)}\n"
"while time.time() < deadline:\n"
" if _anonymous_dm_hidden_transport_enforced():\n"
" print(json.dumps({'ok': True}))\n"
" break\n"
" time.sleep(2)\n"
"else:\n"
" print(json.dumps({'ok': False, 'detail': 'hidden transport not ready'}))\n"
)
return _docker_python(code)
def _release_dm_outbox(admin_key: str, outbox_id: str, *, timeout_s: int = 180) -> dict:
outbox_id = str(outbox_id or "").strip()
if not outbox_id:
return {"ok": False, "detail": "missing outbox_id"}
_docker_json(
"POST",
f"/api/wormhole/private-delivery/{outbox_id}/action",
{"action": "relay"},
admin_key=admin_key,
)
deadline = time.time() + timeout_s
while time.time() < deadline:
status = _docker_json("GET", "/api/wormhole/status", admin_key=admin_key)
items = list((status.get("private_delivery") or {}).get("items") or [])
item = next((entry for entry in items if str(entry.get("id", "")) == outbox_id), None)
if item and str(item.get("release_state", "")) == "delivered":
return {"ok": True, "item": item}
time.sleep(3)
return {"ok": False, "detail": "private release did not complete in time", "outbox_id": outbox_id}
def _drain_pete_request_mailbox() -> None:
drain_code = textwrap.dedent(
"""
import json, secrets, time, urllib.request
from services.mesh.mesh_protocol import PROTOCOL_VERSION
from services.mesh.mesh_wormhole_persona import get_dm_identity, sign_dm_wormhole_event
def _poll_once():
identity = get_dm_identity()
agent_id = str(identity.get("node_id") or "")
claims = [{"type": "requests", "token": "e2e-drain"}]
signed = sign_dm_wormhole_event(
event_type="dm_poll",
payload={"mailbox_claims": claims, "agent_id": agent_id},
)
body = {
"agent_id": agent_id,
"mailbox_claims": claims,
"timestamp": int(time.time()),
"nonce": secrets.token_hex(8),
"public_key": str(signed.get("public_key") or ""),
"public_key_algo": str(signed.get("public_key_algo") or ""),
"signature": str(signed.get("signature") or ""),
"sequence": int(signed.get("sequence") or 0),
"protocol_version": str(signed.get("protocol_version") or PROTOCOL_VERSION),
}
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
req = urllib.request.Request(
"http://127.0.0.1:8000/api/mesh/dm/poll",
data=data,
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req, timeout=60) as resp:
return json.loads(resp.read().decode("utf-8"))
drained = 0
for _ in range(8):
payload = _poll_once()
count = int(payload.get("count", 0) or 0)
drained += count
if count <= 0 and not payload.get("has_more"):
break
time.sleep(1)
print(json.dumps({"ok": True, "drained": drained}))
"""
).strip()
result = _ssh_pete_python(drain_code)
print(f"Pete request mailbox drain: {result.get('drained', 0)} message(s)")
def _warmup_tor() -> None:
"""Prime local Arti SOCKS before fleet lookups (cold Tor can exceed lookup budgets)."""
if not PETE_ONION:
return
proc = subprocess.run(
[
"docker",
"exec",
"shadowbroker-backend",
"curl",
"-s",
"-o",
"/dev/null",
"-w",
"%{http_code}",
"--max-time",
"120",
"--socks5-hostname",
"127.0.0.1:9050",
f"http://{PETE_ONION}/api/health",
],
capture_output=True,
text=True,
timeout=180,
check=False,
)
code = (proc.stdout or "").strip()
print(f"Tor warmup Pete health: {code or proc.stderr.strip() or 'failed'}")
def _ssh_pete_python(code: str) -> dict:
# Pipe script stdin to Pete's running backend container — avoids Windows
# docker-exec base64 bugs and SSH command-line length limits on long polls.
proc = subprocess.run(
[
"ssh",
"-o",
"BatchMode=yes",
SSH_PETE,
"docker exec -i shadowbroker-backend python",
],
input=code.encode("utf-8"),
capture_output=True,
timeout=300,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or "pete python failed")
lines = [line for line in proc.stdout.strip().splitlines() if line.strip()]
if not lines:
raise RuntimeError(proc.stderr.strip() or "pete python produced no output")
return json.loads(lines[-1])
def main() -> int:
if FRESH_BACKEND:
print("== prep: restart local backend for clean in-memory DM relay ==")
_restart_local_backend()
print("== prep: drain stale Pete request mailbox ==")
_drain_pete_request_mailbox()
print("== warmup: prime Tor to Pete ==")
_warmup_tor()
print("== warmup: wait for anonymous hidden transport ==")
hidden = _wait_hidden_transport_ready()
print(json.dumps(hidden, indent=2))
if not hidden.get("ok"):
raise RuntimeError(f"hidden transport not ready: {hidden}")
local_admin = _docker_admin_key()
pete_admin = _ssh_pete_admin_key()
handle, lookup_peer_url = _ensure_pete_invite(pete_admin)
print(f"Pete short handle: {handle}")
if lookup_peer_url:
print(f"Pete lookup peer: {lookup_peer_url}")
print("== step 1: fleet pubkey lookup from local ==")
lookup_path = f"/api/mesh/dm/pubkey?lookup_token={handle}"
if lookup_peer_url:
lookup_path += f"&lookup_peer_url={urllib.parse.quote(lookup_peer_url, safe='')}"
lookup = _json("GET", lookup_path)
if not lookup.get("ok") or not lookup.get("agent_id") or not lookup.get("dh_pub_key"):
print(json.dumps(lookup, indent=2))
raise RuntimeError("pubkey fleet lookup failed")
pete_id = str(lookup["agent_id"])
pete_dh = str(lookup.get("dh_pub_key") or "")
print(f"resolved Pete agent_id: {pete_id}")
print("== step 2: send contact request from local ==")
send_code = (
"import json\n"
"from services.openclaw_infonet import send_contact_request\n"
f"result = send_contact_request(lookup_token={json.dumps(handle)}, note={json.dumps(MARKER)}, lookup_peer_url={json.dumps(lookup_peer_url)})\n"
"print(json.dumps({"
"'ok': bool(result.get('ok')), "
"'send': result, "
"'msg_id': result.get('msg_id',''), "
"'sender_id': result.get('sender_id',''), "
"'recipient_id': result.get('recipient_id','')"
"}))\n"
)
send_result = _docker_python(send_code)
print(json.dumps(send_result, indent=2))
if not send_result.get("ok"):
raise RuntimeError(f"local send failed: {send_result}")
msg_id = str(send_result.get("msg_id", "") or "")
print("== step 2b: approve relay release and wait for fleet push ==")
outbox_id = str((send_result.get("send") or {}).get("outbox_id", "") or "")
release = _release_dm_outbox(local_admin, outbox_id)
print(json.dumps(release, indent=2))
if not release.get("ok"):
raise RuntimeError(f"private release failed: {release}")
print("== step 3: wait for fleet replication, poll Pete relay ==")
# Hit the running uvicorn process via localhost HTTP — dm_relay is in-memory
# and is not visible to one-off `docker exec python` shells.
poll_code = textwrap.dedent(
f"""
import json, secrets, time, urllib.error, urllib.request
from services.mesh.mesh_protocol import PROTOCOL_VERSION
from services.mesh.mesh_wormhole_persona import get_dm_identity, sign_dm_wormhole_event
msg_id = {json.dumps(msg_id)}
marker = {json.dumps(MARKER)}
sender_id = {json.dumps(send_result.get('sender_id', ''))}
def _mailbox_claims():
return [{{"type": "requests", "token": "e2e-poll"}}]
def _poll_once():
identity = get_dm_identity()
agent_id = str(identity.get("node_id") or "")
claims = _mailbox_claims()
signed = sign_dm_wormhole_event(
event_type="dm_poll",
payload={{"mailbox_claims": claims, "agent_id": agent_id}},
)
body = {{
"agent_id": agent_id,
"mailbox_claims": claims,
"timestamp": int(time.time()),
"nonce": secrets.token_hex(8),
"public_key": str(signed.get("public_key") or ""),
"public_key_algo": str(signed.get("public_key_algo") or ""),
"signature": str(signed.get("signature") or ""),
"sequence": int(signed.get("sequence") or 0),
"protocol_version": str(signed.get("protocol_version") or PROTOCOL_VERSION),
}}
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
req = urllib.request.Request(
"http://127.0.0.1:8000/api/mesh/dm/poll",
data=data,
headers={{"Content-Type": "application/json"}},
method="POST",
)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.loads(resp.read().decode("utf-8"))
hit = None
for attempt in range(30):
time.sleep(4)
try:
payload = _poll_once()
except urllib.error.HTTPError as exc:
detail = exc.read().decode("utf-8", errors="replace")
if exc.code == 202:
continue
print(json.dumps({{"ok": False, "detail": f"poll http {{exc.code}}: {{detail}}"}}))
break
except Exception as exc:
print(json.dumps({{"ok": False, "detail": str(exc) or type(exc).__name__}}))
break
for message in list(payload.get("messages") or []):
if str(message.get("msg_id", "")) == msg_id:
hit = message
break
if marker in str(message.get("ciphertext", "")):
hit = message
break
if hit:
print(json.dumps({{"ok": True, "attempt": attempt, "msg_id": msg_id}}))
break
else:
print(json.dumps({{"ok": False, "detail": "request not in Pete relay mailboxes"}}))
"""
).strip()
poll = _ssh_pete_python(poll_code)
print(json.dumps(poll, indent=2))
if not poll.get("ok"):
raise RuntimeError(f"Pete did not receive request: {poll}")
print("== step 4: Pete bootstrap-decrypt contact offer ==")
decrypt_code = textwrap.dedent(
f"""
import json, secrets, time, urllib.error, urllib.request
from services.mesh.mesh_protocol import PROTOCOL_VERSION
from services.mesh.mesh_wormhole_persona import get_dm_identity, sign_dm_wormhole_event
from services.mesh.mesh_wormhole_prekey import bootstrap_decrypt_from_sender
sender_id = {json.dumps(send_result.get('sender_id', ''))}
msg_id = {json.dumps(msg_id)}
identity = get_dm_identity()
agent_id = str(identity.get("node_id") or "")
claims = [{{"type": "requests", "token": "e2e-poll"}}]
signed = sign_dm_wormhole_event(
event_type="dm_poll",
payload={{"mailbox_claims": claims, "agent_id": agent_id}},
)
body = {{
"agent_id": agent_id,
"mailbox_claims": claims,
"timestamp": int(time.time()),
"nonce": secrets.token_hex(8),
"public_key": str(signed.get("public_key") or ""),
"public_key_algo": str(signed.get("public_key_algo") or ""),
"signature": str(signed.get("signature") or ""),
"sequence": int(signed.get("sequence") or 0),
"protocol_version": str(signed.get("protocol_version") or PROTOCOL_VERSION),
}}
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
req = urllib.request.Request(
"http://127.0.0.1:8000/api/mesh/dm/poll",
data=data,
headers={{"Content-Type": "application/json"}},
method="POST",
)
ciphertext = ""
try:
with urllib.request.urlopen(req, timeout=120) as resp:
payload = json.loads(resp.read().decode("utf-8"))
for message in list(payload.get("messages") or []):
if str(message.get("msg_id", "")) == msg_id:
ciphertext = str(message.get("ciphertext", "") or "")
break
except Exception as exc:
print(json.dumps({{"ok": False, "detail": str(exc) or type(exc).__name__}}))
elif not ciphertext:
print(json.dumps({{"ok": False, "detail": "ciphertext missing on Pete"}}))
else:
dec = bootstrap_decrypt_from_sender(sender_id, ciphertext)
print(json.dumps({{"ok": bool(dec.get("ok")), "plaintext": dec.get("result", ""), "detail": dec.get("detail", "")}}))
"""
).strip()
decrypted = _ssh_pete_python(decrypt_code)
print(json.dumps(decrypted, indent=2))
if not decrypted.get("ok") or MARKER not in str(decrypted.get("plaintext", "")):
raise RuntimeError(f"Pete could not decrypt contact offer: {decrypted}")
local_sender_id = str(send_result.get("sender_id", "") or "")
if not local_sender_id:
raise RuntimeError("local sender_id missing from send result")
print("== step 5: Pete accepts contact request ==")
accept_code = textwrap.dedent(
f"""
import json, os
os.environ.setdefault("SB_API_BASE", "http://127.0.0.1:8000")
from services.openclaw_infonet import send_contact_accept
result = send_contact_accept(peer_id={json.dumps(local_sender_id)})
print(json.dumps({{
"ok": bool(result.get("ok")),
"msg_id": result.get("msg_id", ""),
"shared_alias": result.get("shared_alias", ""),
"detail": result.get("detail", ""),
}}))
"""
).strip()
accept_result = _ssh_pete_python(accept_code)
print(json.dumps(accept_result, indent=2))
if not accept_result.get("ok"):
raise RuntimeError(f"Pete accept failed: {accept_result}")
accept_msg_id = str(accept_result.get("msg_id", "") or "")
print("== step 5b: release Pete accept to fleet relay ==")
print(json.dumps(_ssh_pete_python(release_code), indent=2))
print("== step 6: local polls and decrypts contact accept ==")
local_accept_code = textwrap.dedent(
f"""
import json, secrets, time, urllib.error, urllib.request
from services.mesh.mesh_protocol import PROTOCOL_VERSION
from services.mesh.mesh_wormhole_dead_drop import parse_contact_consent
from services.mesh.mesh_wormhole_persona import get_dm_identity, sign_dm_wormhole_event
from services.mesh.mesh_wormhole_prekey import bootstrap_decrypt_from_sender
sender_id = {json.dumps(local_sender_id)}
accept_msg_id = {json.dumps(accept_msg_id)}
pete_id = {json.dumps(pete_id)}
identity = get_dm_identity()
agent_id = str(identity.get("node_id") or "")
claims = [{{"type": "requests", "token": "e2e-local-poll"}}]
signed = sign_dm_wormhole_event(
event_type="dm_poll",
payload={{"mailbox_claims": claims, "agent_id": agent_id}},
)
body = {{
"agent_id": agent_id,
"mailbox_claims": claims,
"timestamp": int(time.time()),
"nonce": secrets.token_hex(8),
"public_key": str(signed.get("public_key") or ""),
"public_key_algo": str(signed.get("public_key_algo") or ""),
"signature": str(signed.get("signature") or ""),
"sequence": int(signed.get("sequence") or 0),
"protocol_version": str(signed.get("protocol_version") or PROTOCOL_VERSION),
}}
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
hit = None
for attempt in range(30):
time.sleep(4)
req = urllib.request.Request(
"http://127.0.0.1:8000/api/mesh/dm/poll",
data=data,
headers={{"Content-Type": "application/json"}},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=120) as resp:
payload = json.loads(resp.read().decode("utf-8"))
except Exception as exc:
print(json.dumps({{"ok": False, "detail": str(exc) or type(exc).__name__}}))
break
for message in list(payload.get("messages") or []):
if str(message.get("msg_id", "")) == accept_msg_id:
hit = message
break
if str(message.get("sender_id", "")) == pete_id:
hit = message
break
if hit:
break
if not hit:
print(json.dumps({{"ok": False, "detail": "accept not in local requests mailbox"}}))
else:
ciphertext = str(hit.get("ciphertext", "") or "")
dec = bootstrap_decrypt_from_sender(pete_id, ciphertext)
consent = parse_contact_consent(str(dec.get("result", "") or ""))
print(json.dumps({{
"ok": bool(dec.get("ok") and consent and consent.get("kind") == "contact_accept"),
"shared_alias": str((consent or {{}}).get("shared_alias", "") or ""),
"detail": dec.get("detail", ""),
}}))
"""
).strip()
local_accept = _docker_python(local_accept_code)
print(json.dumps(local_accept, indent=2))
if not local_accept.get("ok") or not local_accept.get("shared_alias"):
raise RuntimeError(f"local could not decrypt contact accept: {local_accept}")
print("== step 7: local sends shared DM reply ==")
shared_send_code = textwrap.dedent(
f"""
import json, os
os.environ.setdefault("SB_API_BASE", "http://127.0.0.1:8000")
from services.mesh.mesh_wormhole_dead_drop import derive_dead_drop_token_pair
from services.openclaw_infonet import send_dm
token_pair = derive_dead_drop_token_pair(
peer_id={json.dumps(pete_id)},
peer_dh_pub={json.dumps(pete_dh)},
)
if not token_pair.get("ok"):
print(json.dumps(token_pair))
else:
result = send_dm(
{json.dumps(pete_id)},
{json.dumps(REPLY_MARKER)},
delivery_class="shared",
recipient_token=str(token_pair.get("current") or ""),
)
print(json.dumps({{
"ok": bool(result.get("ok")),
"msg_id": result.get("msg_id", ""),
"detail": result.get("detail", ""),
}}))
"""
).strip()
shared_send = _docker_python(shared_send_code)
print(json.dumps(shared_send, indent=2))
if not shared_send.get("ok"):
raise RuntimeError(f"local shared DM send failed: {shared_send}")
shared_msg_id = str(shared_send.get("msg_id", "") or "")
print("== step 7b: release local shared DM to fleet relay ==")
print(json.dumps(_docker_python(release_code), indent=2))
print("== step 8: Pete polls shared mailbox and decrypts reply ==")
shared_poll_code = textwrap.dedent(
f"""
import json, secrets, time, urllib.error, urllib.request
from services.mesh.mesh_protocol import PROTOCOL_VERSION
from services.mesh.mesh_wormhole_dead_drop import derive_dead_drop_token_pair
from services.mesh.mesh_wormhole_persona import get_dm_identity, sign_dm_wormhole_event
sender_id = {json.dumps(local_sender_id)}
shared_msg_id = {json.dumps(shared_msg_id)}
marker = {json.dumps(REPLY_MARKER)}
bundle = __import__(
"services.mesh.mesh_wormhole_prekey",
fromlist=["fetch_dm_prekey_bundle"],
).fetch_dm_prekey_bundle(agent_id=sender_id)
sender_dh = str(bundle.get("dh_pub_key") or "")
token_pair = derive_dead_drop_token_pair(peer_id=sender_id, peer_dh_pub=sender_dh)
if not token_pair.get("ok"):
print(json.dumps(token_pair))
raise SystemExit(0)
tokens = [str(token_pair.get("current") or "")]
prev = str(token_pair.get("previous") or "")
if prev and prev not in tokens:
tokens.append(prev)
identity = get_dm_identity()
agent_id = str(identity.get("node_id") or "")
claims = [{{"type": "shared", "token": token}} for token in tokens if token]
hit = None
for attempt in range(30):
time.sleep(4)
signed = sign_dm_wormhole_event(
event_type="dm_poll",
payload={{"mailbox_claims": claims, "agent_id": agent_id}},
)
body = {{
"agent_id": agent_id,
"mailbox_claims": claims,
"timestamp": int(time.time()),
"nonce": secrets.token_hex(8),
"public_key": str(signed.get("public_key") or ""),
"public_key_algo": str(signed.get("public_key_algo") or ""),
"signature": str(signed.get("signature") or ""),
"sequence": int(signed.get("sequence") or 0),
"protocol_version": str(signed.get("protocol_version") or PROTOCOL_VERSION),
}}
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
req = urllib.request.Request(
"http://127.0.0.1:8000/api/mesh/dm/poll",
data=data,
headers={{"Content-Type": "application/json"}},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=120) as resp:
payload = json.loads(resp.read().decode("utf-8"))
except Exception as exc:
print(json.dumps({{"ok": False, "detail": str(exc) or type(exc).__name__}}))
break
for message in list(payload.get("messages") or []):
if str(message.get("msg_id", "")) == shared_msg_id:
hit = message
break
if hit:
break
if not hit:
print(json.dumps({{"ok": False, "detail": "shared reply not in Pete mailbox"}}))
else:
ciphertext = str(hit.get("ciphertext", "") or "")
dec = __import__("main", fromlist=["decrypt_wormhole_dm_envelope"]).decrypt_wormhole_dm_envelope(
peer_id=sender_id,
ciphertext=ciphertext,
payload_format=str(hit.get("format", "") or "mls1"),
session_welcome=str(hit.get("session_welcome", "") or ""),
)
plaintext = str(dec.get("plaintext", "") or "")
print(json.dumps({{
"ok": bool(dec.get("ok") and marker in plaintext),
"plaintext": plaintext,
"detail": dec.get("detail", ""),
}}))
"""
).strip()
shared_decrypt = _ssh_pete_python(shared_poll_code)
print(json.dumps(shared_decrypt, indent=2))
if not shared_decrypt.get("ok") or REPLY_MARKER not in str(shared_decrypt.get("plaintext", "")):
raise RuntimeError(f"Pete could not decrypt shared DM: {shared_decrypt}")
print("== E2E PASS: invite -> accept -> private shared DM ==")
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as exc:
print(f"E2E FAIL: {exc}", file=sys.stderr)
raise
+172
View File
@@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""Live E2E: OpenClaw HMAC agent posts to Infonet gate and verifies propagation."""
from __future__ import annotations
import asyncio
import json
import os
import subprocess
import sys
import time
import urllib.error
import urllib.request
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
SKILL_DIR = os.path.join(ROOT, "openclaw-skills", "shadowbroker")
API = os.environ.get("SHADOWBROKER_API", "http://127.0.0.1:8000")
MARKER = os.environ.get("E2E_MARKER", f"OPENCLAW-AGENT-E2E-{int(time.time())}")
def _json_request(method: str, path: str, body: dict | None = None, *, inside_docker: bool = False) -> dict:
data = None
headers = {"Content-Type": "application/json"}
if body is not None:
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
req = urllib.request.Request(f"{API}{path}", data=data, headers=headers, method=method.upper())
try:
with urllib.request.urlopen(req, timeout=180) as resp:
return json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as exc:
detail = exc.read().decode("utf-8", errors="replace")
raise RuntimeError(f"{method} {path} -> {exc.code}: {detail}") from exc
def docker_python(code: str) -> str:
proc = subprocess.run(
["docker", "exec", "shadowbroker-backend", "python", "-c", code],
capture_output=True,
text=True,
timeout=300,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or "docker exec failed")
return proc.stdout.strip()
def bootstrap_hmac_and_full_tier() -> str:
setup = r"""
import json, urllib.request
BASE = 'http://127.0.0.1:8000'
def call(method, path, body=None):
data = json.dumps(body or {}, separators=(',', ':'), sort_keys=True).encode() if body is not None else None
req = urllib.request.Request(BASE + path, data=data, headers={'Content-Type': 'application/json'}, method=method)
with urllib.request.urlopen(req, timeout=60) as r:
return json.loads(r.read().decode())
call('POST', '/api/ai/connect-info/bootstrap', {})
call('PUT', '/api/ai/connect-info/access-tier', {'tier': 'full'})
secret = call('POST', '/api/ai/connect-info/reveal', {})['hmac_secret']
print(secret)
"""
secret = docker_python(setup)
if not secret or len(secret) < 16:
raise RuntimeError(f"unexpected HMAC secret: {secret!r}")
return secret
async def agent_post(secret: str, message: str) -> dict:
sys.path.insert(0, SKILL_DIR)
from sb_query import ShadowBrokerClient
os.environ["SHADOWBROKER_HMAC_SECRET"] = secret
client = ShadowBrokerClient(base_url=API)
try:
ready = await client.ensure_infonet_ready(join_swarm=True)
print("ensure_infonet_ready:", json.dumps(ready, indent=2)[:2000])
if not ready.get("ok"):
raise RuntimeError(f"ensure_infonet_ready failed: {ready}")
post = await client.post_to_gate("infonet", message)
print("post_to_gate:", json.dumps(post, indent=2)[:2000])
if not post.get("ok"):
raise RuntimeError(f"post_to_gate failed: {post}")
return post
finally:
await client.close()
def local_gate_has_event(event_id: str) -> bool:
code = f"""
from services.mesh.mesh_hashchain import gate_store
evt = gate_store.get_event({event_id!r})
print('yes' if evt else 'no')
"""
return docker_python(code) == "yes"
REMOTE_CONTAINERS = {
"shadowbroker": "shadowbroker-relay", # seed VPS
"pete": "shadowbroker-backend",
}
def peer_gate_has_event(host: str, event_id: str) -> bool:
container = REMOTE_CONTAINERS.get(host, "shadowbroker-backend")
remote_code = (
"from services.mesh.mesh_hashchain import gate_store; "
f"print('yes' if gate_store.get_event({event_id!r}) else 'no')"
)
import shlex
ssh = [
"ssh",
"-o",
"BatchMode=yes",
"-o",
"StrictHostKeyChecking=accept-new",
host,
f"docker exec {container} python -c {shlex.quote(remote_code)}",
]
proc = subprocess.run(ssh, capture_output=True, text=True, timeout=120, check=False)
out = (proc.stdout or "").strip()
if proc.returncode != 0:
print(f"ssh {host} warn:", proc.stderr.strip() or proc.stdout.strip())
return False
return out == "yes"
def wait_for_propagation(event_id: str, *, seconds: int = 90) -> dict[str, bool]:
deadline = time.time() + seconds
results = {"local": False, "seed": False, "pete": False}
while time.time() < deadline:
results["local"] = local_gate_has_event(event_id)
results["seed"] = peer_gate_has_event("shadowbroker", event_id)
results["pete"] = peer_gate_has_event("pete", event_id)
if all(results.values()):
break
time.sleep(5)
return results
def main() -> int:
print(f"E2E marker: {MARKER}")
secret = bootstrap_hmac_and_full_tier()
print("HMAC secret bootstrapped (full tier)")
post = asyncio.run(agent_post(secret, MARKER))
event_id = str(post.get("event_id") or "")
if not event_id:
raise RuntimeError(f"post succeeded but no event_id in response: {post}")
print(f"event_id={event_id}")
print("Waiting for propagation to local / seed / pete ...")
results = wait_for_propagation(event_id, seconds=120)
print("propagation:", json.dumps(results, indent=2))
if not results["local"]:
raise SystemExit("FAIL: event not in local gate_store")
if not results["seed"] and not results["pete"]:
raise SystemExit("FAIL: event not observed on seed or pete within timeout")
if results["seed"] and results["pete"]:
print("PASS: agent HMAC post propagated to local, seed, and pete")
return 0
print("PARTIAL: local ok; seed=%s pete=%s" % (results["seed"], results["pete"]))
return 0 if results["local"] else 1
if __name__ == "__main__":
raise SystemExit(main())
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
import shlex
import subprocess
import sys
EVENT_ID = sys.argv[1] if len(sys.argv) > 1 else ""
if not EVENT_ID:
raise SystemExit("usage: verify_gate_event.py <event_id>")
code = (
"from services.mesh.mesh_hashchain import gate_store; "
f"e=gate_store.get_event({EVENT_ID!r}); "
"print('ok' if e else 'no')"
)
hosts = [
("local", None, "shadowbroker-backend"),
("seed", "shadowbroker", "shadowbroker-relay"),
("pete", "pete", "shadowbroker-backend"),
]
for label, ssh_host, container in hosts:
remote = f"docker exec {container} python -c {shlex.quote(code)}"
if ssh_host:
proc = subprocess.run(
["ssh", "-o", "BatchMode=yes", ssh_host, remote],
capture_output=True,
text=True,
timeout=60,
)
else:
proc = subprocess.run(
["docker", "exec", container, "python", "-c", code],
capture_output=True,
text=True,
timeout=60,
)
out = (proc.stdout or proc.stderr).strip()
print(f"{label}: {out}")
+135
View File
@@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""Verify v1 Infonet swarm: fleet join, manifest peers, optional gate propagation."""
from __future__ import annotations
import json
import os
import subprocess
import sys
import time
import urllib.error
import urllib.request
API = os.environ.get("SHADOWBROKER_API", "http://127.0.0.1:8000").strip().rstrip("/")
MARKER = os.environ.get("SWARM_VERIFY_MARKER", f"SWARM-V1-{int(time.time())}")
def http_json(method: str, path: str, body: dict | None = None, *, timeout: int = 180) -> dict:
data = None
headers = {"Content-Type": "application/json"}
if body is not None:
data = json.dumps(body, separators=(",", ":"), sort_keys=True).encode("utf-8")
req = urllib.request.Request(f"{API}{path}", data=data, headers=headers, method=method.upper())
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
return json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as exc:
detail = exc.read().decode("utf-8", errors="replace")
raise RuntimeError(f"{method} {path} -> {exc.code}: {detail}") from exc
def docker_python(code: str) -> str:
proc = subprocess.run(
["docker", "exec", "shadowbroker-backend", "python", "-c", code],
capture_output=True,
text=True,
timeout=300,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip() or "docker exec failed")
return proc.stdout.strip()
def step_ghcr_fleet_join() -> None:
out = docker_python(
"import json; "
"from services.mesh.mesh_fleet_defaults import infonet_fleet_join_enabled, FLEET_SEED_ONION_URL; "
"print(json.dumps({'fleet_join': infonet_fleet_join_enabled(), 'seed': FLEET_SEED_ONION_URL}))"
)
payload = json.loads(out)
if not payload.get("fleet_join"):
raise RuntimeError(f"fleet join disabled in container: {payload}")
if not str(payload.get("seed") or "").endswith(".onion:8000"):
raise RuntimeError(f"unexpected fleet seed: {payload}")
print("PASS: container has fleet join defaults")
def step_enable_node_and_join() -> dict:
code = r"""
import json
import main as main_mod
from services.mesh.mesh_swarm_runtime import (
announce_local_peer_to_seeds,
refresh_swarm_manifest_from_seeds,
)
main_mod._set_participant_node_enabled(True)
announce = announce_local_peer_to_seeds(force=True)
manifest = refresh_swarm_manifest_from_seeds(force=True)
print(json.dumps({
'ok': bool(announce.get('ok')) or bool(manifest.get('ok')),
'announce': announce,
'manifest_pull': manifest,
}))
"""
join = json.loads(docker_python(code))
print("swarm/join:", json.dumps(join, indent=2)[:4000])
if not join.get("ok"):
raise RuntimeError(f"swarm join failed: {join}")
manifest = join.get("manifest_pull") or {}
peer_count = int(manifest.get("merged_peer_count") or manifest.get("peer_count") or 0)
if peer_count < 1:
raise RuntimeError(f"manifest has no peers: {join}")
print(f"PASS: swarm join ok ({peer_count} manifest peer(s))")
return join
def step_manifest_lists_pete(join: dict) -> None:
manifest = join.get("manifest_pull") or {}
peer_count = int(manifest.get("merged_peer_count") or manifest.get("peer_count") or 0)
if peer_count < 2:
raise RuntimeError(f"expected fleet manifest with seed + participants, got: {manifest}")
code = r"""
import json
from services.mesh.mesh_router import authenticated_push_peer_urls
print(json.dumps({'push_peers': authenticated_push_peer_urls()[:12]}))
"""
payload = json.loads(docker_python(code))
push_peers = [p for p in payload.get("push_peers") or [] if p]
onion_peers = [p for p in push_peers if ".onion" in p]
print("sync peer store:", json.dumps(payload, indent=2))
if not onion_peers:
raise RuntimeError(f"expected onion peers in local sync store after manifest pull, got: {push_peers}")
print("PASS: manifest pull populated onion fleet peer(s)")
def step_gate_propagation() -> None:
try:
subprocess.run(
[sys.executable, os.path.join(os.path.dirname(__file__), "e2e_openclaw_infonet_agent_live.py")],
env={**os.environ, "E2E_MARKER": MARKER, "SHADOWBROKER_API": API},
check=True,
timeout=600,
)
print("PASS: gate event propagated across fleet")
except subprocess.CalledProcessError as exc:
raise RuntimeError(f"gate propagation check failed (exit {exc.returncode})") from exc
except FileNotFoundError:
print("SKIP: e2e_openclaw_infonet_agent_live.py not available")
def main() -> int:
print(f"Swarm v1 verify against {API}")
step_ghcr_fleet_join()
join = step_enable_node_and_join()
step_manifest_lists_pete(join)
if os.environ.get("SWARM_VERIFY_SKIP_PROPAGATION") != "1":
step_gate_propagation()
print("ALL SWARM V1 CHECKS PASSED")
return 0
if __name__ == "__main__":
raise SystemExit(main())