211 lines
7.5 KiB
Python
211 lines
7.5 KiB
Python
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from ops.capture_vps_canonical_postgres_snapshot import (
|
|
SAFE_AUTHORIZATION_REF_RE,
|
|
SAFE_SSH_TARGET_RE,
|
|
SOURCE_SNAPSHOT_RECEIPT_SCHEMA,
|
|
build_provenance_binding,
|
|
canonical_sha256,
|
|
cleanup_failed_output,
|
|
load_service_state,
|
|
load_snapshot_metadata,
|
|
parse_args,
|
|
remote_capture_script,
|
|
toc_counts,
|
|
)
|
|
|
|
|
|
def test_remote_capture_uses_one_exported_read_only_snapshot() -> None:
|
|
script = remote_capture_script(
|
|
run_id="canonical-20260711",
|
|
container="teleo-pg",
|
|
database="teleo",
|
|
service="leoclean-gateway.service",
|
|
)
|
|
|
|
assert "begin transaction isolation level repeatable read read only" in script
|
|
assert "select pg_export_snapshot()" in script
|
|
assert "[0-9A-F]+-[0-9A-F]+-[0-9]+" in script
|
|
assert '--snapshot="$snapshot_id"' in script
|
|
assert '-v "snapshot_id=$snapshot_id"' in script
|
|
assert "txid_current_snapshot()::text" in script
|
|
assert "pg_current_wal_lsn()::text" in script
|
|
assert "system_identifier::text from pg_control_system()" in script
|
|
assert "source-snapshot.json" in script
|
|
assert "--no-owner --no-acl" in script
|
|
assert "cmp -s" in script
|
|
assert 'assert_service_healthy "$remote_root/service-before.txt"' in script
|
|
assert 'assert_service_healthy "$remote_root/service-after.txt"' in script
|
|
assert "systemctl restart" not in script
|
|
assert "docker restart" not in script
|
|
|
|
|
|
def test_manifest_hash_order_is_collation_independent() -> None:
|
|
manifest = Path("ops/postgres_parity_manifest.sql").read_text()
|
|
|
|
assert 'collate "C"' in manifest
|
|
assert "'server_address', host(inet_server_addr())" in manifest
|
|
assert "'kb_gate_owner', 'kb_apply', 'kb_review'" in manifest
|
|
assert "'kind', 'role_memberships'" in manifest
|
|
assert "'kind', 'object_ownership'" in manifest
|
|
assert "'kind', 'object_acl'" in manifest
|
|
assert "aclexplode(attribute.attacl)" in manifest
|
|
|
|
|
|
def test_toc_counts_database_objects(tmp_path: Path) -> None:
|
|
toc = tmp_path / "dump.toc"
|
|
toc.write_text(
|
|
"; header\n"
|
|
"1; 0 0 TABLE DATA public claims postgres\n"
|
|
"2; 0 0 CONSTRAINT public claims claims_pkey postgres\n"
|
|
"3; 0 0 FK CONSTRAINT public evidence evidence_claim_fkey postgres\n"
|
|
"4; 0 0 INDEX public claims claims_text_idx postgres\n"
|
|
)
|
|
|
|
assert toc_counts(toc) == {"entries": 4, "table_data": 1, "constraints": 2, "indexes": 1}
|
|
|
|
|
|
def test_failure_cleanup_never_removes_preexisting_output(tmp_path: Path) -> None:
|
|
existing = tmp_path / "existing"
|
|
existing.mkdir()
|
|
marker = existing / "user-file"
|
|
marker.write_text("keep")
|
|
cleanup_failed_output(existing, preexisting=True)
|
|
|
|
created_by_run = tmp_path / "created-by-run"
|
|
created_by_run.mkdir()
|
|
cleanup_failed_output(created_by_run, preexisting=False)
|
|
|
|
assert marker.read_text() == "keep"
|
|
assert not created_by_run.exists()
|
|
|
|
|
|
def test_source_service_state_requires_healthy_unchanged_capable_fields(tmp_path: Path) -> None:
|
|
state_path = tmp_path / "service.txt"
|
|
state_path.write_text("ActiveState=active\nSubState=running\nMainPID=347406\nNRestarts=0\n")
|
|
|
|
assert load_service_state(state_path)["MainPID"] == "347406"
|
|
|
|
state_path.write_text("ActiveState=failed\nSubState=dead\nMainPID=0\nNRestarts=0\n")
|
|
with pytest.raises(RuntimeError, match="not active/running"):
|
|
load_service_state(state_path)
|
|
|
|
|
|
def test_ssh_target_rejects_open_ssh_option_injection() -> None:
|
|
assert SAFE_SSH_TARGET_RE.fullmatch("root@77.42.65.182")
|
|
assert SAFE_SSH_TARGET_RE.fullmatch("teleo-staging-1.internal")
|
|
assert not SAFE_SSH_TARGET_RE.fullmatch("-oProxyCommand=malicious")
|
|
assert not SAFE_SSH_TARGET_RE.fullmatch("root@host command")
|
|
|
|
|
|
def test_source_snapshot_metadata_and_provenance_binding(tmp_path: Path) -> None:
|
|
snapshot_path = tmp_path / "source-snapshot.json"
|
|
snapshot_path.write_text(
|
|
json.dumps(
|
|
{
|
|
"exported_snapshot_id": "00000003-000001A2-1",
|
|
"txid_snapshot": "100:120:105,111",
|
|
"wal_lsn": "0/16B6C50",
|
|
"system_identifier": "7649789040005668902",
|
|
"captured_at_utc": "2026-07-15T01:02:03.456789+00:00",
|
|
}
|
|
)
|
|
)
|
|
|
|
snapshot = load_snapshot_metadata(snapshot_path)
|
|
binding = build_provenance_binding(
|
|
run_id="canonical-20260715",
|
|
authorization_ref="codex-delegation:019f47af-f2cc-7c10-b928-a9283afa2621",
|
|
source={
|
|
"ssh_target": "root@77.42.65.182",
|
|
"container": "teleo-pg",
|
|
"database": "teleo",
|
|
"service": "leoclean-gateway.service",
|
|
},
|
|
snapshot=snapshot,
|
|
dump_sha256="1" * 64,
|
|
manifest_sql_sha256="2" * 64,
|
|
source_manifest_sha256="3" * 64,
|
|
source_context_sha256="4" * 64,
|
|
)
|
|
|
|
assert binding["algorithm"] == "sha256"
|
|
assert binding["payload"] == {
|
|
"receipt_schema": SOURCE_SNAPSHOT_RECEIPT_SCHEMA,
|
|
"run_id": "canonical-20260715",
|
|
"capture_authorization_ref": "codex-delegation:019f47af-f2cc-7c10-b928-a9283afa2621",
|
|
"source": {
|
|
"ssh_target": "root@77.42.65.182",
|
|
"container": "teleo-pg",
|
|
"database": "teleo",
|
|
"service": "leoclean-gateway.service",
|
|
},
|
|
"exported_snapshot_id": "00000003-000001A2-1",
|
|
"txid_snapshot": "100:120:105,111",
|
|
"wal_lsn": "0/16B6C50",
|
|
"source_system_identifier": "7649789040005668902",
|
|
"dump_sha256": "1" * 64,
|
|
"manifest_sql_sha256": "2" * 64,
|
|
"source_manifest_sha256": "3" * 64,
|
|
"source_context_sha256": "4" * 64,
|
|
}
|
|
assert binding["sha256"] == canonical_sha256(binding["payload"])
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("field", "value"),
|
|
[
|
|
("exported_snapshot_id", "unsafe snapshot"),
|
|
("txid_snapshot", "100:120:not-a-txid"),
|
|
("wal_lsn", "not-an-lsn"),
|
|
("system_identifier", "system-1"),
|
|
],
|
|
)
|
|
def test_source_snapshot_metadata_rejects_invalid_identity(tmp_path: Path, field: str, value: str) -> None:
|
|
payload = {
|
|
"exported_snapshot_id": "00000003-000001A2-1",
|
|
"txid_snapshot": "100:120:",
|
|
"wal_lsn": "0/16B6C50",
|
|
"system_identifier": "7649789040005668902",
|
|
"captured_at_utc": "2026-07-15T01:02:03+00:00",
|
|
}
|
|
payload[field] = value
|
|
path = tmp_path / "source-snapshot.json"
|
|
path.write_text(json.dumps(payload))
|
|
|
|
with pytest.raises(RuntimeError, match=field):
|
|
load_snapshot_metadata(path)
|
|
|
|
|
|
def test_authorization_ref_is_required_and_safe_metadata(tmp_path: Path) -> None:
|
|
ssh_key = tmp_path / "id_ed25519"
|
|
ssh_key.write_text("test-only")
|
|
manifest = tmp_path / "manifest.sql"
|
|
manifest.write_text("select 1;\n")
|
|
base = [
|
|
"--execute",
|
|
"--ssh-target",
|
|
"root@77.42.65.182",
|
|
"--ssh-key",
|
|
str(ssh_key),
|
|
"--manifest",
|
|
str(manifest),
|
|
"--run-id",
|
|
"canonical-20260715",
|
|
"--output-dir",
|
|
str(tmp_path / "capture"),
|
|
]
|
|
|
|
with pytest.raises(SystemExit):
|
|
parse_args(base)
|
|
with pytest.raises(SystemExit):
|
|
parse_args([*base, "--authorization-ref", "unsafe authorization ref"])
|
|
|
|
authorization_ref = "codex-delegation:019f47af-f2cc-7c10-b928-a9283afa2621"
|
|
args = parse_args([*base, "--authorization-ref", authorization_ref])
|
|
assert args.authorization_ref == authorization_ref
|
|
assert SAFE_AUTHORIZATION_REF_RE.fullmatch(authorization_ref)
|
|
assert not SAFE_AUTHORIZATION_REF_RE.fullmatch("authorization\nforged")
|