Skip to content

Add vitest harness + initial tests for auth-api#151

Merged
pokle merged 4 commits into
masterfrom
claude/auth-api-test-harness
May 30, 2026
Merged

Add vitest harness + initial tests for auth-api#151
pokle merged 4 commits into
masterfrom
claude/auth-api-test-harness

Conversation

@pokle
Copy link
Copy Markdown
Owner

@pokle pokle commented Apr 20, 2026

Summary

auth-api had zero test coverage. This PR wires up a vitest harness (mirroring the competition-api setup) and adds Tier-1 security-invariant tests. Tiers 2–4 are stubbed as test.todo(...) so they show up in the runner and nothing is silently missing.

  • bun run test:auth runs the new suite
  • bun run test:all now includes auth-api
  • Result: 30 passing, 13 todo

API surface reviewed

Method Route Purpose
use /api/auth/* CORS allowlist (SEC-01)
GET /api/auth/me Current user or { user: null }
POST /api/auth/set-username Auth + format + uniqueness → update username
POST /api/auth/delete-account Auth + Google token revoke + cascade delete
POST /api/auth/dev-login Localhost-only (SEC-07); signs up + signs in
all /api/auth/* Better Auth catch-all (sign-in, sign-out, apiKey plugin)

What's in this PR (Tier 1)

  • CORS allowlist mirror of competition-api's SEC-01 test — prod + pages-preview + localhost allowed; suffix-confusion, wrong-scheme, malformed origins rejected.
  • isLocalDev unit tests (SEC-07) — localhost variants → true; glidecomp.com, localhost.evil.example suffix attack, 127.0.0.1 → false.
  • GET /api/auth/me returns { user: null } with no cookie and with a garbage cookie (does not 500).
  • POST /set-username + POST /delete-account return 401 anonymously.
  • POST /dev-login happy-path test (sets a session cookie), plus empty-body and non-JSON body → 400.

Proposed follow-up tests (Tier 2–4, stubbed as test.todo)

Tier 2 — set-username validation

  • Length bounds: ab (2) → 400, abcdefghijklmnopqrstu (21) → 400.
  • Regex: reject leading/trailing hyphen, underscore, space, HTML chars.
  • Trimming: " alice " stored as "alice".
  • Uniqueness: conflict with another user → 409.
  • Self-update is not a conflict — setting own username to same value → 200 (verifies the AND id != ? clause).

Tier 3 — delete-account

  • Removes the user row and cascades session + account rows.
  • Succeeds even when Google token revocation fetch fails (needs outbound fetch mocked).
  • Also removes API keys owned by the deleted user.

Tier 4 — Better Auth apiKey plugin

  • Create → /me with x-api-key resolves to the owner.
  • Revoked key → 401 on next /me call.
  • Rate limit: 61st request in 60 s window → 429 (SEC-08).
  • getSession round-trip: sign up via dev-login, replay Set-Cookie on /me.

Not planned

  • OAuth callback end-to-end (needs Google token server mock — brittle, low ROI).
  • trustedOrigins CSRF enforcement inside Better Auth (covered upstream).
  • Full integration test for "dev-login 404 in production mode" — would need a second vitest project to swap BETTER_AUTH_URL. The isLocalDev unit test covers the same property.

Harness notes

  • vitest.config.ts supplies dummy BETTER_AUTH_SECRET, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET via miniflare bindings. Default BETTER_AUTH_URL is http://localhost:8788 so dev-login is enabled.
  • test/helpers.ts has clearAuthData(), seedUser(), devSignIn(), fetchWorker().
  • test/apply-migrations.ts applies D1 migrations once per pool.

Test plan

  • bun run test:auth passes locally (30 passed, 13 todo)
  • bun run typecheck:auth passes
  • CI runs the new suite on this PR
  • Decide which Tier 2–4 test.todo items to graduate to real tests (separate PRs)

https://claude.ai/code/session_01Tvuta7yC8Axf5iRQy7sjSX

claude added 4 commits April 20, 2026 14:31
auth-api had no test coverage. Mirrors the competition-api setup
(@cloudflare/vitest-pool-workers with D1 migrations applied in the test
pool). Adds root-level `bun run test:auth` and wires it into `test:all`.

Initial coverage (30 passing, 13 todo):

Tier 1 — security invariants
  - CORS allowlist mirror of competition-api's SEC-01 test
  - isLocalDev gate (SEC-07): localhost variants → true;
    glidecomp.com, suffix attacks, 127.0.0.1 → false
  - GET /api/auth/me returns { user: null } with no cookie and with
    garbage cookie (does not 500)
  - POST /set-username and POST /delete-account return 401 anonymously
  - POST /dev-login handles missing fields, non-JSON body, and the
    happy path (sets a session cookie)

Tiers 2-4 stubbed as test.todo(...) so they show up in the runner and
we track what's still to cover: full set-username format rules,
delete-account cascade, Google revocation failure, and apiKey plugin
round-trip / rate-limit. See the PR description for the full plan.

The full SEC-07 "dev-login 404 in production mode" integration test
would need a second vitest project to swap BETTER_AUTH_URL, so for
now we unit-test isLocalDev directly — that's the gate that matters.

https://claude.ai/code/session_01Tvuta7yC8Axf5iRQy7sjSX
The root `tsc --noEmit` walks the auth-api/test directory but doesn't
have @cloudflare/vitest-pool-workers in its types, so it can't resolve
the cloudflare:test module. Mirror the existing exclude for
competition-api/test — the test directories have their own tsconfig
that loads the right types.

https://claude.ai/code/session_01Tvuta7yC8Axf5iRQy7sjSX
…t-harness

# Conflicts:
#	bun.lock
#	package.json
#	tsconfig.json
#	web/workers/auth-api/package.json
#	web/workers/auth-api/test/apply-migrations.ts
#	web/workers/auth-api/test/helpers.ts
#	web/workers/auth-api/vitest.config.ts
The "two users do not see each other's preferences" test in
preferences.test.ts:296 was timing out on CI runners with the default
5s. dev-login does a real signUp + signIn (Better Auth hashes a
password) on every call; the multi-user test does this twice plus four
round trips, which is fine locally but borderline on slower runners.

15s gives a safety margin without masking real perf regressions.
Passed previously on master CI because test:all didn't include
test:auth — this PR is the one wiring it in.

https://claude.ai/code/session_01Tvuta7yC8Axf5iRQy7sjSX
@github-actions
Copy link
Copy Markdown

Preview Deployment
https://5bea9855.glidecomp.pages.dev
Commit: c27a4cc

@pokle pokle marked this pull request as ready for review May 30, 2026 11:23
@pokle pokle merged commit 99f39ce into master May 30, 2026
8 checks passed
@pokle pokle deleted the claude/auth-api-test-harness branch May 30, 2026 11:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants