randomayzer/agents/antigravity/done/TASK-2026-08-21-01-persistent-auth-stores.md

7.5 KiB
Raw Blame History

Task 01: Persistent OAuth-state & Session Store Report

Date: 2026-08-21
Base Commit SHA: b2888950cdd2d948c15acf0004a0cdc91eeb70e6
Status: IMPLEMENTED / PASS
Assigned Agent: Antigravity (Implementation Orchestrator)


1. Executive Summary

Устранена проблема хранения OAuth-состояний и пользовательских сессий исключительно в памяти одного процесса Node.js (MemoryOAuthTransactionStore и MemorySessionStore), из-за которой в multi-instance / serverless среде или при перезапуске сервера происходили сбои аутентификации VK ID и сброс активных сессий пользователей.

Реализованы персистентные хранилища на базе PostgreSQL / Prisma:

  1. В prisma/schema.prisma добавлены модели OAuthTransaction (с полями state, codeVerifier, redirectTarget, createdAt, expiresAt) и Session (с полями sessionId, userId, user, createdAt, expiresAt), а также индексы по expiresAt и userId.
  2. Создана SQL-миграция prisma/migrations/20260821120000_persistent_auth_stores/migration.sql.
  3. В src/lib/auth/oauth-state.ts реализован PrismaOAuthTransactionStore с атомарной транзакционной операцией consumeTransaction ($transaction find + delete), предотвращающей race conditions и гарантирующей single-use семантику OAuth state.
  4. В src/lib/auth/session.ts реализован PrismaSessionStore со строгой валидацией TTL и каскадным удалением сессий при удалении пользователя.
  5. Настроены фабрики createOAuthTransactionStore() и createSessionStore(): при STORAGE_DRIVER=memory или NODE_ENV=test используются in-memory реализации, в остальных случаях — Prisma-драйверы.
  6. Снят фатальный запрет на запуск с MULTI_INSTANCE=true для Prisma-хранилищ.

2. Modified Files

File Type Description
prisma/schema.prisma DB Schema Добавлены модели OAuthTransaction и Session, добавлена связь sessions в модель User.
prisma/migrations/20260821120000_persistent_auth_stores/migration.sql Migration SQL-миграция создания таблиц и индексов для OAuthTransaction и Session.
src/lib/auth/oauth-state.ts Auth Реализован PrismaOAuthTransactionStore, селектор createOAuthTransactionStore, функции установки стора.
src/lib/auth/session.ts Auth Реализован PrismaSessionStore, селектор createSessionStore, функции установки стора.
tests/persistent-auth-stores.test.ts Tests (NEW) Набор тестов на single-use конкурентность, multi-instance обмен, TTL, жизненный цикл и селекторы драйверов (11 тестов).

3. Database Migration & Execution Order

SQL Migration Content:

-- CreateTable
CREATE TABLE "OAuthTransaction" (
    "id" TEXT NOT NULL,
    "state" TEXT NOT NULL,
    "codeVerifier" TEXT NOT NULL,
    "redirectTarget" TEXT,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "expiresAt" TIMESTAMP(3) NOT NULL,

    CONSTRAINT "OAuthTransaction_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Session" (
    "id" TEXT NOT NULL,
    "sessionId" TEXT NOT NULL,
    "userId" TEXT NOT NULL,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "expiresAt" TIMESTAMP(3) NOT NULL,

    CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "OAuthTransaction_state_key" ON "OAuthTransaction"("state");

-- CreateIndex
CREATE INDEX "OAuthTransaction_expiresAt_idx" ON "OAuthTransaction"("expiresAt");

-- CreateIndex
CREATE UNIQUE INDEX "Session_sessionId_key" ON "Session"("sessionId");

-- CreateIndex
CREATE INDEX "Session_expiresAt_idx" ON "Session"("expiresAt");

-- CreateIndex
CREATE INDEX "Session_userId_idx" ON "Session"("userId");

-- AddForeignKey
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

Порядок применения на существующей БД:

  1. Выполнить npx prisma migrate deploy или применить приведенный SQL-скрипт в PostgreSQL.
  2. Никаких изменений существующих данных User, Giveaway, Participant не требуется (обратно-совместимо).

4. Verification Evidence & Test Gate

Фактически выполненные команды:

npx prisma generate  -> EXIT 0 (Prisma Client v5.22.0 generated with OAuthTransaction and Session models)
npx tsc --noEmit     -> EXIT 0 (Clean TypeScript check, 0 errors)
npm test             -> EXIT 0 (50 test suites, 295 passed, 0 failed)
npm run lint         -> EXIT 0 (Next.js ESLint passed clean)
npm run build        -> EXIT 0 (Next.js production build compiled successfully)

Summary of New Tests (tests/persistent-auth-stores.test.ts):

  • concurrent consumeTransaction calls on same state yield exactly 1 success and N-1 UnauthorizedErrorsPASS
  • state created by instance A can be consumed by instance B sharing underlying statePASS
  • expired OAuth state is rejected with UnauthorizedErrorPASS
  • invalidateTransaction removes state explicitlyPASS
  • expired Session is rejected and returns null from getSessionPASS
  • createSession, getSession and destroySession work correctlyPASS
  • session survives re-creation of store instance when sharing storagePASS
  • Memory stores throw fatal error when MULTI_INSTANCE=truePASS
  • Prisma stores do NOT throw when MULTI_INSTANCE=truePASS
  • createOAuthTransactionStore selects Memory in test/memory mode, Prisma in production modePASS
  • createSessionStore selects Memory in test/memory mode, Prisma in production modePASS

5. Core Invariants & Security

  • Randomizer / Audit Proof Invariants: HMAC_SHA256_FY_V1, DeterministicHmacStream, executeDeterministicDrawV1, verifyDrawResult сохранены без изменений.
  • PKCE / State Invariants: S256 code challenge, криптостойкие случайные токены (CSPRNG) сохранены.
  • Single-Use Invariant: Гарантируется как в памяти, так и в базе данных через атомарную транзакцию $transaction.

6. UNVERIFIED Assertions & Tech Debt

  1. UNVERIFIED: Live PostgreSQL CI execution for Prisma auth stores:
    • В текущем тестовом окружении автоматизированные тесты Vitest выполняются с STORAGE_DRIVER=memory и NODE_ENV=test. Хотя PrismaOAuthTransactionStore и PrismaSessionStore скомпилированы и проверены, сквозной прогон с живой базой PostgreSQL в Vitest требует отдельного интеграционного сьюта.