Files
compass_teams_nhs/docs/phase-2-harness-notes.md
Paperclip Builder 78d2822b39 Phase 2: harden Compass fetcher for the Cloudflare login-POST challenge
- retry the login on a fresh browser context (stale cf_chl_rc_ni cookies loop
  the next challenge) and fail loudly with cloudflare_login_post_challenge
- detect the Compass login-rejection message and second-factor prompts
- docs: record that Cloudflare's managed challenge blocks the headless login
  POST (GET passes), what was tried, and the unblock options

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-15 16:14:50 +11:00

98 lines
4.3 KiB
Markdown

# Phase 2 — Compass login + fetch notes
Status: **blocked on Cloudflare.** The credential is available and the login
page loads, but Cloudflare's managed challenge blocks the login **POST** under
the headless harness. See AUD-104.
## Harness used
- `pi-browser-harness` **v0.11.0**
(`/home/sam/.agents/extensions/pi-browser-harness/package.json`).
- Entrypoint: the pi extension `src/index.ts` plus its long-lived daemon
`src/daemon/index.ts`. The daemon bridges `pi → Unix socket
(/tmp/pi-browser-daemon.sock) → Chrome DevTools Protocol`.
- Chrome: systemd user service `chrome-pi.service`
(`/home/sam/.config/systemd/user/chrome-pi.service`), `--headless=new`,
`--remote-debugging-port=9222`, `--user-data-dir=/home/sam/.chrome-pi`.
- The Phase 2 fetcher (`scripts/compass-fetch.mjs`) talks to the harness daemon
socket and drives the harness's Chrome over CDP.
## Compass
- URL: `https://nhs-vic.compass.education/login.aspx` (Northcote High School).
- Login form: `#username`, `#password`, hidden `browserFingerprint`,
`__RequestVerificationToken`, submit `#button1`
(`formaction="/login?handler=Login"`). Also present: a SAML button and
**"Parent sign in with one-time code"** (`formaction="/login?handler=OtpSignin"`).
## Cloudflare finding (important)
Compass is behind a Cloudflare managed challenge. With the default
`HeadlessChrome` user agent, the challenge loops forever
(`title="Just a moment..."`, body "Compass is verifying your connection...").
The fix that works:
1. Override the user agent to a normal desktop Chrome UA
(`Network.setUserAgentOverride`), and
2. run the page in an **isolated browser context**
(`Target.createBrowserContext`) so stale `cf_clearance` / `cf_chl_rc_ni`
cookies from earlier attempts do not loop the challenge.
With both, the challenge clears in ~5 s and the real login page loads. Both are
implemented in `scripts/compass-fetch.mjs`.
### The login POST is the hard part
When the form is submitted (`POST /login?handler=Login`) Cloudflare returns a
**403 managed challenge** and serves `Just a moment...`. Under headless Chrome
that challenge does not clear (`iframes=0`, body "Compass is verifying your
connection..."), so Compass never sees the login. Captured response headers on
the blocked POST show `server: cloudflare`; the GET of the same page passes.
Tested and did **not** fix it: a normal desktop-Chrome UA override, isolated
browser contexts, `Sec-CH-UA` user-agent metadata, focus/visibility emulation,
client hints, and long waits (up to 4 minutes).
The POST passes only intermittently. It was observed returning `200` twice, but
five further attempts (including after a 75 s cooldown, each in a fresh context)
were all challenged. `scripts/compass-fetch.mjs` retries the login on a fresh
browser context up to `COMPASS_LOGIN_ATTEMPTS` (default 4) and fails loudly with
`cloudflare_login_post_challenge` (exit 2) if none get through.
This is the Phase 2 risk: the harness can read Compass but cannot log in from
headless Chrome.
## Proof stored (2026-10-15)
```
var/raw/harry/<runId>/login.html
var/raw/harry/<runId>/login.meta.json
var/raw/harry/<runId>/manifest.json
```
- `var/` is git-ignored. Raw pages stay local, never committed.
- `login` — `https://nhs-vic.compass.education/login.aspx`, title
`Login | Compass`, **125 741 bytes**, sha256
`4d3b731c34d64b6978d4e1bd7f4a7772ae2b5d8687241db3d7163c2beb325f01`.
## Blocked on
A reliable way past Cloudflare's managed challenge for the login POST. The
credential itself is no longer missing: it is in
`~/.config/environment.d/10-secrets.conf` as `COMPASS_USERNAME` / `COMPASS_PASSWORD`.
Options (owner: Sam, because they are host/infra or browser decisions):
1. Give the harness a **headful** Chrome (e.g. add `xvfb` to the `.13` NixOS
config and run Chrome non-headless). Managed challenges normally pass there.
2. Supply a `cf_clearance` cookie from a real browser session on the same public
IP and user agent, as a secret to inject.
3. Confirm a non-CF login path (SAML/SSO or the Compass mobile API) to pursue.
## Smallest useful scope for Phase 3
Until a login succeeds we cannot enumerate the per-child page URLs, so the
smallest useful scope cannot be fixed yet. It is expected to be the
"today/planner" page plus the messages/notices list, which is what answers "what
is overdue".