Skip to content

Add auth claim E2E flow#109

Merged
BASIC-BIT merged 4 commits into
mainfrom
test/auth-claim-e2e
May 31, 2026
Merged

Add auth claim E2E flow#109
BASIC-BIT merged 4 commits into
mainfrom
test/auth-claim-e2e

Conversation

@BASIC-BIT
Copy link
Copy Markdown
Owner

@BASIC-BIT BASIC-BIT commented May 31, 2026

What changed

  • Added a local auth/claim E2E flow that creates an @e2e.vrdex.local password account, captures the OTP through token-gated helpers, links a Discord account, claims an E2E person profile, and verifies the public trust label.
  • Added the required Convex Auth issuer config and local Playwright JWT key generation so real Convex Auth sessions work in local E2E.
  • Hardened public Convex E2E helper mutations so direct Convex calls need the matching server-side helper secret, while browser requests still only receive the browser token.
  • Documented the staged-only auth helper switch and kept production fail-closed.

Why

Issue #100 needs signed-in claim coverage without relying on real SES or OAuth in local CI.

Verification

  • pnpm verify:backend:local
  • pnpm --filter web lint
  • pnpm --filter web typecheck
  • pnpm typecheck:backend
  • pnpm --filter web exec playwright test e2e/profile-submission.flow.spec.ts e2e/auth-claim.flow.spec.ts --project=desktop-chromium
  • pnpm test:e2e
  • pnpm test:backend

Risk notes

  • Hosted auth/claim E2E remains opt-in with VRDEX_ENABLE_E2E_AUTH_HELPERS=true in both Vercel staging and Convex dev.
  • Production remains blocked unless the explicit production E2E override is set.
  • Local JWT keys are generated per Playwright run and are not committed.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vr-dex-web Ready Ready Preview, Comment May 31, 2026 2:32am

Request Review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 31, 2026

Playwright Hosted Data-Flow

Outcome: success
Target: https://staging.vrdex.net
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/26701146008
Artifact: playwright-hosted-data-flow

This optional check runs the mutation-backed profile flow against a configured hosted dev/staging target with isolated E2E test data.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 31, 2026

Playwright Data-Flow Preview

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/26701146008
Artifact: playwright-data-flow

Captured flow:

  • test-gated profile submission form
  • gated helper rejection without the Playwright token
  • Convex profile creation
  • submission success state
  • public profile page readback
  • discovery search readback

Artifacts include screenshots, traces, and recorded video for the flow run.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 31, 2026

Playwright Image Diff

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/26701146008
Artifact: playwright-image-diff

Changed screenshot baselines: none in this PR.

This check compares public route screenshots against committed baselines. Inline images show only added or modified baseline PNGs.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 31, 2026

Playwright Public Screenshot Preview

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/26701146008
Artifact: playwright-public-preview

Screenshots: all public route checks passed on desktop and mobile.

Full screenshot set is available in the artifact. Pixel diff baselines are handled by the separate Playwright Image Diff check.

@BASIC-BIT BASIC-BIT marked this pull request as ready for review May 31, 2026 02:18
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 31, 2026

Greptile Summary

This PR wires up a full local auth/claim E2E path: it creates a @e2e.vrdex.local password account through the Convex Auth password provider, captures the OTP via a new token-gated Next.js helper route backed by an internal Convex mutation, links a synthetic Discord account, and then exercises the profile-claim UI end-to-end.

  • New convex/auth.config.ts and per-run RSA key generation in playwright.config.mjs let Convex Auth issue real sessions in local CI without committing static keys.
  • Existing profile-helper mutations (submitProfile, cleanupProfileBySlug, cleanupProfilesByRunId) are hardened by forwarding the server-side VRDEX_E2E_CONVEX_SECRET through the Next.js route to Convex, closing the gap where direct Convex calls could succeed without the secret.
  • New e2eAuthCodes schema table, recordAuthCode (internal mutation), and three public helper mutations (consumeAuthCode, linkDiscordAccountByEmail, cleanupAuthUserByEmail) are each gated behind both env flags and the deployment secret.

Confidence Score: 3/5

The production auth path is unchanged; the risk is confined to the new local/staging E2E infrastructure. However, the convex env set stdin invocation is unverified and could silently leave JWT keys unsynced on local runs.

The sync-convex-local-env.mjs change removes the value as a positional argument to convex env set and replaces it with stdin input. If the Convex CLI does not read the value from stdin for this sub-command, JWT_PRIVATE_KEY and JWKS would not be set, and every local auth E2E run would fail with an opaque JWT verification error rather than an obvious misconfiguration. The auth.ts arguments[1] pattern is guarded and unlikely to regress production, but is worth cleaning up before the next library upgrade.

scripts/sync-convex-local-env.mjs (stdin input for convex env set) and convex/auth.ts (arguments[1] coupling to the Email provider callback)

Important Files Changed

Filename Overview
convex/auth.ts Adds E2E OTP interception via arguments[1] to access the undeclared second parameter passed by @convex-dev/auth's Email provider; fragile undocumented coupling but guarded by a ctx !== undefined check.
convex/e2e.ts Adds public mutations for E2E auth/claim helpers (consumeAuthCode, linkDiscordAccountByEmail, cleanupAuthUserByEmail), each gated by secret validation; also adds secret arg to existing profile mutations, improving over the previous no-secret-check pattern.
apps/web/src/app/api/e2e/auth/route.ts New E2E auth helper Next.js route; production blocked, token and secret gated, requires both VRDEX_ENABLE_E2E_HELPERS and VRDEX_ENABLE_E2E_AUTH_HELPERS to be set.
scripts/sync-convex-local-env.mjs Switches convex env set from passing the value as a positional CLI arg to passing it via stdin (input: value); also adds JWT_PRIVATE_KEY, JWKS, SITE_URL, and VRDEX_ENABLE_E2E_AUTH_HELPERS to the sync list.
apps/web/e2e/auth-claim.flow.spec.ts New E2E flow covering account creation, OTP capture, Discord link, profile claim, and cleanup; skip guard for hosted environments without VRDEX_ENABLE_E2E_AUTH_HELPERS.
apps/web/playwright.config.mjs Adds per-run RSA key pair generation for local Convex Auth JWT signing; keys are not committed.
convex/schema.ts Adds e2eAuthCodes table with email, code, createdAt, expiresAt fields and a by_email index; test-infrastructure only.

Sequence Diagram

sequenceDiagram
    participant PW as Playwright test
    participant API as Next.js /api/e2e/auth
    participant CVX as Convex (public mutations)
    participant INT as Convex (internal mutation)
    participant UI as Browser / Next.js UI

    PW->>API: POST /api/e2e/profile-submissions
    API->>CVX: e2e.submitProfile(secret, …)
    CVX-->>PW: "{ slug }"

    PW->>UI: /sign-in → create account
    UI->>CVX: signIn(password, signUp)
    CVX->>INT: recordAuthCode(email, code, expiresAt)

    PW->>API: "POST /api/e2e/auth { action:consume-code }"
    API->>CVX: consumeAuthCode(secret, email)
    CVX-->>PW: "{ code }"

    PW->>UI: fill code → Verify email
    UI->>CVX: signIn(password, email-verification)
    CVX-->>UI: signingIn:true → /account

    PW->>API: "POST /api/e2e/auth { action:link-discord }"
    API->>CVX: linkDiscordAccountByEmail(secret, …)

    PW->>UI: /account → Claim with Discord
    UI->>CVX: claimPersonProfile(slug)

    PW->>API: DELETE /api/e2e/profile-submissions
    PW->>API: DELETE /api/e2e/auth
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
convex/auth.ts:65-71
Using `arguments[1]` to access the context object passed by `@convex-dev/auth`'s Email provider relies on the library calling `sendVerificationRequest(params, ctx)` — an undeclared second parameter. This coupling is invisible to TypeScript's type-checker and will silently break if the library ever changes the arity or argument order. Since `@convex-dev/auth` does officially pass a context as the second argument, simply declaring it as a named parameter is both correct and type-safe.

```suggestion
  async sendVerificationRequest(
    params,
    ctx?: {
      runMutation: (mutation: unknown, args: unknown) => Promise<unknown>;
    },
  ) {
    const { identifier, token, expires } = params;
```

### Issue 2 of 2
scripts/sync-convex-local-env.mjs:89-94
**`convex env set` stdin input is undocumented**

The command was changed from `["env", "set", name, value]` (positional arg) to `["env", "set", name]` with `input: value` (stdin). If the Convex CLI does not read the value from stdin for this sub-command, every env var in this list — including `JWT_PRIVATE_KEY` and `JWKS` — would either be set to an empty string or cause the command to fail, silently breaking local auth E2E runs. Can you confirm this is a supported invocation mode for the version of `convex` in use?

Reviews (1): Last reviewed commit: "Cover auth helper gate" | Re-trigger Greptile

Comment thread convex/auth.ts Outdated
Comment thread scripts/sync-convex-local-env.mjs
@BASIC-BIT BASIC-BIT merged commit 3de9b6e into main May 31, 2026
17 checks passed
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.

1 participant