[Test][E2E] Split authenticated e2e into staff + student roles (two identities) #605

Open
opened 2026-07-15 19:17:30 +00:00 by spikerj · 2 comments
Owner

Context / why now

The authenticated Playwright suite (P4 #316) logs in as a single identity via E2E_USER_USERNAME / E2E_USER_PASSWORD (e2e/support/auth.ts, e2e/playwright/auth.setup.ts). As part of the OpenBao CI-secret migration (#545) we set up two Keycloak test users in the live spikersoft realm and stored both credential pairs in OpenBao:

secret/ci/angular/e2e
  staff_username    = e2e.staff      staff_password    = <rotated>
  student_username  = e2e.student    student_password  = <rotated>

To unblock the migration, the suite currently runs as staff onlye2e-nightly.yml fetches staff_username/staff_password into E2E_USER_*; the student pair is parked in Bao, unused. This ticket tracks wiring the suite to exercise both roles so we get role-differentiated coverage (staff reaches management/admin routes a student must not).

Scope

  • auth.setup.ts: perform two Keycloak UI logins → persist two storage states (e.g. e2e/.auth/staff.json, e2e/.auth/student.json).
  • playwright.config.ts: add authenticated-staff / authenticated-student projects (each starting from its storage state); keep anonymous as-is. Name specs authenticated-staff-*.spec.ts / authenticated-student-*.spec.ts.
  • e2e/support/auth.ts: expose the two identities (e.g. E2E_STAFF / E2E_STUDENT) reading E2E_STAFF_USERNAME/PASSWORD + E2E_STUDENT_USERNAME/PASSWORD; keep graceful self-skip when unset.
  • e2e/support/route-manifest.ts: classify routes per role and split the coverage ratchet (a route walked as staff but forbidden to student should assert accordingly) — see the coverage-baseline.json per-environment ratchet note.
  • .gitea/workflows/e2e-nightly.yml: change the OpenBao fetch from the single staff mapping to both pairs:
    E2E_STAFF_USERNAME    secret/ci/angular/e2e  staff_username
    E2E_STAFF_PASSWORD    secret/ci/angular/e2e  staff_password
    E2E_STUDENT_USERNAME  secret/ci/angular/e2e  student_username
    E2E_STUDENT_PASSWORD  secret/ci/angular/e2e  student_password
    

Notes

  • No new secrets/infra needed — both pairs are already in Bao and ci-angular.hcl already grants read on secret/ci/angular/*.
  • Purely a code + one workflow-fetch change; the Bao side is done.

Epic #307 (E2E) · builds on P4 #316 · context #545 (OpenBao CI migration).

**Context / why now** The authenticated Playwright suite (P4 #316) logs in as a **single** identity via `E2E_USER_USERNAME` / `E2E_USER_PASSWORD` (`e2e/support/auth.ts`, `e2e/playwright/auth.setup.ts`). As part of the OpenBao CI-secret migration (#545) we set up **two** Keycloak test users in the live `spikersoft` realm and stored **both** credential pairs in OpenBao: ``` secret/ci/angular/e2e staff_username = e2e.staff staff_password = <rotated> student_username = e2e.student student_password = <rotated> ``` To unblock the migration, the suite currently runs **as staff only** — `e2e-nightly.yml` fetches `staff_username`/`staff_password` into `E2E_USER_*`; the student pair is parked in Bao, unused. This ticket tracks wiring the suite to exercise **both roles** so we get role-differentiated coverage (staff reaches management/admin routes a student must not). **Scope** - `auth.setup.ts`: perform **two** Keycloak UI logins → persist **two** storage states (e.g. `e2e/.auth/staff.json`, `e2e/.auth/student.json`). - `playwright.config.ts`: add `authenticated-staff` / `authenticated-student` projects (each starting from its storage state); keep `anonymous` as-is. Name specs `authenticated-staff-*.spec.ts` / `authenticated-student-*.spec.ts`. - `e2e/support/auth.ts`: expose the two identities (e.g. `E2E_STAFF` / `E2E_STUDENT`) reading `E2E_STAFF_USERNAME/PASSWORD` + `E2E_STUDENT_USERNAME/PASSWORD`; keep graceful self-skip when unset. - `e2e/support/route-manifest.ts`: classify routes per role and split the coverage ratchet (a route walked as staff but forbidden to student should assert accordingly) — see the `coverage-baseline.json` per-environment ratchet note. - `.gitea/workflows/e2e-nightly.yml`: change the OpenBao fetch from the single staff mapping to both pairs: ``` E2E_STAFF_USERNAME secret/ci/angular/e2e staff_username E2E_STAFF_PASSWORD secret/ci/angular/e2e staff_password E2E_STUDENT_USERNAME secret/ci/angular/e2e student_username E2E_STUDENT_PASSWORD secret/ci/angular/e2e student_password ``` **Notes** - No new secrets/infra needed — both pairs are already in Bao and `ci-angular.hcl` already grants read on `secret/ci/angular/*`. - Purely a code + one workflow-fetch change; the Bao side is done. Epic #307 (E2E) · builds on P4 #316 · context #545 (OpenBao CI migration).
Author
Owner

Reconciliation check 2026-07-22 (code vs. ticket): credential tooling is done, the actual suite split is not — stays open.

Done:

  • e2e.staff account exists; pnpm e2e:secrets -- --staff hydrates staff creds (spikersoft-angular PR #197).
  • Persona-selection hydration (--identity <persona>) landed via #782 (angular PR #514 / infra PR #137).

Not done (the core of this ticket): playwright.config.ts still defines a single authenticated project with one auth-setup → one storage state. There are no separate staff/student projects, no role-scoped storage states, and no specs asserting role-based access differences. (Also note #628 — e2e.staff credential drift — currently blocks the staff half.)

Reconciliation check 2026-07-22 (code vs. ticket): **credential tooling is done, the actual suite split is not** — stays open. Done: - e2e.staff account exists; `pnpm e2e:secrets -- --staff` hydrates staff creds (spikersoft-angular PR #197). - Persona-selection hydration (`--identity <persona>`) landed via #782 (angular PR #514 / infra PR #137). Not done (the core of this ticket): `playwright.config.ts` still defines a single `authenticated` project with one `auth-setup` → one storage state. There are no separate staff/student projects, no role-scoped storage states, and no specs asserting role-based access differences. (Also note #628 — e2e.staff credential drift — currently blocks the staff half.)
Author
Owner

Audited against origin/masterPARTIAL, exactly as the 2026-07-22 reconciliation comment says. The credential tooling shipped; the suite split has not started.

Done — persona hydration: tools/e2e/hydrate-env-from-bao.mjs:42 defines KNOWN_PERSONAS = ["staff","student","parent1","parent2","child1","child2","child3"], with --identity / shorthand resolution at :39-52 and per-persona key lookup at :140-143. So the credentials side is genuinely solved.

Not done — all four of this ticket's code items:

  • playwright.config.ts still has a single authenticated project (one testMatch: /authenticated-.*\.spec\.ts$/, one storageState: AUTH_STATE_PATH) and one auth-setup. No authenticated-staff / authenticated-student projects.
  • e2e/support/auth.ts:24 still has a single AUTH_STATE_PATH = ".../.auth/user.json" and a single E2E_USER reading E2E_USER_USERNAME/E2E_USER_PASSWORD (:35-42).
  • .gitea/workflows/e2e-nightly.yml:52-53 still maps only the one pair — E2E_USER_USERNAME → staff_username, E2E_USER_PASSWORD → staff_password. The student pair remains parked and unused.
  • No role classification in e2e/support/route-manifest.ts.

The grep that establishes all of it: git grep -n -iE 'E2E_STAFF|E2E_STUDENT|staff\.json|student\.json|authenticated-staff|authenticated-student' origin/masterzero hits repo-wide.

Blocked in practice on #628 for the staff half, and that interaction is worth spelling out because it's currently masking itself: e2e-nightly.yml feeds staff_password into E2E_USER_PASSWORD, and authenticated specs self-skip when credentials don't work (auth.ts:45, NO_CREDENTIALS_REASON). So a drifted staff password produces a green nightly that tested nothing at all — no failure, no signal. Splitting the suite without first settling #628 would just give you two projects that both silently skip.

Remaining: all four scope items, after #628.

Audited against `origin/master` — **PARTIAL, exactly as the 2026-07-22 reconciliation comment says. The credential tooling shipped; the suite split has not started.** **Done — persona hydration:** `tools/e2e/hydrate-env-from-bao.mjs:42` defines `KNOWN_PERSONAS = ["staff","student","parent1","parent2","child1","child2","child3"]`, with `--identity` / shorthand resolution at `:39-52` and per-persona key lookup at `:140-143`. So the credentials side is genuinely solved. **Not done — all four of this ticket's code items:** - `playwright.config.ts` still has a single `authenticated` project (one `testMatch: /authenticated-.*\.spec\.ts$/`, one `storageState: AUTH_STATE_PATH`) and one `auth-setup`. No `authenticated-staff` / `authenticated-student` projects. - `e2e/support/auth.ts:24` still has a single `AUTH_STATE_PATH = ".../.auth/user.json"` and a single `E2E_USER` reading `E2E_USER_USERNAME`/`E2E_USER_PASSWORD` (`:35-42`). - `.gitea/workflows/e2e-nightly.yml:52-53` still maps only the one pair — `E2E_USER_USERNAME → staff_username`, `E2E_USER_PASSWORD → staff_password`. The student pair remains parked and unused. - No role classification in `e2e/support/route-manifest.ts`. The grep that establishes all of it: `git grep -n -iE 'E2E_STAFF|E2E_STUDENT|staff\.json|student\.json|authenticated-staff|authenticated-student' origin/master` → **zero hits repo-wide**. **Blocked in practice on #628** for the staff half, and that interaction is worth spelling out because it's currently masking itself: `e2e-nightly.yml` feeds `staff_password` into `E2E_USER_PASSWORD`, and authenticated specs **self-skip** when credentials don't work (`auth.ts:45`, `NO_CREDENTIALS_REASON`). So a drifted staff password produces a **green nightly that tested nothing at all** — no failure, no signal. Splitting the suite without first settling #628 would just give you two projects that both silently skip. **Remaining:** all four scope items, after #628.
Sign in to join this conversation.