Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
- name: Check for schema drift
env:
SHADOW_DATABASE_URL: postgresql://rtap:rtap@localhost:5432/rtap_ci_shadow
run: npx prisma migrate diff --from-migrations prisma/migrations --to-schema-datamodel prisma/schema.prisma --exit-code --shadow-database-url "$SHADOW_DATABASE_URL"
run: npx prisma migrate diff --from-migrations prisma/migrations --to-schema prisma/schema.prisma --exit-code

- name: Lint + Typecheck
env:
Expand Down
811 changes: 728 additions & 83 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"generate-admin-login": "tsx scripts/generate-admin-login.ts",
"db:migrate": "prisma migrate dev --schema prisma/schema.prisma",
"db:deploy": "prisma migrate deploy --schema prisma/schema.prisma",
"db:reset": "prisma migrate reset --force --skip-generate --skip-seed --schema prisma/schema.prisma && npm run init",
"db:reset": "prisma migrate reset --force --schema prisma/schema.prisma && npm run init",
"db:status": "prisma migrate status --schema prisma/schema.prisma",
"db:up": "docker compose -f deploy/docker/docker-compose.dev.yml up -d",
"db:down": "docker compose -f deploy/docker/docker-compose.dev.yml down",
Expand All @@ -36,7 +36,9 @@
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@hookform/resolvers": "^5.2.2",
"@prisma/client": "^6.19.0",
"@prisma/adapter-pg": "^7.2.0",
"@prisma/client": "^7.2.0",
"@prisma/config": "^7.2.0",
"@radix-ui/react-select": "^2.2.6",
"@simplewebauthn/browser": "^9.0.1",
"@simplewebauthn/server": "^9.0.3",
Expand All @@ -54,6 +56,7 @@
"next": "^16.1.1",
"next-auth": "5.0.0-beta.30",
"next-themes": "^0.4.6",
"pg": "^8.16.3",
"pino": "^9.14.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
Expand All @@ -70,6 +73,7 @@
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@types/node": "^24.9.1",
"@types/pg": "^8.16.0",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.0",
Expand All @@ -82,7 +86,7 @@
"postcss": "^8.5.3",
"prettier": "^3.7.4",
"prettier-plugin-tailwindcss": "^0.7.2",
"prisma": "^6.19.0",
"prisma": "^7.2.0",
"tailwindcss": "^4.1.17",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
Expand All @@ -93,4 +97,4 @@
"initVersion": "7.39.3"
},
"packageManager": "npm@10.9.2"
}
}
9 changes: 9 additions & 0 deletions prisma.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'dotenv/config';
import { defineConfig } from '@prisma/config';

export default defineConfig({
datasource: {
url: process.env.DATABASE_URL,
shadowDatabaseUrl: process.env.SHADOW_DATABASE_URL,
},
});
1 change: 0 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ generator client {

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Comment on lines 8 to 10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore datasource url for Prisma schema validity

The Prisma schema now omits the url field in the db datasource, which causes validation to fail (P1012: Argument "url" is missing in data source block "db"). The new prisma.config.ts does not satisfy the schema requirement, so prisma validate/migrate/generate and any CI steps that invoke the CLI will error before the app can run. Please keep a datasource url (or equivalent) in the schema so the client and migrations can be produced.

Useful? React with 👍 / 👎.


// Necessary for Next auth
Expand Down
40 changes: 22 additions & 18 deletions scripts/demo-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import {
OutcomeType,
OutcomeStatus,
} from "@prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import pg from "pg";

const db = new PrismaClient();
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
const adapter = new PrismaPg(pool);
const db = new PrismaClient({ adapter });

async function main() {
const user = await db.user.findFirst();
Expand Down Expand Up @@ -861,24 +865,24 @@ async function seedOperations(ctx: SeedCtx) {
executedSuccessfully: t.executedSuccessfully ?? undefined,
outcomes: t.outcome
? {
create: {
type: t.outcome.type,
status: t.outcome.status,
detectionTime: t.outcome.detection
? new Date(t.outcome.detection)
: null,
notes: t.outcome.notes,
logData: t.outcome.log ?? undefined,
tools: {
connect: t.outcome.tools.map((n) => ({ id: tools[n] })),
},
logSources: {
connect: t.outcome.logs.map((n) => ({
id: logSources[n],
})),
},
create: {
type: t.outcome.type,
status: t.outcome.status,
detectionTime: t.outcome.detection
? new Date(t.outcome.detection)
: null,
notes: t.outcome.notes,
logData: t.outcome.log ?? undefined,
tools: {
connect: t.outcome.tools.map((n) => ({ id: tools[n] })),
},
}
logSources: {
connect: t.outcome.logs.map((n) => ({
id: logSources[n],
})),
},
},
}
: undefined,
})),
},
Expand Down
6 changes: 5 additions & 1 deletion scripts/generate-admin-login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import 'dotenv/config';

import { PrismaClient } from '@prisma/client';
import { PrismaPg } from "@prisma/adapter-pg";
import pg from "pg";

async function main() {
const requiredEnv = ['AUTH_SECRET', 'DATABASE_URL'];
Expand All @@ -19,7 +21,9 @@ async function main() {

const initialEmail = process.env.INITIAL_ADMIN_EMAIL?.trim().toLowerCase() ?? 'admin@example.com';

const db = new PrismaClient({ log: ['error'] });
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
const adapter = new PrismaPg(pool);
const db = new PrismaClient({ adapter, log: ['error'] });
try {
const adminUser = await db.user.findUnique({ where: { email: initialEmail } });
if (!adminUser) {
Expand Down
7 changes: 6 additions & 1 deletion scripts/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ async function main() {
try {
console.info('[init] Ensuring initial data (admin + MITRE) ...');
const { PrismaClient } = await import('@prisma/client');
const { PrismaPg } = await import('@prisma/adapter-pg');
const pg = await import('pg');
const { ensureInitialized } = await import('@server/init/ensure-initialized');
const db = new PrismaClient({ log: ['error'] });

const pool = new pg.default.Pool({ connectionString: process.env.DATABASE_URL });
const adapter = new PrismaPg(pool);
const db = new PrismaClient({ adapter, log: ['error'] });
await ensureInitialized(db);
await db.$disconnect();
console.info('[init] Initialization complete.');
Expand Down
7 changes: 7 additions & 0 deletions src/server/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@ import { PrismaClient } from "@prisma/client";
import { env } from "@/env";


import { PrismaPg } from "@prisma/adapter-pg";
import pg from "pg";

const pool = new pg.Pool({ connectionString: env.DATABASE_URL });
const adapter = new PrismaPg(pool);

const createPrismaClient = () =>
new PrismaClient({
adapter,
log:
env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
});
Expand Down
21 changes: 17 additions & 4 deletions src/test/global-setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { spawn } from "node:child_process";
import path from "node:path";
import { PrismaClient } from "@prisma/client";
import { PrismaPg } from "@prisma/adapter-pg";
import pg from "pg";

const DEFAULT_DATABASE_URL = "postgresql://rtap:rtap@localhost:5432/rtap_test";

Expand All @@ -18,7 +20,7 @@ async function runPrismaReset(databaseUrl: string) {
await new Promise<void>((resolve, reject) => {
const child = spawn(
prismaBin,
["migrate", "reset", "--force", "--skip-generate", "--skip-seed", "--schema", "prisma/schema.prisma"],
["migrate", "reset", "--force", "--schema", "prisma/schema.prisma"],
{
stdio: "inherit",
env: { ...process.env, DATABASE_URL: databaseUrl },
Expand All @@ -41,8 +43,17 @@ const isDuplicateDatabaseError = (error: unknown) => {
return false;
}

const prismaError = error as { code?: string; meta?: { code?: string } };
return prismaError.code === "42P04" || prismaError.meta?.code === "42P04";
const prismaError = error as { code?: string; meta?: { code?: string }; message?: string };
if (prismaError.code === "42P04" || prismaError.meta?.code === "42P04") {
return true;
}

// Handle Prisma v7 adapter error wrapping
if (prismaError.code === "P2010" && prismaError.message?.includes("42P04")) {
return true;
}

return false;
};

async function ensureDatabaseExists(databaseUrl: string) {
Expand All @@ -57,7 +68,9 @@ async function ensureDatabaseExists(databaseUrl: string) {
adminUrl.pathname = "/postgres";
adminUrl.search = "";

const prisma = new PrismaClient({ datasources: { db: { url: adminUrl.toString() } } });
const pool = new pg.Pool({ connectionString: adminUrl.toString() });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });

try {
await prisma.$executeRawUnsafe(`CREATE DATABASE "${database}"`);
Expand Down
Loading