feat(backup): protect host188 product data
This commit is contained in:
@@ -15,10 +15,11 @@ EXPECTED_FILES = {
|
||||
"backup-awoooi-frequent.sh",
|
||||
"backup-clawbot.sh",
|
||||
"backup-sentry.sh",
|
||||
"backup-host188-products.sh",
|
||||
}
|
||||
|
||||
|
||||
def test_backup_runtime_deploy_is_fixed_to_host_110_and_six_files() -> None:
|
||||
def test_backup_runtime_deploy_is_fixed_to_host_110_and_seven_files() -> None:
|
||||
plays = yaml.safe_load(PLAYBOOK.read_text(encoding="utf-8"))
|
||||
assert len(plays) == 1
|
||||
play = plays[0]
|
||||
|
||||
@@ -22,15 +22,16 @@ REQUIRED_BACKUP_SCRIPTS = (
|
||||
"backup-ai-artifacts.sh",
|
||||
"backup-configs.sh",
|
||||
"backup-public-routes.sh",
|
||||
"backup-host188-products.sh",
|
||||
)
|
||||
|
||||
|
||||
def test_backup_all_runs_every_required_domain_once() -> None:
|
||||
source = BACKUP_ALL.read_text(encoding="utf-8")
|
||||
|
||||
assert "local total=13" in source
|
||||
assert "local total=14" in source
|
||||
assert [int(value) for value in re.findall(r">>> \[(\d+)/\$\{total\}\]", source)] == list(
|
||||
range(1, 14)
|
||||
range(1, 15)
|
||||
)
|
||||
for script in REQUIRED_BACKUP_SCRIPTS:
|
||||
assert source.count(f"/backup/scripts/{script}") == 1
|
||||
|
||||
101
scripts/backup/tests/test_backup_host188_products_contract.py
Normal file
101
scripts/backup/tests/test_backup_host188_products_contract.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[3]
|
||||
SCRIPT = ROOT / "scripts" / "backup" / "backup-host188-products.sh"
|
||||
BACKUP_ALL = ROOT / "scripts" / "backup" / "backup-all.sh"
|
||||
INTEGRITY = ROOT / "scripts" / "backup" / "check-backup-integrity.sh"
|
||||
OFFSITE_SCRIPTS = (
|
||||
ROOT / "scripts" / "backup" / "sync-offsite-backups.sh",
|
||||
ROOT / "scripts" / "backup" / "backup-offsite-readiness-gate.sh",
|
||||
ROOT / "scripts" / "backup" / "verify-offsite-full-sync.sh",
|
||||
ROOT / "scripts" / "backup" / "enforce-latest-only-retention.sh",
|
||||
)
|
||||
EXPORTER = ROOT / "scripts" / "ops" / "backup-health-textfile-exporter.py"
|
||||
AGENT99 = ROOT / "agent99-control-plane.ps1"
|
||||
FULL_PLAYBOOK = ROOT / "infra" / "ansible" / "playbooks" / "110-devops.yml"
|
||||
BOUNDED_PLAYBOOK = (
|
||||
ROOT / "infra" / "ansible" / "playbooks" / "110-backup-runtime-deploy.yml"
|
||||
)
|
||||
REBOOT_READINESS = (
|
||||
ROOT
|
||||
/ "scripts"
|
||||
/ "reboot-recovery"
|
||||
/ "reboot-recovery-readiness-audit.sh"
|
||||
)
|
||||
|
||||
|
||||
def test_host188_product_backup_has_fixed_sources_and_online_verifiers() -> None:
|
||||
source = SCRIPT.read_text(encoding="utf-8")
|
||||
|
||||
for expected in (
|
||||
'REMOTE_HOST="ollama@192.168.0.188"',
|
||||
"vibework-production-postgres-1",
|
||||
"current-fifa2026-postgres-1",
|
||||
"current-fifa2026-redis-1",
|
||||
"n8n",
|
||||
"pg_dump -Fc",
|
||||
"PGDMP",
|
||||
"pg_restore --list",
|
||||
"redis-cli --rdb",
|
||||
'magic}" != "REDIS"',
|
||||
"sqlite3.OPEN_READONLY",
|
||||
"db.backup",
|
||||
"PRAGMA integrity_check",
|
||||
"n8n export:workflow --backup",
|
||||
"n8n export:credentials --backup",
|
||||
'LOCAL_REPO="${BACKUP_BASE}/host188-products"',
|
||||
"verify_backup",
|
||||
):
|
||||
assert expected in source
|
||||
|
||||
|
||||
def test_host188_product_backup_preserves_secret_and_runtime_boundaries() -> None:
|
||||
source = SCRIPT.read_text(encoding="utf-8")
|
||||
|
||||
assert "umask 077" in source
|
||||
assert '"credentialsDecrypted": False' in source
|
||||
assert '"offsiteWritePerformed": False' in source
|
||||
assert "tarfile.open" in source
|
||||
assert "n8n_archive_unsafe_path" in source
|
||||
assert "REDISCLI_AUTH" in source
|
||||
assert 'if [ "${BACKUP_NOTIFY_SUCCESS:-0}" = "1" ]' in source
|
||||
assert "handle.read(1024 * 1024)" in source
|
||||
|
||||
for forbidden in (
|
||||
"--decrypted",
|
||||
"docker stop",
|
||||
"docker restart",
|
||||
"docker pause",
|
||||
"docker compose down",
|
||||
"docker inspect -f '{{range .Config.Env}}",
|
||||
"rclone ",
|
||||
"sync-offsite-backups.sh",
|
||||
"rm -rf /home/node/.n8n",
|
||||
"path.read_bytes()",
|
||||
):
|
||||
assert forbidden not in source
|
||||
|
||||
|
||||
def test_host188_product_backup_is_wired_into_health_integrity_and_offsite() -> None:
|
||||
assert "/backup/scripts/backup-host188-products.sh" in BACKUP_ALL.read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert "host188-products" in INTEGRITY.read_text(encoding="utf-8")
|
||||
for path in OFFSITE_SCRIPTS:
|
||||
assert "host188-products" in path.read_text(encoding="utf-8")
|
||||
|
||||
exporter = EXPORTER.read_text(encoding="utf-8")
|
||||
assert '"backup-host188-products.sh"' in exporter
|
||||
assert '("host188_products", "/backup/host188-products", 48)' in exporter
|
||||
|
||||
agent99 = AGENT99.read_text(encoding="utf-8")
|
||||
assert 'name = "host188-products"' in agent99
|
||||
assert 'path = "/backup/host188-products/snapshots"' in agent99
|
||||
assert "maxAgeMinutes = 1800; required = $true" in agent99
|
||||
|
||||
for path in (FULL_PLAYBOOK, BOUNDED_PLAYBOOK):
|
||||
assert "backup-host188-products.sh" in path.read_text(encoding="utf-8")
|
||||
assert "backup-host188-products.sh" in REBOOT_READINESS.read_text(encoding="utf-8")
|
||||
Reference in New Issue
Block a user