Refactor owner scope across channels and fix default routing fallback (#1151)

* refactor: add explicit owner scope across channels

* fix: tighten routine owner target routing

* fix: address owner scope review feedback

* Fix owner-scope onboarding and event trigger isolation

* Tighten routing fallback and wizard owner validation

* fix: address owner-scope follow-up review

* fix: tighten owner-scope follow-up details

* fix: import Channel trait in telegram test

* fix: normalize http webhook sender ids

* fix: address remaining owner-scope review issues

* fix: reconcile config rebase fallout

* fix: reconcile extension manager rebase drift

* fix: address current copilot review regressions

* fix: restore clippy matrix after rebase
This commit is contained in:
Henry Park
2026-03-16 13:31:03 -07:00
committed by GitHub
parent 971b4c2ef4
commit 878a67cdb6
50 changed files with 2767 additions and 1071 deletions
+61 -4
View File
@@ -15,7 +15,13 @@ from pathlib import Path
import pytest
from helpers import AUTH_TOKEN, wait_for_port_line, wait_for_ready
from helpers import (
AUTH_TOKEN,
HTTP_WEBHOOK_SECRET,
OWNER_SCOPE_ID,
wait_for_port_line,
wait_for_ready,
)
# Project root (two levels up from tests/e2e/)
ROOT = Path(__file__).resolve().parent.parent.parent
@@ -92,6 +98,21 @@ def _find_free_port() -> int:
return s.getsockname()[1]
def _reserve_loopback_sockets(count: int) -> list[socket.socket]:
"""Bind loopback sockets and keep them open until the server starts."""
sockets: list[socket.socket] = []
try:
while len(sockets) < count:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("127.0.0.1", 0))
sockets.append(sock)
return sockets
except Exception:
for sock in sockets:
sock.close()
raise
@pytest.fixture(scope="session")
def ironclaw_binary():
"""Ensure ironclaw binary is built. Returns the binary path."""
@@ -108,6 +129,21 @@ def ironclaw_binary():
return str(binary)
@pytest.fixture(scope="session")
def server_ports():
"""Reserve dynamic ports for the gateway and HTTP webhook channel."""
reserved = _reserve_loopback_sockets(2)
try:
yield {
"gateway": reserved[0].getsockname()[1],
"http": reserved[1].getsockname()[1],
"sockets": reserved,
}
finally:
for sock in reserved:
sock.close()
@pytest.fixture(scope="session")
async def mock_llm_server():
"""Start the mock LLM server. Yields the base URL."""
@@ -177,10 +213,19 @@ def _wasm_build_symlinks():
@pytest.fixture(scope="session")
async def ironclaw_server(ironclaw_binary, mock_llm_server, wasm_tools_dir):
async def ironclaw_server(
ironclaw_binary,
mock_llm_server,
wasm_tools_dir,
server_ports,
):
"""Start the ironclaw gateway. Yields the base URL."""
gateway_port = _find_free_port()
home_dir = _HOME_TMPDIR.name
gateway_port = server_ports["gateway"]
http_port = server_ports["http"]
for sock in server_ports["sockets"]:
if sock.fileno() != -1:
sock.close()
env = {
# Minimal env: PATH for process spawning, HOME for Rust/cargo defaults
"PATH": os.environ.get("PATH", "/usr/bin:/bin"),
@@ -188,11 +233,15 @@ async def ironclaw_server(ironclaw_binary, mock_llm_server, wasm_tools_dir):
"IRONCLAW_BASE_DIR": os.path.join(home_dir, ".ironclaw"),
"RUST_LOG": "ironclaw=info",
"RUST_BACKTRACE": "1",
"IRONCLAW_OWNER_ID": OWNER_SCOPE_ID,
"GATEWAY_ENABLED": "true",
"GATEWAY_HOST": "127.0.0.1",
"GATEWAY_PORT": str(gateway_port),
"GATEWAY_AUTH_TOKEN": AUTH_TOKEN,
"GATEWAY_USER_ID": "e2e-tester",
"GATEWAY_USER_ID": "e2e-web-sender",
"HTTP_HOST": "127.0.0.1",
"HTTP_PORT": str(http_port),
"HTTP_WEBHOOK_SECRET": HTTP_WEBHOOK_SECRET,
"CLI_ENABLED": "false",
"LLM_BACKEND": "openai_compatible",
"LLM_BASE_URL": mock_llm_server,
@@ -261,6 +310,14 @@ async def ironclaw_server(ironclaw_binary, mock_llm_server, wasm_tools_dir):
proc.kill()
@pytest.fixture(scope="session")
async def http_channel_server(ironclaw_server, server_ports):
"""HTTP webhook channel base URL."""
base_url = f"http://127.0.0.1:{server_ports['http']}"
await wait_for_ready(f"{base_url}/health", timeout=30)
return base_url
@pytest.fixture(scope="session")
async def ironclaw_server_with_webhook_secret(ironclaw_binary, mock_llm_server, wasm_tools_dir):
"""Start ironclaw with HTTP_WEBHOOK_SECRET configured for webhook tests.