teleo-infrastructure/hermes-agent/runtime/leoclean-nosend/bootstrap.py
Fawaz 2d88c9765b
Some checks are pending
CI / lint-and-test (push) Waiting to run
Harden leoclean no-send staging runtime (#183)
* Harden leoclean no-send staging runtime

* Isolate GCP leoclean runtime adapters

* Verify current-main leoclean context contracts

* Constrain no-send operational contracts
2026-07-20 19:06:09 -04:00

794 lines
31 KiB
Python

#!/usr/bin/env python3
"""Start or inspect the structurally no-send Hermes/leoclean staging runtime."""
from __future__ import annotations
import argparse
import asyncio
import hashlib
import importlib
import json
import os
import platform
import shlex
import signal
import stat
import subprocess
import sys
from pathlib import Path
from typing import Any
class NoSendContractError(RuntimeError):
"""The runtime does not satisfy its no-send contract."""
def _require(condition: bool, message: str) -> None:
if not condition:
raise NoSendContractError(message)
class _SealedToolMap(dict[str, Any]):
"""Read-only registry map after the reviewed tools are installed."""
@staticmethod
def _deny(*_args: Any, **_kwargs: Any) -> None:
raise NoSendContractError("Hermes tool registry is sealed by the no-send runtime")
__setitem__ = _deny
__delitem__ = _deny
clear = _deny
pop = _deny
popitem = _deny
setdefault = _deny
update = _deny
def _load_json(path: Path) -> dict[str, Any]:
try:
value = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise NoSendContractError(f"cannot load {path.name}: {type(exc).__name__}") from exc
_require(isinstance(value, dict), f"{path.name} must be a JSON object")
return value
def _sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def _runtime_root() -> Path:
return Path(__file__).resolve().parent
def _validate_contract(value: dict[str, Any]) -> None:
_require(
set(value)
== {
"schema",
"runtime_mode",
"transport_authority",
"service_mode",
"handler_platform",
"plugins",
"toolset",
"profile",
"environment",
"database",
"claim_ceiling",
},
"no-send runtime contract fields are not exact",
)
_require(
value.get("schema") == "livingip.leocleanNoSendRuntimeContract.v1",
"no-send runtime contract schema is invalid",
)
_require(value.get("runtime_mode") == "gcp_staging_no_send", "runtime mode is not no-send staging")
_require(value.get("transport_authority") == "absent", "transport authority is not absent")
_require(value.get("service_mode") == "gateway_without_platform_adapters", "service mode is not no-send")
_require(value.get("handler_platform") == "api_server", "handler platform is not the reviewed surface")
_require(
value.get("plugins")
== {
"allowed": [
{
"name": "leo-db-context",
"source": "user",
"tools": [],
"hooks": ["post_llm_call", "pre_llm_call"],
}
]
},
"plugin contract is not exact",
)
toolset = value.get("toolset") or {}
_require(
toolset.get("allowed_tools") == ["skills_list", "skill_view", "terminal"],
"allowed tool contract is not exact",
)
_require(
set(toolset.get("forbidden_tools") or [])
== {"cronjob", "delegate_task", "memory", "process", "send_message", "skill_manage"},
"forbidden tool contract is not exact",
)
_require(
set(toolset.get("terminal_commands") or [])
== {
"context",
"decision-matrix-status",
"edges",
"evidence",
"list-proposals",
"propose-core-change",
"propose-edge",
"search",
"search-proposals",
"show",
"show-proposal",
"status",
},
"terminal command contract is not exact",
)
profile = value.get("profile") or {}
_require(
set(profile.get("template_entries") or []) == {"bin", "config.yaml", "plugins", "skills"},
"profile template contract is not exact",
)
_require(
set(profile.get("required_runtime_entries") or [])
== {"SOUL.md", "identity-lock.json", "identity-manifest.json"},
"runtime identity contract is not exact",
)
_require(
set(profile.get("forbidden_entries") or [])
== {".env", "BOOT.md", "auth.json", "gateway.json", "hooks", "processes.json", "secrets"},
"forbidden profile contract is not exact",
)
learning_policy = profile.get("learning_policy") or {}
_require(
set(learning_policy)
== {
"automatic_memory_review_interval",
"automatic_skill_review_interval",
"memory_enabled",
"user_profile_enabled",
}
and learning_policy.get("memory_enabled") is False
and learning_policy.get("user_profile_enabled") is False
and type(learning_policy.get("automatic_memory_review_interval")) is int
and learning_policy.get("automatic_memory_review_interval") == 0
and type(learning_policy.get("automatic_skill_review_interval")) is int
and learning_policy.get("automatic_skill_review_interval") == 0,
"learning policy contract is not exact",
)
routing_policy = profile.get("routing_policy") or {}
_require(
set(routing_policy) == {"cheap_model", "smart_model_routing"}
and routing_policy.get("cheap_model") == "absent"
and routing_policy.get("smart_model_routing") is False,
"routing policy contract is not exact",
)
environment = value.get("environment") or {}
_require(
environment.get("allowed_provider_credentials") == ["OPENROUTER_API_KEY"],
"provider credential contract is not exact",
)
_require(
set(environment.get("allowed_runtime_variables") or [])
== {"HERMES_HOME", "PYTHONDONTWRITEBYTECODE", "PYTHONNOUSERSITE", "PYTHONSAFEPATH"},
"runtime environment allowlist is not exact",
)
required_forbidden_exact = {
"ALL_PROXY",
"BASH_ENV",
"BOT_TOKEN",
"ENV",
"GATEWAY_ALLOW_ALL_USERS",
"GATEWAY_ALLOWED_USERS",
"GOOGLE_APPLICATION_CREDENTIALS",
"HERMES_ENABLE_PROJECT_PLUGINS",
"HERMES_SESSION_PLATFORM",
"HTTP_PROXY",
"HTTPS_PROXY",
"LD_PRELOAD",
"PYTHONHOME",
"PYTHONPATH",
"TELEGRAM_BOT_TOKEN",
}
_require(
set(environment.get("forbidden_exact") or []) == required_forbidden_exact,
"forbidden environment contract is not exact",
)
_require(
set(environment.get("forbidden_prefixes") or [])
== {
"CLOUDSDK_",
"DINGTALK_",
"DISCORD_",
"EMAIL_",
"FEISHU_",
"HERMES_",
"LD_",
"MATRIX_",
"MATTERMOST_",
"SIGNAL_",
"SLACK_",
"SMS_",
"TELEGRAM_",
"TWILIO_",
"WEBCOM_",
"WEBHOOK_",
"WHATSAPP_",
},
"transport environment prefix contract is not exact",
)
_require(
set(environment.get("forbidden_suffixes") or []) == {"_PASSWORD", "_SECRET", "_TOKEN", "_API_KEY"},
"secret-shaped environment contract is not exact",
)
database = value.get("database") or {}
_require(
database
== {
"automatic_context_modes": ["claim_evidence_challenge", "review_only_candidate"],
"canonical_database": "teleo_canonical",
"runtime_role": "leoclean_kb_runtime",
"proposal_function": "kb_stage.stage_leoclean_proposal(text,text,text,text,jsonb)",
"direct_canonical_writes": "denied",
"direct_stage_table_writes": "denied",
"proposal_staging": "function_only",
"unsupported_context_policy": "fail_closed",
},
"database authority contract is not exact",
)
_require(isinstance(value.get("claim_ceiling"), str) and bool(value["claim_ceiling"]), "claim ceiling is missing")
def _contract() -> dict[str, Any]:
value = _load_json(_runtime_root() / "runtime-contract.json")
_require(
value.get("schema") == "livingip.leocleanNoSendRuntimeContract.v1",
"unsupported no-send runtime contract",
)
_validate_contract(value)
return value
def _validate_environment(contract: dict[str, Any]) -> None:
policy = contract["environment"]
allowed_provider = set(policy["allowed_provider_credentials"])
allowed_runtime = set(policy["allowed_runtime_variables"])
forbidden_exact = set(policy["forbidden_exact"])
forbidden_prefixes = tuple(policy["forbidden_prefixes"])
forbidden_suffixes = tuple(policy["forbidden_suffixes"])
violations: list[str] = []
for name, value in os.environ.items():
if not value:
continue
if name in allowed_provider or name in allowed_runtime:
continue
if name in forbidden_exact or name.startswith(forbidden_prefixes) or name.endswith(forbidden_suffixes):
violations.append(name)
_require(not violations, f"forbidden transport environment is present: {sorted(violations)}")
def _validate_profile(profile: Path, contract: dict[str, Any], *, template: bool) -> None:
_require(profile.is_dir() and not profile.is_symlink(), "profile root is missing or unsafe")
forbidden = set(contract["profile"]["forbidden_entries"])
actual = {path.name for path in profile.iterdir()}
present_forbidden = sorted(actual & forbidden)
_require(not present_forbidden, f"forbidden profile entries are present: {present_forbidden}")
_require(not any(path.is_symlink() for path in profile.rglob("*")), "profile contains a symlink")
immutable_entries = set(contract["profile"]["template_entries"])
expected_template = _runtime_root() / "profile-template"
_require(expected_template.is_dir(), "bound profile template is missing")
for entry in sorted(immutable_entries):
expected = expected_template / entry
observed = profile / entry
_require(expected.exists() and observed.exists(), f"immutable profile entry is missing: {entry}")
_require(expected.is_dir() == observed.is_dir(), f"immutable profile entry type drifted: {entry}")
if expected.is_file():
_require(_sha256(expected) == _sha256(observed), f"immutable profile file drifted: {entry}")
_require(
stat.S_IMODE(expected.stat().st_mode) == stat.S_IMODE(observed.stat().st_mode),
f"immutable profile file mode drifted: {entry}",
)
continue
expected_files = {
path.relative_to(expected).as_posix(): (
_sha256(path),
stat.S_IMODE(path.stat().st_mode),
)
for path in expected.rglob("*")
if path.is_file()
}
observed_files = {
path.relative_to(observed).as_posix(): (
_sha256(path),
stat.S_IMODE(path.stat().st_mode),
)
for path in observed.rglob("*")
if path.is_file()
}
_require(observed_files == expected_files, f"immutable profile tree drifted: {entry}")
if template:
_require(actual == immutable_entries, "profile template entry set is not exact")
else:
required_identity = set(contract["profile"]["required_runtime_entries"])
state_policy = contract["profile"]["allowed_runtime_state"]
state_directories = set(state_policy["directories"])
state_files = set(state_policy["files"])
allowed = immutable_entries | required_identity | state_directories | state_files
_require(required_identity <= actual, "compiled runtime profile is incomplete")
_require(actual <= allowed, f"compiled runtime profile has unapproved entries: {sorted(actual - allowed)}")
for name in sorted(required_identity):
entry = profile / name
_require(
entry.is_file() and entry.stat().st_size <= 1024 * 1024, f"runtime identity entry is invalid: {name}"
)
for name in sorted(actual & state_directories):
_require((profile / name).is_dir(), f"runtime state entry must be a directory: {name}")
for name in sorted(actual & state_files):
_require((profile / name).is_file(), f"runtime state entry must be a file: {name}")
def _load_profile_config(profile: Path, contract: dict[str, Any]) -> dict[str, Any]:
try:
import yaml
value = yaml.safe_load((profile / "config.yaml").read_text(encoding="utf-8")) or {}
except (OSError, TypeError, ValueError) as exc:
raise NoSendContractError(f"cannot load config.yaml: {type(exc).__name__}") from exc
_require(isinstance(value, dict), "config.yaml must be a mapping")
expected_top_level = {
"agent",
"display",
"known_plugin_toolsets",
"mcp_servers",
"memory",
"model",
"platform_toolsets",
"skills",
"smart_model_routing",
}
_require(set(value) == expected_top_level, "config.yaml top-level fields are not exact")
_require(value.get("mcp_servers") == {}, "MCP servers are forbidden in no-send staging")
memory = value.get("memory") or {}
_require(
set(memory) == {"enabled", "memory_enabled", "nudge_interval", "user_profile_enabled"}
and memory.get("enabled") is False
and memory.get("memory_enabled") is False
and memory.get("user_profile_enabled") is False
and type(memory.get("nudge_interval")) is int
and memory.get("nudge_interval") == 0,
"persistent memory and automatic memory review must be disabled",
)
skills = value.get("skills") or {}
_require(
set(skills) == {"creation_nudge_interval"}
and type(skills.get("creation_nudge_interval")) is int
and skills.get("creation_nudge_interval") == 0,
"automatic skill review must be disabled",
)
_require(value.get("smart_model_routing") is False, "smart-model routing must be disabled")
expected_toolset = contract["toolset"]["name"]
_require(
value.get("platform_toolsets") == {"api_server": [expected_toolset]},
"handler toolset binding is not exact",
)
_require(
value.get("known_plugin_toolsets") == {"api_server": []},
"plugin toolset allowlist is not exact",
)
encoded = json.dumps(value, sort_keys=True).lower()
for marker in (
"telegram",
"discord",
"whatsapp",
"slack",
"signal",
"mattermost",
"matrix",
"dingtalk",
"feishu",
"wecom",
"webhook",
"bot_token",
"send_message",
):
_require(marker not in encoded, f"transport marker is forbidden in config.yaml: {marker}")
return value
def _load_effective_policy(contract: dict[str, Any]) -> dict[str, Any]:
"""Prove what the pinned Hermes loader will give the actual agent runtime."""
try:
from agent.smart_model_routing import choose_cheap_model_route
from hermes_cli.config import load_config
effective = load_config()
except Exception as exc:
raise NoSendContractError(f"cannot load effective Hermes config: {type(exc).__name__}") from exc
_require(isinstance(effective, dict), "effective Hermes config must be a mapping")
learning_policy = contract["profile"]["learning_policy"]
memory = effective.get("memory") or {}
skills = effective.get("skills") or {}
_require(isinstance(memory, dict) and isinstance(skills, dict), "effective learning policy is invalid")
_require(memory.get("memory_enabled") is False, "effective Hermes memory policy is not disabled")
_require(memory.get("user_profile_enabled") is False, "effective Hermes user profile is not disabled")
memory_interval = memory.get("nudge_interval")
_require(
type(memory_interval) is int and memory_interval == learning_policy["automatic_memory_review_interval"],
"effective Hermes memory-review interval is not disabled",
)
skill_interval = skills.get("creation_nudge_interval")
_require(
type(skill_interval) is int and skill_interval == learning_policy["automatic_skill_review_interval"],
"effective Hermes skill-review policy is not disabled",
)
_require(effective.get("smart_model_routing") is False, "effective Hermes smart routing is not disabled")
_require(
choose_cheap_model_route("what time is it?", effective.get("smart_model_routing")) is None,
"effective Hermes config selected a cheap-model route",
)
return {
"memory_enabled": memory.get("memory_enabled"),
"user_profile_enabled": memory.get("user_profile_enabled"),
"memory_nudge_interval": memory.get("nudge_interval"),
"skill_creation_nudge_interval": skills.get("creation_nudge_interval"),
"smart_model_routing": False,
"cheap_model_route": None,
}
def _restricted_terminal_handler(
profile: Path,
allowed_commands: set[str],
tool_args: dict[str, Any],
**_kwargs: Any,
) -> str:
if not isinstance(tool_args, dict):
return json.dumps({"output": "", "exit_code": 126, "error": "terminal arguments must be an object"})
unexpected = sorted(set(tool_args) - {"command", "timeout"})
if unexpected:
return json.dumps({"output": "", "exit_code": 126, "error": "terminal arguments contain unsupported fields"})
command = tool_args.get("command")
if not isinstance(command, str) or not command.strip():
return json.dumps({"output": "", "exit_code": 126, "error": "terminal command is required"})
if "\x00" in command or "\n" in command or "\r" in command:
return json.dumps(
{"output": "", "exit_code": 126, "error": "terminal command contains a forbidden control character"}
)
try:
argv = shlex.split(command, posix=True)
except ValueError as exc:
return json.dumps({"output": "", "exit_code": 126, "error": f"invalid terminal command: {exc}"})
wrapper = (profile / "bin" / "teleo-kb").resolve()
if not argv or argv[0] not in {"teleo-kb", str(wrapper)}:
return json.dumps({"output": "", "exit_code": 126, "error": "only the reviewed teleo-kb wrapper is allowed"})
if len(argv) < 2 or argv[1] not in allowed_commands:
return json.dumps({"output": "", "exit_code": 126, "error": "teleo-kb command is outside the allowlist"})
forbidden_tokens = {";", "&&", "||", "|", ">", ">>", "<", "<<", "&"}
forbidden_overrides = {
"--canonical-db",
"--credential-mode",
"--db",
"--host",
"--password-secret",
"--port",
"--project",
"--user",
}
if any(token in forbidden_tokens for token in argv[2:]):
return json.dumps({"output": "", "exit_code": 126, "error": "terminal command contains a shell control token"})
if any(
token in forbidden_overrides or any(token.startswith(f"{option}=") for option in forbidden_overrides)
for token in argv[2:]
):
return json.dumps({"output": "", "exit_code": 126, "error": "terminal command contains an identity override"})
try:
timeout = int(tool_args.get("timeout") or 60)
except (TypeError, ValueError):
return json.dumps({"output": "", "exit_code": 126, "error": "terminal timeout must be an integer"})
timeout = min(max(timeout, 1), 120)
child_environment = {
"HOME": str(profile / "state"),
"HERMES_HOME": str(profile),
"LANG": "C",
"LC_ALL": "C",
"PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
}
try:
result = subprocess.run(
[str(wrapper), *argv[1:]],
cwd=profile,
env=child_environment,
text=True,
capture_output=True,
check=False,
timeout=timeout,
)
except subprocess.TimeoutExpired:
return json.dumps({"output": "", "exit_code": 124, "error": "teleo-kb command timed out"})
return json.dumps(
{
"output": result.stdout[:65536],
"exit_code": result.returncode,
"error": (result.stderr[:65536] or None),
"truncated": len(result.stdout) > 65536 or len(result.stderr) > 65536,
}
)
def _restricted_terminal_schema(commands: list[str]) -> dict[str, Any]:
return {
"name": "terminal",
"description": "Run one reviewed teleo-kb knowledge command without a shell.",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": f"teleo-kb followed by one of: {', '.join(commands)}",
},
"timeout": {
"type": "integer",
"minimum": 1,
"maximum": 120,
},
},
"required": ["command"],
"additionalProperties": False,
},
}
def _plugin_inventory(contract: dict[str, Any]) -> list[dict[str, Any]]:
from hermes_cli.plugins import get_plugin_manager
manager = get_plugin_manager()
observed: list[dict[str, Any]] = []
for name, loaded in sorted(manager._plugins.items()):
observed.append(
{
"name": name,
"source": loaded.manifest.source,
"tools": sorted(loaded.tools_registered),
"hooks": sorted(loaded.hooks_registered),
"enabled": loaded.enabled,
"error": loaded.error,
}
)
expected = [
{
**item,
"tools": sorted(item["tools"]),
"hooks": sorted(item["hooks"]),
"enabled": True,
"error": None,
}
for item in contract["plugins"]["allowed"]
]
_require(observed == expected, "effective Hermes plugin inventory is not exact")
return observed
def _assert_tool_registry(profile: Path, contract: dict[str, Any]) -> dict[str, Any]:
from tools.registry import registry
allowed_tools = sorted(contract["toolset"]["allowed_tools"])
_require(sorted(registry._tools) == allowed_tools, "effective Hermes tool registry is not exact")
_require(isinstance(registry._tools, _SealedToolMap), "Hermes tool registry is not sealed")
terminal_entry = registry._tools.get("terminal")
_require(terminal_entry is not None, "restricted terminal is not registered")
expected_marker = f"livingip-nosend-terminal:{profile.resolve()}"
_require(
getattr(terminal_entry.handler, "_livingip_no_send_handler", None) == expected_marker,
"restricted terminal handler identity drifted",
)
_require(
terminal_entry.schema == _restricted_terminal_schema(contract["toolset"]["terminal_commands"]),
"restricted terminal schema drifted",
)
for forbidden in contract["toolset"]["forbidden_tools"]:
_require(forbidden not in registry._tools, f"forbidden Hermes tool remains registered: {forbidden}")
dispatched = json.loads(registry.dispatch(forbidden, {}))
_require(
dispatched == {"error": f"Unknown tool: {forbidden}"}, f"forbidden tool dispatch is not denied: {forbidden}"
)
return {
"toolset": contract["toolset"]["name"],
"tools": sorted(registry._tools),
"send_message_present": "send_message" in registry._tools,
"registry_sealed": True,
"terminal_handler": "livingip.restricted_teleo_kb.v1",
"terminal_restricted_to": "profile/bin/teleo-kb",
"plugins": _plugin_inventory(contract),
}
def _prepare_tool_surface(profile: Path, config: dict[str, Any], contract: dict[str, Any]) -> dict[str, Any]:
import toolsets
from hermes_cli import tools_config
from tools.registry import registry
importlib.import_module("tools.skills_tool")
importlib.import_module("tools.terminal_tool")
importlib.import_module("tools.process_registry")
toolset_name = contract["toolset"]["name"]
allowed_tools = list(contract["toolset"]["allowed_tools"])
toolsets.TOOLSETS[toolset_name] = {
"description": "LivingIP no-send Cloud SQL knowledge tools",
"tools": allowed_tools,
"includes": [],
}
resolved = tools_config._get_platform_tools(config, contract["handler_platform"])
_require(resolved == {toolset_name}, "effective Hermes toolset is not exact")
missing = sorted(name for name in allowed_tools if name not in registry._tools)
_require(not missing, f"required Hermes tools are not registered: {missing}")
_plugin_inventory(contract)
retained = {name: registry._tools[name] for name in allowed_tools}
terminal_entry = retained["terminal"]
def restricted_terminal(args: dict[str, Any], **kwargs: Any) -> str:
return _restricted_terminal_handler(
profile,
set(contract["toolset"]["terminal_commands"]),
args,
**kwargs,
)
restricted_terminal._livingip_no_send_handler = f"livingip-nosend-terminal:{profile.resolve()}" # type: ignore[attr-defined]
terminal_entry.handler = restricted_terminal
terminal_entry.schema = _restricted_terminal_schema(contract["toolset"]["terminal_commands"])
terminal_entry.check_fn = None
terminal_entry.requires_env = []
terminal_entry.toolset = toolset_name
for name, entry in retained.items():
entry.toolset = toolset_name
if name != "terminal":
entry.check_fn = None
entry.requires_env = []
registry._tools = _SealedToolMap(retained)
registry._toolset_checks = {}
return _assert_tool_registry(profile, contract)
def _prepare(
profile: Path,
*,
template: bool,
) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any], dict[str, Any]]:
contract = _contract()
_validate_environment(contract)
_validate_profile(profile, contract, template=template)
os.environ["HERMES_HOME"] = str(profile)
hermes_source = _runtime_root() / "hermes-agent"
_require(hermes_source.is_dir(), "bound Hermes source tree is missing")
if str(hermes_source) not in sys.path:
sys.path.insert(0, str(hermes_source))
config = _load_profile_config(profile, contract)
effective_policy = _load_effective_policy(contract)
tool_surface = _prepare_tool_surface(profile, config, contract)
return contract, config, tool_surface, effective_policy
async def _exercise_runner(runner: Any, profile: Path, contract: dict[str, Any]) -> dict[str, Any]:
started = await runner.start()
_require(started, "Hermes no-send gateway did not start")
post_start = _assert_tool_registry(profile, contract)
hooks = [
{"name": item.get("name"), "path": item.get("path"), "events": sorted(item.get("events") or [])}
for item in runner.hooks.loaded_hooks
]
_require(
hooks == [{"name": "boot-md", "path": "(builtin)", "events": ["gateway:startup"]}],
"effective gateway hook inventory is not exact",
)
importlib.import_module("model_tools")
post_discovery = _assert_tool_registry(profile, contract)
await runner.stop()
_require(not runner.adapters, "gateway retained a transport adapter after stop")
return {
"started": True,
"stopped": True,
"post_start_registry": post_start,
"post_discovery_registry": post_discovery,
"gateway_hooks": hooks,
}
def probe(profile: Path, *, template: bool) -> dict[str, Any]:
contract, config, tool_surface, effective_policy = _prepare(profile, template=template)
from gateway.config import GatewayConfig
from gateway.run import GatewayRunner
gateway_config = GatewayConfig.from_dict({"platforms": {}})
runner = GatewayRunner(gateway_config)
adapters = getattr(runner, "adapters", None)
_require(isinstance(adapters, dict), "GatewayRunner adapters are not inspectable")
_require(not adapters, "GatewayRunner unexpectedly has a transport adapter")
_require(getattr(runner, "_smart_model_routing", None) == {}, "GatewayRunner retained smart-model routing")
_require(not gateway_config.get_connected_platforms(), "a messaging platform is connected")
_assert_tool_registry(profile, contract)
lifecycle = asyncio.run(_exercise_runner(runner, profile, contract))
return {
"schema": "livingip.leocleanNoSendRuntimeProbe.v1",
"status": "pass",
"runtime_mode": contract["runtime_mode"],
"config_sha256": _sha256(profile / "config.yaml"),
"gateway_runner": f"{runner.__class__.__module__}.{runner.__class__.__name__}",
"gateway_adapter_count": len(adapters),
"connected_platforms": [],
"tool_surface": tool_surface,
"effective_policy": effective_policy,
"lifecycle": lifecycle,
"provider_credential_names_present": sorted(
name for name in contract["environment"]["allowed_provider_credentials"] if os.getenv(name)
),
"claim_ceiling": contract["claim_ceiling"],
"model": config["model"]["default"],
"python_version": platform.python_version(),
}
async def _run_service(profile: Path) -> bool:
contract, _config, _surface, _effective_policy = _prepare(profile, template=False)
from gateway.config import GatewayConfig
from gateway.run import GatewayRunner
config = GatewayConfig.from_dict({"platforms": {}})
runner = GatewayRunner(config)
_require(not runner.adapters, "service cannot start with a transport adapter")
_require(getattr(runner, "_smart_model_routing", None) == {}, "service retained smart-model routing")
_assert_tool_registry(profile, contract)
importlib.import_module("model_tools")
_assert_tool_registry(profile, contract)
loop = asyncio.get_running_loop()
stop_tasks: set[asyncio.Task[Any]] = set()
def stop() -> None:
task = asyncio.create_task(runner.stop())
stop_tasks.add(task)
task.add_done_callback(stop_tasks.discard)
for sig in (signal.SIGINT, signal.SIGTERM):
try:
loop.add_signal_handler(sig, stop)
except NotImplementedError:
pass
started = await runner.start()
_require(started, "Hermes no-send gateway did not start")
_assert_tool_registry(profile, contract)
await runner.wait_for_shutdown()
return True
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
for name in ("probe", "service"):
child = subparsers.add_parser(name)
child.add_argument("--profile", required=True, type=Path)
if name == "probe":
child.add_argument("--template", action="store_true")
args = parser.parse_args()
try:
if args.command == "probe":
print(json.dumps(probe(args.profile.resolve(), template=args.template), sort_keys=True))
return 0
return 0 if asyncio.run(_run_service(args.profile.resolve())) else 1
except NoSendContractError as exc:
print(json.dumps({"status": "fail", "error": str(exc)}, sort_keys=True), file=sys.stderr)
return 65
if __name__ == "__main__":
raise SystemExit(main())