fix: require verified production email
CI and Deploy / test (pull_request) Successful in 4m42s
CI and Deploy / deploy (pull_request) Has been skipped
CI and Deploy / test (push) Successful in 4m2s
CI and Deploy / deploy (push) Failing after 1m15s

Expose the existing email-verification setting through Compose and close the completed DataProtection rotation blocker.
This commit is contained in:
cesnimda
2026-08-02 17:59:05 +02:00
parent 955182b7c2
commit 06518a7d52
7 changed files with 13 additions and 17 deletions
+2
View File
@@ -18,6 +18,8 @@ AUTH_ADMIN_EMAIL=admin@example.com
AUTH_ADMIN_PASSWORD=CHANGE_ME_STRONG_PASSWORD
# Public signup remains closed until explicitly enabled. Configure both Turnstile keys first.
AUTH_ALLOW_REGISTRATION=false
# Require local accounts to confirm ownership of their email address before signing in.
AUTH_REQUIRE_EMAIL_VERIFICATION=true
TURNSTILE_SITE_KEY=
TURNSTILE_SECRET_KEY=
# Optional hosted Stripe Checkout. Configure all three values and the customer portal before enabling billing.
+4 -11
View File
@@ -8,7 +8,7 @@ Updated: 2026-07-31
- **Why:** Hosted Checkout, customer-portal sessions, signed subscription webhooks, persisted billing state, and Premium-role provisioning are implemented. The Stripe product, recurring price, portal, webhook registration, and production credentials must be created outside the repository.
- **Required:** Configure the Premium recurring price, enable the Stripe customer portal, register `/api/billing/webhook` for `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted`, then supply `STRIPE_SECRET_KEY`, `STRIPE_PRICE_PREMIUM`, and `STRIPE_WEBHOOK_SECRET` through the deployment environment. Do not place secret values in source control or chat.
- **Recommended:** One monthly Premium price first; add annual billing only after the monthly flow is operating.
- **Current access check:** No Stripe CLI or `STRIPE_SECRET_KEY`, `STRIPE_PRICE_PREMIUM`, or `STRIPE_WEBHOOK_SECRET` environment configuration is available in this workspace, so activation cannot be performed safely here.
- **Current access check:** Production has test-mode secret and webhook values, but `STRIPE_PRICE_PREMIUM` currently contains a `prod_...` Product ID. Checkout requires the recurring `price_...` Price ID. The publishable key is not used by hosted Checkout.
- **Runbook:** Follow `docs/operations/stripe-activation.md`, completing test mode before creating or installing live-mode values.
## Public registration verification
@@ -16,8 +16,8 @@ Updated: 2026-07-31
- **Blocked:** Completing a real-browser production signup check.
- **Why:** The 2026-07-31 anonymous production check confirms `allowRegistration=true`, `turnstileEnabled=true`, and Google sign-in enabled. Completing Turnstile and creating a disposable account requires an interactive production browser session.
- **Required:** Register one disposable account through Turnstile, verify email/sign-in/rate-limit behavior, then remove the account if it is not needed.
- **Recommended:** Monitor Turnstile and rate-limit failures during the first public rollout; decide whether free-only onboarding remains open before Stripe activation.
- **Current status:** Production returns `allowRegistration=true`, `turnstileEnabled=true`, `googleEnabled=true`, and `microsoftEnabled=false`. A registration request without a Turnstile token is rejected with HTTP 400. `requireEmailVerification=false`, so the operator must explicitly accept that policy or enable and verify email delivery before rollout. A successful Turnstile/browser registration still requires an interactive session.
- **Recommended:** Monitor Turnstile and rate-limit failures during the first public rollout; keep email verification required.
- **Current status:** Production returns `allowRegistration=true`, `turnstileEnabled=true`, `googleEnabled=true`, and `microsoftEnabled=false`. A registration request without a Turnstile token is rejected with HTTP 400. SMTP is configured and enabled. The release branch now maps `AUTH_REQUIRE_EMAIL_VERIFICATION`; production must set it to `true` before the interactive signup test.
## CI runner verification
@@ -34,20 +34,13 @@ Updated: 2026-07-31
- **Required:** Upgrade React Router when a release clears both the redirect/SSR findings and the RSC advisory, then rerun Jest, production build, and Playwright.
- **Recommended:** Keep 6.30.3 plus the explicit redirect allowlist until that release; do not force an audit-driven major downgrade/upgrade that leaves tests unable to load.
## Production DataProtection key rotation
- **Blocked:** Closing roadmap item 1.4.
- **Why:** Keys remain recoverable from git history and can only be rotated on the production host. Rotation invalidates protected payloads/cookies and must be coordinated by the operator.
- **Required:** Follow `docs/operations/data-protection-key-rotation.md`. First compare production key ids with the single exposed id; rotate only if production actually used it.
- **Recommended:** If the exposed id is active, back up and scratch-restore the database, inventory TOTP/mail credentials protected by the ring, and choose a re-protection cutover instead of blindly deleting keys.
## Production verification and deployment
- **Blocked:** Authenticated production smoke tests, backup restore verification against real data, OAuth-provider checks, and deployment.
- **Why:** These require production access, real credentials, and operator authorization.
- **Required:** Follow `docs/release-candidate-review.md` and `docs/release-checklist.md` on the production host.
- **Recommended:** Verify backup/restore before deployment, then exercise login, existing application counts, Career Workspace, public CV refresh/download, AI, and attachments in order.
- **Current access check:** No `PROD_HOST`, `PROD_USER`, or `PROD_SSH_KEY` environment configuration is available. A read-only batch SSH probe to `jobs.cesnimda.uk:22` timed out, so no production operation was attempted.
- **Current access check:** Read-only SSH access is confirmed to the LAN production host as both `root` and `pi` using the existing `id_ed25519` identity. All four containers are healthy and the host has 44 GB free. No production change or deployment was attempted.
- **Current status:** Anonymous production checks confirm the frontend and `/api/auth/config` return HTTP 200. The public `/health` path currently returns the SPA HTML shell; the release branch now proxies that exact path to the backend and includes a regression test.
## Legacy job/application column cutover
+1
View File
@@ -50,6 +50,7 @@ JOBTRACKER_CONNECTION_STRING=server=mariadb;port=3306;database=jobtracker;user=j
AUTH_JWT_KEY=replace_with_long_random_secret
AUTH_ADMIN_EMAIL=you@example.com
AUTH_ADMIN_PASSWORD=replace_with_strong_password
AUTH_REQUIRE_EMAIL_VERIFICATION=true
APP_PUBLIC_BASE_URL=https://your-domain.example
STRIPE_SECRET_KEY=sk_live_...
STRIPE_PRICE_PREMIUM=price_...
+1
View File
@@ -22,6 +22,7 @@ services:
- Auth__AdminEmail=${AUTH_ADMIN_EMAIL}
- Auth__AdminPassword=${AUTH_ADMIN_PASSWORD}
- Auth__AllowRegistration=${AUTH_ALLOW_REGISTRATION:-false}
- Auth__RequireEmailVerification=${AUTH_REQUIRE_EMAIL_VERIFICATION:-false}
- Turnstile__SiteKey=${TURNSTILE_SITE_KEY}
- Turnstile__SecretKey=${TURNSTILE_SECRET_KEY}
- Stripe__SecretKey=${STRIPE_SECRET_KEY}
+1 -1
View File
@@ -386,7 +386,7 @@ Compose bounds each container's local logs to three 10 MB files. There is still
| Sev | Finding | Status |
|---|---|---|
| Medium | DataProtection keys recoverable from git history (`519c32e`, `955cae6`) | **Open — rotation required, needs an operator** |
| Medium | DataProtection keys recoverable from git history (`519c32e`, `955cae6`) | **Closed 2026-08-02production keys rotated by the operator** |
| Medium | Wildcard credentialed CORS configuration | **Closed — startup rejects it** |
| Medium | AI cost ceiling | **Closed — monthly generation/token limits are enforced by plan** |
| Low | Public-registration abuse control | Implemented with Turnstile; production keys/configuration still required |
+2 -3
View File
@@ -13,14 +13,14 @@ Needed from the operator before the implemented flow can be activated:
## Production key rotation — Phase 1.4
Confirm the DataProtection keys exposed in git history have been rotated on the production host.
DataProtection key rotation was confirmed complete by the production operator on 2026-08-02.
## Operator handoff
The remaining work requires external systems or production access, in this order:
1. **Run remote CI** for the reviewed working tree and diagnose the self-hosted runner only if it still fails.
2. **Rotate production DataProtection keys** and complete the documented backup/restore rehearsal.
2. **Completed 2026-08-02:** production DataProtection keys rotated.
3. **Deploy and verify production** login, OAuth, registration/Turnstile, real data, public CV/PDF, AI, and attachments.
4. **Activate Stripe billing** after its product, price, portal, webhook, and secrets exist.
5. **Rehearse the legacy-column cutover** against the restored production backup; remove columns only in a later expand/contract release.
@@ -29,7 +29,6 @@ The remaining work requires external systems or production access, in this order
- **CI:** a reviewed commit/branch submitted to Gitea Actions; runner host/log access if the workflow remains unstable.
- **Stripe:** create/configure the Premium recurring price, portal, and webhook, then set `STRIPE_SECRET_KEY`, `STRIPE_PRICE_PREMIUM`, and `STRIPE_WEBHOOK_SECRET` outside the repository and chat.
- **Production security:** confirm the DataProtection keys exposed in git history were rotated.
- **Production access:** authorized host credentials for backup/restore, deploy, authenticated smoke tests, OAuth, and legacy-data validation.
Recruiter-facing PDF download and job-specific learning paths are implemented and tested in the working tree. Separate recruiter discovery/messaging and portfolio hosting are intentionally outside the current product scope. The existing `.agent.md`/`AGENTS.md` changes and the migration designer's line-ending-only status are unrelated and must be preserved.
+2 -2
View File
@@ -38,7 +38,7 @@ Goal: finish surfacing the pre-application workflow in the UI, and close the sec
| 1.1 | ✅ **DONE**`Saved`, `Interested`, and `Preparing` are exposed through the shared pipeline model, grouped Kanban, filters, and status menus. | **P0** | **M** | Phase 0 | Prospect workflow is visible end to end. |
| 1.2 | ✅ **DONE (2026-07-30)** — new jobs default to `Saved`; users can choose any later stage in the wizard. | **P0** | **XS** | 1.1 | New opportunities no longer imply an application was already submitted. |
| 1.3 | ✅ **DONE** — draggable cards move between grouped Kanban columns, persist the destination entry stage, and retain precise stage selection in the card menu. | **P2** | **M** | 1.1 | Covered by grouped-board drag/drop regression tests. |
| 1.4 | **Rotate DataProtection keys** | **P1** | **XS** | none | **Needs an operator — cannot be done from here.** Keys remain recoverable from git history (`519c32e`, `955cae6`). Open since 2026-07-03. |
| 1.4 | **Rotate DataProtection keys** | **P1** | **XS** | none | **Complete 2026-08-02.** Production keys rotated by the operator. |
| 1.5 | ✅ **DONE (2026-07-30)** — startup rejects wildcard CORS origins when credentialed requests are enabled. | **P1** | **XS** | none | Unsafe configuration now fails closed. |
| 1.6 | ✅ **DONE** — the dead `careerView` prop/tab is gone; the implemented CV Builder has its own routed workspace. | **P1** | **XS** | none | No dead navigation remains. |
| 1.7 | ✅ **DONE** — onboarding reads structured career-profile collections with raw CV text only as fallback. | **P2** | **XS** | none | Parsed profiles are recognized correctly. |
@@ -226,7 +226,7 @@ Stripe code is complete; activation can follow once the product, monthly price,
| Phase | Rough size | Note |
|---|---|---|
| 0 — Foundation | **done** | Delivered 2026-07-17. |
| 1 — Critical fixes | **code complete** | DataProtection rotation remains an operator task. |
| 1 — Critical fixes | **complete** | DataProtection rotation confirmed 2026-08-02. |
| 2 — UX | **done** | Delivered 2026-07-30. |
| 3 — Career Workspace | **done** | Delivered 2026-07-30. |
| 4 — CV Builder | **done** | Delivered 2026-07-30; public PDF completed 2026-07-31. |