pg_sql_triggers 1.0.0 → 1.1.0

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.erb_lint.yml +47 -0
  3. data/.rubocop.yml +4 -1
  4. data/CHANGELOG.md +112 -1
  5. data/COVERAGE.md +58 -0
  6. data/Goal.md +450 -123
  7. data/README.md +53 -215
  8. data/app/controllers/pg_sql_triggers/application_controller.rb +46 -0
  9. data/app/controllers/pg_sql_triggers/dashboard_controller.rb +4 -1
  10. data/app/controllers/pg_sql_triggers/generator_controller.rb +76 -8
  11. data/app/controllers/pg_sql_triggers/migrations_controller.rb +18 -0
  12. data/app/models/pg_sql_triggers/trigger_registry.rb +93 -12
  13. data/app/views/layouts/pg_sql_triggers/application.html.erb +34 -1
  14. data/app/views/pg_sql_triggers/dashboard/index.html.erb +70 -30
  15. data/app/views/pg_sql_triggers/generator/new.html.erb +22 -4
  16. data/app/views/pg_sql_triggers/generator/preview.html.erb +244 -16
  17. data/app/views/pg_sql_triggers/shared/_confirmation_modal.html.erb +221 -0
  18. data/app/views/pg_sql_triggers/shared/_kill_switch_status.html.erb +40 -0
  19. data/app/views/pg_sql_triggers/tables/index.html.erb +0 -2
  20. data/app/views/pg_sql_triggers/tables/show.html.erb +3 -4
  21. data/config/initializers/pg_sql_triggers.rb +69 -0
  22. data/db/migrate/20251222000001_create_pg_sql_triggers_tables.rb +3 -1
  23. data/db/migrate/20251229071916_add_timing_to_pg_sql_triggers_registry.rb +8 -0
  24. data/docs/README.md +66 -0
  25. data/docs/api-reference.md +681 -0
  26. data/docs/configuration.md +541 -0
  27. data/docs/getting-started.md +135 -0
  28. data/docs/kill-switch.md +586 -0
  29. data/docs/screenshots/.gitkeep +1 -0
  30. data/docs/screenshots/Generate Trigger.png +0 -0
  31. data/docs/screenshots/Triggers Page.png +0 -0
  32. data/docs/screenshots/kill error.png +0 -0
  33. data/docs/screenshots/kill modal for migration down.png +0 -0
  34. data/docs/usage-guide.md +493 -0
  35. data/docs/web-ui.md +353 -0
  36. data/lib/generators/pg_sql_triggers/templates/create_pg_sql_triggers_tables.rb +3 -1
  37. data/lib/generators/pg_sql_triggers/templates/initializer.rb +44 -2
  38. data/lib/pg_sql_triggers/drift/db_queries.rb +116 -0
  39. data/lib/pg_sql_triggers/drift/detector.rb +187 -0
  40. data/lib/pg_sql_triggers/drift/reporter.rb +179 -0
  41. data/lib/pg_sql_triggers/drift.rb +14 -11
  42. data/lib/pg_sql_triggers/dsl/trigger_definition.rb +15 -1
  43. data/lib/pg_sql_triggers/generator/form.rb +3 -1
  44. data/lib/pg_sql_triggers/generator/service.rb +82 -26
  45. data/lib/pg_sql_triggers/migration.rb +1 -1
  46. data/lib/pg_sql_triggers/migrator/pre_apply_comparator.rb +344 -0
  47. data/lib/pg_sql_triggers/migrator/pre_apply_diff_reporter.rb +143 -0
  48. data/lib/pg_sql_triggers/migrator/safety_validator.rb +258 -0
  49. data/lib/pg_sql_triggers/migrator.rb +85 -3
  50. data/lib/pg_sql_triggers/registry/manager.rb +100 -13
  51. data/lib/pg_sql_triggers/sql/kill_switch.rb +300 -0
  52. data/lib/pg_sql_triggers/testing/dry_run.rb +5 -7
  53. data/lib/pg_sql_triggers/testing/function_tester.rb +66 -24
  54. data/lib/pg_sql_triggers/testing/safe_executor.rb +23 -11
  55. data/lib/pg_sql_triggers/testing/syntax_validator.rb +24 -1
  56. data/lib/pg_sql_triggers/version.rb +1 -1
  57. data/lib/pg_sql_triggers.rb +24 -0
  58. data/lib/tasks/trigger_migrations.rake +33 -0
  59. data/scripts/generate_coverage_report.rb +129 -0
  60. metadata +45 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 868dfd4da507455302b3e00e6dd27a8cc5440c6e81c60e978e10a031a339e8c1
4
- data.tar.gz: e8b013e8485431fac4d30bfd7f3faade2130b4b55d1be4cfbf0f9ffdbad2ef6f
3
+ metadata.gz: e72011f4407b6d60e5002202eedccf7e34c03075faebdf24301f74521e817904
4
+ data.tar.gz: b9df169c3fecf2a3b5bb34bc6a8fd7c3cad9707ded4297276a9d73af3c57871c
5
5
  SHA512:
6
- metadata.gz: 1265add39a041703438f7406a6a4b9c6f7b6e5dcf06240c8dc53c53f97c747cea850f1fa603d9eacbe072a43fbc4fe0cc371536e2bd8a215f30609171ccb8ffa
7
- data.tar.gz: e0d649df16316ef840fd5d42ef199b5dcf9f22d4ebe20134250ffe8b369d52c16f3774640ab95294ca487f4cb065d624bb7e386d1c223de536fc3dfc16d03511
6
+ metadata.gz: 7868c6518becf693b0d34e28c18423220e8fb29ef6a5bf331123e6f0bec08735d1de582f49064b3140106f1906f1d4430fb569dcea1953c2204e5355552b4e89
7
+ data.tar.gz: c6d7c92d4588482fe526d7e747d646e5abfcd542d094942348186719bf9b5240d85752e5a3485abe4d72fd21037d013bd155da8e8ddd388d5c36d4dfe88d5fd8
data/.erb_lint.yml ADDED
@@ -0,0 +1,47 @@
1
+ ---
2
+ # Enable all linters by default
3
+ EnableDefaultLinters: true
4
+
5
+ # Exclude vendor files from linting
6
+ exclude:
7
+ - 'vendor/**/*'
8
+
9
+ linters:
10
+ # Syntax and parsing
11
+ ParserErrors:
12
+ enabled: true
13
+
14
+ # Whitespace and formatting
15
+ TrailingWhitespace:
16
+ enabled: true
17
+ ExtraWhitespace:
18
+ enabled: true
19
+ SpaceAroundErbTag:
20
+ enabled: true
21
+ ClosingErbTagIndent:
22
+ enabled: true
23
+ SpaceInHtmlTag:
24
+ enabled: true
25
+
26
+ # Code quality
27
+ CommentSyntax:
28
+ enabled: true
29
+ SelfClosingTag:
30
+ enabled: true
31
+
32
+ # Security
33
+ NoJavascriptTagHelper:
34
+ enabled: true
35
+ RequireScriptNonce:
36
+ enabled: false # Disable if not using CSP nonces
37
+
38
+ # Accessibility
39
+ RequireInputLabel:
40
+ enabled: true
41
+
42
+ # Rails best practices
43
+ DeprecatedClasses:
44
+ enabled: true
45
+ SimpleFormat:
46
+ enabled: false # Disable if you intentionally use simple_format
47
+
data/.rubocop.yml CHANGED
@@ -8,7 +8,7 @@ plugins:
8
8
  - rubocop-factory_bot
9
9
 
10
10
  AllCops:
11
- TargetRubyVersion: 2.7
11
+ TargetRubyVersion: 3.0
12
12
  NewCops: enable
13
13
  SuggestExtensions: false
14
14
  Exclude:
@@ -88,6 +88,9 @@ Rails:
88
88
  Rails/I18nLocaleTexts:
89
89
  Enabled: false
90
90
 
91
+ Rails/StrongParametersExpect:
92
+ Enabled: false
93
+
91
94
  # RSpec
92
95
  RSpec/ExampleLength:
93
96
  Max: 10
data/CHANGELOG.md CHANGED
@@ -5,6 +5,112 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [1.1.0] - 2025-12-29
11
+
12
+ ### Added
13
+ - Trigger timing support (BEFORE/AFTER) in generator and registry
14
+ - Added `timing` field to generator form with "before" and "after" options
15
+ - Added `timing` column to `pg_sql_triggers_registry` table (defaults to "before")
16
+ - Timing is now included in DSL generation, migration generation, and registry storage
17
+ - Timing is included in checksum calculation for drift detection
18
+ - Preview page now displays trigger timing and condition information
19
+ - Comprehensive test coverage for both "before" and "after" timing scenarios
20
+ - Enhanced preview page UI for better testing and editing
21
+ - Timing and condition fields are now editable directly in the preview page
22
+ - Real-time DSL preview updates when timing or condition changes
23
+ - Improved visual layout with clear distinction between editable and read-only fields
24
+ - Better user experience for testing different timing and condition combinations before generating files
25
+ - JavaScript-powered dynamic preview that updates automatically as you type
26
+
27
+ ### Performance
28
+ - Optimized `Registry::Manager.register` to prevent N+1 queries when loading multiple trigger files
29
+ - Added request-level caching for registry lookups to avoid redundant database queries
30
+ - Added `preload_triggers` method for batch loading triggers into cache
31
+ - Cache is automatically populated during registration and can be manually cleared
32
+ - Significantly reduces database queries when multiple trigger files are loaded during request processing
33
+
34
+ ### Added
35
+ - Safety validation for trigger migrations (prevents unsafe DROP + CREATE operations)
36
+ - `Migrator::SafetyValidator` class that detects unsafe DROP + CREATE patterns in migrations
37
+ - Blocks migrations that would drop existing database objects (triggers/functions) and recreate them without validation
38
+ - Only flags as unsafe if the object actually exists in the database
39
+ - Configuration option `allow_unsafe_migrations` (default: false) for global override
40
+ - Environment variable `ALLOW_UNSAFE_MIGRATIONS=true` for per-migration override
41
+ - Provides clear error messages explaining unsafe operations and how to proceed if override is needed
42
+ - New error class `PgSqlTriggers::UnsafeMigrationError` for safety validation failures
43
+ - Pre-apply comparison for trigger migrations (diff expected vs actual)
44
+ - `Migrator::PreApplyComparator` class that extracts expected SQL from migrations and compares with database state
45
+ - `Migrator::PreApplyDiffReporter` class for formatting comparison results into human-readable diff reports
46
+ - Automatic pre-apply comparison before executing migrations to show what will change
47
+ - Comparison reports show new objects (will be created), modified objects (will be overwritten), and unchanged objects
48
+ - Detailed diff output for functions and triggers including expected vs actual SQL
49
+ - Summary output in verbose mode or when called from console
50
+ - Non-blocking: shows differences but doesn't prevent migration execution (warns only)
51
+ - Complete drift detection system implementation
52
+ - `Drift::Detector` class with all 6 drift states (IN_SYNC, DRIFTED, DISABLED, DROPPED, UNKNOWN, MANUAL_OVERRIDE)
53
+ - `Drift::Reporter` class for formatting drift reports and summaries
54
+ - `Drift::DbQueries` helper module for PostgreSQL system catalog queries
55
+ - Dashboard integration: drift count now calculated from actual detection results
56
+ - Console API: `PgSqlTriggers::Registry.diff` now fully functional with drift detection
57
+ - Comprehensive test coverage for all drift detection components (>90% coverage)
58
+
59
+ ### Added
60
+ - Comprehensive test coverage for generator components (>90% coverage)
61
+ - Added extensive test cases for `Generator::Service` covering all edge cases:
62
+ - Function name quoting (special characters vs simple patterns)
63
+ - Multiple environments handling
64
+ - Condition escaping with quotes
65
+ - Single and multiple event combinations
66
+ - All event types (insert, update, delete, truncate)
67
+ - Blank events and environments filtering
68
+ - Migration number generation edge cases (no existing migrations, timestamp collisions, multiple migrations)
69
+ - Standalone gem context (without Rails)
70
+ - Error handling and logging
71
+ - Checksum calculation with nil values
72
+ - Added test coverage for generator classes:
73
+ - `TriggerMigrationGenerator` - migration number generation, file naming, template usage
74
+ - `MigrationGenerator` (Trigger::Generators) - migration number generation, file naming, class name generation
75
+ - `InstallGenerator` - initializer creation, migration copying, route mounting, readme display
76
+
77
+ ### Fixed
78
+ - Fixed form data persistence when navigating between preview and edit pages
79
+ - Form data (including edits to condition, timing, and function_body) is now preserved when clicking "Back to Edit" from preview page
80
+ - Implemented session-based storage to maintain form state across page navigation
81
+ - All form fields are restored when returning to edit page: trigger_name, table_name, function_name, function_body, events, version, enabled, timing, condition, and environments
82
+ - Session data is automatically cleared after successful trigger creation
83
+ - Comprehensive test coverage added for session persistence functionality
84
+ - Fixed checksum calculation consistency across all code paths (field-concatenation algorithm)
85
+ - Fixed `Registry::Manager.diff` method to use drift detection
86
+ - Fixed dashboard controller to display actual drifted trigger count
87
+ - Fixed SQL parameter handling in `DbQueries.execute_query` method
88
+ - Fixed generator service to properly handle function body whitespace stripping
89
+ - Fixed generator service to handle standalone gem context (without Rails.root)
90
+
91
+ ## [1.0.1] - 2025-12-28
92
+
93
+ - Production kill switch for safety (blocks destructive operations in production by default)
94
+ - Core kill switch module with environment detection, confirmation validation, and thread-safe overrides
95
+ - CLI integration: All rake tasks protected (`trigger:migrate`, `trigger:rollback`, `trigger:migrate:up`, `trigger:migrate:down`, `trigger:migrate:redo`, `db:migrate:with_triggers`, `db:rollback:with_triggers`, `db:migrate:up:with_triggers`, `db:migrate:down:with_triggers`, `db:migrate:redo:with_triggers`)
96
+ - Console integration: Kill switch checks in `TriggerRegistry#enable!`, `TriggerRegistry#disable!`, `Migrator.run_up`, and `Migrator.run_down` methods
97
+ - UI integration: Kill switch enforcement in `MigrationsController` (up/down/redo actions) and `GeneratorController#create` action
98
+ - Configuration options: `kill_switch_enabled`, `kill_switch_environments`, `kill_switch_confirmation_required`, `kill_switch_confirmation_pattern`, `kill_switch_logger`
99
+ - ENV variable override support: `KILL_SWITCH_OVERRIDE` and `CONFIRMATION_TEXT` for emergency overrides
100
+ - Comprehensive logging and audit trail for all operations
101
+ - Confirmation modal UI component with client-side and server-side validation
102
+ - Kill switch status indicator in web UI
103
+
104
+ ### Fixed
105
+ - Added missing `mattr_accessor` declarations for kill switch configuration attributes (`kill_switch_environments`, `kill_switch_confirmation_required`, `kill_switch_confirmation_pattern`, `kill_switch_logger`) to ensure proper configuration access
106
+ - Fixed debug info display issues
107
+ - Fixed README documentation formatting
108
+ - Fixed Rails 6.1 compatibility issues
109
+ - Fixed BigDecimal dependency issues
110
+ - Fixed gemlock file conflicts
111
+ - Fixed RuboCop linting issues
112
+ - Fixed spec test issues
113
+
8
114
  ## [1.0.0] - 2025-12-27
9
115
 
10
116
  ### Added
@@ -14,7 +120,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
14
120
  - Drift detection between DSL definitions and database state (Managed & In Sync, Managed & Drifted, Manual Override, Disabled, Dropped, Unknown)
15
121
  - Permission system with three levels (Viewer, Operator, Admin)
16
122
  - Mountable Rails Engine with web UI for trigger management
17
- - Production kill switch for safety (blocks destructive operations in production by default)
18
123
  - Console introspection APIs (list, enabled, disabled, for_table, diff, validate!)
19
124
  - Migration system for registry table
20
125
  - Install generator (`rails generate pg_sql_triggers:install`)
@@ -49,4 +154,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
49
154
 
50
155
  ### Security
51
156
  - Production kill switch prevents destructive operations in production environments
157
+ - Blocks all destructive operations (migrations, trigger enable/disable) in production and staging by default
158
+ - Requires explicit confirmation text matching operation-specific patterns
159
+ - Thread-safe override mechanism for programmatic control
160
+ - ENV variable override support for emergency scenarios (`KILL_SWITCH_OVERRIDE`)
161
+ - Comprehensive logging of all kill switch checks and overrides
162
+ - Protection enforced across CLI (rake tasks), UI (controller actions), and Console (model/migrator methods)
52
163
  - Permission system enforces role-based access control (Viewer, Operator, Admin)
data/COVERAGE.md ADDED
@@ -0,0 +1,58 @@
1
+ # Code Coverage Report
2
+
3
+ **Total Coverage: 95.4%**
4
+
5
+ Covered: 1678 / 1759 lines
6
+
7
+ ---
8
+
9
+ ## File Coverage
10
+
11
+ | File | Coverage | Covered Lines | Missed Lines | Total Lines |
12
+ |------|----------|---------------|--------------|-------------|
13
+ | `lib/pg_sql_triggers/testing/dry_run.rb` | 100.0% ✅ | 24 | 0 | 24 |
14
+ | `lib/pg_sql_triggers/testing.rb` | 100.0% ✅ | 6 | 0 | 6 |
15
+ | `lib/pg_sql_triggers/registry/validator.rb` | 100.0% ✅ | 5 | 0 | 5 |
16
+ | `lib/pg_sql_triggers/registry.rb` | 100.0% ✅ | 18 | 0 | 18 |
17
+ | `lib/pg_sql_triggers/permissions/checker.rb` | 100.0% ✅ | 15 | 0 | 15 |
18
+ | `lib/pg_sql_triggers/permissions.rb` | 100.0% ✅ | 11 | 0 | 11 |
19
+ | `lib/pg_sql_triggers/migrator/safety_validator.rb` | 100.0% ✅ | 110 | 0 | 110 |
20
+ | `lib/pg_sql_triggers/migrator/pre_apply_diff_reporter.rb` | 100.0% ✅ | 75 | 0 | 75 |
21
+ | `lib/pg_sql_triggers/migrator/pre_apply_comparator.rb` | 100.0% ✅ | 123 | 0 | 123 |
22
+ | `lib/pg_sql_triggers/migration.rb` | 100.0% ✅ | 4 | 0 | 4 |
23
+ | `lib/generators/trigger/migration_generator.rb` | 100.0% ✅ | 27 | 0 | 27 |
24
+ | `lib/generators/pg_sql_triggers/install_generator.rb` | 100.0% ✅ | 18 | 0 | 18 |
25
+ | `lib/pg_sql_triggers/generator/service.rb` | 100.0% ✅ | 93 | 0 | 93 |
26
+ | `lib/pg_sql_triggers/generator/form.rb` | 100.0% ✅ | 36 | 0 | 36 |
27
+ | `lib/pg_sql_triggers/generator.rb` | 100.0% ✅ | 4 | 0 | 4 |
28
+ | `lib/pg_sql_triggers/dsl/trigger_definition.rb` | 100.0% ✅ | 37 | 0 | 37 |
29
+ | `lib/pg_sql_triggers.rb` | 100.0% ✅ | 45 | 0 | 45 |
30
+ | `config/initializers/pg_sql_triggers.rb` | 100.0% ✅ | 10 | 0 | 10 |
31
+ | `app/models/pg_sql_triggers/application_record.rb` | 100.0% ✅ | 3 | 0 | 3 |
32
+ | `app/controllers/pg_sql_triggers/application_controller.rb` | 100.0% ✅ | 28 | 0 | 28 |
33
+ | `app/controllers/pg_sql_triggers/dashboard_controller.rb` | 100.0% ✅ | 25 | 0 | 25 |
34
+ | `app/controllers/pg_sql_triggers/migrations_controller.rb` | 100.0% ✅ | 63 | 0 | 63 |
35
+ | `lib/pg_sql_triggers/dsl.rb` | 100.0% ✅ | 9 | 0 | 9 |
36
+ | `lib/pg_sql_triggers/drift.rb` | 100.0% ✅ | 13 | 0 | 13 |
37
+ | `lib/pg_sql_triggers/drift/db_queries.rb` | 100.0% ✅ | 24 | 0 | 24 |
38
+ | `lib/pg_sql_triggers/drift/detector.rb` | 98.48% ✅ | 65 | 1 | 66 |
39
+ | `lib/pg_sql_triggers/registry/manager.rb` | 96.36% ✅ | 53 | 2 | 55 |
40
+ | `lib/generators/pg_sql_triggers/trigger_migration_generator.rb` | 96.3% ✅ | 26 | 1 | 27 |
41
+ | `lib/pg_sql_triggers/sql/kill_switch.rb` | 96.0% ✅ | 96 | 4 | 100 |
42
+ | `lib/pg_sql_triggers/migrator.rb` | 95.42% ✅ | 125 | 6 | 131 |
43
+ | `app/controllers/pg_sql_triggers/generator_controller.rb` | 94.68% ✅ | 89 | 5 | 94 |
44
+ | `app/controllers/pg_sql_triggers/tables_controller.rb` | 94.44% ✅ | 17 | 1 | 18 |
45
+ | `lib/pg_sql_triggers/drift/reporter.rb` | 94.12% ✅ | 96 | 6 | 102 |
46
+ | `lib/pg_sql_triggers/engine.rb` | 92.86% ✅ | 13 | 1 | 14 |
47
+ | `lib/pg_sql_triggers/database_introspection.rb` | 92.86% ✅ | 65 | 5 | 70 |
48
+ | `lib/pg_sql_triggers/testing/safe_executor.rb` | 91.89% ✅ | 34 | 3 | 37 |
49
+ | `lib/pg_sql_triggers/sql.rb` | 90.91% ✅ | 10 | 1 | 11 |
50
+ | `lib/pg_sql_triggers/testing/syntax_validator.rb` | 89.66% ⚠️ | 52 | 6 | 58 |
51
+ | `app/models/pg_sql_triggers/trigger_registry.rb` | 84.62% ⚠️ | 55 | 10 | 65 |
52
+ | `lib/pg_sql_triggers/testing/function_tester.rb` | 79.1% ⚠️ | 53 | 14 | 67 |
53
+ | `config/routes.rb` | 16.67% ❌ | 3 | 15 | 18 |
54
+
55
+ ---
56
+
57
+ *Report generated automatically from SimpleCov results*
58
+ *To regenerate: Run `bundle exec rspec` and then `ruby scripts/generate_coverage_report.rb`*