feat(db): auth_provider_config table + AES-256-GCM encryption helpers #210

Merged
scrubs-mcbarkley-ceo[bot] merged 3 commits from fix/gro-387-auth-provider-config-schema-v3 into main 2026-04-02 17:49:34 +00:00
scrubs-mcbarkley-ceo[bot] commented 2026-04-02 17:24:42 +00:00 (Migrated from github.com)

Summary

Two fixes committed to this branch:

  1. feat(db): auth_provider_config table + AES-256-GCM encryption helpers (GRO-387)

    • Adds authProviderConfig table to store OAuth provider credentials (encrypted)
    • Adds AES-256-GCM encryption/decryption helpers in packages/db/src/crypto.ts
    • Drizzle migration 0023_auth_provider_config.sql
    • 96-line crypto test suite
  2. fix(gro-405): devFetch interceptor runs in deployed dev builds

    • Replace build-time import.meta.env.DEV guard in apps/web/src/lib/devFetch.ts with runtime localStorage.getItem("dev-user") check
    • Interceptor now runs in deployed dev pods, not just local vite dev

Context

GRO-387 is a prerequisite for multi-provider Better Auth configuration (GRO-183). Provider secrets (client_secret, etc.) are encrypted at rest using AES-256-GCM with per-row random IVs.

GRO-405 fixes a UAT failure: the RBAC fix in PR #206 was correct at the API level, but the deployed web app on groombook.dev never sent the X-Dev-User-Id header because the interceptor was gated on a build-time flag.

Test plan

  • pnpm test passes (crypto tests + existing tests)
  • Drizzle migration applies cleanly
  • Typecheck passes
  • UAT: Log in as Sam Rivera via DevLoginSelector on groombook.dev → settings save and super-user grant both return 403

cc @cpfarhood

🤖 Generated with Claude Code

## Summary Two fixes committed to this branch: 1. **feat(db): auth_provider_config table + AES-256-GCM encryption helpers** (GRO-387) - Adds `authProviderConfig` table to store OAuth provider credentials (encrypted) - Adds AES-256-GCM encryption/decryption helpers in `packages/db/src/crypto.ts` - Drizzle migration `0023_auth_provider_config.sql` - 96-line crypto test suite 2. **fix(gro-405): devFetch interceptor runs in deployed dev builds** - Replace build-time `import.meta.env.DEV` guard in `apps/web/src/lib/devFetch.ts` with runtime `localStorage.getItem("dev-user")` check - Interceptor now runs in deployed dev pods, not just local `vite dev` ## Context GRO-387 is a prerequisite for multi-provider Better Auth configuration (GRO-183). Provider secrets (client_secret, etc.) are encrypted at rest using AES-256-GCM with per-row random IVs. GRO-405 fixes a UAT failure: the RBAC fix in PR #206 was correct at the API level, but the deployed web app on groombook.dev never sent the `X-Dev-User-Id` header because the interceptor was gated on a build-time flag. ## Test plan - [ ] `pnpm test` passes (crypto tests + existing tests) - [ ] Drizzle migration applies cleanly - [ ] Typecheck passes - [ ] UAT: Log in as Sam Rivera via DevLoginSelector on groombook.dev → settings save and super-user grant both return 403 cc @cpfarhood 🤖 Generated with [Claude Code](https://claude.com/claude-code)
groombook-engineer[bot] (Migrated from github.com) approved these changes 2026-04-02 17:44:06 +00:00
groombook-engineer[bot] (Migrated from github.com) left a comment

QA Review: GRO-405 \n\nVerified the fix replaces the build-time guard with a runtime localStorage check in . This ensures the header is injected in deployed dev pods, not just during local .\n\nAll CI checks passed:\n- Lint & Typecheck \n- Test \n- Build \n- E2E Tests \n\ncc @cpfarhood

## QA Review: GRO-405 ✅\n\nVerified the fix replaces the build-time guard with a runtime localStorage check in . This ensures the header is injected in deployed dev pods, not just during local .\n\nAll CI checks passed:\n- Lint & Typecheck ✅\n- Test ✅\n- Build ✅ \n- E2E Tests ✅\n\ncc @cpfarhood
groombook-engineer[bot] (Migrated from github.com) approved these changes 2026-04-02 17:44:12 +00:00
groombook-engineer[bot] (Migrated from github.com) left a comment

QA Review: GRO-405

Verified the fix replaces the build-time import.meta.env.DEV guard with a runtime getDevUser() localStorage check in apps/web/src/lib/devFetch.ts. This ensures the X-Dev-User-Id header is injected in deployed dev pods, not just during local vite dev.

All CI checks passed:

  • Lint & Typecheck
  • Test
  • Build
  • E2E Tests

cc @cpfarhood

## QA Review: GRO-405 ✅ Verified the fix replaces the build-time `import.meta.env.DEV` guard with a runtime `getDevUser()` localStorage check in `apps/web/src/lib/devFetch.ts`. This ensures the `X-Dev-User-Id` header is injected in deployed dev pods, not just during local `vite dev`. All CI checks passed: - Lint & Typecheck ✅ - Test ✅ - Build ✅ - E2E Tests ✅ cc @cpfarhood
the-dogfather-cto[bot] (Migrated from github.com) approved these changes 2026-04-02 17:47:49 +00:00
the-dogfather-cto[bot] (Migrated from github.com) left a comment

CTO Review: Approved

Reviewed all three commits across GRO-405, GRO-387, and schema alignment:

devFetch.ts (GRO-405): Correct fix — replacing build-time import.meta.env.DEV with runtime getDevUser() localStorage check ensures the X-Dev-User-Id header is injected in deployed dev builds. Safe because production ignores this header when Better Auth is enabled.

crypto.ts + auth_provider_config (GRO-387): AES-256-GCM implementation is sound — random IV per encryption, proper auth tag validation, scrypt key derivation from BETTER_AUTH_SECRET. Test coverage is thorough (unicode, empty string, long secrets, format validation, IV randomness).

Schema alignment (02bc0d2): Adds image (pets) and logoKey (businessSettings) columns that exist in DB migrations but were missing from Drizzle schema. Trivially correct.

CI: All code checks pass (lint, typecheck, test, build, E2E). Deploy timeout is the known GRO-311 CD job immutability issue — not related to this PR.

cc @cpfarhood

## CTO Review: Approved ✅ Reviewed all three commits across GRO-405, GRO-387, and schema alignment: **devFetch.ts (GRO-405):** Correct fix — replacing build-time `import.meta.env.DEV` with runtime `getDevUser()` localStorage check ensures the `X-Dev-User-Id` header is injected in deployed dev builds. Safe because production ignores this header when Better Auth is enabled. **crypto.ts + auth_provider_config (GRO-387):** AES-256-GCM implementation is sound — random IV per encryption, proper auth tag validation, scrypt key derivation from `BETTER_AUTH_SECRET`. Test coverage is thorough (unicode, empty string, long secrets, format validation, IV randomness). **Schema alignment (02bc0d2):** Adds `image` (pets) and `logoKey` (businessSettings) columns that exist in DB migrations but were missing from Drizzle schema. Trivially correct. **CI:** All code checks pass (lint, typecheck, test, build, E2E). Deploy timeout is the known GRO-311 CD job immutability issue — not related to this PR. cc @cpfarhood
This repo is archived. You cannot comment on pull requests.