Invite acceptance (verified live on 8 agents): Pankow forms need
click + keyboard.type (fill() silently no-ops), submit button is
<div role="button"> "Set up" which starts disabled until the form
is valid.
2FA enablement: fresh accounts land on setupaccount.html ("Your
account is ready") and hash navigation cannot leave that page --
load the panel root first. Also match "Set up" (forced-enrollment
screen says "Set up passkey", profile page says "Setup").
Verified in the 8-agent run: coo/svp-knel/svp-tctc/vp-investing/
vp-trading/vp-compliance enrolled with TOTP. vp-secops and
vp-techcompliance ran pre-fix and need the --enable-2fa second pass.
51 lines
1.9 KiB
Python
51 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
dump-invite-page.py -- DOM dump of a Cloudron invite/setup page (pre-acceptance).
|
|
|
|
Usage:
|
|
docker compose run --rm --entrypoint python3 \
|
|
-e AGENT=vp-secops provision dump-invite-page.py
|
|
"""
|
|
|
|
import os, sys, time
|
|
from pathlib import Path
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
STATE_DIR = Path("/app/state")
|
|
|
|
AGENT = os.environ.get("AGENT", "vp-secops")
|
|
|
|
import yaml
|
|
with open("/app/agents.yaml") as f:
|
|
manifest = yaml.safe_load(f)
|
|
agent = next(a for a in manifest["agents"] if a["name"] == AGENT)
|
|
invite_url = agent["cloudron_invite"]
|
|
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch(headless=True)
|
|
page = browser.new_context(viewport={"width": 1280, "height": 1024}).new_page()
|
|
page.goto(invite_url, wait_until="networkidle", timeout=20000)
|
|
page.wait_for_timeout(3000)
|
|
|
|
ts = time.strftime("%H%M%S")
|
|
page.screenshot(path=str(STATE_DIR / f"invite-{AGENT}-{ts}.png"), full_page=True)
|
|
elements = page.evaluate("""() => {
|
|
const out = [];
|
|
document.querySelectorAll('input, button, [role="button"], label, a, h1, h2, h3, form').forEach(el => {
|
|
const tag = el.tagName.toLowerCase();
|
|
const text = (el.textContent || '').trim().substring(0, 60);
|
|
const id = el.id || '';
|
|
const type = el.getAttribute('type') || '';
|
|
const cls = (el.getAttribute('class') || '').substring(0, 50);
|
|
const role = el.getAttribute('role') || '';
|
|
const vis = el.offsetParent !== null;
|
|
out.push(`<${tag}> id=${id} type=${type} role=${role} class=${cls} vis=${vis} text="${text}"`);
|
|
});
|
|
return out;
|
|
}""")
|
|
body = page.evaluate("() => document.body.innerText.substring(0, 400)")
|
|
out = f"URL: {page.url}\n\nBODY:\n{body}\n\nELEMENTS:\n" + "\n".join(elements)
|
|
(STATE_DIR / f"invite-{AGENT}-{ts}.txt").write_text(out)
|
|
print(out)
|
|
browser.close()
|