migraguard 0.8.1 → 0.8.3

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.
package/README.md CHANGED
@@ -605,6 +605,8 @@ No. `verify` creates a temporary shadow DB, applies migrations twice, then drops
605
605
 
606
606
  ## Detailed Documentation
607
607
 
608
+ - [docs/cli-reference.md](docs/cli-reference.md) — Generated CLI reference (commands, options, exit codes, AI agent policies)
609
+ - [cli-contract.yaml](cli-contract.yaml) — Machine-readable CLI contract ([CLI Contracts](https://www.npmjs.com/package/cli-contracts) format)
608
610
  - [docs/commands.md](docs/commands.md) — Full command reference with options and examples
609
611
  - [docs/state-model.md](docs/state-model.md) — Apply/check/resolve/squash flows, INSERT-only design, regression detection
610
612
  - [docs/dag-internals.md](docs/dag-internals.md) — Dependency analysis, explicit declarations, DAG migration compatibility
@@ -0,0 +1,706 @@
1
+ # yaml-language-server: $schema=./node_modules/cli-contracts/schemas/cli-contract.schema.json
2
+ cliContracts: 0.1.0
3
+
4
+ info:
5
+ title: migraguard CLI
6
+ version: 0.8.3
7
+ description: >-
8
+ PostgreSQL-first schema-aware deployment control — idempotent SQL migrations
9
+ with CI-enforced integrity checks, expand/contract migration orchestration,
10
+ schema drift detection, and unified gating across database, application,
11
+ and infrastructure rollouts. MySQL and SQLite supported as secondary dialects.
12
+ license:
13
+ name: MIT
14
+
15
+ commandSets:
16
+ migraguard:
17
+ summary: Schema-aware deployment control for SQL migrations.
18
+ executable: migraguard
19
+
20
+ globalOptions:
21
+ - name: version
22
+ aliases: [V]
23
+ description: Print version and exit.
24
+ schema:
25
+ type: boolean
26
+
27
+ - name: help
28
+ aliases: [h]
29
+ description: Show help and exit.
30
+ schema:
31
+ type: boolean
32
+
33
+ commands:
34
+ # ── new ──────────────────────────────────────────
35
+ new:
36
+ summary: Create a new migration SQL file with UTC timestamp.
37
+ description: >-
38
+ Generates a timestamped SQL migration file in the configured migrations
39
+ directory. With --expand-contract, creates a migration group directory
40
+ containing phased files (expand, backfill, switch, contract).
41
+ usage:
42
+ - migraguard new create_users_table
43
+ - migraguard new --expand-contract rename_username_to_handle
44
+
45
+ arguments:
46
+ - name: name
47
+ index: 0
48
+ required: true
49
+ description: Migration name (alphanumeric and underscores).
50
+ schema:
51
+ type: string
52
+
53
+ options:
54
+ - name: expand-contract
55
+ description: Create an expand/contract migration group (Class B).
56
+ schema:
57
+ type: boolean
58
+ default: false
59
+
60
+ exits:
61
+ '0':
62
+ description: Migration file (or group directory) created successfully.
63
+ stdout:
64
+ format: text
65
+ files:
66
+ - path: db/migrations/{timestamp}__{name}.sql
67
+ required: false
68
+ mediaType: application/sql
69
+ encoding: utf-8
70
+ description: Single migration file (Class A).
71
+ - path: db/migrations/{timestamp}__{name}/1_expand.sql
72
+ required: false
73
+ mediaType: application/sql
74
+ encoding: utf-8
75
+ description: Expand phase file (Class B, with --expand-contract).
76
+
77
+ '1':
78
+ description: Creation failed (config error or naming conflict).
79
+ stderr:
80
+ format: text
81
+
82
+ x-agent:
83
+ riskLevel: low
84
+ requiresConfirmation: false
85
+ idempotent: false
86
+ sideEffects:
87
+ - file_write
88
+
89
+ # ── apply ────────────────────────────────────────
90
+ apply:
91
+ summary: Apply pending migrations via native database CLI.
92
+ description: >-
93
+ Executes pending migrations using the database's native CLI
94
+ (psql, mysql, or sqlite3). Uses advisory locks to prevent
95
+ concurrent execution. Records each application attempt in
96
+ the schema_migrations table.
97
+ usage:
98
+ - migraguard apply
99
+ - migraguard apply --with-drift-check
100
+ - migraguard apply --from-baseline
101
+
102
+ options:
103
+ - name: with-drift-check
104
+ description: Check schema drift before apply and update dump after.
105
+ schema:
106
+ type: boolean
107
+ default: false
108
+
109
+ - name: from-baseline
110
+ description: Apply schema.sql first, then remaining migrations.
111
+ schema:
112
+ type: boolean
113
+ default: false
114
+
115
+ exits:
116
+ '0':
117
+ description: All pending migrations applied successfully.
118
+ stdout:
119
+ format: text
120
+
121
+ '1':
122
+ description: >-
123
+ Apply failed (migration error, drift detected, regression
124
+ detected, or advisory lock conflict).
125
+ stderr:
126
+ format: text
127
+
128
+ x-agent:
129
+ riskLevel: high
130
+ requiresConfirmation: true
131
+ idempotent: false
132
+ sideEffects:
133
+ - database_write
134
+ recommendedBeforeUse:
135
+ - Run migraguard check to verify metadata integrity.
136
+ - Run migraguard lint to check for unsafe DDL patterns.
137
+ - Consider running with --with-drift-check for local development.
138
+
139
+ # ── check ────────────────────────────────────────
140
+ check:
141
+ summary: Verify metadata integrity (no DB connection required).
142
+ description: >-
143
+ Validates file list and checksums in metadata.json against the
144
+ actual migration files on disk. Detects tampered, missing, or
145
+ extra files. Runs offline without a database connection, making
146
+ it suitable for CI/CD PR checks.
147
+ usage:
148
+ - migraguard check
149
+
150
+ exits:
151
+ '0':
152
+ description: Metadata integrity verified. All checksums match.
153
+ stdout:
154
+ format: text
155
+
156
+ '1':
157
+ description: Integrity check failed (tampered, missing, or extra files).
158
+ stderr:
159
+ format: text
160
+
161
+ x-agent:
162
+ riskLevel: low
163
+ requiresConfirmation: false
164
+ idempotent: true
165
+ sideEffects: []
166
+
167
+ # ── squash ───────────────────────────────────────
168
+ squash:
169
+ summary: Squash multiple new migration files into one.
170
+ description: >-
171
+ Merges pending (unapplied) migration files into a single file
172
+ for release. Ensures one release = one file, simplifying error
173
+ recovery and hotfix workflows.
174
+ usage:
175
+ - migraguard squash
176
+
177
+ exits:
178
+ '0':
179
+ description: Migration files squashed successfully.
180
+ stdout:
181
+ format: text
182
+ files:
183
+ - path: db/migrations/{timestamp}__{description}.sql
184
+ required: true
185
+ mediaType: application/sql
186
+ encoding: utf-8
187
+ description: Squashed migration file.
188
+
189
+ '1':
190
+ description: Squash failed (nothing to squash or conflict).
191
+ stderr:
192
+ format: text
193
+
194
+ x-agent:
195
+ riskLevel: medium
196
+ requiresConfirmation: false
197
+ idempotent: false
198
+ sideEffects:
199
+ - file_write
200
+ - file_delete
201
+ recommendedBeforeUse:
202
+ - Ensure all pending files are ready for release.
203
+
204
+ # ── lint ─────────────────────────────────────────
205
+ lint:
206
+ summary: Run built-in safety rules on migration files.
207
+ description: >-
208
+ Performs AST-based lint analysis on migration SQL files using
209
+ libpg-query (38 rules for PostgreSQL) or node-sql-parser
210
+ (17 generic rules for MySQL/SQLite). Detects unsafe DDL patterns
211
+ such as missing IF NOT EXISTS, non-concurrent index creation,
212
+ missing lock timeouts, and prohibited operations.
213
+ usage:
214
+ - migraguard lint
215
+
216
+ exits:
217
+ '0':
218
+ description: All lint rules passed.
219
+ stdout:
220
+ format: text
221
+
222
+ '1':
223
+ description: Lint violations found.
224
+ stderr:
225
+ format: text
226
+
227
+ x-agent:
228
+ riskLevel: low
229
+ requiresConfirmation: false
230
+ idempotent: true
231
+ sideEffects: []
232
+
233
+ # ── dump ─────────────────────────────────────────
234
+ dump:
235
+ summary: Dump and normalize current DB schema.
236
+ description: >-
237
+ Executes pg_dump (PostgreSQL), mysqldump (MySQL), or sqlite3 .schema
238
+ (SQLite) to capture the current database schema, then normalizes the
239
+ output and saves it to schema.sql.
240
+ usage:
241
+ - migraguard dump
242
+
243
+ exits:
244
+ '0':
245
+ description: Schema dump saved successfully.
246
+ stdout:
247
+ format: text
248
+ files:
249
+ - path: db/schema.sql
250
+ required: true
251
+ mediaType: application/sql
252
+ encoding: utf-8
253
+ description: Normalized schema dump.
254
+
255
+ '1':
256
+ description: Dump failed (connection error or CLI not found).
257
+ stderr:
258
+ format: text
259
+
260
+ x-agent:
261
+ riskLevel: low
262
+ requiresConfirmation: false
263
+ idempotent: true
264
+ sideEffects:
265
+ - file_write
266
+
267
+ # ── diff ─────────────────────────────────────────
268
+ diff:
269
+ summary: Show diff between current DB schema and saved schema.sql.
270
+ description: >-
271
+ Dumps the current database schema, normalizes it, and compares
272
+ it against the saved schema.sql file. Exits with code 1 if
273
+ differences are found, enabling CI gating for schema drift.
274
+ usage:
275
+ - migraguard diff
276
+
277
+ exits:
278
+ '0':
279
+ description: No differences found. DB schema matches schema.sql.
280
+ stdout:
281
+ format: text
282
+
283
+ '1':
284
+ description: Differences found between DB schema and schema.sql.
285
+ stdout:
286
+ format: text
287
+
288
+ x-agent:
289
+ riskLevel: low
290
+ requiresConfirmation: false
291
+ idempotent: true
292
+ sideEffects: []
293
+
294
+ # ── status ───────────────────────────────────────
295
+ status:
296
+ summary: Show migration status (applied / pending / failed / skipped).
297
+ description: >-
298
+ Queries the schema_migrations table and cross-references with
299
+ migration files on disk to display the status of each migration.
300
+ usage:
301
+ - migraguard status
302
+
303
+ exits:
304
+ '0':
305
+ description: Status displayed successfully.
306
+ stdout:
307
+ format: text
308
+
309
+ '1':
310
+ description: Failed to retrieve status (connection error).
311
+ stderr:
312
+ format: text
313
+
314
+ x-agent:
315
+ riskLevel: low
316
+ requiresConfirmation: false
317
+ idempotent: true
318
+ sideEffects: []
319
+
320
+ # ── resolve ──────────────────────────────────────
321
+ resolve:
322
+ summary: Mark a failed migration as skipped (requires human judgment).
323
+ description: >-
324
+ Records a 'skipped' entry in schema_migrations for the specified
325
+ failed migration file. This unblocks subsequent migrations but
326
+ requires explicit human judgment that the failure has been
327
+ addressed by other means.
328
+ usage:
329
+ - migraguard resolve 20260301_120000__create_users_table.sql
330
+
331
+ arguments:
332
+ - name: file
333
+ index: 0
334
+ required: true
335
+ description: Failed migration file name to resolve.
336
+ schema:
337
+ type: string
338
+
339
+ exits:
340
+ '0':
341
+ description: Migration marked as skipped.
342
+ stdout:
343
+ format: text
344
+
345
+ '1':
346
+ description: Resolve failed (file not found or not in failed state).
347
+ stderr:
348
+ format: text
349
+
350
+ x-agent:
351
+ riskLevel: high
352
+ requiresConfirmation: true
353
+ idempotent: false
354
+ sideEffects:
355
+ - database_write
356
+ recommendedBeforeUse:
357
+ - Verify that the failure has been addressed by a subsequent migration or manual fix.
358
+ - Run migraguard status to confirm the file is in failed state.
359
+
360
+ # ── editable ─────────────────────────────────────
361
+ editable:
362
+ summary: List migration files that are currently editable.
363
+ description: >-
364
+ Shows which migration files can be safely modified. In linear mode,
365
+ only the tail file is editable. In DAG mode, all leaf nodes are editable.
366
+ usage:
367
+ - migraguard editable
368
+
369
+ exits:
370
+ '0':
371
+ description: Editable files listed.
372
+ stdout:
373
+ format: text
374
+
375
+ '1':
376
+ description: Failed to determine editable files.
377
+ stderr:
378
+ format: text
379
+
380
+ x-agent:
381
+ riskLevel: low
382
+ requiresConfirmation: false
383
+ idempotent: true
384
+ sideEffects: []
385
+
386
+ # ── verify ───────────────────────────────────────
387
+ verify:
388
+ summary: Verify migration idempotency using a shadow DB.
389
+ description: >-
390
+ Creates a temporary shadow database, applies migrations twice,
391
+ and confirms no errors or schema differences occur. Proves that
392
+ migrations are safely re-executable. The shadow DB is dropped
393
+ after verification.
394
+ usage:
395
+ - migraguard verify
396
+ - migraguard verify --all
397
+
398
+ options:
399
+ - name: all
400
+ description: Verify all migrations from scratch, not only pending.
401
+ schema:
402
+ type: boolean
403
+ default: false
404
+
405
+ exits:
406
+ '0':
407
+ description: All migrations verified as idempotent.
408
+ stdout:
409
+ format: text
410
+
411
+ '1':
412
+ description: One or more migrations failed idempotency verification.
413
+ stderr:
414
+ format: text
415
+
416
+ x-agent:
417
+ riskLevel: low
418
+ requiresConfirmation: false
419
+ idempotent: true
420
+ sideEffects:
421
+ - database_write
422
+ recommendedBeforeUse:
423
+ - Ensure the database server is running and accessible.
424
+
425
+ # ── group-status ─────────────────────────────────
426
+ group-status:
427
+ path: [group-status]
428
+ summary: Show migration group state (expand/contract phases).
429
+ description: >-
430
+ Displays the current phase state of migration groups. When a
431
+ group name is specified, shows detailed state for that group.
432
+ Without arguments, shows all groups.
433
+ usage:
434
+ - migraguard group-status
435
+ - migraguard group-status rename_username_to_handle
436
+
437
+ arguments:
438
+ - name: group
439
+ index: 0
440
+ required: false
441
+ description: Specific group name. Shows all groups if omitted.
442
+ schema:
443
+ type: string
444
+
445
+ exits:
446
+ '0':
447
+ description: Group status displayed.
448
+ stdout:
449
+ format: text
450
+
451
+ '1':
452
+ description: Failed to retrieve group status.
453
+ stderr:
454
+ format: text
455
+
456
+ x-agent:
457
+ riskLevel: low
458
+ requiresConfirmation: false
459
+ idempotent: true
460
+ sideEffects: []
461
+
462
+ # ── baseline ─────────────────────────────────────
463
+ baseline:
464
+ summary: Squash applied migrations into schema.sql baseline.
465
+ description: >-
466
+ Consolidates all applied migrations into schema.sql and
467
+ removes the original files. Optionally keeps migration files
468
+ from a specified point forward using --keep-since.
469
+ usage:
470
+ - migraguard baseline
471
+ - migraguard baseline --keep-since 20260301_120000__create_users_table.sql
472
+
473
+ options:
474
+ - name: keep-since
475
+ description: Keep migration files from this point forward.
476
+ valueName: file
477
+ repeatable: true
478
+ schema:
479
+ type: string
480
+
481
+ exits:
482
+ '0':
483
+ description: Baseline created successfully.
484
+ stdout:
485
+ format: text
486
+
487
+ '1':
488
+ description: Baseline failed.
489
+ stderr:
490
+ format: text
491
+
492
+ x-agent:
493
+ riskLevel: high
494
+ requiresConfirmation: true
495
+ idempotent: false
496
+ sideEffects:
497
+ - file_write
498
+ - file_delete
499
+ recommendedBeforeUse:
500
+ - Ensure all migrations have been applied to all environments.
501
+ - Back up migration files before running.
502
+
503
+ # ── advance ──────────────────────────────────────
504
+ advance:
505
+ summary: Record a phase state transition (for external executor).
506
+ description: >-
507
+ Updates the state of a migration group phase. Used by external
508
+ executors to record phase transitions in the expand/contract workflow.
509
+ Valid phases: expand, backfill, switch, contract.
510
+ Valid statuses: running, completed, failed.
511
+ usage:
512
+ - migraguard advance rename_username_to_handle expand completed
513
+ - migraguard advance rename_username_to_handle backfill running
514
+
515
+ arguments:
516
+ - name: group
517
+ index: 0
518
+ required: true
519
+ description: Migration group name.
520
+ schema:
521
+ type: string
522
+
523
+ - name: phase
524
+ index: 1
525
+ required: true
526
+ description: Phase to advance.
527
+ schema:
528
+ type: string
529
+ enum: [expand, backfill, switch, contract]
530
+
531
+ - name: status
532
+ index: 2
533
+ required: true
534
+ description: New status for the phase.
535
+ schema:
536
+ type: string
537
+ enum: [running, completed, failed]
538
+
539
+ exits:
540
+ '0':
541
+ description: Phase state transition recorded.
542
+ stdout:
543
+ format: text
544
+
545
+ '1':
546
+ description: >-
547
+ Advance failed (invalid phase/status, group not found,
548
+ or invalid state transition).
549
+ stderr:
550
+ format: text
551
+
552
+ x-agent:
553
+ riskLevel: medium
554
+ requiresConfirmation: true
555
+ idempotent: false
556
+ sideEffects:
557
+ - database_write
558
+
559
+ # ── apply-phase ──────────────────────────────────
560
+ apply-phase:
561
+ path: [apply-phase]
562
+ summary: Apply a specific phase of a migration group via native CLI.
563
+ description: >-
564
+ Executes the SQL file for a specific phase of a migration group
565
+ using the database's native CLI (psql, mysql, or sqlite3).
566
+ Valid phases: expand, backfill, switch, contract.
567
+ usage:
568
+ - migraguard apply-phase rename_username_to_handle expand
569
+ - migraguard apply-phase rename_username_to_handle contract
570
+
571
+ arguments:
572
+ - name: group
573
+ index: 0
574
+ required: true
575
+ description: Migration group name.
576
+ schema:
577
+ type: string
578
+
579
+ - name: phase
580
+ index: 1
581
+ required: true
582
+ description: Phase to apply.
583
+ schema:
584
+ type: string
585
+ enum: [expand, backfill, switch, contract]
586
+
587
+ exits:
588
+ '0':
589
+ description: Phase applied successfully.
590
+ stdout:
591
+ format: text
592
+
593
+ '1':
594
+ description: >-
595
+ Phase apply failed (SQL error, group not found,
596
+ or invalid phase for current state).
597
+ stderr:
598
+ format: text
599
+
600
+ x-agent:
601
+ riskLevel: high
602
+ requiresConfirmation: true
603
+ idempotent: false
604
+ sideEffects:
605
+ - database_write
606
+ recommendedBeforeUse:
607
+ - Run migraguard group-status to verify current phase state.
608
+
609
+ # ── gate ─────────────────────────────────────────
610
+ gate:
611
+ summary: Evaluate deployment gate conditions against migration group states.
612
+ description: >-
613
+ Checks whether the current migration group states satisfy
614
+ the specified deployment gate conditions. Used in CI/CD pipelines
615
+ to gate deployments on schema state. Conditions can be specified
616
+ via CLI options or a JSON contract file.
617
+ usage:
618
+ - 'migraguard gate --require "group:rename_username_to_handle.expand_applied"'
619
+ - 'migraguard gate --forbid "group:rename_username_to_handle.contract_pending"'
620
+ - migraguard gate --contract-file deploy-gates.json
621
+
622
+ options:
623
+ - name: require
624
+ description: Required schema state conditions.
625
+ valueName: condition
626
+ repeatable: true
627
+ schema:
628
+ type: string
629
+
630
+ - name: forbid
631
+ description: Forbidden schema state conditions.
632
+ valueName: condition
633
+ repeatable: true
634
+ schema:
635
+ type: string
636
+
637
+ - name: contract-file
638
+ description: JSON file with schema requirements.
639
+ valueName: path
640
+ schema:
641
+ type: string
642
+ file:
643
+ mode: read
644
+ exists: true
645
+ mediaType: application/json
646
+ encoding: utf-8
647
+
648
+ exits:
649
+ '0':
650
+ description: All gate conditions satisfied.
651
+ stdout:
652
+ format: text
653
+
654
+ '1':
655
+ description: One or more gate conditions not satisfied.
656
+ stderr:
657
+ format: text
658
+
659
+ x-agent:
660
+ riskLevel: low
661
+ requiresConfirmation: false
662
+ idempotent: true
663
+ sideEffects: []
664
+
665
+ # ── deps ─────────────────────────────────────────
666
+ deps:
667
+ summary: Analyze and display migration dependency graph.
668
+ description: >-
669
+ Parses migration SQL files to extract object creation/reference
670
+ relationships and builds a dependency graph. In DAG mode, shows
671
+ the full dependency tree. Optionally outputs as an interactive
672
+ HTML visualization.
673
+ usage:
674
+ - migraguard deps
675
+ - migraguard deps --html deps.html
676
+
677
+ options:
678
+ - name: html
679
+ description: Output as HTML file with interactive visualization.
680
+ valueName: path
681
+ schema:
682
+ type: string
683
+
684
+ exits:
685
+ '0':
686
+ description: Dependency graph displayed or HTML file generated.
687
+ stdout:
688
+ format: text
689
+ files:
690
+ - path: '{options.html}'
691
+ required: false
692
+ mediaType: text/html
693
+ encoding: utf-8
694
+ description: HTML dependency visualization (when --html specified).
695
+
696
+ '1':
697
+ description: Dependency analysis failed.
698
+ stderr:
699
+ format: text
700
+
701
+ x-agent:
702
+ riskLevel: low
703
+ requiresConfirmation: false
704
+ idempotent: true
705
+ sideEffects:
706
+ - file_write