feat: Audit remediation + Stripe webhook + test suites
Some checks failed
Build and Push Docker Image / lint-and-typecheck (push) Failing after 1m47s
Build and Push Docker Image / build (push) Has been skipped

- Apply 3 Prisma schema changes (Pending2FASession, hubApiKeyHash, SecurityVerificationCode attempts)
- Add Stripe webhook handler (checkout.session.completed -> User + Subscription + Order)
- Add stripe-service, api-key-service, rate-limit middleware
- Add security headers (CSP, HSTS, X-Frame-Options) in next.config.ts
- Harden auth routes, require ADMIN_API_KEY for orchestrator endpoints
- Add Docker auto-migration via startup.sh
- Add 7 unit test suites (api-key, dns, config-generator, automation-worker, permission, security-verification, auth-helpers)
- Fix Prisma 7 compatibility with adapter-pg mock for vitest

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 08:02:33 +01:00
parent bcc1e17934
commit 1c96c3a85e
36 changed files with 3255 additions and 224 deletions

View File

@@ -0,0 +1,34 @@
-- AlterTable: Add brute-force attempt tracking to security verification codes
ALTER TABLE "security_verification_codes" ADD COLUMN "attempts" INTEGER NOT NULL DEFAULT 0;
-- AlterTable: Add hash-based API key lookup to server connections
ALTER TABLE "server_connections" ADD COLUMN "hub_api_key_hash" TEXT;
-- CreateTable: DB-backed 2FA sessions (replacing in-memory Map)
CREATE TABLE "pending_2fa_sessions" (
"id" TEXT NOT NULL,
"token" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"user_type" TEXT NOT NULL,
"email" TEXT NOT NULL,
"name" TEXT,
"role" TEXT,
"company" TEXT,
"subscription" JSONB,
"expires_at" TIMESTAMP(3) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "pending_2fa_sessions_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "pending_2fa_sessions_token_key" ON "pending_2fa_sessions"("token");
-- CreateIndex
CREATE INDEX "pending_2fa_sessions_token_idx" ON "pending_2fa_sessions"("token");
-- CreateIndex
CREATE INDEX "pending_2fa_sessions_expires_at_idx" ON "pending_2fa_sessions"("expires_at");
-- CreateIndex
CREATE UNIQUE INDEX "server_connections_hub_api_key_hash_key" ON "server_connections"("hub_api_key_hash");

View File

@@ -7,7 +7,7 @@ generator client {
datasource db {
provider = "postgresql"
// url configured in prisma.config.ts (Prisma 7+)
// url configured in prisma.config.mjs (Prisma 7+)
}
// ============================================================================
@@ -417,6 +417,7 @@ model ServerConnection {
// Hub API key (issued after successful registration, used for heartbeats/commands)
hubApiKey String? @unique @map("hub_api_key")
hubApiKeyHash String? @unique @map("hub_api_key_hash")
// Orchestrator connection info (provided during registration)
orchestratorUrl String? @map("orchestrator_url")
@@ -613,11 +614,12 @@ model DetectedError {
model SecurityVerificationCode {
id String @id @default(cuid())
clientId String @map("client_id")
code String // 6-digit code
code String // 8-digit code
action String // "WIPE" | "REINSTALL"
targetServerId String @map("target_server_id") // Which server
expiresAt DateTime @map("expires_at")
usedAt DateTime? @map("used_at")
attempts Int @default(0) // Failed verification attempts
createdAt DateTime @default(now()) @map("created_at")
// Relations
@@ -705,6 +707,28 @@ model NotificationSetting {
@@map("notification_settings")
}
// ============================================================================
// PENDING 2FA SESSIONS
// ============================================================================
model Pending2FASession {
id String @id @default(cuid())
token String @unique
userId String @map("user_id")
userType String @map("user_type") // 'customer' | 'staff'
email String
name String?
role String? // StaffRole for staff users
company String?
subscription Json? // Subscription data for customer users
expiresAt DateTime @map("expires_at")
createdAt DateTime @default(now()) @map("created_at")
@@index([token])
@@index([expiresAt])
@@map("pending_2fa_sessions")
}
// ============================================================================
// SYSTEM-WIDE NOTIFICATION COOLDOWN
// ============================================================================