From b35fc7fd17b8a3ea9a5c8962f3bcdcc258deb75d Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Mon, 28 Sep 2026 11:01:09 +0200 Subject: [PATCH] =?UTF-8?q?harness:=20calcom=20fixture=20=E2=80=94=20its?= =?UTF-8?q?=20own=20first-run=20API=20(/api/auth/setup)=20+=20the=20public?= =?UTF-8?q?=20page=20readback,=20proven=20on=209202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- scripts/upgrade_fixtures_box.py | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/scripts/upgrade_fixtures_box.py b/scripts/upgrade_fixtures_box.py index ecd290b..d253f66 100644 --- a/scripts/upgrade_fixtures_box.py +++ b/scripts/upgrade_fixtures_box.py @@ -376,6 +376,52 @@ class Django: return found is True +# ============================================================================================= +class Calcom: + """Cal.com's OWN first-run API: `POST /api/auth/setup` creates the first (admin) user while the + instance has none — the route its own setup wizard calls (upstream v6.2.0 + `apps/web/app/api/auth/setup/route.ts`). The readback is the user's PUBLIC booking page, `GET + /`, rendered by the app from its own database. Measured on 9202 2026-09-28 (v6.2.0, + PostgreSQL 16, memory raised to 2048M in the DRILL catalog only — R-703): setup → 200, a second + setup → 400 "No setup needed.", the page → 200, an unknown name → 404. + + THE FIXTURE PROVES ITSELF ON EVERY CALL: verify() also asks for a name that cannot exist and + requires 404 — a readback that has broken into "always 200" fails instead of passing everything. + """ + sub = "cal" + + def seed(self, w, sub, say): + if not w.wait_app(sub, "/api/auth/providers", want=("200",), tries=120): + return None + user = "drill" + secrets.token_hex(3) + pw = "Drill-" + secrets.token_hex(6) + "Aa9x" # >= 15 chars, a digit, both cases (its own rule) + body = json.dumps({"username": user, "full_name": "Drill Gate", "email_address": f"{user}@gate.invalid", + "password": pw}) + rc, code, out = w.app_curl(sub, "/api/auth/setup", "-H", "Content-Type: application/json", + data=body, method="POST") + say(f" calcom: /api/auth/setup http={code} :: {out[:120]}") + if code not in ("200", "201"): + return None + rc, code, _ = w.app_curl(sub, "/" + user, timeout=60) + if code != "200": + say(f" calcom: the seeded user's page answered {code}, not 200") + return None + say(f" calcom: seeded user {user}") + return {"user": user, "pw": pw} + + def verify(self, w, sub, t, say): + if not w.wait_app(sub, "/api/auth/providers", want=("200",), tries=120): + say(" calcom: the app never served /api/auth/providers") + return False + rc, code, _ = w.app_curl(sub, "/nobody" + secrets.token_hex(6), timeout=60) + if code != "404": + say(f" calcom: READBACK UNUSABLE — a name that cannot exist answered {code}, not 404") + return False + rc, code, _ = w.app_curl(sub, "/" + t["user"], timeout=60) + say(f" calcom: readback — the seeded user's page http={code}") + return code == "200" + + # ============================================================================================= class Claper: """Claper's OWN release CLI inside its own container: `bin/claper rpc` runs Elixir code in the @@ -1145,4 +1191,5 @@ FIXTURES = { "vaultwarden": Vaultwarden(), "wishlist": Wishlist(), "claper": Claper(), + "calcom": Calcom(), }