fix: require verified production email
Expose the existing email-verification setting through Compose and close the completed DataProtection rotation blocker.
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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_...
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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-02 — production 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 |
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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. |
|
||||
|
||||
Reference in New Issue
Block a user