PostgreSQL-first SQL security gate for AI-generated queries, migrations, and automation workflows.
DBwall reviews PostgreSQL SQL before it reaches a database or merge target. It is intentionally PostgreSQL-only and focuses on high-risk statements: destructive DDL/DML, risky privilege changes, and suspicious bulk-access patterns. The repository is named DBwall; the CLI binary is dbguard.
AI-generated SQL is often syntactically valid but operationally unsafe. DBwall is meant to catch statements such as:
- unbounded
DELETEandUPDATE - destructive schema operations like
DROP TABLE,DROP SCHEMA, and safety-boundary removal - privilege expansion such as
GRANT ... TO PUBLIC - suspicious reads or exports from protected objects
It returns one of three decisions:
allowwarnblock
DBwall is a SQL review gate, not a database firewall or a substitute for database permissions.
- It does not execute queries or enforce runtime access control.
- It does not claim full semantic understanding of every PostgreSQL migration pattern.
- It does not support non-PostgreSQL dialects.
- In
corecoverage mode it deliberately keeps reduced advanced-rule coverage rather than pretending parity with the parser-backed path.
Exit codes:
| Code | Meaning |
|---|---|
0 |
Allow |
1 |
Tool or parse error |
2 |
Warn |
3 |
Block |
DBwall reports its parser coverage mode explicitly:
full(CGO_ENABLED=1): security metadata is derived by walking the structured PostgreSQL AST frompg_query_go(relations, grants, predicates, nested CTE/subquery sources). JSON/SARIF also expose per-statementcompleteness.core(CGO_ENABLED=0): portable token parser with explicitly reduced semantic coverage. Multi-table joins, nested CTE mutations, and several GRANT/DROP multi-object shapes are only accurate infullmode.
Checks that need full mode for accurate relation discovery include:
- join /
UPDATE ... FROM/DELETE ... USINGsecondary relations - CTE and subquery sources (including
COPY (SELECT ...)) - multi-object
DROP TABLE/TRUNCATE/GRANT ... ON TABLE a, b - constant-folded trivial predicates beyond
TRUEand1 = 1 - explicit
semantic_analysis_incompletefindings for unsupported AST statement types
Release binaries are built with CGO_ENABLED=0 for portability, so they run in core mode unless you build from source with CGO enabled.
This is the reliable install path for the current repo state.
Portable build:
git clone https://github.com/ChimdumebiNebolisa/DBwall.git
cd DBwall
go build -o dbguard ./cmd/dbguardFull PostgreSQL parser-backed build:
CGO_ENABLED=1 go build -o dbguard ./cmd/dbguardgo install github.com/ChimdumebiNebolisa/DBwall/cmd/dbguard@latestRelease archives are produced by .github/workflows/release.yml when a semver tag such as v0.2.0 is pushed. Use the GitHub Releases page for the currently published version instead of hardcoding a version string from the README.
Build the CLI and review one statement:
go build -o dbguard ./cmd/dbguard
./dbguard review-sql "DELETE FROM users;"Review a file with policy and machine-readable output:
./dbguard review-file ./migrations/latest.sql --policy ./examples/dbguard.yaml --format jsonHuman-readable review:
dbguard review-sql "DELETE FROM users;"JSON for automation:
dbguard review-file ./migrations/latest.sql --policy ./dbguard.yaml --format jsonSARIF for code scanning:
dbguard review-file ./migrations/latest.sql --policy ./dbguard.yaml --format sarif > dbwall.sarifVersion:
dbguard versionhuman: concise summary, per-statement findings, rationale, remediation, and coverage-mode notejson: stable machine-readable output with decision, severity, summary, tool/version metadata, and finding detailssarif: code-scanning output for GitHub and similar tooling
DBwall stays additive and PostgreSQL-specific. The policy file supports:
dialectprotected_tablesprotected_schemasprotected_roles- per-rule
allow|warn|blockoverrides inrules
Example:
dialect: postgres
protected_tables:
- users
- payments
protected_schemas:
- finance
protected_roles:
- pg_read_all_data
rules:
delete_without_where: block
truncate_table: block
writes_to_protected_tables: warn
select_without_limit_from_protected_table: warnFull example: examples/dbguard.yaml
- GitHub Actions: examples/GITHUB_ACTION_EXAMPLE.md
- Pre-commit: examples/PRE_COMMIT_EXAMPLE.md
- Generic CI: examples/CI_EXAMPLE.md
Repo workflows:
- CI: .github/workflows/ci.yml
- Release: .github/workflows/release.yml
DBwall includes an adversarial corpus under test_e2e/testdata/corpus.json covering:
- good queries
- borderline queries
- obviously dangerous queries
- false-positive cases
- multi-table / CTE / COPY-select / multi-object and incomplete-analysis cases (many require
fullmode)
The reproducible benchmark harness lives under benchmark/.
Run it from the repo root:
CGO_ENABLED=1 go run ./benchmark/cmd/dbwallbench --repo-root . --manifest ./benchmark/manifest.json --json-out ./benchmark/results/benchmark_results.json --report-out ./benchmark/reports/benchmark_report.mdSaved artifacts:
- Raw benchmark results: benchmark/results/benchmark_results.json
- Human-readable report: benchmark/reports/benchmark_report.md
Current saved run from benchmark/results/benchmark_results.json:
- Corpus:
benchmark/manifest.json - Coverage mode:
full - Total cases:
29 - Correct blocks:
13 - Correct allows:
6 - Correct warns:
10 - False positives:
0 - False negatives:
0 - Precision (
blockas positive class):1.0000 - Recall (
blockas positive class):1.0000 - Accuracy (exact decision match):
1.0000 - Average runtime per case:
4.157 ms
Those numbers are measured results from the saved artifact, not a generalized product claim. Precision and recall use block as the positive class. Cases marked requires_full are included only when the built binary reports coverage_mode=full.
CGO_ENABLED=1 go test ./...
CGO_ENABLED=0 go test ./...
go vet ./...