Admin-Plattform für die Tenants von Onyscribe: Editor mit Live-Vorschau (echter Core in Sandbox), Versionen, KI-Agent (Cortecs), OIDC-Abgleich über die Login-Developer-API, Deploy-Engine (Mittwald, gesperrt ohne DEPLOY_LIVE, Freigabe pro Tenant), Core-Vertrag (Schema/Manifest), Core-Releases mit Kompatibilitätsprüfung, Canary-Rollout und Rollback, Zustandsabgleich. Runbook: docs/RUNBOOK_PARALLELTEST.md Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
40 lines
1.7 KiB
Python
40 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Beweis für den Cut-over: Bundle aus der DB == Git-Ordner (Hash-Vergleich, ohne deploy-Block)."""
|
|
import hashlib
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
from app.db import session # noqa: E402
|
|
from app.models import Tenant # noqa: E402
|
|
from app.services import store # noqa: E402
|
|
from app.settings import LEGACY_PLATFORM # noqa: E402
|
|
from sqlalchemy import select # noqa: E402
|
|
|
|
root = Path(sys.argv[1]) if len(sys.argv) > 1 else LEGACY_PLATFORM
|
|
bad = 0
|
|
with session() as db:
|
|
for t in db.scalars(select(Tenant).order_by(Tenant.id)):
|
|
tdir = root / "tenants" / t.id
|
|
cfg, files = store.content(db, t, "current")
|
|
git_cfg = json.loads((tdir / "tenant.json").read_text(encoding="utf-8"))
|
|
git_cfg.pop("deploy", None)
|
|
problems = []
|
|
if json.dumps(git_cfg, sort_keys=True) != json.dumps(cfg, sort_keys=True):
|
|
problems.append("tenant.json weicht ab")
|
|
for path, sha in files.items():
|
|
p = tdir / path
|
|
if not p.exists():
|
|
problems.append(f"{path}: fehlt in Git")
|
|
elif hashlib.sha256(p.read_bytes()).hexdigest() != sha:
|
|
problems.append(f"{path}: Hash weicht ab")
|
|
for p in tdir.rglob("*"):
|
|
rel = p.relative_to(tdir).as_posix()
|
|
if p.is_file() and rel not in files and rel not in ("tenant.json", "secrets.enc.yaml") and "__pycache__" not in rel:
|
|
problems.append(f"{rel}: fehlt in DB")
|
|
print(("✔" if not problems else "✘"), t.id, "; ".join(problems))
|
|
bad += bool(problems)
|
|
sys.exit(1 if bad else 0)
|