fix(1d): G1 backup/restore + F1d-1 cert-check reframe

- backup artifact: read snapshot_id from 'abra app backup create' output (snapshots needs a TTY);
  generic.parse_snapshot_id + do_backup assert it
- restore serving race: lifecycle.http_fetch (one request -> status+body, never raises) +
  assert_serving is now a bounded poll (settles a post-op reconverge, no bare sleep); drop wait_serving
- F1d-1 (Adversary, low): reframe served_cert/assert_serving honestly as an INFRA TLS sanity check
  (catches a lapsed/mis-rotated wildcard cert), NOT app-vs-fallback (Traefik serves the wildcard
  zone-wide); the genuine serving proof is services_converged + non-404 status. Awaiting re-test.

DG1 Adversary PASS @ef44d46. G1 full-lifecycle re-verification in flight.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 23:39:45 +01:00
parent a8f78b8673
commit 6c5d8f28ea
5 changed files with 144 additions and 76 deletions

View File

@ -127,11 +127,13 @@ def upgrade(domain: str, version: str | None = None, timeout: int = 900) -> None
_run(args, timeout=timeout)
def backup_create(domain: str, timeout: int = 900) -> None:
def backup_create(domain: str, timeout: int = 900) -> str:
# -C -o: use the current recipe checkout, no remote fetch — like every other recipe-touching
# call (DECISIONS.md). Without -o, abra tries to fetch recipe tags from the (possibly private)
# remote and fails "authentication required: Unauthorized".
_run_pty(["app", "backup", "create", domain, "-n", "-C", "-o"], timeout=timeout)
# remote and fails "authentication required: Unauthorized". Returns the captured output, whose
# restic JSON summary line carries the produced "snapshot_id" (the backup artifact, DG3) — note
# `abra app backup snapshots` needs a TTY and is awkward to script, so we read the create output.
return _run_pty(["app", "backup", "create", domain, "-n", "-C", "-o"], timeout=timeout).stdout
def restore(domain: str, timeout: int = 900) -> None: