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

126 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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:
```sql
-- 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
Фактически выполненные команды:
```text
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 UnauthorizedErrors`**PASS**
- `state created by instance A can be consumed by instance B sharing underlying state`**PASS**
- `expired OAuth state is rejected with UnauthorizedError`**PASS**
- `invalidateTransaction removes state explicitly`**PASS**
- `expired Session is rejected and returns null from getSession`**PASS**
- `createSession, getSession and destroySession work correctly`**PASS**
- `session survives re-creation of store instance when sharing storage`**PASS**
- `Memory stores throw fatal error when MULTI_INSTANCE=true`**PASS**
- `Prisma stores do NOT throw when MULTI_INSTANCE=true`**PASS**
- `createOAuthTransactionStore selects Memory in test/memory mode, Prisma in production mode`**PASS**
- `createSessionStore selects Memory in test/memory mode, Prisma in production mode`**PASS**
---
## 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 требует отдельного интеграционного сьюта.