Skip to content

Commit

Permalink
Add prisma postgres test
Browse files Browse the repository at this point in the history
  • Loading branch information
timokoessler committed Nov 22, 2024
1 parent 1d349b9 commit 33bb42e
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 98 deletions.
98 changes: 0 additions & 98 deletions library/sinks/Prisma.sqlite.test.ts

This file was deleted.

215 changes: 215 additions & 0 deletions library/sinks/Prisma.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import * as t from "tap";
import { runWithContext, type Context } from "../agent/Context";
import { Prisma } from "./Prisma";
import { createTestAgent } from "../helpers/createTestAgent";
import { promisify } from "util";
import { exec as execCb } from "child_process";
import path = require("path");

const execAsync = promisify(execCb);

const context: Context = {
remoteAddress: "::1",
method: "POST",
url: "http://localhost:4000",
query: {},
headers: {},
body: {
myTitle: `-- should be blocked`,
},
cookies: {},
routeParams: {},
source: "express",
route: "/posts/:id",
};

t.test("it works with sqlite", async (t) => {
const agent = createTestAgent();
agent.start([new Prisma()]);

process.env.DATABASE_URL = "file:./dev.db";

// Generate prismajs client
const { stdout, stderr } = await execAsync(
"npx prisma migrate reset --force", // Generate prisma client, reset db and apply migrations
{
cwd: path.join(__dirname, "fixtures/prisma/sqlite"),
}
);

if (stderr) {
t.fail(stderr);
}

const { PrismaClient } = require("@prisma/client");

const client = new PrismaClient();

await client.user.create({
data: {
name: "Alice",
email: "[email protected]",
},
});

t.same(await client.$queryRawUnsafe("SELECT * FROM USER"), [
{
id: 1,
name: "Alice",
email: "[email protected]",
},
]);

await runWithContext(context, async () => {
t.same(await client.$queryRawUnsafe("SELECT * FROM USER"), [
{
id: 1,
name: "Alice",
email: "[email protected]",
},
]);

try {
await client.$queryRawUnsafe("SELECT * FROM USER -- should be blocked");
t.fail("Query should be blocked");
} catch (error) {
t.ok(error instanceof Error);
if (error instanceof Error) {
t.same(
error.message,
"Zen has blocked an SQL injection: prisma.$queryRawUnsafe(...) originating from body.myTitle"
);
}
}
});

await client.$executeRawUnsafe("DELETE FROM USER WHERE id = 1");

await client.user.create({
data: {
name: "Alice2",
email: "[email protected]",
},
});

await runWithContext(context, async () => {
await client.$executeRawUnsafe("DELETE FROM USER WHERE id = 2");

try {
await client.$executeRawUnsafe("DELETE FROM USER WHERE id = 2");
await client.$executeRawUnsafe(
"DELETE FROM USER WHERE id = 1 -- should be blocked"
);
t.fail("Execution should be blocked");
} catch (error) {
t.ok(error instanceof Error);
if (error instanceof Error) {
t.same(
error.message,
"Zen has blocked an SQL injection: prisma.$executeRawUnsafe(...) originating from body.myTitle"
);
}
}
});

await client.$disconnect();
});

t.test("it works with postgres", async (t) => {
const agent = createTestAgent();
agent.start([new Prisma()]);

process.env.DATABASE_URL = "postgres://root:[email protected]:27016/main_db";

// Generate prismajs client
const { stdout, stderr } = await execAsync(
"npx prisma migrate reset --force", // Generate prisma client, reset db and apply migrations
{
cwd: path.join(__dirname, "fixtures/prisma/postgres"),
}
);

if (stderr) {
t.fail(stderr);
}

// Clear require cache
for (const key in require.cache) {
delete require.cache[key];
}

const { PrismaClient } = require("@prisma/client");

const client = new PrismaClient();

await client.appUser.create({
data: {
name: "Alice",
email: "[email protected]",
},
});

t.same(await client.$queryRawUnsafe('SELECT * FROM "AppUser";'), [
{
id: 1,
name: "Alice",
email: "[email protected]",
},
]);

await runWithContext(context, async () => {
t.same(await client.$queryRawUnsafe('SELECT * FROM "AppUser";'), [
{
id: 1,
name: "Alice",
email: "[email protected]",
},
]);

try {
await client.$queryRawUnsafe(
'SELECT * FROM "AppUser" -- should be blocked'
);
t.fail("Query should be blocked");
} catch (error) {
t.ok(error instanceof Error);
if (error instanceof Error) {
t.same(
error.message,
"Zen has blocked an SQL injection: prisma.$queryRawUnsafe(...) originating from body.myTitle"
);
}
}
});

await client.$executeRawUnsafe('DELETE FROM "AppUser" WHERE id = 1');

await client.appUser.create({
data: {
name: "Alice2",
email: "[email protected]",
},
});

await runWithContext(context, async () => {
await client.$executeRawUnsafe('DELETE FROM "AppUser" WHERE id = 2');

try {
await client.$executeRawUnsafe('DELETE FROM "AppUser" WHERE id = 2');
await client.$executeRawUnsafe(
'DELETE FROM "AppUser" WHERE id = 1 -- should be blocked'
);
t.fail("Execution should be blocked");
} catch (error) {
t.ok(error instanceof Error);
if (error instanceof Error) {
t.same(
error.message,
"Zen has blocked an SQL injection: prisma.$executeRawUnsafe(...) originating from body.myTitle"
);
}
}
});

await client.$disconnect();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- CreateTable
CREATE TABLE "AppUser" (
"id" SERIAL NOT NULL,
"email" TEXT NOT NULL,
"name" TEXT,

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

-- CreateTable
CREATE TABLE "Post" (
"id" SERIAL NOT NULL,
"title" TEXT NOT NULL,
"content" TEXT,
"published" BOOLEAN NOT NULL DEFAULT false,
"authorId" INTEGER NOT NULL,

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

-- CreateIndex
CREATE UNIQUE INDEX "AppUser_email_key" ON "AppUser"("email");

-- AddForeignKey
ALTER TABLE "Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "AppUser"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"
27 changes: 27 additions & 0 deletions library/sinks/fixtures/prisma/postgres/schema.prisma
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model AppUser {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}

model Post {
id Int @id @default(autoincrement())
title String
content String?
published Boolean @default(false)
author AppUser @relation(fields: [authorId], references: [id])
authorId Int
}

0 comments on commit 33bb42e

Please sign in to comment.