ligbox-ops-platform/deploy/vm112-wizard/provision-zone037b.patch.py
Ligbox Spec Hub 038fb8f7ce feat(dns): Spec 037 DNS Viewer — Desk, Console e patches Wizard V4
Entrega read-only de apontamentos DNS (Cloudflare, OpenPanel BIND, público)
no Desk e Console /admin/dominio, com spec, scripts de rollback e patches
VM112 para painel lateral no passo DNS do onboarding (deploy wizard pendente).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 16:36:25 +00:00

119 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""Spec 037b — provision-zone cria zona do cliente na CF Ligbox."""
from pathlib import Path
ROUTER = Path("/opt/ligbox-wizard/backend/app/routers/onboarding.py")
REGISTRY = Path("/opt/ligbox-wizard/backend/app/services/dns_account_registry.py")
CF = Path("/opt/ligbox-wizard/backend/app/services/cloudflare.py")
# --- cloudflare ensure_zone account_id ---
cf_text = CF.read_text(encoding="utf-8")
OLD_ENSURE = """ def ensure_zone(self, domain: str) -> dict:
\"\"\"Garante que a zona existe na conta Ibytera; cria se necessário.\"\"\"
zone = self.get_zone_by_name(domain)
if zone:
return {"zone": zone, "created": False}
zone = self.create_zone(domain)
return {"zone": zone, "created": True}"""
NEW_ENSURE = """ def ensure_zone(self, domain: str, account_id: str | None = None) -> dict:
\"\"\"Garante que a zona existe na conta CF; cria se necessário.\"\"\"
zone = self.get_zone_by_name(domain)
if zone:
return {"zone": zone, "created": False}
zone = self.create_zone(domain, account_id=account_id)
return {"zone": zone, "created": True}"""
if "account_id: str | None = None" not in cf_text:
cf_text = cf_text.replace(OLD_ENSURE, NEW_ENSURE)
CF.write_text(cf_text, encoding="utf-8")
print("cloudflare.py patched")
# --- registry: ensure pick_provision_account exists (copy from monorepo if needed) ---
# handled via scp separately
# --- onboarding import ---
text = ROUTER.read_text(encoding="utf-8")
if "provision_ligbox_zone" not in text:
text = text.replace(
"from app.services.dns_account_registry import resolve_ligbox_zone, resolve_payload",
"from app.services.dns_account_registry import (\n pick_provision_account,\n provision_ligbox_zone,\n resolve_ligbox_zone,\n resolve_payload,\n)",
)
OLD_BLOCK = ''' match = resolve_ligbox_zone(domain)
if match:
activity_log.info(
f"Zona {domain} já na conta {match.account.id} — sem create",
source="cloudflare",
)
payload = _portal_onboarding_payload(domain, zone_created=False)
payload["zone_id"] = match.zone_id
payload["ligbox_account_id"] = match.account.id
payload["dns_mode"] = match.dns_mode
payload["message"] = (
f"Domínio {domain} já está na Cloudflare Ligbox ({match.account.label})."
)
if nameservers := wizard_nameservers(match.zone):
payload["nameservers"] = nameservers
payload["status"]["nameservers"] = nameservers
return payload
raise HTTPException(
status_code=422,
detail={
"code": "zone_not_in_ligbox_accounts",
"domain": domain,
"message": (
"Domínio não está nas contas Ligbox (ligit, itecnologys, ibytera). "
"Use API Token da sua Cloudflare ou apontamentos no registrador."
),
"paths_available": ["byo", "external"],
},
)
cf = CloudflareDNS()
try:
activity_log.info(f"Criar zona Cloudflare: {domain}", source="cloudflare")
cf.verify_token()
result = cf.ensure_zone(domain)'''
NEW_BLOCK = ''' provision_acct = pick_provision_account()
if not provision_acct:
raise HTTPException(
400,
"Nenhuma conta Cloudflare Ligbox configurada. Ver dns-accounts.yaml e secrets/.",
)
try:
activity_log.info(
f"Provision zona cliente {domain} (conta Ligbox {provision_acct.id})",
source="cloudflare",
)
provision_acct.client().verify_token()
result = provision_ligbox_zone(domain, account=provision_acct)
match = result["account"]
cf = match.client()
result = {"zone": result["zone"], "created": result["created"]}'''
if "provision_ligbox_zone(domain" not in text:
text = text.replace(OLD_BLOCK, NEW_BLOCK)
# fix variable shadowing - after replace, need to fix zone/created extraction
text = text.replace(
" match = result["account"]\n cf = match.client()\n result = {"zone": result["zone"], "created": result["created"]}",
" ligbox_acct = result["account"]\n cf = ligbox_acct.client()\n zone = result["zone"]\n created = result["created"]",
)
# Remove duplicate zone = result["zone"] if the old code still has it - read and fix
text = text.replace(
" zone = result[\"zone\"]\n created = result[\"created\"]\n zone = result[\"zone\"]\n created = result[\"created\"]",
" zone = result[\"zone\"]\n created = result[\"created\"]",
)
# Add ligbox_account_id to payload after zone created
if 'payload["ligbox_account_id"]' not in text.split("provision_cloudflare_zone")[1][:2500]:
text = text.replace(
' payload["zone_id"] = zone.get("id")\n payload["sandbox"] = sandbox',
' payload["zone_id"] = zone.get("id")\n payload["ligbox_account_id"] = ligbox_acct.id\n payload["dns_mode"] = f"ligbox_cf_{ligbox_acct.id}"\n payload["sandbox"] = sandbox',
)
ROUTER.write_text(text, encoding="utf-8")
print("onboarding.py provision-zone patched OK")