db-guardrail 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- db_guardrail-0.1.0/LICENSE +21 -0
- db_guardrail-0.1.0/PKG-INFO +286 -0
- db_guardrail-0.1.0/README.md +265 -0
- db_guardrail-0.1.0/pyproject.toml +45 -0
- db_guardrail-0.1.0/setup.cfg +4 -0
- db_guardrail-0.1.0/src/db_guardrail/__init__.py +1 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/__init__.py +0 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/dependency_analyzer.py +85 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/dependency_models.py +13 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/explain.py +17 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/issue_models.py +13 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/issue_serialization.py +18 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/lock_analyzer.py +82 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/lock_models.py +11 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/migration_analyzer.py +201 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/migration_models.py +25 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/plan_models.py +12 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/plan_parser.py +49 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/rule_engine.py +110 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/sql_splitter.py +31 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/statement_models.py +8 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/table_extractor.py +48 -0
- db_guardrail-0.1.0/src/db_guardrail/analysis/table_size.py +39 -0
- db_guardrail-0.1.0/src/db_guardrail/cli.py +205 -0
- db_guardrail-0.1.0/src/db_guardrail/database/__init__.py +0 -0
- db_guardrail-0.1.0/src/db_guardrail/database/connection.py +22 -0
- db_guardrail-0.1.0/src/db_guardrail/database/history_repository.py +201 -0
- db_guardrail-0.1.0/src/db_guardrail/database/sandbox.py +12 -0
- db_guardrail-0.1.0/src/db_guardrail/database/schema.sql +26 -0
- db_guardrail-0.1.0/src/db_guardrail/multi_statement_demo.py +26 -0
- db_guardrail-0.1.0/src/db_guardrail/reports/__init__.py +0 -0
- db_guardrail-0.1.0/src/db_guardrail/reports/console_reports.py +55 -0
- db_guardrail-0.1.0/src/db_guardrail/reports/migration_console_report.py +98 -0
- db_guardrail-0.1.0/src/db_guardrail.egg-info/PKG-INFO +286 -0
- db_guardrail-0.1.0/src/db_guardrail.egg-info/SOURCES.txt +42 -0
- db_guardrail-0.1.0/src/db_guardrail.egg-info/dependency_links.txt +1 -0
- db_guardrail-0.1.0/src/db_guardrail.egg-info/entry_points.txt +2 -0
- db_guardrail-0.1.0/src/db_guardrail.egg-info/requires.txt +7 -0
- db_guardrail-0.1.0/src/db_guardrail.egg-info/top_level.txt +1 -0
- db_guardrail-0.1.0/tests/test_migration_status.py +30 -0
- db_guardrail-0.1.0/tests/test_plan_parser.py +42 -0
- db_guardrail-0.1.0/tests/test_rule_engine.py +47 -0
- db_guardrail-0.1.0/tests/test_sql_splitter.py +21 -0
- db_guardrail-0.1.0/tests/test_table_extractor.py +20 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Qudsiya Siddique
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: db-guardrail
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A PostgreSQL migration safety analyzer
|
|
5
|
+
Author: Qudsiya Siddique
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Qudsiya954/Db-Gaurdrail.git
|
|
8
|
+
Project-URL: Repository, https://github.com/Qudsiya954/Db-Gaurdrail.git
|
|
9
|
+
Project-URL: Issues, https://github.com/Qudsiya954/Db-Gaurdrail.git/issues
|
|
10
|
+
Keywords: postgresql,sql,migration,database,cli
|
|
11
|
+
Requires-Python: >=3.11
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: psycopg[binary]>=3.2.0
|
|
15
|
+
Requires-Dist: sqlparse>=0.5.0
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
18
|
+
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
19
|
+
Requires-Dist: twine>=6.0.0; extra == "dev"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# DB-Guardrail
|
|
23
|
+
|
|
24
|
+
DB-Guardrail is a Python CLI tool for analyzing PostgreSQL SQL migrations before they are run against a database.
|
|
25
|
+
|
|
26
|
+
It executes migration statements inside a rollback-safe PostgreSQL transaction, reads planner output from `EXPLAIN (FORMAT JSON)`, inspects table scale and locks from PostgreSQL system catalogs, and produces deterministic risk reports.
|
|
27
|
+
|
|
28
|
+
No AI. No ML. No guessing. Every finding comes from PostgreSQL metadata or planner output.
|
|
29
|
+
|
|
30
|
+
## Why This Project Exists
|
|
31
|
+
|
|
32
|
+
Production SQL migrations can be risky. A migration may scan a large table, acquire an aggressive lock, or touch a table that is referenced by foreign keys.
|
|
33
|
+
|
|
34
|
+
DB-Guardrail helps answer questions like:
|
|
35
|
+
|
|
36
|
+
- Will this query use a sequential scan?
|
|
37
|
+
- Is PostgreSQL estimating a high execution cost?
|
|
38
|
+
- Is the table small enough that a sequential scan is acceptable?
|
|
39
|
+
- Does a schema change acquire an `AccessExclusiveLock`?
|
|
40
|
+
- Is the table involved in foreign key relationships?
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
- Multi-statement SQL migration analysis
|
|
45
|
+
- Transaction sandbox using `BEGIN` and `ROLLBACK`
|
|
46
|
+
- PostgreSQL `EXPLAIN (FORMAT JSON)` parser
|
|
47
|
+
- Recursive execution-plan flattening
|
|
48
|
+
- Rule-based performance analysis
|
|
49
|
+
- Table scale analysis using `pg_class.reltuples`
|
|
50
|
+
- Lock analysis using `pg_locks`
|
|
51
|
+
- Foreign key dependency analysis using PostgreSQL catalogs
|
|
52
|
+
- CLI commands for `analyze`, `init-db`, and `history`
|
|
53
|
+
- Optional PostgreSQL-backed report history
|
|
54
|
+
- Docker Compose setup for local PostgreSQL
|
|
55
|
+
- Unit tests for parser and rule logic
|
|
56
|
+
|
|
57
|
+
## Architecture
|
|
58
|
+
|
|
59
|
+
```mermaid
|
|
60
|
+
flowchart TD
|
|
61
|
+
A["SQL migration file"] --> B["SQL splitter"]
|
|
62
|
+
B --> C["Statement analyzer"]
|
|
63
|
+
C --> D["EXPLAIN JSON analyzer"]
|
|
64
|
+
C --> E["Lock analyzer"]
|
|
65
|
+
C --> F["Dependency analyzer"]
|
|
66
|
+
D --> G["Rule engine"]
|
|
67
|
+
E --> H["Migration report"]
|
|
68
|
+
F --> H
|
|
69
|
+
G --> H
|
|
70
|
+
H --> I["Console output"]
|
|
71
|
+
H --> J["PostgreSQL JSONB history"]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Project Structure
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
src/db_guardrail/
|
|
78
|
+
analysis/
|
|
79
|
+
explain.py Runs EXPLAIN (FORMAT JSON)
|
|
80
|
+
plan_parser.py Converts PostgreSQL plan JSON into PlanNode objects
|
|
81
|
+
rule_engine.py Applies deterministic performance rules
|
|
82
|
+
table_size.py Reads estimated row counts from pg_class
|
|
83
|
+
lock_analyzer.py Reads current locks from pg_locks
|
|
84
|
+
dependency_analyzer.py Reads foreign key relationships from pg_constraint
|
|
85
|
+
migration_analyzer.py Coordinates multi-statement migration analysis
|
|
86
|
+
database/
|
|
87
|
+
connection.py Opens psycopg connections
|
|
88
|
+
schema.sql Bundled history-table schema for init-db
|
|
89
|
+
history_repository.py Saves analysis results
|
|
90
|
+
reports/
|
|
91
|
+
migration_console_report.py
|
|
92
|
+
cli.py CLI entry point
|
|
93
|
+
|
|
94
|
+
examples/ Example migrations
|
|
95
|
+
sql/ Test-data setup
|
|
96
|
+
tests/ Unit tests
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
- Python 3.11+
|
|
102
|
+
- An external PostgreSQL database (local PostgreSQL or Docker Compose)
|
|
103
|
+
- `psycopg3`
|
|
104
|
+
- `sqlparse`
|
|
105
|
+
|
|
106
|
+
PostgreSQL is not bundled inside the Python package because DB-Guardrail uses
|
|
107
|
+
PostgreSQL-specific functionality such as `EXPLAIN (FORMAT JSON)`, `pg_class`,
|
|
108
|
+
`pg_locks`, and `pg_constraint`.
|
|
109
|
+
|
|
110
|
+
## Install From Source
|
|
111
|
+
|
|
112
|
+
Create and activate a virtual environment:
|
|
113
|
+
|
|
114
|
+
```powershell
|
|
115
|
+
python -m venv .venv
|
|
116
|
+
.venv\Scripts\Activate.ps1
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Install the CLI:
|
|
120
|
+
|
|
121
|
+
```powershell
|
|
122
|
+
python -m pip install .
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
For contributor tooling, including tests and package-build checks:
|
|
126
|
+
|
|
127
|
+
```powershell
|
|
128
|
+
python -m pip install -e ".[dev]"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## PostgreSQL With Docker Compose
|
|
132
|
+
|
|
133
|
+
Start PostgreSQL:
|
|
134
|
+
|
|
135
|
+
```powershell
|
|
136
|
+
docker compose up -d
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
If your Docker installation uses the older Compose command:
|
|
140
|
+
|
|
141
|
+
```powershell
|
|
142
|
+
docker-compose up -d
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Set the database URL:
|
|
146
|
+
|
|
147
|
+
```powershell
|
|
148
|
+
$env:DB_GUARDRAIL_DATABASE_URL = "postgresql://postgres:postgres@localhost:55432/db_guardrail_dev"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If you use CMD instead of PowerShell:
|
|
152
|
+
|
|
153
|
+
```cmd
|
|
154
|
+
set DB_GUARDRAIL_DATABASE_URL=postgresql://postgres:postgres@localhost:55432/db_guardrail_dev
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
If your password contains `@`, encode it as `%40` inside the URL.
|
|
158
|
+
|
|
159
|
+
## Initialize Database Tables
|
|
160
|
+
|
|
161
|
+
DB-Guardrail can save analysis history in PostgreSQL:
|
|
162
|
+
|
|
163
|
+
```powershell
|
|
164
|
+
db-guardrail init-db
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The command uses the schema bundled with the installed package.
|
|
168
|
+
|
|
169
|
+
This creates:
|
|
170
|
+
|
|
171
|
+
- `checked_scripts`
|
|
172
|
+
- `performance_metrics`
|
|
173
|
+
- `lint_reports`
|
|
174
|
+
|
|
175
|
+
## Load Demo Data
|
|
176
|
+
|
|
177
|
+
```powershell
|
|
178
|
+
psql -d "postgresql://postgres:postgres@localhost:55432/db_guardrail_dev" -f sql/test_data.sql
|
|
179
|
+
psql -d "postgresql://postgres:postgres@localhost:55432/db_guardrail_dev" -f sql/dependency_test_data.sql
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Usage
|
|
183
|
+
|
|
184
|
+
Analyze a migration without saving:
|
|
185
|
+
|
|
186
|
+
```powershell
|
|
187
|
+
db-guardrail analyze examples/large_table_seq_scan.sql --no-save
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Analyze and save the result:
|
|
191
|
+
|
|
192
|
+
```powershell
|
|
193
|
+
db-guardrail analyze examples/multi_statement_migration.sql
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Show SQL before analysis:
|
|
197
|
+
|
|
198
|
+
```powershell
|
|
199
|
+
db-guardrail analyze examples/multi_statement_migration.sql --show-sql --no-save
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Fail with exit code `1` when the migration is unsafe or has errors:
|
|
203
|
+
|
|
204
|
+
```powershell
|
|
205
|
+
db-guardrail analyze examples/large_table_seq_scan.sql --fail-on-unsafe
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Show saved analysis history:
|
|
209
|
+
|
|
210
|
+
```powershell
|
|
211
|
+
db-guardrail history
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Example Output
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
DB-Guardrail
|
|
218
|
+
============
|
|
219
|
+
Loaded SQL file: examples\large_table_seq_scan.sql
|
|
220
|
+
Migration Status: UNSAFE
|
|
221
|
+
|
|
222
|
+
Statement 1
|
|
223
|
+
-----------
|
|
224
|
+
Type: SELECT
|
|
225
|
+
Status: UNSAFE
|
|
226
|
+
SQL: SELECT * FROM large_orders WHERE status = 'paid'
|
|
227
|
+
|
|
228
|
+
Execution Plan:
|
|
229
|
+
- Seq Scan on large_orders | cost=3029.0 | rows=49605
|
|
230
|
+
|
|
231
|
+
Issues:
|
|
232
|
+
[CRITICAL] PERF_SEQ_SCAN
|
|
233
|
+
Message: Sequential Scan detected on large table large_orders.
|
|
234
|
+
Estimated table rows: 150000
|
|
235
|
+
Table size: large
|
|
236
|
+
Recommendation: Consider adding an index for the filtered column before running this query.
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Example Migrations
|
|
240
|
+
|
|
241
|
+
| File | Purpose |
|
|
242
|
+
| --- | --- |
|
|
243
|
+
| `examples/small_table_seq_scan.sql` | Shows an informational sequential scan on a small table |
|
|
244
|
+
| `examples/indexed_lookup.sql` | Shows PostgreSQL using an index-backed plan |
|
|
245
|
+
| `examples/large_table_seq_scan.sql` | Shows a critical sequential scan on a large table |
|
|
246
|
+
| `examples/high_cost_sort.sql` | Shows high estimated sort cost |
|
|
247
|
+
| `examples/multi_statement_migration.sql` | Shows per-statement reporting and error capture |
|
|
248
|
+
| `examples/lock_migration.sql` | Shows lock severity detection |
|
|
249
|
+
| `examples/dependency_migration.sql` | Shows foreign key dependency detection |
|
|
250
|
+
|
|
251
|
+
## Testing
|
|
252
|
+
|
|
253
|
+
Run unit tests:
|
|
254
|
+
|
|
255
|
+
```powershell
|
|
256
|
+
python -m pytest
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The tests cover:
|
|
260
|
+
|
|
261
|
+
- SQL statement splitting
|
|
262
|
+
- Plan JSON parsing
|
|
263
|
+
- Table name extraction
|
|
264
|
+
- Rule severity decisions
|
|
265
|
+
- Migration status aggregation
|
|
266
|
+
|
|
267
|
+
## Interview Talking Points
|
|
268
|
+
|
|
269
|
+
- The tool uses PostgreSQL planner output as the source of truth.
|
|
270
|
+
- The analyzer is deterministic and rule-based.
|
|
271
|
+
- `ROLLBACK` protects the database after sandboxed execution.
|
|
272
|
+
- `pg_class`, `pg_locks`, and `pg_constraint` demonstrate PostgreSQL internals knowledge.
|
|
273
|
+
- Multi-statement analysis makes the project realistic for migration files.
|
|
274
|
+
- JSONB history storage gives the CLI a backend-style persistence layer without requiring a web app.
|
|
275
|
+
|
|
276
|
+
## Current Scope
|
|
277
|
+
|
|
278
|
+
DB-Guardrail intentionally does not:
|
|
279
|
+
|
|
280
|
+
- Rewrite SQL automatically
|
|
281
|
+
- Create indexes automatically
|
|
282
|
+
- Predict deadlocks
|
|
283
|
+
- Simulate production traffic
|
|
284
|
+
- Use machine learning or AI
|
|
285
|
+
|
|
286
|
+
The goal is explainable migration risk analysis, not automatic optimization.
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# DB-Guardrail
|
|
2
|
+
|
|
3
|
+
DB-Guardrail is a Python CLI tool for analyzing PostgreSQL SQL migrations before they are run against a database.
|
|
4
|
+
|
|
5
|
+
It executes migration statements inside a rollback-safe PostgreSQL transaction, reads planner output from `EXPLAIN (FORMAT JSON)`, inspects table scale and locks from PostgreSQL system catalogs, and produces deterministic risk reports.
|
|
6
|
+
|
|
7
|
+
No AI. No ML. No guessing. Every finding comes from PostgreSQL metadata or planner output.
|
|
8
|
+
|
|
9
|
+
## Why This Project Exists
|
|
10
|
+
|
|
11
|
+
Production SQL migrations can be risky. A migration may scan a large table, acquire an aggressive lock, or touch a table that is referenced by foreign keys.
|
|
12
|
+
|
|
13
|
+
DB-Guardrail helps answer questions like:
|
|
14
|
+
|
|
15
|
+
- Will this query use a sequential scan?
|
|
16
|
+
- Is PostgreSQL estimating a high execution cost?
|
|
17
|
+
- Is the table small enough that a sequential scan is acceptable?
|
|
18
|
+
- Does a schema change acquire an `AccessExclusiveLock`?
|
|
19
|
+
- Is the table involved in foreign key relationships?
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- Multi-statement SQL migration analysis
|
|
24
|
+
- Transaction sandbox using `BEGIN` and `ROLLBACK`
|
|
25
|
+
- PostgreSQL `EXPLAIN (FORMAT JSON)` parser
|
|
26
|
+
- Recursive execution-plan flattening
|
|
27
|
+
- Rule-based performance analysis
|
|
28
|
+
- Table scale analysis using `pg_class.reltuples`
|
|
29
|
+
- Lock analysis using `pg_locks`
|
|
30
|
+
- Foreign key dependency analysis using PostgreSQL catalogs
|
|
31
|
+
- CLI commands for `analyze`, `init-db`, and `history`
|
|
32
|
+
- Optional PostgreSQL-backed report history
|
|
33
|
+
- Docker Compose setup for local PostgreSQL
|
|
34
|
+
- Unit tests for parser and rule logic
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart TD
|
|
40
|
+
A["SQL migration file"] --> B["SQL splitter"]
|
|
41
|
+
B --> C["Statement analyzer"]
|
|
42
|
+
C --> D["EXPLAIN JSON analyzer"]
|
|
43
|
+
C --> E["Lock analyzer"]
|
|
44
|
+
C --> F["Dependency analyzer"]
|
|
45
|
+
D --> G["Rule engine"]
|
|
46
|
+
E --> H["Migration report"]
|
|
47
|
+
F --> H
|
|
48
|
+
G --> H
|
|
49
|
+
H --> I["Console output"]
|
|
50
|
+
H --> J["PostgreSQL JSONB history"]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Project Structure
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
src/db_guardrail/
|
|
57
|
+
analysis/
|
|
58
|
+
explain.py Runs EXPLAIN (FORMAT JSON)
|
|
59
|
+
plan_parser.py Converts PostgreSQL plan JSON into PlanNode objects
|
|
60
|
+
rule_engine.py Applies deterministic performance rules
|
|
61
|
+
table_size.py Reads estimated row counts from pg_class
|
|
62
|
+
lock_analyzer.py Reads current locks from pg_locks
|
|
63
|
+
dependency_analyzer.py Reads foreign key relationships from pg_constraint
|
|
64
|
+
migration_analyzer.py Coordinates multi-statement migration analysis
|
|
65
|
+
database/
|
|
66
|
+
connection.py Opens psycopg connections
|
|
67
|
+
schema.sql Bundled history-table schema for init-db
|
|
68
|
+
history_repository.py Saves analysis results
|
|
69
|
+
reports/
|
|
70
|
+
migration_console_report.py
|
|
71
|
+
cli.py CLI entry point
|
|
72
|
+
|
|
73
|
+
examples/ Example migrations
|
|
74
|
+
sql/ Test-data setup
|
|
75
|
+
tests/ Unit tests
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Requirements
|
|
79
|
+
|
|
80
|
+
- Python 3.11+
|
|
81
|
+
- An external PostgreSQL database (local PostgreSQL or Docker Compose)
|
|
82
|
+
- `psycopg3`
|
|
83
|
+
- `sqlparse`
|
|
84
|
+
|
|
85
|
+
PostgreSQL is not bundled inside the Python package because DB-Guardrail uses
|
|
86
|
+
PostgreSQL-specific functionality such as `EXPLAIN (FORMAT JSON)`, `pg_class`,
|
|
87
|
+
`pg_locks`, and `pg_constraint`.
|
|
88
|
+
|
|
89
|
+
## Install From Source
|
|
90
|
+
|
|
91
|
+
Create and activate a virtual environment:
|
|
92
|
+
|
|
93
|
+
```powershell
|
|
94
|
+
python -m venv .venv
|
|
95
|
+
.venv\Scripts\Activate.ps1
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Install the CLI:
|
|
99
|
+
|
|
100
|
+
```powershell
|
|
101
|
+
python -m pip install .
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
For contributor tooling, including tests and package-build checks:
|
|
105
|
+
|
|
106
|
+
```powershell
|
|
107
|
+
python -m pip install -e ".[dev]"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## PostgreSQL With Docker Compose
|
|
111
|
+
|
|
112
|
+
Start PostgreSQL:
|
|
113
|
+
|
|
114
|
+
```powershell
|
|
115
|
+
docker compose up -d
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
If your Docker installation uses the older Compose command:
|
|
119
|
+
|
|
120
|
+
```powershell
|
|
121
|
+
docker-compose up -d
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Set the database URL:
|
|
125
|
+
|
|
126
|
+
```powershell
|
|
127
|
+
$env:DB_GUARDRAIL_DATABASE_URL = "postgresql://postgres:postgres@localhost:55432/db_guardrail_dev"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
If you use CMD instead of PowerShell:
|
|
131
|
+
|
|
132
|
+
```cmd
|
|
133
|
+
set DB_GUARDRAIL_DATABASE_URL=postgresql://postgres:postgres@localhost:55432/db_guardrail_dev
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If your password contains `@`, encode it as `%40` inside the URL.
|
|
137
|
+
|
|
138
|
+
## Initialize Database Tables
|
|
139
|
+
|
|
140
|
+
DB-Guardrail can save analysis history in PostgreSQL:
|
|
141
|
+
|
|
142
|
+
```powershell
|
|
143
|
+
db-guardrail init-db
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The command uses the schema bundled with the installed package.
|
|
147
|
+
|
|
148
|
+
This creates:
|
|
149
|
+
|
|
150
|
+
- `checked_scripts`
|
|
151
|
+
- `performance_metrics`
|
|
152
|
+
- `lint_reports`
|
|
153
|
+
|
|
154
|
+
## Load Demo Data
|
|
155
|
+
|
|
156
|
+
```powershell
|
|
157
|
+
psql -d "postgresql://postgres:postgres@localhost:55432/db_guardrail_dev" -f sql/test_data.sql
|
|
158
|
+
psql -d "postgresql://postgres:postgres@localhost:55432/db_guardrail_dev" -f sql/dependency_test_data.sql
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Usage
|
|
162
|
+
|
|
163
|
+
Analyze a migration without saving:
|
|
164
|
+
|
|
165
|
+
```powershell
|
|
166
|
+
db-guardrail analyze examples/large_table_seq_scan.sql --no-save
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Analyze and save the result:
|
|
170
|
+
|
|
171
|
+
```powershell
|
|
172
|
+
db-guardrail analyze examples/multi_statement_migration.sql
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Show SQL before analysis:
|
|
176
|
+
|
|
177
|
+
```powershell
|
|
178
|
+
db-guardrail analyze examples/multi_statement_migration.sql --show-sql --no-save
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Fail with exit code `1` when the migration is unsafe or has errors:
|
|
182
|
+
|
|
183
|
+
```powershell
|
|
184
|
+
db-guardrail analyze examples/large_table_seq_scan.sql --fail-on-unsafe
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Show saved analysis history:
|
|
188
|
+
|
|
189
|
+
```powershell
|
|
190
|
+
db-guardrail history
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Example Output
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
DB-Guardrail
|
|
197
|
+
============
|
|
198
|
+
Loaded SQL file: examples\large_table_seq_scan.sql
|
|
199
|
+
Migration Status: UNSAFE
|
|
200
|
+
|
|
201
|
+
Statement 1
|
|
202
|
+
-----------
|
|
203
|
+
Type: SELECT
|
|
204
|
+
Status: UNSAFE
|
|
205
|
+
SQL: SELECT * FROM large_orders WHERE status = 'paid'
|
|
206
|
+
|
|
207
|
+
Execution Plan:
|
|
208
|
+
- Seq Scan on large_orders | cost=3029.0 | rows=49605
|
|
209
|
+
|
|
210
|
+
Issues:
|
|
211
|
+
[CRITICAL] PERF_SEQ_SCAN
|
|
212
|
+
Message: Sequential Scan detected on large table large_orders.
|
|
213
|
+
Estimated table rows: 150000
|
|
214
|
+
Table size: large
|
|
215
|
+
Recommendation: Consider adding an index for the filtered column before running this query.
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Example Migrations
|
|
219
|
+
|
|
220
|
+
| File | Purpose |
|
|
221
|
+
| --- | --- |
|
|
222
|
+
| `examples/small_table_seq_scan.sql` | Shows an informational sequential scan on a small table |
|
|
223
|
+
| `examples/indexed_lookup.sql` | Shows PostgreSQL using an index-backed plan |
|
|
224
|
+
| `examples/large_table_seq_scan.sql` | Shows a critical sequential scan on a large table |
|
|
225
|
+
| `examples/high_cost_sort.sql` | Shows high estimated sort cost |
|
|
226
|
+
| `examples/multi_statement_migration.sql` | Shows per-statement reporting and error capture |
|
|
227
|
+
| `examples/lock_migration.sql` | Shows lock severity detection |
|
|
228
|
+
| `examples/dependency_migration.sql` | Shows foreign key dependency detection |
|
|
229
|
+
|
|
230
|
+
## Testing
|
|
231
|
+
|
|
232
|
+
Run unit tests:
|
|
233
|
+
|
|
234
|
+
```powershell
|
|
235
|
+
python -m pytest
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The tests cover:
|
|
239
|
+
|
|
240
|
+
- SQL statement splitting
|
|
241
|
+
- Plan JSON parsing
|
|
242
|
+
- Table name extraction
|
|
243
|
+
- Rule severity decisions
|
|
244
|
+
- Migration status aggregation
|
|
245
|
+
|
|
246
|
+
## Interview Talking Points
|
|
247
|
+
|
|
248
|
+
- The tool uses PostgreSQL planner output as the source of truth.
|
|
249
|
+
- The analyzer is deterministic and rule-based.
|
|
250
|
+
- `ROLLBACK` protects the database after sandboxed execution.
|
|
251
|
+
- `pg_class`, `pg_locks`, and `pg_constraint` demonstrate PostgreSQL internals knowledge.
|
|
252
|
+
- Multi-statement analysis makes the project realistic for migration files.
|
|
253
|
+
- JSONB history storage gives the CLI a backend-style persistence layer without requiring a web app.
|
|
254
|
+
|
|
255
|
+
## Current Scope
|
|
256
|
+
|
|
257
|
+
DB-Guardrail intentionally does not:
|
|
258
|
+
|
|
259
|
+
- Rewrite SQL automatically
|
|
260
|
+
- Create indexes automatically
|
|
261
|
+
- Predict deadlocks
|
|
262
|
+
- Simulate production traffic
|
|
263
|
+
- Use machine learning or AI
|
|
264
|
+
|
|
265
|
+
The goal is explainable migration risk analysis, not automatic optimization.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "db-guardrail"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A PostgreSQL migration safety analyzer"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Qudsiya Siddique" }
|
|
15
|
+
]
|
|
16
|
+
keywords = ["postgresql", "sql", "migration", "database", "cli"]
|
|
17
|
+
dependencies = [
|
|
18
|
+
"psycopg[binary]>=3.2.0",
|
|
19
|
+
"sqlparse>=0.5.0"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/Qudsiya954/Db-Gaurdrail.git"
|
|
24
|
+
Repository = "https://github.com/Qudsiya954/Db-Gaurdrail.git"
|
|
25
|
+
Issues = "https://github.com/Qudsiya954/Db-Gaurdrail.git/issues"
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
db-guardrail = "db_guardrail.cli:main"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = [
|
|
32
|
+
"pytest>=8.0.0",
|
|
33
|
+
"build>=1.2.2",
|
|
34
|
+
"twine>=6.0.0"
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.packages.find]
|
|
38
|
+
where = ["src"]
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.package-data]
|
|
41
|
+
"db_guardrail.database" = ["schema.sql"]
|
|
42
|
+
|
|
43
|
+
[tool.pytest.ini_options]
|
|
44
|
+
pythonpath = ["src"]
|
|
45
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
File without changes
|