feat(observability): add safe SigNoz metadata backup lane

This commit is contained in:
ogt
2026-07-15 13:57:13 +08:00
parent 4dc5b51d0f
commit 1730c5bb71
12 changed files with 3485 additions and 28 deletions

View File

@@ -0,0 +1,505 @@
#!/usr/bin/env bash
# P0-OBS-002 - deploy an immutable, inactive SigNoz metadata toolchain to host110.
#
# The deployer never reads credentials, SQLite, or Docker volumes. It does not
# change an active pointer or invoke an authenticated metadata export. Failed
# candidates are moved into the run receipt directory rather than deleted.
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TARGET_HOST="${SIGNOZ_METADATA_TARGET_HOST:-wooo@192.168.0.110}"
REMOTE_ROOT="${SIGNOZ_METADATA_REMOTE_ROOT:-/backup/toolchains/signoz-metadata}"
RECEIPT_ROOT="${SIGNOZ_METADATA_RECEIPT_ROOT:-/backup/deploy-receipts/signoz-metadata-toolchain}"
STAGE_ROOT="${SIGNOZ_METADATA_STAGE_ROOT:-/tmp}"
SSH_TIMEOUT_SECONDS="${SIGNOZ_METADATA_SSH_TIMEOUT_SECONDS:-120}"
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}"
LABELS=(
metadata-export-policy.json
signoz_metadata_contract.py
signoz-metadata-export.py
verify-signoz-metadata-export.py
signoz-metadata-restore-drill.py
)
LOCAL_SOURCES=(
"${ROOT_DIR}/config/signoz/metadata-export-policy.json"
"${ROOT_DIR}/scripts/backup/signoz_metadata_contract.py"
"${ROOT_DIR}/scripts/backup/signoz-metadata-export.py"
"${ROOT_DIR}/scripts/backup/verify-signoz-metadata-export.py"
"${ROOT_DIR}/scripts/backup/signoz-metadata-restore-drill.py"
)
MODES=(0644 0644 0755 0755 0755)
SSH_OPTIONS=(
-o BatchMode=yes
-o ConnectTimeout=8
-o ConnectionAttempts=1
-o ServerAliveInterval=5
-o ServerAliveCountMax=2
)
usage() {
cat <<'USAGE'
Usage: deploy-signoz-metadata-toolchain.sh [--check|--apply]
Required environment:
TRACE_ID Path-safe controlled-apply trace identifier
RUN_ID Unique path-safe execution identifier
WORK_ITEM_ID Must be P0-OBS-002
--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.
USAGE
}
MODE="${1:---check}"
case "${MODE}" in
--check|--apply) ;;
-h|--help) usage; exit 0 ;;
*) usage >&2; exit 64 ;;
esac
[ "$#" -le 1 ] || { usage >&2; exit 64; }
TRACE_ID="${TRACE_ID:-}"
RUN_ID="${RUN_ID:-}"
WORK_ITEM_ID="${WORK_ITEM_ID:-}"
valid_identity() {
[[ "$1" =~ ^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$ ]]
}
valid_positive_integer() {
[[ "$1" =~ ^[1-9][0-9]*$ ]]
}
safe_absolute_path() {
local path="$1"
[[ "${path}" == /* ]] || return 1
[[ "${path}" != / && "${path}" != */ ]] || return 1
[[ "${path}" =~ ^/[A-Za-z0-9._/-]+$ ]] || return 1
case "/${path#/}/" in
*'//'*|*'/../'*|*'/./'*) return 1 ;;
esac
}
valid_identity "${TRACE_ID}" || { echo "invalid TRACE_ID" >&2; exit 64; }
valid_identity "${RUN_ID}" || { echo "invalid RUN_ID" >&2; exit 64; }
[ "${WORK_ITEM_ID}" = "P0-OBS-002" ] || {
echo "WORK_ITEM_ID must be P0-OBS-002" >&2
exit 64
}
for value in "${SSH_TIMEOUT_SECONDS}" "${SCP_TIMEOUT_SECONDS}" \
"${REMOTE_TIMEOUT_SECONDS}" "${KILL_AFTER_SECONDS}"; do
valid_positive_integer "${value}" || { echo "invalid timeout" >&2; exit 64; }
done
for path in "${REMOTE_ROOT}" "${RECEIPT_ROOT}" "${STAGE_ROOT}"; do
safe_absolute_path "${path}" || { echo "unsafe remote path" >&2; exit 64; }
done
bounded_ssh() {
timeout --kill-after="${KILL_AFTER_SECONDS}" "${SSH_TIMEOUT_SECONDS}" ssh "$@"
}
bounded_scp() {
timeout --kill-after="${KILL_AFTER_SECONDS}" "${SCP_TIMEOUT_SECONDS}" scp "$@"
}
hash_file() {
sha256sum "$1" | awk '{print $1}'
}
emit() {
local phase="$1" terminal="$2" detail="$3"
printf '{"schema":"awoooi_controlled_apply_receipt_v1","trace_id":"%s","run_id":"%s","work_item_id":"%s","asset_id":"host110-signoz-metadata-toolchain","phase":"%s","terminal":"%s","detail":"%s"}\n' \
"${TRACE_ID}" "${RUN_ID}" "${WORK_ITEM_ID}" "${phase}" "${terminal}" "${detail}"
}
validate_local_sources() {
local source
command -v "${LOCAL_PYTHON_BIN}" >/dev/null 2>&1
"${LOCAL_PYTHON_BIN}" -c 'import sys; assert sys.version_info >= (3, 10)'
for source in "${LOCAL_SOURCES[@]}"; do
[ -f "${source}" ] && [ ! -L "${source}" ] && [ -s "${source}" ]
done
"${LOCAL_PYTHON_BIN}" - "${LOCAL_SOURCES[@]:1}" <<'PY'
from pathlib import Path
import sys
for value in sys.argv[1:]:
path = Path(value)
compile(path.read_text(encoding="utf-8"), str(path), "exec")
PY
PYTHONPATH="${ROOT_DIR}/scripts/backup" "${LOCAL_PYTHON_BIN}" - \
"${LOCAL_SOURCES[0]}" <<'PY'
from pathlib import Path
import sys
from signoz_metadata_contract import load_policy
policy = load_policy(Path(sys.argv[1]))
assert policy["work_item_id"] == "P0-OBS-002"
assert policy["source_runtime"]["raw_database_access_allowed"] is False
assert policy["source_runtime"]["raw_volume_access_allowed"] is False
assert policy["completion_contract"]["full_sqlite_completion_claim_allowed"] is False
PY
}
validate_local_sources
SOURCE_HASHES=()
SOURCE_DETAIL=""
for index in "${!LOCAL_SOURCES[@]}"; do
source_hash="$(hash_file "${LOCAL_SOURCES[index]}")"
SOURCE_HASHES+=("${source_hash}")
SOURCE_DETAIL+="${LABELS[index]}_${source_hash}_"
done
SOURCE_DETAIL="${SOURCE_DETAIL%_}"
BUNDLE_ID="$(printf '%s\n' "${SOURCE_HASHES[@]}" | sha256sum | awk '{print $1}')"
TARGET_DIR="${REMOTE_ROOT}/${BUNDLE_ID}"
STAGE_DIR="${STAGE_ROOT}/awoooi-signoz-metadata-toolchain.${RUN_ID}"
emit sensor_source pass "local_exact_sources_5"
emit normalized_asset_identity pass "bundle_${BUNDLE_ID}"
emit ai_decision pass "candidate_additive_immutable_inactive_source_deploy"
emit risk_policy_decision pass "medium_no_active_pointer_no_secret_no_raw_sqlite"
remote_check() {
bounded_ssh "${SSH_OPTIONS[@]}" "${TARGET_HOST}" bash -s -- \
"${REMOTE_ROOT}" "${BUNDLE_ID}" "${REMOTE_TIMEOUT_SECONDS}" \
"${KILL_AFTER_SECONDS}" "${SOURCE_HASHES[@]}" <<'REMOTE_CHECK'
set -euo pipefail
REMOTE_ROOT="$1"
BUNDLE_ID="$2"
REMOTE_TIMEOUT_SECONDS="$3"
KILL_AFTER_SECONDS="$4"
shift 4
EXPECTED_HASHES=("$@")
LABELS=(
metadata-export-policy.json
signoz_metadata_contract.py
signoz-metadata-export.py
verify-signoz-metadata-export.py
signoz-metadata-restore-drill.py
)
MODES=(0644 0644 0755 0755 0755)
TARGET_DIR="${REMOTE_ROOT}/${BUNDLE_ID}"
[ "${#EXPECTED_HASHES[@]}" -eq 5 ]
[ -d /backup ] && [ ! -L /backup ]
[ ! -e "${REMOTE_ROOT}/current" ] && [ ! -L "${REMOTE_ROOT}/current" ]
for command_name in curl docker pgrep python3 sha256sum stat timeout; do
command -v "${command_name}" >/dev/null 2>&1
done
python3 -c 'import sys; assert sys.version_info >= (3, 10)'
container_state="$(timeout --kill-after="${KILL_AFTER_SECONDS}" \
"${REMOTE_TIMEOUT_SECONDS}" docker inspect --format \
'{{.Id}}\t{{.State.Running}}\t{{.State.StartedAt}}\t{{.RestartCount}}\t{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' signoz)"
api_status="$(timeout --kill-after="${KILL_AFTER_SECONDS}" \
"${REMOTE_TIMEOUT_SECONDS}" curl -sS -o /dev/null -w '%{http_code}' \
http://127.0.0.1:8080/api/v1/health)"
[ "${api_status}" = "200" ]
active_operations="$(
(pgrep -af '(^|/|[[:space:]])(backup-signoz|clickhouse-native-backup|clickhouse-native-restore-drill|run-signoz-backup-canary)[.]sh([[:space:]]|$)' || true) \
| wc -l | tr -d ' '
)"
[ "${active_operations}" = "0" ]
state=absent
drift=0
if [ -e "${TARGET_DIR}" ] || [ -L "${TARGET_DIR}" ]; then
[ -d "${TARGET_DIR}" ] && [ ! -L "${TARGET_DIR}" ] || drift=$((drift + 1))
for index in "${!LABELS[@]}"; do
target="${TARGET_DIR}/${LABELS[index]}"
if [ ! -f "${target}" ] || [ -L "${target}" ]; then
drift=$((drift + 1))
continue
fi
[ "$(sha256sum "${target}" | awk '{print $1}')" = "${EXPECTED_HASHES[index]}" ] || drift=$((drift + 1))
[ "0$(stat -c '%a' "${target}")" = "${MODES[index]}" ] || drift=$((drift + 1))
done
state=exact
[ "${drift}" -eq 0 ] || state=drift
fi
candidate_count=0
for candidate in "${REMOTE_ROOT}"/."${BUNDLE_ID}".candidate.*; do
[ -e "${candidate}" ] || [ -L "${candidate}" ] || continue
candidate_count=$((candidate_count + 1))
done
[ "${candidate_count}" -eq 0 ]
[ "${drift}" -eq 0 ]
printf 'REMOTE_CHECK terminal=check_pass_no_write state=%s drift=%s candidate_count=%s api=%s active_operations=%s container_state_sha256=%s\n' \
"${state}" "${drift}" "${candidate_count}" "${api_status}" "${active_operations}" \
"$(printf '%s' "${container_state}" | sha256sum | awk '{print $1}')"
REMOTE_CHECK
}
quarantine_transport_stage() {
bounded_ssh "${SSH_OPTIONS[@]}" "${TARGET_HOST}" sudo -n bash -s -- \
"${STAGE_DIR}" "${RECEIPT_ROOT}" "${RUN_ID}" <<'REMOTE_QUARANTINE'
set -euo pipefail
stage_dir="$1"
receipt_root="$2"
run_id="$3"
receipt_dir="${receipt_root}/${run_id}"
if [ ! -e "${stage_dir}" ] && [ ! -L "${stage_dir}" ]; then
exit 0
fi
[ -d "${stage_dir}" ] && [ ! -L "${stage_dir}" ]
mkdir -p "${receipt_root}"
if [ ! -e "${receipt_dir}" ] && [ ! -L "${receipt_dir}" ]; then
mkdir -m 0700 "${receipt_dir}"
fi
[ -d "${receipt_dir}" ] && [ ! -L "${receipt_dir}" ]
[ ! -e "${receipt_dir}/transport-stage" ] && [ ! -L "${receipt_dir}/transport-stage" ]
mv "${stage_dir}" "${receipt_dir}/transport-stage"
REMOTE_QUARANTINE
}
if ! REMOTE_CHECK_OUTPUT="$(remote_check)"; then
emit source_of_truth_diff failed "remote_read_only_check_failed"
emit terminal failed_no_write "remote_check_failed"
exit 1
fi
case "${REMOTE_CHECK_OUTPUT}" in
*"terminal=check_pass_no_write state=absent "*) REMOTE_STATE=absent ;;
*"terminal=check_pass_no_write state=exact "*) REMOTE_STATE=exact ;;
*)
emit source_of_truth_diff failed "remote_check_receipt_invalid"
emit terminal failed_no_write "remote_check_receipt_invalid"
exit 1
;;
esac
emit source_of_truth_diff pass "remote_state_${REMOTE_STATE}_drift_0"
if [ "${MODE}" = "--check" ]; then
emit check_mode check_pass_no_write "bundle_${BUNDLE_ID}_remote_state_${REMOTE_STATE}"
emit rollback no_write "active_pointer_unchanged"
emit terminal check_pass_no_write "source_ready_remote_state_${REMOTE_STATE}"
exit 0
fi
if [ "${REMOTE_STATE}" = "exact" ]; then
emit check_mode pass "immutable_bundle_already_exact"
emit bounded_execution idempotent_no_write "bundle_${BUNDLE_ID}"
emit independent_post_verifier pass "remote_exact_hash_mode_api_identity"
emit rollback no_write "active_pointer_absent"
emit learning_writeback partial_degraded "runtime_export_not_executed"
emit terminal pass_source_deployed_inactive "idempotent_runtime_export_pending"
exit 0
fi
if ! bounded_ssh "${SSH_OPTIONS[@]}" "${TARGET_HOST}" bash -s -- \
"${STAGE_DIR}" <<'REMOTE_STAGE'; then
set -euo pipefail
stage_dir="$1"
[ ! -e "${stage_dir}" ] && [ ! -L "${stage_dir}" ]
stage_root="${stage_dir%/*}"
[ -d "${stage_root}" ] && [ ! -L "${stage_root}" ] && [ -w "${stage_root}" ]
umask 077
mkdir -m 0700 "${stage_dir}"
REMOTE_STAGE
emit bounded_execution failed "transport_stage_create_failed"
emit terminal failed_no_active_pointer_write "stage_create_failed"
exit 1
fi
for index in "${!LOCAL_SOURCES[@]}"; do
if ! bounded_scp -q "${SSH_OPTIONS[@]}" "${LOCAL_SOURCES[index]}" \
"${TARGET_HOST}:${STAGE_DIR}/${LABELS[index]}"; then
quarantine_transport_stage >/dev/null 2>&1 || true
emit bounded_execution failed "transport_failed_index_${index}"
emit terminal failed_no_active_pointer_write "transport_stage_quarantine_attempted"
exit 1
fi
done
if ! REMOTE_APPLY_OUTPUT="$(bounded_ssh "${SSH_OPTIONS[@]}" "${TARGET_HOST}" \
sudo -n bash -s -- "${TRACE_ID}" "${RUN_ID}" "${WORK_ITEM_ID}" \
"${REMOTE_ROOT}" "${RECEIPT_ROOT}" "${STAGE_DIR}" "${BUNDLE_ID}" \
"${REMOTE_TIMEOUT_SECONDS}" "${KILL_AFTER_SECONDS}" \
"${SOURCE_HASHES[@]}" <<'REMOTE_APPLY'
set -euo pipefail
TRACE_ID="$1"
RUN_ID="$2"
WORK_ITEM_ID="$3"
REMOTE_ROOT="$4"
RECEIPT_ROOT="$5"
STAGE_DIR="$6"
BUNDLE_ID="$7"
REMOTE_TIMEOUT_SECONDS="$8"
KILL_AFTER_SECONDS="$9"
shift 9
EXPECTED_HASHES=("$@")
LABELS=(
metadata-export-policy.json
signoz_metadata_contract.py
signoz-metadata-export.py
verify-signoz-metadata-export.py
signoz-metadata-restore-drill.py
)
MODES=(0644 0644 0755 0755 0755)
TARGET_DIR="${REMOTE_ROOT}/${BUNDLE_ID}"
CANDIDATE_DIR="${REMOTE_ROOT}/.${BUNDLE_ID}.candidate.${RUN_ID}"
RECEIPT_DIR="${RECEIPT_ROOT}/${RUN_ID}"
RECEIPT_LOG="${RECEIPT_DIR}/receipts.jsonl"
DEPLOYED=0
TERMINAL=failed
emit_remote() {
local phase="$1" terminal="$2" detail="$3"
printf '{"schema":"awoooi_controlled_apply_receipt_v1","trace_id":"%s","run_id":"%s","work_item_id":"%s","asset_id":"host110-signoz-metadata-toolchain","phase":"%s","terminal":"%s","detail":"%s"}\n' \
"${TRACE_ID}" "${RUN_ID}" "${WORK_ITEM_ID}" "${phase}" "${terminal}" "${detail}" | tee -a "${RECEIPT_LOG}"
}
finalize() {
local rc=$? quarantine_terminal=not_required
trap - EXIT HUP INT TERM
set +e
if [ -d "${RECEIPT_DIR}" ] && [ ! -L "${RECEIPT_DIR}" ]; then
if [ -d "${STAGE_DIR}" ] && [ ! -L "${STAGE_DIR}" ]; then
mv "${STAGE_DIR}" "${RECEIPT_DIR}/transport-stage"
fi
if [ "${rc}" -ne 0 ]; then
quarantine_terminal=inactive_candidates_preserved
if [ -d "${CANDIDATE_DIR}" ] && [ ! -L "${CANDIDATE_DIR}" ]; then
mv "${CANDIDATE_DIR}" "${RECEIPT_DIR}/quarantine-candidate"
fi
if [ "${DEPLOYED}" -eq 1 ] && [ -d "${TARGET_DIR}" ] && [ ! -L "${TARGET_DIR}" ]; then
mv "${TARGET_DIR}" "${RECEIPT_DIR}/quarantine-target"
fi
fi
emit_remote rollback "${quarantine_terminal}" "active_pointer_never_created"
emit_remote terminal "${TERMINAL}" "exit_${rc}_runtime_export_not_executed"
fi
exit "${rc}"
}
trap finalize EXIT HUP INT TERM
[ "${#EXPECTED_HASHES[@]}" -eq 5 ]
[ -d "${STAGE_DIR}" ] && [ ! -L "${STAGE_DIR}" ]
[ ! -e "${TARGET_DIR}" ] && [ ! -L "${TARGET_DIR}" ]
[ ! -e "${CANDIDATE_DIR}" ] && [ ! -L "${CANDIDATE_DIR}" ]
[ ! -e "${REMOTE_ROOT}/current" ] && [ ! -L "${REMOTE_ROOT}/current" ]
[ ! -e "${RECEIPT_DIR}" ] && [ ! -L "${RECEIPT_DIR}" ]
python3 -c 'import sys; assert sys.version_info >= (3, 10)'
umask 077
mkdir -p "${REMOTE_ROOT}" "${RECEIPT_ROOT}"
mkdir -m 0700 "${RECEIPT_DIR}" "${CANDIDATE_DIR}"
: > "${RECEIPT_LOG}"
chmod 0600 "${RECEIPT_LOG}"
exec 8>>/tmp/awoooi-signoz-backup-operation.lock
flock -n 8
active_operations="$(
(pgrep -af '(^|/|[[:space:]])(backup-signoz|clickhouse-native-backup|clickhouse-native-restore-drill|run-signoz-backup-canary)[.]sh([[:space:]]|$)' || true) \
| wc -l | tr -d ' '
)"
[ "${active_operations}" = "0" ]
runtime_before="$(timeout --kill-after="${KILL_AFTER_SECONDS}" \
"${REMOTE_TIMEOUT_SECONDS}" docker inspect --format \
'{{.Id}}\t{{.State.Running}}\t{{.State.StartedAt}}\t{{.RestartCount}}\t{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' signoz)"
api_before="$(timeout --kill-after="${KILL_AFTER_SECONDS}" \
"${REMOTE_TIMEOUT_SECONDS}" curl -sS -o /dev/null -w '%{http_code}' \
http://127.0.0.1:8080/api/v1/health)"
[ "${api_before}" = "200" ]
emit_remote sensor_source pass "staged_sources_5_runtime_api_200"
for index in "${!LABELS[@]}"; do
staged="${STAGE_DIR}/${LABELS[index]}"
[ -f "${staged}" ] && [ ! -L "${staged}" ]
[ "$(sha256sum "${staged}" | awk '{print $1}')" = "${EXPECTED_HASHES[index]}" ]
install -o root -g root -m "${MODES[index]}" "${staged}" \
"${CANDIDATE_DIR}/${LABELS[index]}"
done
python3 - "${CANDIDATE_DIR}" <<'PY'
from pathlib import Path
import sys
root = Path(sys.argv[1])
for name in (
"signoz_metadata_contract.py",
"signoz-metadata-export.py",
"verify-signoz-metadata-export.py",
"signoz-metadata-restore-drill.py",
):
path = root / name
compile(path.read_text(encoding="utf-8"), str(path), "exec")
PY
PYTHONPATH="${CANDIDATE_DIR}" python3 "${CANDIDATE_DIR}/signoz-metadata-export.py" \
--check --base-url https://signoz.invalid \
--output-dir "${RECEIPT_DIR}/offline-output-must-not-exist" \
--policy "${CANDIDATE_DIR}/metadata-export-policy.json" \
--trace-id "${TRACE_ID}" --run-id "${RUN_ID}" \
--work-item-id "${WORK_ITEM_ID}" >/dev/null
[ ! -e "${RECEIPT_DIR}/offline-output-must-not-exist" ]
emit_remote check_mode pass "candidate_hash_mode_compile_policy_check"
mv "${CANDIDATE_DIR}" "${TARGET_DIR}"
chmod 0750 "${TARGET_DIR}"
DEPLOYED=1
for index in "${!LABELS[@]}"; do
target="${TARGET_DIR}/${LABELS[index]}"
[ -f "${target}" ] && [ ! -L "${target}" ]
[ "$(sha256sum "${target}" | awk '{print $1}')" = "${EXPECTED_HASHES[index]}" ]
[ "0$(stat -c '%a' "${target}")" = "${MODES[index]}" ]
printf '%s\t%s\t%s\n' "${LABELS[index]}" "${EXPECTED_HASHES[index]}" "${MODES[index]}" \
>> "${RECEIPT_DIR}/deployed-manifest.tsv"
done
chmod 0600 "${RECEIPT_DIR}/deployed-manifest.tsv"
runtime_after="$(timeout --kill-after="${KILL_AFTER_SECONDS}" \
"${REMOTE_TIMEOUT_SECONDS}" docker inspect --format \
'{{.Id}}\t{{.State.Running}}\t{{.State.StartedAt}}\t{{.RestartCount}}\t{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' signoz)"
api_after="$(timeout --kill-after="${KILL_AFTER_SECONDS}" \
"${REMOTE_TIMEOUT_SECONDS}" curl -sS -o /dev/null -w '%{http_code}' \
http://127.0.0.1:8080/api/v1/health)"
[ "${runtime_after}" = "${runtime_before}" ]
[ "${api_after}" = "200" ]
emit_remote bounded_execution pass "immutable_bundle_deployed_active_pointer_0"
emit_remote independent_post_verifier pass "hash_mode_compile_api_identity_unchanged"
emit_remote learning_writeback partial_degraded "authenticated_export_restore_pending"
TERMINAL=pass_source_deployed_inactive
REMOTE_APPLY
)"; then
quarantine_transport_stage >/dev/null 2>&1 || true
emit bounded_execution failed "remote_apply_failed_inactive_candidate_quarantined"
emit terminal failed_no_active_pointer_write "runtime_export_not_executed"
exit 1
fi
case "${REMOTE_APPLY_OUTPUT}" in
*'"phase":"terminal","terminal":"pass_source_deployed_inactive"'*) ;;
*)
emit independent_post_verifier failed "remote_apply_terminal_invalid"
emit terminal failed_no_active_pointer_write "runtime_export_not_executed"
exit 1
;;
esac
if ! POSTCHECK_OUTPUT="$(remote_check)"; then
emit independent_post_verifier failed "remote_postcheck_failed"
emit terminal failed_source_deploy_unverified "active_pointer_0"
exit 1
fi
case "${POSTCHECK_OUTPUT}" in
*"terminal=check_pass_no_write state=exact "*) ;;
*)
emit independent_post_verifier failed "remote_postcheck_receipt_invalid"
emit terminal failed_source_deploy_unverified "active_pointer_0"
exit 1
;;
esac
emit check_mode pass "precheck_absent"
emit bounded_execution pass "immutable_bundle_${BUNDLE_ID}_active_pointer_0"
emit independent_post_verifier pass "postcheck_exact_hash_mode_api_identity"
emit rollback not_required "inactive_additive_bundle"
emit learning_writeback partial_degraded "runtime_export_restore_zero_residue_pending"
emit terminal pass_source_deployed_inactive "runtime_export_not_executed"

View File

@@ -0,0 +1,179 @@
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"
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 "$@"
""",
)
_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
""",
)
_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",
}
def run_deployer(
tmp_path: Path, *, mode: str, apply: bool
) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["bash", str(DEPLOYER), "--apply" if apply else "--check"],
env=fake_environment(tmp_path, mode=mode),
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_five_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 ")]) == 5
assert len([line for line in events if line.startswith("ssh ")]) == 4
def test_deployer_has_no_active_pointer_or_destructive_fallback() -> 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
def test_exact_five_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",
):
assert path in source
assert "MODES=(0644 0644 0755 0755 0755)" in source
assert '[ "${#EXPECTED_HASHES[@]}" -eq 5 ]' in source