@withpanache/postgres
v0.1.0
Published
Push your PostgreSQL schema to Panache for security and RLS analysis. Framework-agnostic, works with any Postgres project.
Maintainers
Readme
@withpanache/postgres
Push your PostgreSQL schema DDL to Panache for security and RLS analysis. Framework-agnostic: works with any Postgres project, any ORM, any CI/CD.
Install
pnpm add -D @withpanache/postgres
# or npm install -D @withpanache/postgres
# or yarn add -D @withpanache/postgresCLI
panache-postgres push [options]Examples
From a pg_dump output (works with any Postgres project):
pg_dump --schema-only "$DATABASE_URL" \
| panache-postgres push --token "$PANACHE_SITE_TOKEN"From a SQL file:
panache-postgres push --schema ./db/schema.sql --token "$PANACHE_SITE_TOKEN"From a Drizzle project (auto-detects drizzle.config.* and runs
drizzle-kit export for you):
panache-postgres push --from drizzle --token "$PANACHE_SITE_TOKEN"With CI metadata:
panache-postgres push \
--schema ./db/schema.sql \
--git-sha "$CI_COMMIT_SHA" \
--branch "$CI_COMMIT_BRANCH" \
--preview-url "$CI_PREVIEW_URL"Options
| Flag | Description |
|---|---|
| --schema <file> | Read DDL from a SQL file |
| --from drizzle | Auto-detect a Drizzle project and export via drizzle-kit export --dialect=postgresql |
| (stdin) | If neither --schema nor --from is set, read from stdin |
| --token <token> | Panache site token (or PANACHE_SITE_TOKEN env var) |
| --api-url <url> | Ingest API URL (default https://withpanache.dev/api/v1/ingest) |
| --orm <name> | Informational label (prisma, pg-dump, knex, etc.) |
| --git-sha <sha> | Git commit SHA metadata |
| --branch <name> | Git branch name metadata |
| --preview-url <url> | Preview deployment URL metadata |
Exit codes
0: schema pushed successfully1: push failed (network error, non-2xx response, validation error)2: invalid arguments or missing inputs
Library API
Use from any Node script:
import { pushSchema, generateSchemaFromDrizzle } from "@withpanache/postgres"
import { readFileSync } from "node:fs"
// Raw DDL from a file
const ddl = readFileSync("./db/schema.sql", "utf-8")
const result = await pushSchema({
token: process.env.PANACHE_SITE_TOKEN!,
ddl,
metadata: {
orm: "pg-dump",
gitSha: process.env.CI_COMMIT_SHA,
branch: process.env.CI_COMMIT_BRANCH,
},
})
if (!result.ok) {
console.error("push failed:", result.error)
process.exit(1)
}Drizzle helper
import { pushSchema, generateSchemaFromDrizzle } from "@withpanache/postgres"
const schema = generateSchemaFromDrizzle(process.cwd())
if (!schema) {
throw new Error("no Drizzle project detected")
}
await pushSchema({
token: process.env.PANACHE_SITE_TOKEN!,
ddl: schema.ddl,
metadata: {
orm: "drizzle",
ormVersion: schema.ormVersion,
},
})The walk-up detection handles split-workspace monorepos: drizzle.config.ts
can live in apps/web/ while drizzle-kit is declared in the root
package.json, or vice versa.
What Panache does with your schema
Panache imports your DDL into an ephemeral, sandboxed PostgreSQL instance and
runs a set of pg_catalog queries to detect:
- Tables missing Row Level Security
- RLS-enabled tables with no policies (effectively denying all access)
- PUBLIC role grants on destructive privileges (
INSERT,UPDATE,DELETE,TRUNCATE) - Roles with
BYPASSRLSorSUPERUSERprivileges - A full per-table × per-role permissions matrix
Results appear in your Panache dashboard under /databases.
The analysis database is dropped and recreated between every run. Your DDL is never persisted beyond the temporary ingest bucket scoped to your site.
License
MIT
