feat(signoz): add recoverable Agent99 metadata toolchain route
This commit is contained in:
@@ -1,267 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[3]
|
||||
DEPLOYER = ROOT / "scripts" / "ops" / "deploy-signoz-metadata-toolchain.sh"
|
||||
DEPLOYER = ROOT / "scripts/ops/deploy-signoz-metadata-toolchain.sh"
|
||||
|
||||
|
||||
def _write_executable(path: Path, text: str) -> None:
|
||||
path.write_text(text, encoding="utf-8")
|
||||
path.chmod(0o755)
|
||||
|
||||
|
||||
def fake_environment(tmp_path: Path, *, mode: str) -> dict[str, str]:
|
||||
fake_bin = tmp_path / "bin"
|
||||
fake_bin.mkdir()
|
||||
event_log = tmp_path / "events.log"
|
||||
ssh_count = tmp_path / "ssh.count"
|
||||
event_log.touch()
|
||||
ssh_count.write_text("0\n", encoding="utf-8")
|
||||
|
||||
_write_executable(
|
||||
fake_bin / "timeout",
|
||||
"""#!/bin/bash
|
||||
set -eu
|
||||
while [[ "${1:-}" == --kill-after=* ]]; do shift; done
|
||||
shift
|
||||
exec "$@"
|
||||
""",
|
||||
def test_historical_direct_host110_deployer_is_syntax_valid_and_fail_closed() -> None:
|
||||
syntax = subprocess.run(
|
||||
["bash", "-n", str(DEPLOYER)],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
_write_executable(
|
||||
fake_bin / "ssh",
|
||||
"""#!/bin/bash
|
||||
set -eu
|
||||
count="$(cat "${TEST_SSH_COUNT:?}")"
|
||||
count=$((count + 1))
|
||||
printf '%s\n' "$count" > "${TEST_SSH_COUNT:?}"
|
||||
printf 'ssh %s\n' "$*" >> "${TEST_EVENT_LOG:?}"
|
||||
cat >/dev/null || true
|
||||
case "${FAKE_SSH_MODE:?}" in
|
||||
check_absent)
|
||||
printf 'REMOTE_CHECK terminal=check_pass_no_write state=absent drift=0 candidate_count=0 api=200 active_operations=0 container_state_sha256=%064d\n' 0
|
||||
;;
|
||||
check_drift)
|
||||
exit 3
|
||||
;;
|
||||
apply)
|
||||
case "$count" in
|
||||
1)
|
||||
printf 'REMOTE_CHECK terminal=check_pass_no_write state=absent drift=0 candidate_count=0 api=200 active_operations=0 container_state_sha256=%064d\n' 0
|
||||
;;
|
||||
2) ;;
|
||||
3)
|
||||
printf '{"phase":"terminal","terminal":"pass_source_deployed_inactive"}\n'
|
||||
;;
|
||||
4)
|
||||
printf 'REMOTE_CHECK terminal=check_pass_no_write state=exact drift=0 candidate_count=0 api=200 active_operations=0 container_state_sha256=%064d\n' 0
|
||||
;;
|
||||
*) exit 90 ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
""",
|
||||
result = subprocess.run(
|
||||
["bash", str(DEPLOYER), "--apply"],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
_write_executable(
|
||||
fake_bin / "scp",
|
||||
"""#!/bin/bash
|
||||
set -eu
|
||||
printf 'scp %s\n' "$*" >> "${TEST_EVENT_LOG:?}"
|
||||
""",
|
||||
)
|
||||
return {
|
||||
**os.environ,
|
||||
"PATH": f"{fake_bin}:{os.environ['PATH']}",
|
||||
"TEST_EVENT_LOG": str(event_log),
|
||||
"TEST_SSH_COUNT": str(ssh_count),
|
||||
"FAKE_SSH_MODE": mode,
|
||||
"TRACE_ID": "trace-P0-OBS-002-metadata-deploy",
|
||||
"RUN_ID": f"run-{mode}",
|
||||
"WORK_ITEM_ID": "P0-OBS-002",
|
||||
|
||||
assert syntax.returncode == 0, syntax.stderr
|
||||
assert result.returncode == 78
|
||||
receipt = json.loads(result.stdout)
|
||||
assert receipt == {
|
||||
"schema": "awoooi_signoz_metadata_toolchain_route_retirement_v1",
|
||||
"terminal": "blocked_direct_host110_route_retired",
|
||||
"replacement": "scripts/ops/deploy-signoz-metadata-toolchain-via-agent99.sh",
|
||||
"production_mutation_performed": False,
|
||||
"completion_claim": False,
|
||||
}
|
||||
|
||||
|
||||
def run_deployer(
|
||||
tmp_path: Path,
|
||||
*,
|
||||
mode: str,
|
||||
apply: bool,
|
||||
env_overrides: dict[str, str] | None = None,
|
||||
) -> subprocess.CompletedProcess[str]:
|
||||
env = fake_environment(tmp_path, mode=mode)
|
||||
if env_overrides:
|
||||
env.update(env_overrides)
|
||||
return subprocess.run(
|
||||
["bash", str(DEPLOYER), "--apply" if apply else "--check"],
|
||||
env=env,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
timeout=20,
|
||||
check=False,
|
||||
)
|
||||
|
||||
|
||||
def receipt_rows(stdout: str) -> list[dict[str, object]]:
|
||||
return [json.loads(line) for line in stdout.splitlines() if line.startswith("{")]
|
||||
|
||||
|
||||
def test_help_documents_inactive_immutable_contract() -> None:
|
||||
result = subprocess.run(
|
||||
["bash", str(DEPLOYER), "--help"],
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
timeout=10,
|
||||
check=False,
|
||||
)
|
||||
assert result.returncode == 0
|
||||
assert "immutable exact-hash directory" in result.stdout
|
||||
assert "does not create or" in result.stdout
|
||||
assert "active pointer" in result.stdout
|
||||
|
||||
|
||||
def test_check_mode_is_no_write_and_ready_when_bundle_absent(tmp_path: Path) -> None:
|
||||
result = run_deployer(tmp_path, mode="check_absent", apply=False)
|
||||
assert result.returncode == 0, result.stderr
|
||||
rows = receipt_rows(result.stdout)
|
||||
assert rows[-1]["terminal"] == "check_pass_no_write"
|
||||
assert rows[-1]["detail"].endswith("remote_state_absent")
|
||||
events = (tmp_path / "events.log").read_text(encoding="utf-8").splitlines()
|
||||
assert len([line for line in events if line.startswith("ssh ")]) == 1
|
||||
assert not [line for line in events if line.startswith("scp ")]
|
||||
|
||||
|
||||
def test_check_mode_fails_closed_on_remote_drift(tmp_path: Path) -> None:
|
||||
result = run_deployer(tmp_path, mode="check_drift", apply=False)
|
||||
assert result.returncode == 1
|
||||
rows = receipt_rows(result.stdout)
|
||||
assert rows[-1]["terminal"] == "failed_no_write"
|
||||
|
||||
|
||||
def test_apply_uses_seven_transfers_and_exact_postcheck(tmp_path: Path) -> None:
|
||||
result = run_deployer(tmp_path, mode="apply", apply=True)
|
||||
assert result.returncode == 0, result.stderr
|
||||
rows = receipt_rows(result.stdout)
|
||||
assert rows[-1]["terminal"] == "pass_source_deployed_inactive"
|
||||
assert rows[-1]["detail"] == "runtime_export_not_executed"
|
||||
events = (tmp_path / "events.log").read_text(encoding="utf-8").splitlines()
|
||||
assert len([line for line in events if line.startswith("scp ")]) == 7
|
||||
assert len([line for line in events if line.startswith("ssh ")]) == 4
|
||||
|
||||
|
||||
def test_deployer_has_no_active_pointer_or_destructive_fallback() -> None:
|
||||
def test_historical_entrypoint_contains_no_transport_or_mutation_primitive() -> None:
|
||||
source = DEPLOYER.read_text(encoding="utf-8")
|
||||
assert '"${REMOTE_ROOT}/current"' in source
|
||||
assert "active_pointer_0" in source
|
||||
assert "pass_source_deployed_inactive" in source
|
||||
assert "quarantine-candidate" in source
|
||||
assert "quarantine-target" in source
|
||||
assert "docker stop" not in source
|
||||
assert "docker start" not in source
|
||||
assert "docker restart" not in source
|
||||
assert "sqlite3" not in source
|
||||
assert "github.com" not in source.casefold()
|
||||
assert "curl |" not in source
|
||||
assert "curl -fsSL" not in source
|
||||
assert "\nrm " not in source
|
||||
assert "ln -s" not in source
|
||||
assert "signoz-metadata-isolated-restore.py" in source
|
||||
assert "isolated-cluster.xml" in source
|
||||
assert "local_exact_sources_7" in source
|
||||
assert "[ \"${#EXPECTED_HASHES[@]}\" -eq 7 ]" in source
|
||||
|
||||
|
||||
def test_transport_propagates_strict_fixed_paths_with_spaces(tmp_path: Path) -> None:
|
||||
transport_dir = tmp_path / "transport paths"
|
||||
transport_dir.mkdir()
|
||||
identity = transport_dir / "agent99 identity"
|
||||
known_hosts = transport_dir / "known hosts"
|
||||
identity.write_text("test-only-identity\n", encoding="utf-8")
|
||||
known_hosts.write_text("test-only-known-host\n", encoding="utf-8")
|
||||
|
||||
result = run_deployer(
|
||||
tmp_path,
|
||||
mode="check_absent",
|
||||
apply=False,
|
||||
env_overrides={
|
||||
"SIGNOZ_METADATA_SSH_IDENTITY_FILE": str(identity),
|
||||
"SIGNOZ_METADATA_KNOWN_HOSTS_FILE": str(known_hosts),
|
||||
},
|
||||
)
|
||||
|
||||
assert result.returncode == 0, result.stderr
|
||||
event = (tmp_path / "events.log").read_text(encoding="utf-8")
|
||||
assert "IdentitiesOnly=yes" in event
|
||||
assert "StrictHostKeyChecking=yes" in event
|
||||
assert str(identity) in event
|
||||
assert f"UserKnownHostsFile={known_hosts}" in event
|
||||
|
||||
|
||||
def test_transport_rejects_missing_fixed_path_before_remote_use(tmp_path: Path) -> None:
|
||||
result = run_deployer(
|
||||
tmp_path,
|
||||
mode="check_absent",
|
||||
apply=False,
|
||||
env_overrides={
|
||||
"SIGNOZ_METADATA_SSH_IDENTITY_FILE": str(tmp_path / "missing identity")
|
||||
},
|
||||
)
|
||||
|
||||
assert result.returncode == 64
|
||||
assert "invalid SSH identity file" in result.stderr
|
||||
assert not (tmp_path / "events.log").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_transport_rejects_symlink_fixed_path_before_remote_use(tmp_path: Path) -> None:
|
||||
target = tmp_path / "known-hosts-target"
|
||||
target.write_text("test-only-known-host\n", encoding="utf-8")
|
||||
symlink = tmp_path / "known hosts link"
|
||||
symlink.symlink_to(target)
|
||||
|
||||
result = run_deployer(
|
||||
tmp_path,
|
||||
mode="check_absent",
|
||||
apply=False,
|
||||
env_overrides={"SIGNOZ_METADATA_KNOWN_HOSTS_FILE": str(symlink)},
|
||||
)
|
||||
|
||||
assert result.returncode == 64
|
||||
assert "invalid SSH known_hosts file" in result.stderr
|
||||
assert not (tmp_path / "events.log").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_shared_operation_lock_is_existing_read_only_and_fail_closed() -> None:
|
||||
source = DEPLOYER.read_text(encoding="utf-8")
|
||||
assert "OPERATION_LOCK=/tmp/awoooi-signoz-backup-operation.lock" in source
|
||||
assert '[ -f "${OPERATION_LOCK}" ] && [ ! -L "${OPERATION_LOCK}" ]' in source
|
||||
assert 'exec 8<"${OPERATION_LOCK}"' in source
|
||||
assert "flock -n 8" in source
|
||||
assert "exec 8>>/tmp/awoooi-signoz-backup-operation.lock" not in source
|
||||
|
||||
|
||||
def test_remote_check_uses_privileged_read_only_visibility() -> None:
|
||||
source = DEPLOYER.read_text(encoding="utf-8")
|
||||
remote_check = source.split("remote_check() {", 1)[1].split("\n}", 1)[0]
|
||||
assert '"${TARGET_HOST}" sudo -n bash -s --' in remote_check
|
||||
assert "REMOTE_CHECK contains only stat/hash/process/API" in remote_check
|
||||
|
||||
|
||||
def test_exact_seven_file_supply_chain_and_modes_are_fixed() -> None:
|
||||
source = DEPLOYER.read_text(encoding="utf-8")
|
||||
for path in (
|
||||
"config/signoz/metadata-export-policy.json",
|
||||
"scripts/backup/signoz_metadata_contract.py",
|
||||
"scripts/backup/signoz-metadata-export.py",
|
||||
"scripts/backup/verify-signoz-metadata-export.py",
|
||||
"scripts/backup/signoz-metadata-restore-drill.py",
|
||||
"scripts/backup/signoz-metadata-isolated-restore.py",
|
||||
"ops/signoz/clickhouse/restore-drill/config.d/isolated-cluster.xml",
|
||||
for forbidden in (
|
||||
"192.168.0.110",
|
||||
"ssh ",
|
||||
"scp ",
|
||||
"docker ",
|
||||
"sudo ",
|
||||
"curl ",
|
||||
"rm ",
|
||||
"mv ",
|
||||
"ln ",
|
||||
):
|
||||
assert path in source
|
||||
assert "MODES=(0644 0644 0755 0755 0755 0755 0644)" in source
|
||||
assert '[ "${#EXPECTED_HASHES[@]}" -eq 7 ]' in source
|
||||
assert forbidden not in source
|
||||
assert "blocked_direct_host110_route_retired" in source
|
||||
assert "production_mutation_performed" in source
|
||||
assert "completion_claim" in source
|
||||
|
||||
|
||||
def test_historical_entrypoint_points_only_to_agent99_replacement() -> None:
|
||||
source = DEPLOYER.read_text(encoding="utf-8")
|
||||
|
||||
assert "scripts/ops/deploy-signoz-metadata-toolchain-via-agent99.sh" in source
|
||||
assert "github.com" not in source.casefold()
|
||||
assert "ghcr.io" not in source.casefold()
|
||||
|
||||
Reference in New Issue
Block a user