fix(signoz): bind alert rules export shape

This commit is contained in:
Your Name
2026-07-22 18:09:21 +08:00
parent 8bafc8af23
commit dd54c35667
10 changed files with 163 additions and 24 deletions

View File

@@ -26,7 +26,10 @@ TOKEN = "test-only-signoz-token-reference"
SOURCE_ASSETS: dict[str, Any] = {
"/api/v1/dashboards": {"data": [{"id": "dash-1", "title": "Ops"}]},
"/api/v1/rules": {"data": [{"id": "rule-1", "name": "Latency"}]},
"/api/v1/rules": {
"status": "success",
"data": {"rules": [{"id": "rule-1", "name": "Latency"}]},
},
"/api/v1/explorer/views": {"data": [{"id": "view-1", "name": "Errors"}]},
"/api/v1/roles": {"data": [{"id": "role-1", "name": "Viewer"}]},
"/api/v1/org/preferences": {"data": [{"name": "theme", "value": "dark"}]},
@@ -74,9 +77,16 @@ class MetadataHandler(BaseHTTPRequestHandler):
self._send_json(401, {"error": "unauthorized"})
return
path = self.path.split("?", 1)[0]
if path not in self.assets or not isinstance(
self.assets[path].get("data"), list
):
if path not in self.assets:
self._send_json(404, {"error": "not found"})
return
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
length = int(self.headers.get("Content-Length", "0"))
@@ -86,7 +96,7 @@ class MetadataHandler(BaseHTTPRequestHandler):
return
type(self).post_count += 1
restored = {"id": f"server-{type(self).post_count}", **value}
self.assets[path]["data"].append(restored)
collection.append(restored)
self._send_json(201, {"data": restored})
@@ -254,6 +264,9 @@ def test_policy_is_explicitly_non_raw_and_non_completion() -> None:
"/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"
def test_check_mode_writes_nothing(tmp_path: Path) -> None:
@@ -415,7 +428,7 @@ 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": {"data": []},
"/api/v1/rules": {"status": "success", "data": {"rules": []}},
"/api/v1/explorer/views": {"data": []},
}
with metadata_server(target_assets) as (target_base_url, handler):

View File

@@ -17,6 +17,8 @@ SCP_TIMEOUT_SECONDS="${SIGNOZ_METADATA_SCP_TIMEOUT_SECONDS:-120}"
REMOTE_TIMEOUT_SECONDS="${SIGNOZ_METADATA_REMOTE_TIMEOUT_SECONDS:-60}"
KILL_AFTER_SECONDS="${SIGNOZ_METADATA_KILL_AFTER_SECONDS:-10}"
LOCAL_PYTHON_BIN="${SIGNOZ_METADATA_LOCAL_PYTHON_BIN:-python3.11}"
SSH_IDENTITY_FILE="${SIGNOZ_METADATA_SSH_IDENTITY_FILE:-}"
SSH_KNOWN_HOSTS_FILE="${SIGNOZ_METADATA_KNOWN_HOSTS_FILE:-}"
LABELS=(
metadata-export-policy.json
@@ -35,11 +37,27 @@ LOCAL_SOURCES=(
MODES=(0644 0644 0755 0755 0755)
SSH_OPTIONS=(
-o BatchMode=yes
-o IdentitiesOnly=yes
-o StrictHostKeyChecking=yes
-o ConnectTimeout=8
-o ConnectionAttempts=1
-o ServerAliveInterval=5
-o ServerAliveCountMax=2
)
if [ -n "${SSH_IDENTITY_FILE}" ]; then
[ -f "${SSH_IDENTITY_FILE}" ] && [ ! -L "${SSH_IDENTITY_FILE}" ] || {
echo "invalid SSH identity file" >&2
exit 64
}
SSH_OPTIONS+=( -i "${SSH_IDENTITY_FILE}" )
fi
if [ -n "${SSH_KNOWN_HOSTS_FILE}" ]; then
[ -f "${SSH_KNOWN_HOSTS_FILE}" ] && [ ! -L "${SSH_KNOWN_HOSTS_FILE}" ] || {
echo "invalid SSH known_hosts file" >&2
exit 64
}
SSH_OPTIONS+=( -o "UserKnownHostsFile=${SSH_KNOWN_HOSTS_FILE}" )
fi
usage() {
cat <<'USAGE'
@@ -50,6 +68,10 @@ Required environment:
RUN_ID Unique path-safe execution identifier
WORK_ITEM_ID Must be P0-OBS-002
Optional fixed transport paths:
SIGNOZ_METADATA_SSH_IDENTITY_FILE
SIGNOZ_METADATA_KNOWN_HOSTS_FILE
--check validates the five local sources and performs a no-write host110 diff.
--apply creates one immutable exact-hash directory. It does not create or
change an active pointer and does not run an authenticated metadata export.

View File

@@ -31,7 +31,7 @@ def test_entrypoint_is_fixed_to_windows99_host110_and_p0_obs_002() -> None:
assert "$result.entrypointHashMatched" in source
assert '$CredentialFile = "/etc/awoooi/secrets/signoz-metadata-api-key"' in source
assert (
'$BundleId = "bb6d78b67f506072b2e45e92bc1d415364e25852282a9b068900665c578df011"'
'$BundleId = "337b5f86921d9b0af1a49e3bfe3e16c6a359f8fdfa1521c9dcbf230582ec286e"'
in source
)
assert '$BaseUrl = "http://127.0.0.1:8080"' in source

View File

@@ -86,11 +86,18 @@ printf 'scp %s\n' "$*" >> "${TEST_EVENT_LOG:?}"
def run_deployer(
tmp_path: Path, *, mode: str, apply: bool
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=fake_environment(tmp_path, mode=mode),
env=env,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -165,6 +172,65 @@ def test_deployer_has_no_active_pointer_or_destructive_fallback() -> None:
assert "ln -s" not 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

View File

@@ -858,6 +858,9 @@ def evaluate(root: Path, contract_path: Path) -> dict[str, Any]:
"signoz_sqlite_application_consistent_backup", {}
)
metadata_export_source_contract = sqlite_backup.get("source_contract", {})
metadata_candidate_deployment = metadata_export_source_contract.get(
"candidate_deployment", {}
)
metadata_deployment = metadata_export_source_contract.get("deployment", {})
declared_metadata_export_hashes = metadata_export_source_contract.get("hashes", {})
actual_metadata_export_hashes = _current_metadata_export_source_hashes(root)
@@ -866,7 +869,7 @@ def evaluate(root: Path, contract_path: Path) -> dict[str, Any]:
== len(METADATA_EXPORT_SOURCE_PATHS)
and set(declared_metadata_export_hashes) == set(METADATA_EXPORT_SOURCE_PATHS)
and declared_metadata_export_hashes == actual_metadata_export_hashes
and metadata_export_source_contract.get("test_terminal") == "21_passed"
and metadata_export_source_contract.get("test_terminal") == "24_passed"
)
offsite_backup = pending_verifiers.get("signoz_backup_offsite_dr", {})
failed_artifacts = pending_verifiers.get(
@@ -889,7 +892,8 @@ def evaluate(root: Path, contract_path: Path) -> dict[str, Any]:
== "pending_supported_non_raw_export_or_coordinated_snapshot"
and sqlite_backup.get("raw_sqlite_read_or_sync_allowed") is False
and sqlite_backup.get("sqlite_cli_present_in_runtime") is False
and sqlite_backup.get("source_contract_status") == "deployed_inactive_verified"
and sqlite_backup.get("source_contract_status")
== "source_candidate_pending_deployment"
and metadata_export_source_contract.get("policy")
== "config/signoz/metadata-export-policy.json"
and metadata_export_source_contract.get("exporter")
@@ -902,6 +906,18 @@ def evaluate(root: Path, contract_path: Path) -> dict[str, Any]:
and metadata_export_source_contract.get("raw_volume_read") is False
and metadata_export_source_contract.get("secret_value_persistence") is False
and metadata_export_source_contract.get("full_sqlite_completion_claim") is False
and metadata_candidate_deployment.get("status")
== "pending_exact_check_apply_postcheck"
and metadata_candidate_deployment.get("asset_id")
== "host110-signoz-metadata-toolchain"
and metadata_candidate_deployment.get("target_host") == "192.168.0.110"
and metadata_candidate_deployment.get("bundle_id")
== "337b5f86921d9b0af1a49e3bfe3e16c6a359f8fdfa1521c9dcbf230582ec286e"
and metadata_candidate_deployment.get("target_path")
== "/backup/toolchains/signoz-metadata/337b5f86921d9b0af1a49e3bfe3e16c6a359f8fdfa1521c9dcbf230582ec286e"
and metadata_candidate_deployment.get("active_pointer_present") is False
and metadata_candidate_deployment.get("runtime_export_executed") is False
and metadata_candidate_deployment.get("completion_claim") is False
and metadata_deployment.get("status") == "deployed_inactive_verified"
and metadata_deployment.get("asset_id") == "host110-signoz-metadata-toolchain"
and metadata_deployment.get("target_host") == "192.168.0.110"

View File

@@ -834,7 +834,9 @@ def test_post_release_verifier_and_native_backup_close_with_remaining_gaps() ->
]
assert sqlite_pending["raw_sqlite_read_or_sync_allowed"] is False
assert sqlite_pending["sqlite_cli_present_in_runtime"] is False
assert sqlite_pending["source_contract_status"] == ("deployed_inactive_verified")
assert sqlite_pending["source_contract_status"] == (
"source_candidate_pending_deployment"
)
source_contract = sqlite_pending["source_contract"]
assert source_contract["policy"] == "config/signoz/metadata-export-policy.json"
assert source_contract["exporter"] == ("scripts/backup/signoz-metadata-export.py")
@@ -875,7 +877,17 @@ def test_post_release_verifier_and_native_backup_close_with_remaining_gaps() ->
field: hashlib.sha256((ROOT / relative).read_bytes()).hexdigest()
for field, relative in metadata_paths.items()
}
assert source_contract["test_terminal"] == "21_passed"
assert source_contract["test_terminal"] == "24_passed"
candidate = source_contract["candidate_deployment"]
assert candidate["status"] == "pending_exact_check_apply_postcheck"
assert candidate["asset_id"] == "host110-signoz-metadata-toolchain"
assert candidate["target_host"] == "192.168.0.110"
assert candidate["bundle_id"] == (
"337b5f86921d9b0af1a49e3bfe3e16c6a359f8fdfa1521c9dcbf230582ec286e"
)
assert candidate["active_pointer_present"] is False
assert candidate["runtime_export_executed"] is False
assert candidate["completion_claim"] is False
deployment = source_contract["deployment"]
assert deployment["status"] == "deployed_inactive_verified"
assert deployment["asset_id"] == "host110-signoz-metadata-toolchain"
@@ -1094,7 +1106,7 @@ def test_post_closure_contract_mirror_and_program_blockers_are_consistent() -> N
post_closure["signoz_sqlite_application_consistent_backup_status"] == "pending"
)
assert post_closure["signoz_metadata_export_source_contract_status"] == (
"deployed_inactive_verified"
"source_candidate_pending_deployment"
)
assert post_closure["signoz_metadata_export_policy"] == (
"config/signoz/metadata-export-policy.json"