kctl-pg 0.7.2__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.
Files changed (55) hide show
  1. kctl_pg-0.7.2/.gitignore +7 -0
  2. kctl_pg-0.7.2/PKG-INFO +18 -0
  3. kctl_pg-0.7.2/README.md +388 -0
  4. kctl_pg-0.7.2/e2e/.gitignore +3 -0
  5. kctl_pg-0.7.2/e2e/README.md +32 -0
  6. kctl_pg-0.7.2/e2e/fixtures/auth.ts +26 -0
  7. kctl_pg-0.7.2/e2e/package.json +15 -0
  8. kctl_pg-0.7.2/e2e/playwright.config.ts +15 -0
  9. kctl_pg-0.7.2/e2e/tests/smoke/connectivity.spec.ts +18 -0
  10. kctl_pg-0.7.2/pyproject.toml +46 -0
  11. kctl_pg-0.7.2/skills/postgres-admin/SKILL.md +402 -0
  12. kctl_pg-0.7.2/src/kctl_pg/__init__.py +3 -0
  13. kctl_pg-0.7.2/src/kctl_pg/__main__.py +5 -0
  14. kctl_pg-0.7.2/src/kctl_pg/cli.py +162 -0
  15. kctl_pg-0.7.2/src/kctl_pg/commands/__init__.py +0 -0
  16. kctl_pg-0.7.2/src/kctl_pg/commands/activity.py +176 -0
  17. kctl_pg-0.7.2/src/kctl_pg/commands/automation.py +666 -0
  18. kctl_pg-0.7.2/src/kctl_pg/commands/backup.py +177 -0
  19. kctl_pg-0.7.2/src/kctl_pg/commands/config_cmd.py +545 -0
  20. kctl_pg-0.7.2/src/kctl_pg/commands/dashboard.py +104 -0
  21. kctl_pg-0.7.2/src/kctl_pg/commands/db.py +354 -0
  22. kctl_pg-0.7.2/src/kctl_pg/commands/doctor_cmd.py +87 -0
  23. kctl_pg-0.7.2/src/kctl_pg/commands/dr.py +821 -0
  24. kctl_pg-0.7.2/src/kctl_pg/commands/extensions.py +126 -0
  25. kctl_pg-0.7.2/src/kctl_pg/commands/health.py +91 -0
  26. kctl_pg-0.7.2/src/kctl_pg/commands/indexes.py +578 -0
  27. kctl_pg-0.7.2/src/kctl_pg/commands/lint.py +590 -0
  28. kctl_pg-0.7.2/src/kctl_pg/commands/maintenance.py +379 -0
  29. kctl_pg-0.7.2/src/kctl_pg/commands/performance.py +727 -0
  30. kctl_pg-0.7.2/src/kctl_pg/commands/pg_config.py +235 -0
  31. kctl_pg-0.7.2/src/kctl_pg/commands/pgbouncer.py +486 -0
  32. kctl_pg-0.7.2/src/kctl_pg/commands/pipeline.py +601 -0
  33. kctl_pg-0.7.2/src/kctl_pg/commands/query.py +60 -0
  34. kctl_pg-0.7.2/src/kctl_pg/commands/replication.py +727 -0
  35. kctl_pg-0.7.2/src/kctl_pg/commands/schemas.py +216 -0
  36. kctl_pg-0.7.2/src/kctl_pg/commands/security.py +762 -0
  37. kctl_pg-0.7.2/src/kctl_pg/commands/skill_cmd.py +76 -0
  38. kctl_pg-0.7.2/src/kctl_pg/commands/stats.py +537 -0
  39. kctl_pg-0.7.2/src/kctl_pg/commands/tables.py +996 -0
  40. kctl_pg-0.7.2/src/kctl_pg/commands/users.py +493 -0
  41. kctl_pg-0.7.2/src/kctl_pg/core/__init__.py +0 -0
  42. kctl_pg-0.7.2/src/kctl_pg/core/callbacks.py +58 -0
  43. kctl_pg-0.7.2/src/kctl_pg/core/client.py +152 -0
  44. kctl_pg-0.7.2/src/kctl_pg/core/config.py +165 -0
  45. kctl_pg-0.7.2/src/kctl_pg/core/exceptions.py +42 -0
  46. kctl_pg-0.7.2/src/kctl_pg/core/output.py +5 -0
  47. kctl_pg-0.7.2/tests/__init__.py +0 -0
  48. kctl_pg-0.7.2/tests/conftest.py +137 -0
  49. kctl_pg-0.7.2/tests/test_activity.py +309 -0
  50. kctl_pg-0.7.2/tests/test_automation.py +41 -0
  51. kctl_pg-0.7.2/tests/test_backup.py +258 -0
  52. kctl_pg-0.7.2/tests/test_dr.py +105 -0
  53. kctl_pg-0.7.2/tests/test_existing.py +265 -0
  54. kctl_pg-0.7.2/tests/test_lint.py +131 -0
  55. kctl_pg-0.7.2/tests/test_pipeline.py +218 -0
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ uv.lock
kctl_pg-0.7.2/PKG-INFO ADDED
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.4
2
+ Name: kctl-pg
3
+ Version: 0.7.2
4
+ Summary: Kodemeio PostgreSQL CLI — manage PostgreSQL servers via SSH tunnel
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: kctl-lib>=0.8.0
7
+ Requires-Dist: paramiko<4.0.0,>=3.4.0
8
+ Requires-Dist: psycopg[binary]>=3.2.0
9
+ Requires-Dist: pydantic>=2.10.0
10
+ Requires-Dist: pyyaml>=6.0.2
11
+ Requires-Dist: rich>=13.9.0
12
+ Requires-Dist: sshtunnel>=0.4.0
13
+ Requires-Dist: typer>=0.15.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: mypy>=1.14.0; extra == 'dev'
16
+ Requires-Dist: pytest>=8.3.0; extra == 'dev'
17
+ Requires-Dist: ruff>=0.9.0; extra == 'dev'
18
+ Requires-Dist: types-pyyaml>=6.0.0; extra == 'dev'
@@ -0,0 +1,388 @@
1
+ # kctl-pg
2
+
3
+ Kodemeio PostgreSQL CLI -- manage PostgreSQL servers via SSH tunnel.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ uv tool install ./packages/kctl-pg
9
+ ```
10
+
11
+ To upgrade after code changes:
12
+
13
+ ```bash
14
+ uv tool install --force --reinstall ./packages/kctl-pg
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Configure a profile (interactive)
21
+ kctl-pg config init
22
+
23
+ # Verify connection
24
+ kctl-pg health
25
+
26
+ # Dashboard overview
27
+ kctl-pg dashboard
28
+
29
+ # List databases
30
+ kctl-pg db list
31
+
32
+ # List users
33
+ kctl-pg users list
34
+
35
+ # Check active connections
36
+ kctl-pg activity list
37
+
38
+ # Run a raw SQL query
39
+ kctl-pg query "SELECT version()"
40
+
41
+ # Dump a database backup
42
+ kctl-pg backup dump --database mydb
43
+
44
+ # Show slow queries
45
+ kctl-pg performance slow-queries
46
+
47
+ # Full health report
48
+ kctl-pg pipeline report
49
+ ```
50
+
51
+ ## Command Groups
52
+
53
+ | Group | Commands | Description |
54
+ |----------------|---------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------|
55
+ | `activity` | `list`, `kill`, `locks` | Active connections, long-running queries, lock waits |
56
+ | `automation` | `plan`, `alerts`, `report`, `baseline` | Automated maintenance planning and alert rules |
57
+ | `backup` | `dump`, `restore`, `list` | Database backup and restore via pg_dump / pg_restore |
58
+ | `config` | `init`, `add`, `use`, `show`, `validate`, `remove`, `set`, `profiles`, `current` | CLI configuration and profile management |
59
+ | `dashboard` | `dashboard` | Single-screen server overview (size, connections, health) |
60
+ | `db` | `list`, `create`, `drop`, `size`, `info`, `rename`, `copy`, `owner` | Database CRUD and metadata |
61
+ | `dr` | `verify-backup`, `test-failover`, `capacity-forecast`, `rpo-rto` | Disaster recovery checks, RPO/RTO status, capacity |
62
+ | `extensions` | `list`, `install`, `uninstall` | PostgreSQL extension management |
63
+ | `health` | `health` | Quick server health check (connections, replication, etc) |
64
+ | `indexes` | `list`, `bloat`, `duplicate`, `invalid`, `missing`, `create-concurrently`, `reindex-concurrently` | Index analysis, bloat detection, and safe concurrent ops |
65
+ | `lint` | `schema`, `indexes`, `permissions`, `all` | Static analysis for schema, index, and permission issues |
66
+ | `maintenance` | `vacuum`, `analyze`, `reindex`, `autovacuum`, `freeze`, `cluster`, `checkpoint`, `frozen-xid` | Table maintenance, vacuum, freeze, and statistics |
67
+ | `performance` | `overview`, `slow-queries`, `cache`, `settings`, `explain`, `temp-files`, `progress` | Query performance, cache hit ratios, and EXPLAIN plans |
68
+ | `pg-config` | `show`, `get`, `set`, `reset`, `reload`, `diff` | PostgreSQL server configuration (postgresql.conf) |
69
+ | `pgbouncer` | `status`, `pools`, `clients`, `servers`, `databases`, `stats`, `reload`, `pause`, `resume` | PgBouncer connection pooler management |
70
+ | `pipeline` | `gate`, `report` | CI/CD pipeline gates and full health reports |
71
+ | `query` | `query` | Execute raw SQL queries |
72
+ | `replication` | `status`, `lag`, `slots`, `create-slot`, `drop-slot`, `publications`, `subscriptions`, `promote`, `senders`, `receiver` | Streaming and logical replication management |
73
+ | `schemas` | `list`, `create`, `drop`, `size` | Schema management and sizing |
74
+ | `security` | `ssl`, `hba-rules`, `privileges`, `rls`, `rls-policies`, `superuser-audit`, `password-check` | SSL, pg_hba.conf, row-level security, and auditing |
75
+ | `stats` | `tables`, `indexes`, `bgwriter`, `replication`, `wal`, `io`, `database` | pg_stat_* statistics views |
76
+ | `tables` | `list`, `describe`, `size`, `partitions`, `constraints`, `triggers`, `dependencies`, `toast`, `sequences` | Table inspection, sizing, and metadata |
77
+ | `users` | `list`, `create`, `drop`, `password`, `get`, `grant`, `revoke`, `alter`, `grant-db`, `grant-schema`, `grant-table`, `default-privileges` | User and role management |
78
+
79
+ ## SSH Tunnel Architecture
80
+
81
+ kctl-pg does **not** connect directly to PostgreSQL. All connections are established through an SSH tunnel to avoid exposing the PostgreSQL port on the network.
82
+
83
+ ```
84
+ kctl-pg CLI
85
+ |
86
+ | SSH (port 22)
87
+ v
88
+ Remote Server (ssh_host)
89
+ |
90
+ | localhost tunnel -> 5432
91
+ v
92
+ PostgreSQL (host:port, internal network only)
93
+ ```
94
+
95
+ The tunnel is opened automatically when any command needs a database connection and closed when the command completes. This is handled transparently by `PostgresClient` using `SSHTunnel` from `kctl-lib`.
96
+
97
+ For Dokploy-managed servers, the `host` in the config refers to the PostgreSQL host as seen **from the SSH server** (e.g. `10.0.0.2` for internal Hetzner network addresses), not from your local machine.
98
+
99
+ ## Global Options
100
+
101
+ These options are available on every command:
102
+
103
+ ```
104
+ --json Output as JSON (machine-readable)
105
+ --quiet, -q Suppress informational messages
106
+ --profile, -p Use a named config profile
107
+ --host, -H PostgreSQL host override
108
+ --port PostgreSQL port override
109
+ --user, -U PostgreSQL user override
110
+ --password PostgreSQL password override
111
+ --version, -V Show version and exit
112
+ ```
113
+
114
+ ## Configuration
115
+
116
+ ### Config File Format
117
+
118
+ kctl-pg shares the platform-wide config at `~/.config/kodemeio/config.yaml`. PostgreSQL settings are scoped under the `postgres` service key:
119
+
120
+ ```yaml
121
+ default_profile: production
122
+
123
+ profiles:
124
+ production:
125
+ postgres:
126
+ host: 10.0.0.2 # Internal PG host (as seen from SSH server)
127
+ port: 5432
128
+ user: postgres
129
+ password: ${PG_PASSWORD} # Env var expansion supported
130
+ ssh_host: 49.13.14.79 # Public SSH host
131
+ ssh_port: 22
132
+ ssh_user: root
133
+ ssh_key: ~/.ssh/id_ed25519
134
+ databases:
135
+ - authentik
136
+ - odoo_production
137
+ staging:
138
+ postgres:
139
+ host: 10.0.0.3
140
+ port: 5432
141
+ user: postgres
142
+ password: ${PG_PASSWORD_STG}
143
+ ssh_host: staging.example.com
144
+ ssh_port: 22
145
+ ssh_user: root
146
+ ssh_key: ~/.ssh/id_ed25519
147
+ ```
148
+
149
+ ### Profile Management
150
+
151
+ ```bash
152
+ # Interactive setup wizard
153
+ kctl-pg config init
154
+
155
+ # Add a named profile
156
+ kctl-pg config add production \
157
+ --host 10.0.0.2 \
158
+ --ssh-host 49.13.14.79 \
159
+ --user postgres
160
+
161
+ # Switch the default profile
162
+ kctl-pg config use production
163
+
164
+ # Show current profile config (secrets masked)
165
+ kctl-pg config show
166
+
167
+ # List all profiles
168
+ kctl-pg config profiles
169
+
170
+ # Validate current config
171
+ kctl-pg config validate
172
+ ```
173
+
174
+ ### Environment Variables
175
+
176
+ CLI flags take precedence over env vars, which take precedence over the config file.
177
+
178
+ | Variable | Description |
179
+ |---------------------|-----------------------------------------------|
180
+ | `KCTL_PG_HOST` | PostgreSQL host override |
181
+ | `KCTL_PG_PORT` | PostgreSQL port override |
182
+ | `KCTL_PG_USER` | PostgreSQL user override |
183
+ | `KCTL_PG_PASSWORD` | PostgreSQL password override |
184
+ | `KCTL_PG_SSH_HOST` | SSH host override |
185
+ | `KCTL_PG_PROFILE` | Active profile name override |
186
+ | `PGHOST` | Standard libpq host (lower priority) |
187
+ | `PGPORT` | Standard libpq port (lower priority) |
188
+ | `PGUSER` | Standard libpq user (lower priority) |
189
+ | `PGPASSWORD` | Standard libpq password (lower priority) |
190
+
191
+ ### Connection Resolution Priority
192
+
193
+ 1. CLI flags (`--host`, `--user`, `--password`, etc.)
194
+ 2. `KCTL_PG_*` environment variables
195
+ 3. Standard `PG*` environment variables (`PGHOST`, `PGUSER`, etc.)
196
+ 4. Config file profile
197
+
198
+ ## Common DBA Workflows
199
+
200
+ ### Database Provisioning
201
+
202
+ ```bash
203
+ # Create a role first
204
+ kctl-pg users create myuser --password secret --login
205
+
206
+ # Create a database with owner
207
+ kctl-pg db create mydb --owner myuser
208
+
209
+ # Grant full access on the database
210
+ kctl-pg users grant-db myuser mydb
211
+
212
+ # Grant usage on public schema
213
+ kctl-pg users grant-schema myuser public --database mydb
214
+ ```
215
+
216
+ ### Backup and Restore
217
+
218
+ ```bash
219
+ # Dump a database
220
+ kctl-pg backup dump --database mydb --file mydb.dump
221
+
222
+ # List available backups
223
+ kctl-pg backup list
224
+
225
+ # Restore a backup
226
+ kctl-pg backup restore --file mydb.dump --database mydb_restore
227
+ ```
228
+
229
+ ### Performance Investigation
230
+
231
+ ```bash
232
+ # Full performance overview
233
+ kctl-pg performance overview --database mydb
234
+
235
+ # Slow queries (top 20 by total time)
236
+ kctl-pg performance slow-queries --database mydb --limit 20
237
+
238
+ # Cache hit ratio
239
+ kctl-pg performance cache --database mydb
240
+
241
+ # EXPLAIN a query
242
+ kctl-pg performance explain "SELECT * FROM orders WHERE status = 'pending'" --database mydb
243
+
244
+ # Operations currently in progress
245
+ kctl-pg performance progress
246
+ ```
247
+
248
+ ### Index Maintenance
249
+
250
+ ```bash
251
+ # Find bloated indexes
252
+ kctl-pg indexes bloat --database mydb
253
+
254
+ # Find duplicate indexes
255
+ kctl-pg indexes duplicate --database mydb
256
+
257
+ # Find invalid indexes (failed CONCURRENTLY build)
258
+ kctl-pg indexes invalid --database mydb
259
+
260
+ # Rebuild a specific index without locking writes
261
+ kctl-pg indexes reindex-concurrently --index my_index --database mydb
262
+ ```
263
+
264
+ ### Security Audit
265
+
266
+ ```bash
267
+ # Check SSL configuration
268
+ kctl-pg security ssl
269
+
270
+ # Review pg_hba.conf rules
271
+ kctl-pg security hba-rules
272
+
273
+ # Superuser audit
274
+ kctl-pg security superuser-audit
275
+
276
+ # Password hash methods in use
277
+ kctl-pg security password-check
278
+ ```
279
+
280
+ ### Replication Monitoring
281
+
282
+ ```bash
283
+ # Replication status
284
+ kctl-pg replication status
285
+
286
+ # Replication lag per replica
287
+ kctl-pg replication lag
288
+
289
+ # List replication slots
290
+ kctl-pg replication slots
291
+
292
+ # WAL senders
293
+ kctl-pg replication senders
294
+ ```
295
+
296
+ ### CI/CD Pipeline Integration
297
+
298
+ ```bash
299
+ # Gate: fail if replication lag > threshold, cache hit < 95%, connections > 80%
300
+ kctl-pg pipeline gate --database mydb
301
+
302
+ # Generate a full Markdown health report
303
+ kctl-pg pipeline report --database mydb --output report.md
304
+ ```
305
+
306
+ ### Server Configuration Tuning
307
+
308
+ ```bash
309
+ # Show all non-default settings
310
+ kctl-pg pg-config show --changed-only
311
+
312
+ # Get a specific parameter
313
+ kctl-pg pg-config get shared_buffers
314
+
315
+ # Set a parameter (requires superuser)
316
+ kctl-pg pg-config set work_mem 64MB
317
+
318
+ # Reload config without restart
319
+ kctl-pg pg-config reload
320
+
321
+ # Diff current settings against defaults
322
+ kctl-pg pg-config diff
323
+ ```
324
+
325
+ ## Development
326
+
327
+ ### Running Tests
328
+
329
+ ```bash
330
+ cd packages/kctl-pg
331
+ uv run pytest tests/ -v
332
+ ```
333
+
334
+ ### Linting and Formatting
335
+
336
+ ```bash
337
+ cd packages/kctl-pg
338
+ uv run ruff check src/
339
+ uv run ruff format src/
340
+ ```
341
+
342
+ ### Type Checking
343
+
344
+ ```bash
345
+ cd packages/kctl-pg
346
+ uv run mypy src/kctl_pg/
347
+ ```
348
+
349
+ ### Project Structure
350
+
351
+ ```
352
+ packages/kctl-pg/
353
+ src/kctl_pg/
354
+ cli.py Main Typer app + command group registration
355
+ __init__.py Version
356
+ core/
357
+ callbacks.py AppContext (subclasses AppContextBase from kctl-lib)
358
+ client.py PostgresClient (psycopg + SSHTunnel)
359
+ config.py Profile and connection resolution (SERVICE_KEY = "postgres")
360
+ exceptions.py KctlError subclasses
361
+ commands/
362
+ activity.py list, kill, locks
363
+ automation.py plan, alerts, report, baseline
364
+ backup.py dump, restore, list
365
+ config_cmd.py init, add, use, show, validate, remove, set, profiles, current
366
+ dashboard.py single-screen server overview
367
+ db.py list, create, drop, size, info, rename, copy, owner
368
+ dr.py verify-backup, test-failover, capacity-forecast, rpo-rto
369
+ extensions.py list, install, uninstall
370
+ health.py health
371
+ indexes.py list, bloat, duplicate, invalid, missing, create-concurrently, reindex-concurrently
372
+ lint.py schema, indexes, permissions, all
373
+ maintenance.py vacuum, analyze, reindex, autovacuum, freeze, cluster, checkpoint, frozen-xid
374
+ performance.py overview, slow-queries, cache, settings, explain, temp-files, progress
375
+ pg_config.py show, get, set, reset, reload, diff
376
+ pgbouncer.py status, pools, clients, servers, databases, stats, reload, pause, resume
377
+ pipeline.py gate, report
378
+ query.py raw SQL execution
379
+ replication.py status, lag, slots, create-slot, drop-slot, publications, subscriptions, promote, senders, receiver
380
+ schemas.py list, create, drop, size
381
+ security.py ssl, hba-rules, privileges, rls, rls-policies, superuser-audit, password-check
382
+ stats.py tables, indexes, bgwriter, replication, wal, io, database
383
+ tables.py list, describe, size, partitions, constraints, triggers, dependencies, toast, sequences
384
+ users.py list, create, drop, password, get, grant, revoke, alter, grant-db, grant-schema, grant-table, default-privileges
385
+ tests/ pytest test suite
386
+ pyproject.toml Package metadata and tool config
387
+ README.md This file
388
+ ```
@@ -0,0 +1,3 @@
1
+ node_modules/
2
+ playwright-report/
3
+ test-results/
@@ -0,0 +1,32 @@
1
+ # kctl-pg E2E Tests
2
+
3
+ Playwright-based E2E tests for kctl-pg verifying SSH connectivity and CLI health checks.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ pnpm install
9
+ pnpm run install-browsers
10
+ ```
11
+
12
+ ## Run
13
+
14
+ ```bash
15
+ # Against staging PostgreSQL host via SSH
16
+ export PG_HOST=10.0.0.2
17
+ export PG_PASSWORD=<your-password>
18
+ export KCTL_PG_PROFILE=production
19
+ pnpm test
20
+
21
+ # Smoke tests only
22
+ pnpm test:smoke
23
+
24
+ # Visible browser
25
+ pnpm test:headed
26
+ ```
27
+
28
+ ## Env Vars
29
+
30
+ - `PG_HOST` — PostgreSQL host (SSH target)
31
+ - `PG_PASSWORD` — PostgreSQL password
32
+ - `KCTL_PG_PROFILE` — kctl-pg profile name to use (required for smoke tests)
@@ -0,0 +1,26 @@
1
+ import { test as base } from "@playwright/test";
2
+
3
+ export interface AuthFixtures {
4
+ pgHost: string;
5
+ pgPassword: string;
6
+ pgProfile: string;
7
+ }
8
+
9
+ export const test = base.extend<AuthFixtures>({
10
+ pgHost: async ({}, use) => {
11
+ const host = process.env.PG_HOST;
12
+ if (!host) throw new Error("PG_HOST env var required");
13
+ await use(host);
14
+ },
15
+ pgPassword: async ({}, use) => {
16
+ const password = process.env.PG_PASSWORD;
17
+ if (!password) throw new Error("PG_PASSWORD env var required");
18
+ await use(password);
19
+ },
20
+ pgProfile: async ({}, use) => {
21
+ const profile = process.env.KCTL_PG_PROFILE || "default";
22
+ await use(profile);
23
+ },
24
+ });
25
+
26
+ export { expect } from "@playwright/test";
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "kctl-pg-e2e",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "test": "playwright test",
7
+ "test:smoke": "playwright test --project=smoke",
8
+ "test:headed": "playwright test --headed",
9
+ "install-browsers": "playwright install chromium"
10
+ },
11
+ "devDependencies": {
12
+ "@playwright/test": "^1.48.0",
13
+ "typescript": "^5.5.0"
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from "@playwright/test";
2
+
3
+ export default defineConfig({
4
+ testDir: "./tests",
5
+ timeout: 60_000,
6
+ retries: 1,
7
+ reporter: "list",
8
+ use: {
9
+ baseURL: process.env.PG_HOST || "localhost",
10
+ },
11
+ projects: [
12
+ { name: "smoke", testMatch: /smoke\/.*\.spec\.ts/ },
13
+ { name: "scenarios", testMatch: /scenarios\/.*\.spec\.ts/ },
14
+ ],
15
+ });
@@ -0,0 +1,18 @@
1
+ import { test, expect } from "@playwright/test";
2
+ import { execFileSync } from "node:child_process";
3
+
4
+ test.describe("kctl-pg CLI", () => {
5
+ test.skip(!process.env.KCTL_PG_PROFILE, "KCTL_PG_PROFILE not set");
6
+
7
+ test("health check succeeds", async () => {
8
+ const profile = process.env.KCTL_PG_PROFILE!;
9
+ const output = execFileSync(
10
+ "kctl-pg",
11
+ ["--profile", profile, "health", "check"],
12
+ {
13
+ encoding: "utf-8",
14
+ },
15
+ );
16
+ expect(output).toBeTruthy();
17
+ });
18
+ });
@@ -0,0 +1,46 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "kctl-pg"
7
+ version = "0.7.2"
8
+ description = "Kodemeio PostgreSQL CLI — manage PostgreSQL servers via SSH tunnel"
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "kctl-lib>=0.8.0",
12
+ "typer>=0.15.0",
13
+ "rich>=13.9.0",
14
+ "pydantic>=2.10.0",
15
+ "pyyaml>=6.0.2",
16
+ "psycopg[binary]>=3.2.0",
17
+ "sshtunnel>=0.4.0",
18
+ "paramiko>=3.4.0,<4.0.0",
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ dev = [
23
+ "pytest>=8.3.0",
24
+ "ruff>=0.9.0",
25
+ "mypy>=1.14.0",
26
+ "types-PyYAML>=6.0.0",
27
+ ]
28
+
29
+ [project.scripts]
30
+ kctl-pg = "kctl_pg.cli:_run"
31
+
32
+ [tool.uv.sources]
33
+ kctl-lib = { workspace = true }
34
+
35
+ [project.entry-points."kctl_pg.plugins"]
36
+
37
+ [tool.hatch.build.targets.wheel]
38
+ packages = ["src/kctl_pg"]
39
+
40
+ [tool.ruff]
41
+ target-version = "py312"
42
+ line-length = 120
43
+
44
+ [tool.mypy]
45
+ python_version = "3.12"
46
+ strict = true