fix(recovery): persist Host111 broker transport
Some checks failed
CD Pipeline / select-latest-carrier (push) Successful in 38s
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 1m17s
CD Pipeline / revalidate-deploy-carrier (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / revalidate-post-deploy-carrier (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
Some checks failed
CD Pipeline / select-latest-carrier (push) Successful in 38s
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Failing after 1m17s
CD Pipeline / revalidate-deploy-carrier (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / revalidate-post-deploy-carrier (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
This commit is contained in:
@@ -6,6 +6,7 @@ import asyncio
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import time
|
||||
from collections.abc import Awaitable, Callable, Mapping
|
||||
from dataclasses import dataclass
|
||||
@@ -24,9 +25,11 @@ VERIFIER_ID = "asset_specific_read_only_host_postconditions"
|
||||
INDEPENDENT_SOURCE = "broker_ssh_host_runtime_readback"
|
||||
_SAFE_HOST_ALIAS_RE = re.compile(r"^[A-Za-z0-9_.-]+$")
|
||||
_SAFE_REMOTE_ID_RE = re.compile(r"^[A-Za-z0-9_.-]+$")
|
||||
_FIXED_PROXY_JUMP_BY_HOST = {
|
||||
_FIXED_PROXY_TARGET_BY_HOST = {
|
||||
"host_111": "wooo@192.168.0.110",
|
||||
}
|
||||
_INVENTORY_PROXY_KEY_PATH = Path("/run/secrets/ssh_mcp_key")
|
||||
_INVENTORY_PROXY_KNOWN_HOSTS_PATH = Path("/etc/ssh-mcp/known_hosts")
|
||||
_RUNTIME_CLOSURE_RECEIPT_CATALOGS = frozenset(
|
||||
{"ansible:188-openclaw-callback-forwarder"}
|
||||
)
|
||||
@@ -699,6 +702,23 @@ def _load_inventory_hosts(inventory_path: Path) -> dict[str, dict[str, str]]:
|
||||
return hosts
|
||||
|
||||
|
||||
def _pinned_proxy_command(
|
||||
*,
|
||||
proxy_target: str,
|
||||
ssh_key_path: Path,
|
||||
known_hosts_path: Path,
|
||||
) -> str:
|
||||
if not re.fullmatch(r"[A-Za-z0-9_.-]+@[A-Za-z0-9_.-]+", proxy_target):
|
||||
raise ValueError("postcondition_proxy_target_invalid")
|
||||
return (
|
||||
f"ssh -i {shlex.quote(str(ssh_key_path))} "
|
||||
f"-o UserKnownHostsFile={shlex.quote(str(known_hosts_path))} "
|
||||
"-o StrictHostKeyChecking=yes -o IdentitiesOnly=yes "
|
||||
"-o BatchMode=yes -o ConnectTimeout=10 "
|
||||
f"-W %h:%p {proxy_target}"
|
||||
)
|
||||
|
||||
|
||||
def build_read_only_probe_command(
|
||||
condition: AssetPostcondition,
|
||||
*,
|
||||
@@ -729,14 +749,30 @@ def build_read_only_probe_command(
|
||||
"-o",
|
||||
"ConnectTimeout=10",
|
||||
]
|
||||
proxy_jump = _FIXED_PROXY_JUMP_BY_HOST.get(condition.inventory_host)
|
||||
if proxy_jump is not None:
|
||||
proxy_target = _FIXED_PROXY_TARGET_BY_HOST.get(condition.inventory_host)
|
||||
if proxy_target is not None:
|
||||
inventory_proxy_command = _pinned_proxy_command(
|
||||
proxy_target=proxy_target,
|
||||
ssh_key_path=_INVENTORY_PROXY_KEY_PATH,
|
||||
known_hosts_path=_INVENTORY_PROXY_KNOWN_HOSTS_PATH,
|
||||
)
|
||||
expected_common_args = (
|
||||
f"-o ProxyJump={proxy_jump} -o StrictHostKeyChecking=yes"
|
||||
f'-o ProxyCommand="{inventory_proxy_command}" '
|
||||
"-o StrictHostKeyChecking=yes"
|
||||
)
|
||||
if target.get("ansible_ssh_common_args") != expected_common_args:
|
||||
raise ValueError("postcondition_proxy_jump_policy_mismatch")
|
||||
command.extend(["-o", f"ProxyJump={proxy_jump}"])
|
||||
raise ValueError("postcondition_proxy_command_policy_mismatch")
|
||||
command.extend(
|
||||
[
|
||||
"-o",
|
||||
"ProxyCommand="
|
||||
+ _pinned_proxy_command(
|
||||
proxy_target=proxy_target,
|
||||
ssh_key_path=ssh_key_path,
|
||||
known_hosts_path=known_hosts_path,
|
||||
),
|
||||
]
|
||||
)
|
||||
command.extend([f"{user}@{host}", condition.probe])
|
||||
return command
|
||||
|
||||
|
||||
@@ -187,9 +187,14 @@ def test_cd_applies_rolls_back_and_verifies_network_boundary() -> None:
|
||||
"192.168.0.110 192.168.0.112 192.168.0.120 "
|
||||
"192.168.0.121 192.168.0.188"
|
||||
)
|
||||
assert f"ssh-keyscan -T 5 {expected_hosts}" in workflow
|
||||
assert "EXPECTED_HOSTS=5" in workflow
|
||||
assert workflow.count(expected_hosts) >= 4
|
||||
expected_known_hosts = (
|
||||
"192.168.0.110 192.168.0.111 192.168.0.112 192.168.0.120 "
|
||||
"192.168.0.121 192.168.0.188"
|
||||
)
|
||||
assert f"ssh-keyscan -T 5 {expected_known_hosts}" in workflow
|
||||
assert "EXPECTED_HOSTS=6" in workflow
|
||||
assert workflow.count(expected_known_hosts) >= 4
|
||||
assert workflow.count(expected_hosts) >= 2
|
||||
assert "except ConnectionRefusedError:" in workflow
|
||||
assert "broker_ssh_refused_but_egress_permitted=" in workflow
|
||||
assert "broker_ssh_allowlisted_endpoint_unavailable=" in workflow
|
||||
|
||||
@@ -30,6 +30,13 @@ EXPECTED_ALLOWLIST = (
|
||||
"192.168.0.120/32,192.168.0.121/32"
|
||||
)
|
||||
EXPECTED_PROXY_JUMP = "wooo@192.168.0.110"
|
||||
EXPECTED_PROXY_COMMAND = (
|
||||
"ssh -i /run/secrets/ssh_mcp_key "
|
||||
"-o UserKnownHostsFile=/etc/ssh-mcp/known_hosts "
|
||||
"-o StrictHostKeyChecking=yes -o IdentitiesOnly=yes "
|
||||
"-o BatchMode=yes -o ConnectTimeout=10 "
|
||||
f"-W %h:%p {EXPECTED_PROXY_JUMP}"
|
||||
)
|
||||
|
||||
|
||||
def _flatten_tasks(tasks: list[dict]) -> list[dict]:
|
||||
@@ -150,7 +157,12 @@ def test_host111_playbook_is_launchagent_bounded_and_check_mode_safe() -> None:
|
||||
assert play["vars"]["proxy_label"] == "com.momo.ollama111-allow-proxy"
|
||||
assert play["vars"]["allowed_cidrs"] == EXPECTED_ALLOWLIST
|
||||
assert "192.168.0.110/32" not in play["vars"]["allowed_cidrs"].split(",")
|
||||
assert "launchctl bootstrap" in source
|
||||
assert source.count("launchctl bootout") == 2
|
||||
assert source.count("launchctl bootstrap") == 2
|
||||
assert source.count("launchctl kickstart -k") == 2
|
||||
assert source.count('test "$stopped" -eq 1') == 2
|
||||
assert source.count('test "$loaded" -eq 1') == 2
|
||||
assert source.count('test "$running" -eq 1') == 2
|
||||
assert "systemctl" not in source
|
||||
assert "docker restart" not in source
|
||||
|
||||
@@ -203,9 +215,10 @@ def test_host111_broker_transport_preserves_fixed_proxyjump_and_strict_safety(
|
||||
host111 = inventory["all"]["children"]["ollama_fallback"]["hosts"][
|
||||
"host_111"
|
||||
]
|
||||
assert host111["ansible_ssh_common_args"] == (
|
||||
f"-o ProxyJump={EXPECTED_PROXY_JUMP} -o StrictHostKeyChecking=yes"
|
||||
assert f'-o ProxyCommand="{EXPECTED_PROXY_COMMAND}"' in (
|
||||
host111["ansible_ssh_common_args"]
|
||||
)
|
||||
assert "ProxyJump" not in host111["ansible_ssh_common_args"]
|
||||
assert "accept-new" not in host111["ansible_ssh_common_args"]
|
||||
|
||||
key = tmp_path / "ssh_mcp_key"
|
||||
@@ -227,7 +240,7 @@ def test_host111_broker_transport_preserves_fixed_proxyjump_and_strict_safety(
|
||||
assert "ProxyJump" not in spec.env["ANSIBLE_SSH_ARGS"]
|
||||
|
||||
|
||||
def test_host111_independent_verifier_uses_same_fixed_proxyjump(
|
||||
def test_host111_independent_verifier_uses_same_pinned_proxy_command(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
condition = next(
|
||||
@@ -245,7 +258,13 @@ def test_host111_independent_verifier_uses_same_fixed_proxyjump(
|
||||
known_hosts_path=known_hosts,
|
||||
)
|
||||
|
||||
assert f"ProxyJump={EXPECTED_PROXY_JUMP}" in command
|
||||
expected_verifier_proxy_command = (
|
||||
f"ssh -i {key} -o UserKnownHostsFile={known_hosts} "
|
||||
"-o StrictHostKeyChecking=yes -o IdentitiesOnly=yes "
|
||||
"-o BatchMode=yes -o ConnectTimeout=10 "
|
||||
f"-W %h:%p {EXPECTED_PROXY_JUMP}"
|
||||
)
|
||||
assert f"ProxyCommand={expected_verifier_proxy_command}" in command
|
||||
assert "StrictHostKeyChecking=yes" in command
|
||||
assert "BatchMode=yes" in command
|
||||
assert "ooo@192.168.0.111" in command
|
||||
|
||||
Reference in New Issue
Block a user