Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,354 @@
|
||||
"""Contracts for autonomous cross-gateway hosted-room members."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import stat
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from gateway.hosted_room_execution_policy import execution_policy_mapping
|
||||
from gateway.hosted_room_peer import (
|
||||
GatewayRoomCatalog,
|
||||
HostedMemberDispatch,
|
||||
HostedRoomGrantError,
|
||||
HostedRoomPeerError,
|
||||
PROTOCOL_VERSION,
|
||||
RoomLinkProbe,
|
||||
catalog_mapping,
|
||||
derive_room_grant_secret,
|
||||
gateway_room_grant_secret,
|
||||
issue_room_grant,
|
||||
local_room_link_endpoint,
|
||||
select_room_link,
|
||||
verify_room_grant,
|
||||
)
|
||||
from hermes_constants import reset_hermes_home_override, set_hermes_home_override
|
||||
|
||||
|
||||
SECRET = b"s" * 32
|
||||
EXECUTION_POLICY = execution_policy_mapping(target_profile="reviewer")
|
||||
|
||||
|
||||
def test_gateway_room_grant_secret_is_private_persistent_and_not_an_api_key(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
home = tmp_path / ".hermes"
|
||||
profile_home = home / "profiles" / "reviewer"
|
||||
profile_home.mkdir(parents=True)
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
|
||||
first = gateway_room_grant_secret()
|
||||
token = set_hermes_home_override(str(profile_home))
|
||||
try:
|
||||
second = gateway_room_grant_secret()
|
||||
finally:
|
||||
reset_hermes_home_override(token)
|
||||
|
||||
secret_path = home / ".room-link-grant-secret"
|
||||
assert first == second
|
||||
assert len(first) == 32
|
||||
assert stat.S_IMODE(secret_path.stat().st_mode) == 0o600
|
||||
assert secret_path.read_bytes() != first
|
||||
assert first != derive_room_grant_secret("gateway-api-key-1234567890")
|
||||
|
||||
|
||||
def test_gateway_room_grant_secret_is_atomic_across_concurrent_workers(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
home = tmp_path / ".hermes"
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
|
||||
with ThreadPoolExecutor(max_workers=8) as pool:
|
||||
secrets = list(pool.map(lambda _index: gateway_room_grant_secret(), range(8)))
|
||||
|
||||
assert len(set(secrets)) == 1
|
||||
assert (home / ".room-link-grant-secret").stat().st_size == 32
|
||||
|
||||
|
||||
def test_gateway_room_grant_secret_is_cached_by_installation_root(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
home = tmp_path / ".hermes"
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
|
||||
first = gateway_room_grant_secret()
|
||||
original_read = Path.read_bytes
|
||||
|
||||
def reject_secret_reread(path):
|
||||
if path == home / ".room-link-grant-secret":
|
||||
raise AssertionError("grant secret was read again")
|
||||
return original_read(path)
|
||||
|
||||
monkeypatch.setattr(Path, "read_bytes", reject_secret_reread)
|
||||
assert gateway_room_grant_secret() == first
|
||||
|
||||
|
||||
def test_room_link_protocol_fixture_matches_backend_contract():
|
||||
fixture = json.loads(
|
||||
(Path(__file__).parents[1] / "fixtures" / "room_link_protocol_v2.json").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
)
|
||||
|
||||
assert fixture["protocol_version"] == PROTOCOL_VERSION
|
||||
assert fixture["catalog"]["protocol_versions"] == [PROTOCOL_VERSION]
|
||||
|
||||
|
||||
def test_room_link_endpoint_reads_supported_config_with_env_override(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
home = tmp_path / ".hermes"
|
||||
home.mkdir()
|
||||
(home / "config.yaml").write_text(
|
||||
"gateway:\n room_link_url: https://configured.example.test/hermes\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
monkeypatch.delenv("HERMES_ROOM_LINK_URL", raising=False)
|
||||
assert local_room_link_endpoint() == {
|
||||
"available": True,
|
||||
"url": "https://configured.example.test/hermes",
|
||||
"transport_security": "tls",
|
||||
}
|
||||
|
||||
monkeypatch.setenv(
|
||||
"HERMES_ROOM_LINK_URL", "https://override.example.test/hermes"
|
||||
)
|
||||
assert local_room_link_endpoint()["url"] == (
|
||||
"https://override.example.test/hermes"
|
||||
)
|
||||
|
||||
|
||||
def test_named_profile_inherits_gateway_room_link_endpoint(tmp_path, monkeypatch):
|
||||
root = tmp_path / "hermes"
|
||||
profile = root / "profiles" / "reviewer"
|
||||
profile.mkdir(parents=True)
|
||||
(root / "config.yaml").write_text(
|
||||
"gateway:\n room_link_url: https://gateway.example.test/hermes\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(profile / "config.yaml").write_text("gateway: {}\n", encoding="utf-8")
|
||||
monkeypatch.setenv("HERMES_HOME", str(root))
|
||||
monkeypatch.delenv("HERMES_ROOM_LINK_URL", raising=False)
|
||||
|
||||
token = set_hermes_home_override(profile)
|
||||
try:
|
||||
assert local_room_link_endpoint() == {
|
||||
"available": True,
|
||||
"url": "https://gateway.example.test/hermes",
|
||||
"transport_security": "tls",
|
||||
}
|
||||
finally:
|
||||
reset_hermes_home_override(token)
|
||||
|
||||
|
||||
def test_named_profile_room_link_override_wins_over_gateway_root(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
root = tmp_path / "hermes"
|
||||
profile = root / "profiles" / "reviewer"
|
||||
profile.mkdir(parents=True)
|
||||
(root / "config.yaml").write_text(
|
||||
"gateway:\n room_link_url: https://gateway.example.test/hermes\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(profile / "config.yaml").write_text(
|
||||
"gateway:\n room_link_url: https://profile.example.test/hermes\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setenv("HERMES_HOME", str(root))
|
||||
monkeypatch.delenv("HERMES_ROOM_LINK_URL", raising=False)
|
||||
|
||||
token = set_hermes_home_override(profile)
|
||||
try:
|
||||
assert local_room_link_endpoint()["url"] == (
|
||||
"https://profile.example.test/hermes"
|
||||
)
|
||||
finally:
|
||||
reset_hermes_home_override(token)
|
||||
|
||||
|
||||
def _dispatch(**overrides):
|
||||
prompt = overrides.pop("prompt", "Review the current room state.")
|
||||
value = {
|
||||
"protocol_version": 2,
|
||||
"room_id": "room-1",
|
||||
"home_install_id": "install-home",
|
||||
"authority_gateway_id": "gateway-home",
|
||||
"authority_epoch": 2,
|
||||
"member_id": "member-reviewer",
|
||||
"target_install_id": "install-peer",
|
||||
"target_profile": "reviewer",
|
||||
"task_id": "task-1",
|
||||
"execution_generation": 1,
|
||||
"source_event_seq": 9,
|
||||
"cancellation_scope_id": "cancel-1",
|
||||
"prompt": prompt,
|
||||
"prompt_digest": hashlib.sha256(prompt.encode()).hexdigest(),
|
||||
"capability_digest": "a" * 64,
|
||||
"execution_policy_digest": EXECUTION_POLICY["policy_digest"],
|
||||
"trace_id": "trace-1",
|
||||
**overrides,
|
||||
}
|
||||
return HostedMemberDispatch.from_mapping(value)
|
||||
|
||||
|
||||
def test_catalog_digest_is_canonical_and_tamper_evident():
|
||||
value = catalog_mapping(
|
||||
installation_id="install-peer",
|
||||
protocol_versions=(2,),
|
||||
link_modes=("direct", "pull"),
|
||||
persistent_process=True,
|
||||
)
|
||||
catalog = GatewayRoomCatalog.from_mapping(value)
|
||||
assert catalog.text is True
|
||||
assert catalog.attachments is False
|
||||
|
||||
value["attachments"] = True
|
||||
with pytest.raises(HostedRoomPeerError, match="catalog_digest"):
|
||||
GatewayRoomCatalog.from_mapping(value)
|
||||
|
||||
|
||||
def test_dispatch_rejects_unknown_fields_and_prompt_digest_mismatch():
|
||||
with pytest.raises(HostedRoomPeerError, match="unknown fields"):
|
||||
_dispatch(extra=True)
|
||||
with pytest.raises(HostedRoomPeerError, match="prompt_digest"):
|
||||
_dispatch(prompt_digest="0" * 64)
|
||||
|
||||
|
||||
def test_room_grant_is_scoped_to_exact_room_home_target_and_profile():
|
||||
dispatch = _dispatch()
|
||||
token = issue_room_grant(
|
||||
SECRET,
|
||||
grant_id="grant-1",
|
||||
room_id=dispatch.room_id,
|
||||
home_install_id=dispatch.home_install_id,
|
||||
authority_gateway_id=dispatch.authority_gateway_id,
|
||||
authority_epoch=dispatch.authority_epoch,
|
||||
member_id=dispatch.member_id,
|
||||
target_install_id=dispatch.target_install_id,
|
||||
target_profile=dispatch.target_profile,
|
||||
execution_policy_digest=dispatch.execution_policy_digest,
|
||||
issued_at=100,
|
||||
ttl_seconds=60,
|
||||
)
|
||||
claims = verify_room_grant(SECRET, token, dispatch, now=120)
|
||||
assert claims["grant_id"] == "grant-1"
|
||||
|
||||
wrong_target = _dispatch(target_profile="other")
|
||||
with pytest.raises(HostedRoomGrantError, match="scope"):
|
||||
verify_room_grant(SECRET, token, wrong_target, now=120)
|
||||
with pytest.raises(HostedRoomGrantError, match="scope"):
|
||||
verify_room_grant(
|
||||
SECRET, token, _dispatch(member_id="member-other"), now=120
|
||||
)
|
||||
with pytest.raises(HostedRoomGrantError, match="scope"):
|
||||
verify_room_grant(
|
||||
SECRET, token, _dispatch(authority_epoch=999), now=120
|
||||
)
|
||||
|
||||
|
||||
def test_room_grant_fails_closed_for_tamper_expiry_and_permission():
|
||||
dispatch = _dispatch()
|
||||
token = issue_room_grant(
|
||||
SECRET,
|
||||
grant_id="grant-1",
|
||||
room_id=dispatch.room_id,
|
||||
home_install_id=dispatch.home_install_id,
|
||||
authority_gateway_id=dispatch.authority_gateway_id,
|
||||
authority_epoch=dispatch.authority_epoch,
|
||||
member_id=dispatch.member_id,
|
||||
target_install_id=dispatch.target_install_id,
|
||||
target_profile=dispatch.target_profile,
|
||||
execution_policy_digest=dispatch.execution_policy_digest,
|
||||
permissions=("status",),
|
||||
issued_at=100,
|
||||
ttl_seconds=10,
|
||||
status_expires_at=120,
|
||||
)
|
||||
with pytest.raises(HostedRoomGrantError, match="allow"):
|
||||
verify_room_grant(SECRET, token, dispatch, now=105)
|
||||
# Dispatch expires quickly, while observation/stop remains available for
|
||||
# bounded headless recovery after the Desktop has closed.
|
||||
assert (
|
||||
verify_room_grant(SECRET, token, dispatch, permission="status", now=111)[
|
||||
"grant_id"
|
||||
]
|
||||
== "grant-1"
|
||||
)
|
||||
with pytest.raises(HostedRoomGrantError, match="expired"):
|
||||
verify_room_grant(
|
||||
SECRET,
|
||||
token,
|
||||
dispatch,
|
||||
permission="status",
|
||||
now=100 + 30 * 24 * 60 * 60,
|
||||
)
|
||||
with pytest.raises(HostedRoomGrantError, match="signature"):
|
||||
verify_room_grant(SECRET, token[:-1] + "A", dispatch, now=105)
|
||||
|
||||
|
||||
def test_link_selection_prefers_safe_direct_then_overlay_then_relay_then_pull():
|
||||
selected = select_room_link(
|
||||
[
|
||||
RoomLinkProbe("relay", True, True, 10),
|
||||
RoomLinkProbe("direct", True, True, 50),
|
||||
RoomLinkProbe("overlay", True, True, 5),
|
||||
RoomLinkProbe("pull", True, True, 1),
|
||||
],
|
||||
desktop_available=False,
|
||||
)
|
||||
assert selected is not None
|
||||
assert selected.mode == "direct"
|
||||
|
||||
|
||||
def test_link_selection_never_falls_back_to_unencrypted_route():
|
||||
assert (
|
||||
select_room_link(
|
||||
[RoomLinkProbe("direct", True, False, 1)],
|
||||
desktop_available=False,
|
||||
)
|
||||
is None
|
||||
)
|
||||
fallback = select_room_link([], desktop_available=True)
|
||||
assert fallback is not None
|
||||
assert fallback.mode == "desktop"
|
||||
|
||||
|
||||
def test_local_catalog_is_honest_for_app_managed_process(monkeypatch):
|
||||
from gateway.hosted_room_peer import local_catalog_mapping
|
||||
|
||||
monkeypatch.setenv("HERMES_DESKTOP", "1")
|
||||
catalog = local_catalog_mapping(installation_id="install-desktop")
|
||||
assert catalog["persistent_process"] is False
|
||||
assert catalog["link_modes"] == ["direct"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("configured", "available", "reason", "security"),
|
||||
[
|
||||
(None, False, "not_configured", None),
|
||||
("http://peer.example.test:8000", False, "invalid_configuration", None),
|
||||
("http://127.0.0.1:8000", True, None, "loopback"),
|
||||
("https://peer.example.test", True, None, "tls"),
|
||||
],
|
||||
)
|
||||
def test_self_advertised_endpoint_is_explicit_and_validated(
|
||||
monkeypatch, configured, available, reason, security
|
||||
):
|
||||
from gateway.hosted_room_peer import local_catalog_mapping
|
||||
|
||||
if configured is None:
|
||||
monkeypatch.delenv("HERMES_ROOM_LINK_URL", raising=False)
|
||||
else:
|
||||
monkeypatch.setenv("HERMES_ROOM_LINK_URL", configured)
|
||||
endpoint = local_catalog_mapping(installation_id="install-peer")["endpoint"]
|
||||
assert endpoint["available"] is available
|
||||
if reason is not None:
|
||||
assert endpoint == {"available": False, "reason": reason}
|
||||
else:
|
||||
assert endpoint["transport_security"] == security
|
||||
Reference in New Issue
Block a user