fix: codegen + cms relations#117
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Security Review — No High-Confidence Vulnerabilities Found
The diff introduces two focused changes: a hardcoded --output path for Prisma codegen and updated Prisma scaffold templates. After reviewing each change against the threat checklist, no exploitable security vulnerabilities were identified.
Analysis
Injection risks (CLI argument building)
getOutputForAdapter returns one of three hardcoded literal strings ("prisma/schema.prisma", "src/db/schema.ts", "migrations/schema.sql"). The adapter and orm values are resolved through a constant allowlist (ADAPTERS), so no user-controlled data flows into the constructed argument array. runCliPassthrough calls execa in array mode (not a shell string), which fully eliminates shell-injection risk regardless of argument content.
Path traversal
The new --output argument value is derived from a hardcoded lookup, not from user or filesystem input. No traversal vector exists.
Secrets / credential handling
The scaffolded stack.ts uses process.env.DATABASE_URL! and the prisma.config.ts uses process.env.DATABASE_URL ?? ''. Both are standard environment-variable references in generated template code. Neither logs nor leaks credentials.
Supply-chain
The only new dependency introduced in generated code is @prisma/adapter-pg, a first-party Prisma package. No novel or unknown third-party packages are added.
Functional notes (not security findings)
- The generated
prisma/schema.prismaomits aurlfield indatasource db; Prisma will refuse to run without it. This is a misconfiguration bug, not a vulnerability. DATABASE_URL ?? ''inprisma.config.tssilently passes an empty string when the env var is unset, causing a confusing runtime failure rather than an early error. Consider failing loudly instead.- The non-null assertion
process.env.DATABASE_URL!instack.tspassesundefinedat runtime if the variable is missing; a guard or explicit error would be safer ergonomically, though not exploitable.
Sent by Cursor Automation: Find vulnerabilities
…k file depth Co-authored-by: Ollie <olliethedev@users.noreply.github.com>
Co-authored-by: Ollie <olliethedev@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Missing
pgdependency in Prisma adapter extra packages- Added
"pg"to theextraPackagesarray for the prisma adapter inconstants.tsso it gets installed alongside@prisma/adapter-pg.
- Added
Preview (1a6c772ba3)
diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts
--- a/packages/cli/src/commands/init.ts
+++ b/packages/cli/src/commands/init.ts
@@ -321,8 +321,13 @@
const orm = ADAPTERS.find(
(item) => item.key === adapter,
)?.ormForGenerate;
+ const outputPath = getOutputForAdapter(adapter);
const args = orm
- ? [`--orm=${orm}`, `--config=${stackPath}`]
+ ? [
+ `--orm=${orm}`,
+ `--config=${stackPath}`,
+ ...(outputPath ? [`--output=${outputPath}`] : []),
+ ]
: [`--config=${stackPath}`];
const exitCode = await runCliPassthrough({
cwd,
diff --git a/packages/cli/src/utils/constants.ts b/packages/cli/src/utils/constants.ts
--- a/packages/cli/src/utils/constants.ts
+++ b/packages/cli/src/utils/constants.ts
@@ -5,6 +5,8 @@
label: string;
packageName: string;
ormForGenerate?: "prisma" | "drizzle" | "kysely";
+ /** Additional npm packages that must be installed when this adapter is selected. */
+ extraPackages?: string[];
}
export interface PluginMeta {
@@ -33,6 +35,7 @@
label: "Prisma",
packageName: "@btst/adapter-prisma",
ormForGenerate: "prisma",
+ extraPackages: ["@prisma/adapter-pg", "pg"],
},
{
key: "drizzle",
diff --git a/packages/cli/src/utils/package-installer.ts b/packages/cli/src/utils/package-installer.ts
--- a/packages/cli/src/utils/package-installer.ts
+++ b/packages/cli/src/utils/package-installer.ts
@@ -39,6 +39,7 @@
"@btst/yar",
"@tanstack/react-query",
adapterMeta.packageName,
+ ...(adapterMeta.extraPackages ?? []),
...pluginExtraPackages,
];
const { command, args } = getInstallCommand(input.packageManager, packages);
diff --git a/packages/cli/src/utils/passthrough.ts b/packages/cli/src/utils/passthrough.ts
--- a/packages/cli/src/utils/passthrough.ts
+++ b/packages/cli/src/utils/passthrough.ts
@@ -7,6 +7,15 @@
return Boolean(ADAPTERS.find((item) => item.key === adapter)?.ormForGenerate);
}
+export function getOutputForAdapter(adapter: Adapter): string | null {
+ const meta = ADAPTERS.find((item) => item.key === adapter);
+ if (!meta?.ormForGenerate) return null;
+
+ if (meta.ormForGenerate === "prisma") return "prisma/schema.prisma";
+ if (meta.ormForGenerate === "drizzle") return "src/db/schema.ts";
+ return "migrations/schema.sql";
+}
+
export function getGenerateHintForAdapter(
adapter: Adapter,
configPath: string,
@@ -14,12 +23,8 @@
const meta = ADAPTERS.find((item) => item.key === adapter);
if (!meta?.ormForGenerate) return null;
- const output =
- meta.ormForGenerate === "prisma"
- ? "schema.prisma"
- : meta.ormForGenerate === "drizzle"
- ? "src/db/schema.ts"
- : "migrations/schema.sql";
+ const output = getOutputForAdapter(adapter);
+ if (!output) return null;
return `npx @btst/codegen generate --orm=${meta.ormForGenerate} --config=${configPath} --output=${output}`;
}
diff --git a/packages/cli/src/utils/scaffold-plan.ts b/packages/cli/src/utils/scaffold-plan.ts
--- a/packages/cli/src/utils/scaffold-plan.ts
+++ b/packages/cli/src/utils/scaffold-plan.ts
@@ -322,7 +322,7 @@
};
}
-function buildAdapterTemplateContext(adapter: Adapter) {
+function buildAdapterTemplateContext(adapter: Adapter, stackPath: string) {
const meta = ADAPTERS.find((item) => item.key === adapter);
if (!meta) {
throw new Error(`Unsupported adapter: ${adapter}`);
@@ -337,15 +337,19 @@
}
if (adapter === "prisma") {
+ const depth = stackPath.split("/").length - 1;
+ const prismaClientPath = `${"../".repeat(depth)}generated/prisma/client`;
return {
adapterImport: `import { createPrismaAdapter } from "${meta.packageName}"
-import { PrismaClient } from "@prisma/client"`,
- adapterSetup: `const prisma = new PrismaClient()
+import { PrismaClient } from "${prismaClientPath}"
+import { PrismaPg } from "@prisma/adapter-pg"`,
+ adapterSetup: `const pgAdapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! })
+const prisma = new PrismaClient({ adapter: pgAdapter })
-const provider = process.env.BTST_PRISMA_PROVIDER ?? "postgresql"
+const provider = (process.env.BTST_PRISMA_PROVIDER ?? "postgresql") as "postgresql" | "sqlite" | "cockroachdb" | "mysql" | "sqlserver" | "mongodb"
`,
adapterStackLine:
- "adapter: (db) => createPrismaAdapter(prisma, db, { provider }),",
+ "adapter: (db) => createPrismaAdapter(prisma, db, { provider })({}),",
};
}
@@ -385,7 +389,10 @@
input.plugins,
input.framework,
);
- const adapterContext = buildAdapterTemplateContext(input.adapter);
+ const adapterContext = buildAdapterTemplateContext(
+ input.adapter,
+ frameworkPaths.stackPath,
+ );
const sharedContext = {
alias: input.alias,
@@ -402,6 +409,20 @@
content: await renderTemplate("shared/lib/stack.ts.hbs", sharedContext),
description: "BTST backend stack configuration",
},
+ ...(input.adapter === "prisma"
+ ? [
+ {
+ path: "prisma/schema.prisma",
+ content: `generator client {\n provider = "prisma-client"\n output = "../generated/prisma"\n}\n\ndatasource db {\n provider = "postgresql"\n}\n`,
+ description: "Prisma schema with explicit client output path",
+ },
+ {
+ path: "prisma.config.ts",
+ content: `import { defineConfig } from 'prisma/config'\n\nexport default defineConfig({\n schema: 'prisma/schema.prisma',\n datasource: {\n url: process.env.DATABASE_URL ?? '',\n },\n})\n`,
+ description: "Prisma configuration file",
+ },
+ ]
+ : []),
{
path: frameworkPaths.stackClientPath,
content: await renderTemplate(You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit c112ecd. Configure here.
Co-authored-by: Ollie <olliethedev@users.noreply.github.com>
|
✅ Shadcn registry validated — no registry changes detected. |



Summary
Type of change
Checklist
pnpm buildpassespnpm typecheckpassespnpm lintpassesdocs/content/docs/) if consumer-facing types or behavior changedScreenshots
Note
Medium Risk
CLI scaffolding changes affect Prisma project setup and codegen invocation (dependencies, generated client import path, and
generateargs), which could break new-project initialization if paths/configs are off. CMS adds an optional write-path to thecontentRelationtable; it’s gated by a flag but touches persistence logic.Overview
CLI init/scaffolding now better supports Prisma by installing required extra packages (e.g.
@prisma/adapter-pg,pg), generatingprisma/schema.prisma(with explicit client output) +prisma.config.ts, updating the Prisma adapter template to use the generated Prisma client +PrismaPg, and passing an explicit--outputpath when delegating togenerate.CMS server-side
createContentItemgains an optional{ syncRelations: true }to also populate thecontentRelationjunction table from relation fields in the payload (reusing new shared helpers inapi/relations.ts), and docs are updated to clarify authorization/validation bypass and relation limitations/behavior.Reviewed by Cursor Bugbot for commit 7ce1721. Bugbot is set up for automated code reviews on this repo. Configure here.