Files
awoooi/scripts/backup/tests/test_signoz_metadata_export_contract.py

944 lines
32 KiB
Python

from __future__ import annotations
import hashlib
import json
import os
import socket
import subprocess
import sys
import threading
import urllib.parse
from contextlib import contextmanager
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from typing import Any, Iterator
ROOT = Path(__file__).resolve().parents[3]
EXPORTER = ROOT / "scripts" / "backup" / "signoz-metadata-export.py"
VERIFIER = ROOT / "scripts" / "backup" / "verify-signoz-metadata-export.py"
RESTORE = ROOT / "scripts" / "backup" / "signoz-metadata-restore-drill.py"
POLICY = ROOT / "config" / "signoz" / "metadata-export-policy.json"
TRACE_ID = "trace-P0-OBS-002-metadata"
RUN_ID = "run-P0-OBS-002-metadata"
WORK_ITEM_ID = "P0-OBS-002"
TOKEN = "test-only-signoz-token-reference"
SOURCE_ASSETS: dict[str, Any] = {
"/api/v1/dashboards": {"data": [{"id": "dash-1", "title": "Ops"}]},
"/api/v1/rules": {
"status": "success",
"data": {"rules": [{"id": "rule-1", "name": "Latency"}]},
},
"/api/v1/explorer/views?sourcePage=logs": {
"data": [
{
"id": "view-1",
"name": "Errors",
"sourcePage": "logs",
}
]
},
"/api/v1/explorer/views?sourcePage=meter": {"data": None},
"/api/v1/explorer/views?sourcePage=metrics": {"data": {}},
"/api/v1/explorer/views?sourcePage=traces": {"data": []},
"/api/v1/roles": {"data": [{"id": "role-1", "name": "Viewer"}]},
"/api/v1/org/preferences": {"data": [{"name": "theme", "value": "dark"}]},
"/api/v1/user/preferences": {"data": [{"name": "timezone", "value": "UTC"}]},
"/api/v1/global/config": {"data": {"setupCompleted": True}},
}
class MetadataHandler(BaseHTTPRequestHandler):
assets: dict[str, Any] = {}
drift_path: str | None = None
get_counts: dict[str, int] = {}
post_count = 0
def log_message(self, format: str, *args: object) -> None:
return
def _authorized(self) -> bool:
return (
self.headers.get("SIGNOZ-API-KEY") == TOKEN
or self.headers.get("Authorization") == f"Bearer {TOKEN}"
)
def _send_json(self, status: int, value: Any) -> None:
payload = json.dumps(value, separators=(",", ":")).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.wfile.write(payload)
def do_GET(self) -> None:
if not self._authorized():
self._send_json(401, {"error": "unauthorized"})
return
path = self.path.split("?", 1)[0]
asset_key = self.path if self.path in self.assets else path
if asset_key not in self.assets:
self._send_json(404, {"error": "not found"})
return
self.get_counts[asset_key] = self.get_counts.get(asset_key, 0) + 1
value = json.loads(json.dumps(self.assets[asset_key]))
if self.drift_path in {path, asset_key} and self.get_counts[asset_key] >= 2:
value["data"].append({"id": "drift", "title": "changed"})
self._send_json(200, value)
def do_POST(self) -> None:
if not self._authorized():
self._send_json(401, {"error": "unauthorized"})
return
path = self.path.split("?", 1)[0]
if path != "/api/v1/explorer/views" and path not in self.assets:
self._send_json(404, {"error": "not found"})
return
length = int(self.headers.get("Content-Length", "0"))
value = json.loads(self.rfile.read(length))
if not isinstance(value, dict):
self._send_json(400, {"error": "object required"})
return
if path == "/api/v1/explorer/views":
source_page = value.get("sourcePage")
if source_page not in {"logs", "meter", "metrics", "traces"}:
self._send_json(400, {"error": "sourcePage required"})
return
asset_key = (
f"{path}?{urllib.parse.urlencode({'sourcePage': source_page})}"
)
if asset_key not in self.assets:
self._send_json(404, {"error": "not found"})
return
data = self.assets[asset_key].get("data")
if data is None or data == {}:
self.assets[asset_key]["data"] = []
data = self.assets[asset_key]["data"]
collection = data
else:
data = self.assets[path].get("data")
collection = (
data.get("rules")
if path == "/api/v1/rules" and isinstance(data, dict)
else data
)
if not isinstance(collection, list):
self._send_json(404, {"error": "not found"})
return
type(self).post_count += 1
restored = {"id": f"server-{type(self).post_count}", **value}
collection.append(restored)
self._send_json(201, {"data": restored})
@contextmanager
def metadata_server(
assets: dict[str, Any],
*,
drift_path: str | None = None,
) -> Iterator[tuple[str, type[MetadataHandler]]]:
handler = type("BoundMetadataHandler", (MetadataHandler,), {})
handler.assets = json.loads(json.dumps(assets))
handler.drift_path = drift_path
handler.get_counts = {}
handler.post_count = 0
server = ThreadingHTTPServer(("127.0.0.1", 0), handler)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
host, port = server.server_address
yield f"http://{host}:{port}", handler
finally:
server.shutdown()
server.server_close()
thread.join(timeout=5)
def credential_file(tmp_path: Path, *, mode: int = 0o600) -> Path:
path = tmp_path / "signoz-api-key.ref"
path.write_text(f"{TOKEN}\n", encoding="ascii")
path.chmod(mode)
return path
def export_command(
*,
base_url: str,
output_dir: Path,
credential: Path | None,
apply: bool,
receipt_file: Path | None = None,
policy: Path | None = None,
) -> list[str]:
command = [
sys.executable,
str(EXPORTER),
"--apply" if apply else "--check",
"--base-url",
base_url,
"--output-dir",
str(output_dir),
"--trace-id",
TRACE_ID,
"--run-id",
RUN_ID,
"--work-item-id",
WORK_ITEM_ID,
]
if credential is not None:
command.extend(["--credential-file", str(credential)])
if policy is not None:
command.extend(["--policy", str(policy)])
if apply:
terminal_path = receipt_file or output_dir.with_name(
f"{output_dir.name}.terminal.json"
)
command.extend(["--receipt-file", str(terminal_path)])
return command
def create_bundle(tmp_path: Path) -> tuple[Path, Path]:
credential = credential_file(tmp_path)
bundle = tmp_path / "bundle"
with metadata_server(SOURCE_ASSETS) as (base_url, _):
result = subprocess.run(
export_command(
base_url=base_url,
output_dir=bundle,
credential=credential,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 0, result.stderr
return bundle, credential
def isolation_receipt(tmp_path: Path, target_base_url: str) -> Path:
policy = json.loads(POLICY.read_text(encoding="utf-8"))
identity = hashlib.sha256(
TRACE_ID.encode("utf-8")
+ b"\0"
+ RUN_ID.encode("utf-8")
+ b"\0"
+ WORK_ITEM_ID.encode("utf-8")
).hexdigest()
short_id = identity[:16]
prefix = f"awoooi-signoz-md-restore-{short_id}"
port_text = target_base_url.rsplit(":", 1)[-1]
port = int(port_text) if port_text.isdigit() else 443
production_before = {
entry["container"]: {
"id": hashlib.sha256(entry["container"].encode()).hexdigest(),
"image_id": entry["image_id"],
"image_ref": entry["image_ref"],
"running": True,
"started_at": "2026-07-22T00:00:00Z",
"restart_count": 0,
}
for entry in policy["restore_isolation"]["production_continuity"].values()
}
value = {
"schema": "awoooi_signoz_metadata_restore_isolation_v1",
"trace_id": TRACE_ID,
"run_id": RUN_ID,
"work_item_id": WORK_ITEM_ID,
"target": {
"identity": identity,
"prefix": prefix,
"canonical_id": f"ephemeral-signoz-metadata-restore-{short_id}",
"base_url_sha256": hashlib.sha256(
target_base_url.encode("utf-8")
).hexdigest(),
"image_ref": "signoz/signoz:v0.113.0",
"image_id": policy["restore_isolation"]["required_image_id"],
"images": policy["restore_isolation"]["images"],
"image_present_locally": True,
"image_pull_performed": False,
"image_build_performed": False,
"production_network_attached": False,
"production_volume_attached": False,
"ephemeral_volumes_only": True,
"cleanup_controller_armed": True,
"zero_residue_verifier_armed": True,
"network_scope": "loopback_and_internal_only",
"resource_label_key": policy["restore_isolation"]["resource_label_key"],
"resource_label_value": RUN_ID,
"identity_label_key": "com.awoooi.restore.identity",
"identity_label_value": identity,
"resources": {
"network": f"{prefix}-net",
"containers": [
f"{prefix}-server",
f"{prefix}-clickhouse",
f"{prefix}-zookeeper",
],
"volumes": [
f"{prefix}-zk-data",
f"{prefix}-zk-log",
f"{prefix}-ch-data",
f"{prefix}-server-data",
],
"workspace": f"/tmp/{prefix}-private",
},
"listener": {"host": "127.0.0.1", "port": port},
"authentication_mode": "isolated_session_bearer",
},
"production_before": production_before,
"image_inventory_before": ["sha256:test|test:fixture"],
}
path = tmp_path / "isolation.json"
path.write_text(json.dumps(value), encoding="utf-8")
path.chmod(0o600)
return path
def restore_command(
*,
mode: str,
bundle: Path,
target_base_url: str,
credential: Path | None,
isolation: Path,
receipt_file: Path | None = None,
) -> list[str]:
command = [
sys.executable,
str(RESTORE),
mode,
"--bundle-dir",
str(bundle),
"--target-base-url",
target_base_url,
"--auth-mode",
"isolated_session_bearer",
"--isolation-receipt",
str(isolation),
"--trace-id",
TRACE_ID,
"--run-id",
RUN_ID,
"--work-item-id",
WORK_ITEM_ID,
]
if credential is not None:
command.extend(["--credential-file", str(credential)])
if mode == "--apply":
terminal_path = receipt_file or bundle.parent / "restore-terminal.json"
command.extend(["--receipt-file", str(terminal_path)])
return command
def test_policy_is_explicitly_non_raw_and_non_completion() -> None:
policy = json.loads(POLICY.read_text(encoding="utf-8"))
assert policy["source_runtime"]["raw_database_access_allowed"] is False
assert policy["source_runtime"]["raw_volume_access_allowed"] is False
assert policy["source_runtime"]["github_supply_chain_allowed"] is False
assert policy["completion_contract"]["portable_export_alone_is_completion"] is False
assert (
policy["completion_contract"]["full_sqlite_completion_claim_allowed"] is False
)
assert {item["path"] for item in policy["forbidden_endpoints"]} >= {
"/api/v1/pats",
"/api/v1/domains",
"/api/v1/channels",
}
alert_rules = next(item for item in policy["assets"] if item["id"] == "alert_rules")
assert alert_rules["endpoint"] == "/api/v1/rules"
assert alert_rules["response_pointer"] == "/data/rules"
explorer_views = [
item for item in policy["assets"] if item["id"].startswith("explorer_views_")
]
assert {item["query_parameters"]["sourcePage"] for item in explorer_views} == {
"logs",
"meter",
"metrics",
"traces",
}
assert all(item["response_pointer"] == "/data" for item in explorer_views)
assert all(
item["empty_collection_sentinels"] == ["null", "empty_object"]
for item in explorer_views
)
def test_policy_rejects_unhashable_empty_collection_sentinel_as_contract_error(
tmp_path: Path,
) -> None:
policy_value = json.loads(POLICY.read_text(encoding="utf-8"))
explorer = next(
item
for item in policy_value["assets"]
if item["id"] == "explorer_views_logs"
)
explorer["empty_collection_sentinels"] = [{}]
malformed_policy = tmp_path / "malformed-policy.json"
malformed_policy.write_text(json.dumps(policy_value), encoding="utf-8")
result = subprocess.run(
export_command(
base_url="https://signoz.invalid",
output_dir=tmp_path / "must-not-exist",
credential=None,
apply=False,
policy=malformed_policy,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
check=False,
)
assert result.returncode == 1
assert "policy_empty_collection_sentinels_invalid_explorer_views_logs" in (
result.stderr
)
assert "Traceback" not in result.stderr
def test_policy_pins_reviewed_isolated_restore_runtime() -> None:
policy = json.loads(POLICY.read_text(encoding="utf-8"))
isolation = policy["restore_isolation"]
assert isolation["required_image_id"] == (
"sha256:c17991d10966aedcb0d4d83805a0baf5310f1553d90611629036fcfaee8d969b"
)
assert isolation["startup_contract"]["reviewed"] is True
assert isolation["startup_contract"]["server_entrypoint"] == [
"./signoz",
"server",
]
assert isolation["startup_contract"]["server_environment"] == {
"SIGNOZ_TELEMETRYSTORE_CLICKHOUSE_DSN": "tcp://clickhouse:9000",
"SIGNOZ_SQLSTORE_SQLITE_PATH": "/var/lib/signoz/signoz.db",
}
def test_check_mode_writes_nothing(tmp_path: Path) -> None:
output = tmp_path / "must-not-exist"
result = subprocess.run(
export_command(
base_url="https://signoz.invalid",
output_dir=output,
credential=None,
apply=False,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
check=False,
)
assert result.returncode == 0, result.stderr
assert json.loads(result.stdout)["terminal"] == "check_pass_no_write"
assert not output.exists()
def test_apply_and_independent_verifier_pass(tmp_path: Path) -> None:
bundle, _ = create_bundle(tmp_path)
result = subprocess.run(
[
sys.executable,
str(VERIFIER),
"--bundle-dir",
str(bundle),
"--expected-trace-id",
TRACE_ID,
"--expected-run-id",
RUN_ID,
"--expected-work-item-id",
WORK_ITEM_ID,
],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
check=False,
)
assert result.returncode == 0, result.stderr
assert json.loads(result.stdout)["terminal"] == (
"pass_export_verified_restore_pending"
)
manifest = json.loads((bundle / "manifest.json").read_text(encoding="utf-8"))
assert manifest["stable_read_count"] == 2
assert manifest["raw_sqlite_read"] is False
assert manifest["sensitive_value_persisted"] is False
assert manifest["completion_claim"] is False
assert oct((bundle / "manifest.json").stat().st_mode & 0o777) == "0o600"
def test_explorer_views_are_source_scoped_and_empty_sentinels_are_bounded(
tmp_path: Path,
) -> None:
credential = credential_file(tmp_path)
bundle = tmp_path / "bundle"
with metadata_server(SOURCE_ASSETS) as (base_url, handler):
result = subprocess.run(
export_command(
base_url=base_url,
output_dir=bundle,
credential=credential,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 0, result.stderr
expected_keys = {
f"/api/v1/explorer/views?sourcePage={source_page}"
for source_page in ("logs", "meter", "metrics", "traces")
}
assert expected_keys <= set(handler.get_counts)
assert all(handler.get_counts[key] == 2 for key in expected_keys)
assert "/api/v1/explorer/views" not in handler.get_counts
manifest = json.loads((bundle / "manifest.json").read_text(encoding="utf-8"))
view_counts = {
item["id"]: item["item_count"]
for item in manifest["assets"]
if item["id"].startswith("explorer_views_")
}
assert view_counts == {
"explorer_views_logs": 1,
"explorer_views_meter": 0,
"explorer_views_metrics": 0,
"explorer_views_traces": 0,
}
view_queries = {
item["id"]: item["query_parameters"]
for item in manifest["assets"]
if item["id"].startswith("explorer_views_")
}
assert view_queries == {
"explorer_views_logs": {"sourcePage": "logs"},
"explorer_views_meter": {"sourcePage": "meter"},
"explorer_views_metrics": {"sourcePage": "metrics"},
"explorer_views_traces": {"sourcePage": "traces"},
}
def test_explorer_views_nonempty_scalar_fails_closed(tmp_path: Path) -> None:
assets = json.loads(json.dumps(SOURCE_ASSETS))
assets["/api/v1/explorer/views?sourcePage=metrics"]["data"] = "unexpected"
output = tmp_path / "bundle"
credential = credential_file(tmp_path)
with metadata_server(assets) as (base_url, _):
result = subprocess.run(
export_command(
base_url=base_url,
output_dir=output,
credential=credential,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 1
assert "asset_collection_shape_invalid_explorer_views_metrics" in result.stderr
assert not output.exists()
def test_explorer_view_item_must_match_scoped_source_page(tmp_path: Path) -> None:
assets = json.loads(json.dumps(SOURCE_ASSETS))
assets["/api/v1/explorer/views?sourcePage=logs"]["data"][0][
"sourcePage"
] = "traces"
output = tmp_path / "bundle"
credential = credential_file(tmp_path)
with metadata_server(assets) as (base_url, _):
result = subprocess.run(
export_command(
base_url=base_url,
output_dir=output,
credential=credential,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 1
assert "asset_collection_scope_invalid_explorer_views_logs" in result.stderr
assert not output.exists()
def test_secret_key_fails_closed_without_bundle(tmp_path: Path) -> None:
assets = json.loads(json.dumps(SOURCE_ASSETS))
assets["/api/v1/global/config"]["data"]["clientSecret"] = "must-not-persist"
output = tmp_path / "bundle"
credential = credential_file(tmp_path)
with metadata_server(assets) as (base_url, _):
result = subprocess.run(
export_command(
base_url=base_url,
output_dir=output,
credential=credential,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 1
assert "forbidden_key_detected" in result.stderr
assert "must-not-persist" not in result.stderr
assert not output.exists()
def test_source_drift_fails_closed_without_bundle(tmp_path: Path) -> None:
output = tmp_path / "bundle"
credential = credential_file(tmp_path)
with metadata_server(SOURCE_ASSETS, drift_path="/api/v1/dashboards") as (
base_url,
_,
):
result = subprocess.run(
export_command(
base_url=base_url,
output_dir=output,
credential=credential,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 1
assert "source_metadata_drift_between_stable_reads" in result.stderr
assert not output.exists()
def test_tamper_breaks_independent_verifier(tmp_path: Path) -> None:
bundle, _ = create_bundle(tmp_path)
asset = bundle / "assets" / "dashboards.json"
asset.write_text('{"data":[]}\n', encoding="utf-8")
asset.chmod(0o600)
result = subprocess.run(
[
sys.executable,
str(VERIFIER),
"--bundle-dir",
str(bundle),
"--expected-trace-id",
TRACE_ID,
"--expected-run-id",
RUN_ID,
],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
check=False,
)
assert result.returncode == 1
assert "manifest_asset_hash_mismatch_dashboards" in result.stderr
def test_unexpected_bundle_file_breaks_independent_verifier(tmp_path: Path) -> None:
bundle, _ = create_bundle(tmp_path)
unexpected = bundle / "unlisted.json"
unexpected.write_text('{"not":"manifested"}\n', encoding="utf-8")
unexpected.chmod(0o600)
result = subprocess.run(
[
sys.executable,
str(VERIFIER),
"--bundle-dir",
str(bundle),
"--expected-trace-id",
TRACE_ID,
"--expected-run-id",
RUN_ID,
],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
check=False,
)
assert result.returncode == 1
assert "bundle_tree_contains_unexpected_entries" in result.stderr
def test_restore_check_and_semantic_apply_are_bounded(tmp_path: Path) -> None:
bundle, credential = create_bundle(tmp_path)
target_assets = {
"/api/v1/dashboards": {"data": []},
"/api/v1/rules": {"status": "success", "data": {"rules": []}},
"/api/v1/explorer/views?sourcePage=logs": {"data": []},
"/api/v1/explorer/views?sourcePage=meter": {"data": None},
"/api/v1/explorer/views?sourcePage=metrics": {"data": {}},
"/api/v1/explorer/views?sourcePage=traces": {"data": []},
}
with metadata_server(target_assets) as (target_base_url, handler):
isolation = isolation_receipt(tmp_path, target_base_url)
check_result = subprocess.run(
restore_command(
mode="--check",
bundle=bundle,
target_base_url=target_base_url,
credential=credential,
isolation=isolation,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert check_result.returncode == 0, check_result.stderr
assert json.loads(check_result.stdout)["terminal"] == "check_pass_no_write"
assert handler.post_count == 0
apply_result = subprocess.run(
restore_command(
mode="--apply",
bundle=bundle,
target_base_url=target_base_url,
credential=credential,
isolation=isolation,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert apply_result.returncode == 0, apply_result.stderr
assert json.loads(apply_result.stdout)["terminal"] == (
"partial_degraded_cleanup_pending"
)
apply_receipt = json.loads(apply_result.stdout)
assert apply_receipt["restored_asset_counts"] == {
"dashboards": 1,
"alert_rules": 1,
"explorer_views_logs": 1,
"explorer_views_meter": 0,
"explorer_views_metrics": 0,
"explorer_views_traces": 0,
}
assert len(apply_receipt["portable_semantic_sha256"]) == 64
assert apply_receipt["completion_scope"] == "portable_assets_only"
assert apply_receipt["full_sqlite_completion_claim"] is False
phase_receipts = apply_receipt["phase_receipts"]
assert [item["phase"] for item in phase_receipts] == [
"sensor_source",
"normalized_asset_identity",
"source_of_truth_diff",
"ai_decision",
"risk_policy_decision",
"check_mode",
"bounded_execution",
"independent_post_verifier",
"rollback",
"learning_writeback",
]
assert phase_receipts[-1]["terminal"] == "pending"
assert handler.post_count == 3
def test_restore_rejects_non_loopback_target_before_writes(tmp_path: Path) -> None:
bundle, credential = create_bundle(tmp_path)
target = "https://signoz.example.invalid"
isolation = isolation_receipt(tmp_path, target)
result = subprocess.run(
restore_command(
mode="--apply",
bundle=bundle,
target_base_url=target,
credential=credential,
isolation=isolation,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 1
assert "restore_target_must_be_loopback" in result.stderr
def test_restore_rejects_non_exact_isolation_image_before_writes(
tmp_path: Path,
) -> None:
bundle, credential = create_bundle(tmp_path)
with socket.socket() as sock:
sock.bind(("127.0.0.1", 0))
port = sock.getsockname()[1]
target = f"http://127.0.0.1:{port}"
isolation = isolation_receipt(tmp_path, target)
value = json.loads(isolation.read_text(encoding="utf-8"))
value["target"]["image_id"] = f"sha256:{'a' * 64}"
isolation.write_text(json.dumps(value), encoding="utf-8")
isolation.chmod(0o600)
result = subprocess.run(
restore_command(
mode="--apply",
bundle=bundle,
target_base_url=target,
credential=credential,
isolation=isolation,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 1
assert "isolation_target_image_id_mismatch" in result.stderr
def test_cleanup_verifier_requires_zero_labeled_residue(tmp_path: Path) -> None:
bundle, _ = create_bundle(tmp_path)
fake_bin = tmp_path / "bin"
fake_bin.mkdir()
docker = fake_bin / "docker"
policy = json.loads(POLICY.read_text(encoding="utf-8"))
production = {
entry["container"]: {
"Id": hashlib.sha256(entry["container"].encode()).hexdigest(),
"Image": entry["image_id"],
"Config": {"Image": entry["image_ref"]},
"State": {
"Running": True,
"StartedAt": "2026-07-22T00:00:00Z",
},
"RestartCount": 0,
}
for entry in policy["restore_isolation"]["production_continuity"].values()
}
docker.write_text(
"#!/usr/bin/env python3\n"
"import json, sys\n"
f"production = {production!r}\n"
"args = sys.argv[1:]\n"
"if args[:2] == ['container', 'inspect'] and args[2] in production:\n"
" print(json.dumps([production[args[2]]]))\n"
" raise SystemExit(0)\n"
"if args[:3] == ['image', 'ls', '--no-trunc']:\n"
" print('sha256:test|test:fixture')\n"
" raise SystemExit(0)\n"
"if len(args) >= 2 and args[1] == 'inspect':\n"
" raise SystemExit(1)\n"
"raise SystemExit(0)\n",
encoding="utf-8",
)
docker.chmod(0o755)
with socket.socket() as sock:
sock.bind(("127.0.0.1", 0))
port = sock.getsockname()[1]
target = f"http://127.0.0.1:{port}"
isolation = isolation_receipt(tmp_path, target)
env = {**os.environ, "PATH": f"{fake_bin}:{os.environ['PATH']}"}
result = subprocess.run(
restore_command(
mode="--verify-cleanup",
bundle=bundle,
target_base_url=target,
credential=None,
isolation=isolation,
),
env=env,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 0, result.stderr
assert json.loads(result.stdout)["terminal"] == "pass_zero_residue_verified"
def test_credential_reference_mode_fails_before_network(tmp_path: Path) -> None:
credential = credential_file(tmp_path, mode=0o644)
output = tmp_path / "bundle"
result = subprocess.run(
export_command(
base_url="https://signoz.invalid",
output_dir=output,
credential=credential,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
check=False,
)
assert result.returncode == 1
assert "credential_reference_mode_must_be_0400_or_0600" in result.stderr
assert not output.exists()
def test_credential_symlink_fails_before_network(tmp_path: Path) -> None:
credential = credential_file(tmp_path)
link = tmp_path / "credential-link"
link.symlink_to(credential)
output = tmp_path / "bundle"
result = subprocess.run(
export_command(
base_url="https://signoz.invalid",
output_dir=output,
credential=link,
apply=True,
),
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=10,
check=False,
)
assert result.returncode == 1
assert "credential_reference_symlink_component_forbidden" in result.stderr
assert not output.exists()
def test_apply_failure_writes_terminal_receipt_without_secret(tmp_path: Path) -> None:
assets = json.loads(json.dumps(SOURCE_ASSETS))
secret_value = "must-not-appear-in-terminal-receipt"
assets["/api/v1/global/config"]["data"]["clientSecret"] = secret_value
output = tmp_path / "bundle"
receipt_file = tmp_path / "terminal.json"
credential = credential_file(tmp_path)
with metadata_server(assets) as (base_url, _):
command = export_command(
base_url=base_url,
output_dir=output,
credential=credential,
apply=True,
receipt_file=receipt_file,
)
result = subprocess.run(
command,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=20,
check=False,
)
assert result.returncode == 1
terminal = json.loads(receipt_file.read_text(encoding="utf-8"))
assert terminal["terminal"] == "failed_export_not_closable"
assert secret_value not in receipt_file.read_text(encoding="utf-8")
assert not output.exists()