From 15131b72f0388ae0c2bc63cff67f4875d52dff32 Mon Sep 17 00:00:00 2001 From: "groombook-cto[bot]" <269737991+groombook-cto[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2026 03:30:45 +0000 Subject: [PATCH] fix(GRO-574): add rate_limit table migration for Better Auth Adds the missing rate_limit table that Better Auth v1.5.6 requires when rateLimit.storage is set to 'database'. Without this table, all auth endpoints return HTTP 500. Also includes GRO-566: SKIP_OOBE env var to bypass setup wizard in dev/test. cc @cpfarhood --- .env.example | 6 ++++ apps/api/src/__tests__/setup.test.ts | 42 ++++++++++++++++++++++ apps/api/src/routes/setup.ts | 11 ++++++ packages/db/migrations/0025_rate_limit.sql | 6 ++++ packages/db/migrations/meta/_journal.json | 7 ++++ 5 files changed, 72 insertions(+) create mode 100644 packages/db/migrations/0025_rate_limit.sql diff --git a/.env.example b/.env.example index 293f815..f91cd54 100644 --- a/.env.example +++ b/.env.example @@ -11,6 +11,12 @@ AUTH_DISABLED=false OIDC_ISSUER=https://authentik.example.com OIDC_AUDIENCE=groombook +# ── Setup Wizard ───────────────────────────────────────────────────────────── +# When SKIP_OOBE=true, the setup wizard is bypassed regardless of whether a +# super user exists in the database. Useful in dev/test environments where the +# database has data but the setup wizard would otherwise block access. +SKIP_OOBE=false + # ── API ─────────────────────────────────────────────────────────────────────── PORT=3000 CORS_ORIGIN=http://localhost:8080 diff --git a/apps/api/src/__tests__/setup.test.ts b/apps/api/src/__tests__/setup.test.ts index 8fc4ffd..9884e96 100644 --- a/apps/api/src/__tests__/setup.test.ts +++ b/apps/api/src/__tests__/setup.test.ts @@ -418,6 +418,48 @@ describe("GET /setup/status — OOBE bootstrap logic", () => { expect(body.showAuthProviderStep).toBe(false); // DB config already exists expect(body.authConfigExists).toBe(true); }); + + it("SKIP_OOBE=true bypasses setup check regardless of DB state", async () => { + dbStaffRows = []; // no super user + dbAuthConfigRows = []; + process.env.SKIP_OOBE = "true"; + + const app = makeApp(); + const { status, body } = await getStatus(app); + + expect(status).toBe(200); + expect(body.needsSetup).toBe(false); + expect(body.showAuthProviderStep).toBe(false); + expect(body.authConfigExists).toBe(false); + expect(body.authEnvVarsSet).toBe(false); + expect(body.skipped).toBe(true); + }); + + it("SKIP_OOBE=1 also bypasses setup check", async () => { + dbStaffRows = []; + dbAuthConfigRows = []; + process.env.SKIP_OOBE = "1"; + + const app = makeApp(); + const { status, body } = await getStatus(app); + + expect(status).toBe(200); + expect(body.needsSetup).toBe(false); + expect(body.skipped).toBe(true); + }); + + it("SKIP_OOBE=yes also bypasses setup check", async () => { + dbStaffRows = []; + dbAuthConfigRows = []; + process.env.SKIP_OOBE = "yes"; + + const app = makeApp(); + const { status, body } = await getStatus(app); + + expect(status).toBe(200); + expect(body.needsSetup).toBe(false); + expect(body.skipped).toBe(true); + }); }); describe("POST /setup/auth-provider — OOBE bootstrap", () => { diff --git a/apps/api/src/routes/setup.ts b/apps/api/src/routes/setup.ts index 079636a..a614b5c 100644 --- a/apps/api/src/routes/setup.ts +++ b/apps/api/src/routes/setup.ts @@ -9,6 +9,17 @@ export const setupRouter = new Hono(); // GET /api/setup/status — public (no auth), returns whether setup is needed // and whether the auth provider bootstrap step should be shown setupRouter.get("/status", async (c) => { + const skipOobe = ["true", "1", "yes"].includes((process.env.SKIP_OOBE || "").toLowerCase()); + if (skipOobe) { + return c.json({ + needsSetup: false, + showAuthProviderStep: false, + authConfigExists: false, + authEnvVarsSet: false, + skipped: true, + }); + } + const db = getDb(); // Check if any super user exists diff --git a/packages/db/migrations/0025_rate_limit.sql b/packages/db/migrations/0025_rate_limit.sql new file mode 100644 index 0000000..0a83e14 --- /dev/null +++ b/packages/db/migrations/0025_rate_limit.sql @@ -0,0 +1,6 @@ +-- Better-Auth rate limiting table (GRO-574) +CREATE TABLE "rate_limit" ( + key TEXT NOT NULL PRIMARY KEY, + count INTEGER NOT NULL, + last_request BIGINT NOT NULL +); diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 3a1ec9c..7ca1dc5 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -176,6 +176,13 @@ "when": 1775396067192, "tag": "0024_invoice_indexes", "breakpoints": true + }, + { + "idx": 25, + "version": "7", + "when": 1775482467192, + "tag": "0025_rate_limit", + "breakpoints": true } ] } \ No newline at end of file