pg_sql_triggers 1.0.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/.erb_lint.yml +47 -0
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +29 -1
- data/Goal.md +408 -123
- data/README.md +47 -215
- data/app/controllers/pg_sql_triggers/application_controller.rb +46 -0
- data/app/controllers/pg_sql_triggers/generator_controller.rb +10 -4
- data/app/controllers/pg_sql_triggers/migrations_controller.rb +18 -0
- data/app/models/pg_sql_triggers/trigger_registry.rb +20 -2
- data/app/views/layouts/pg_sql_triggers/application.html.erb +34 -1
- data/app/views/pg_sql_triggers/dashboard/index.html.erb +70 -30
- data/app/views/pg_sql_triggers/generator/new.html.erb +4 -4
- data/app/views/pg_sql_triggers/generator/preview.html.erb +14 -6
- data/app/views/pg_sql_triggers/shared/_confirmation_modal.html.erb +189 -0
- data/app/views/pg_sql_triggers/shared/_kill_switch_status.html.erb +40 -0
- data/app/views/pg_sql_triggers/tables/index.html.erb +0 -2
- data/app/views/pg_sql_triggers/tables/show.html.erb +3 -4
- data/db/migrate/20251222000001_create_pg_sql_triggers_tables.rb +1 -1
- data/docs/README.md +66 -0
- data/docs/api-reference.md +663 -0
- data/docs/configuration.md +541 -0
- data/docs/getting-started.md +135 -0
- data/docs/kill-switch.md +586 -0
- data/docs/screenshots/.gitkeep +1 -0
- data/docs/screenshots/Generate Trigger.png +0 -0
- data/docs/screenshots/Triggers Page.png +0 -0
- data/docs/screenshots/kill error.png +0 -0
- data/docs/screenshots/kill modal for migration down.png +0 -0
- data/docs/usage-guide.md +420 -0
- data/docs/web-ui.md +339 -0
- data/lib/generators/pg_sql_triggers/templates/create_pg_sql_triggers_tables.rb +1 -1
- data/lib/generators/pg_sql_triggers/templates/initializer.rb +36 -2
- data/lib/pg_sql_triggers/generator/service.rb +1 -1
- data/lib/pg_sql_triggers/migration.rb +1 -1
- data/lib/pg_sql_triggers/migrator.rb +27 -3
- data/lib/pg_sql_triggers/registry/manager.rb +6 -6
- data/lib/pg_sql_triggers/sql/kill_switch.rb +300 -0
- data/lib/pg_sql_triggers/testing/dry_run.rb +5 -7
- data/lib/pg_sql_triggers/testing/safe_executor.rb +23 -11
- data/lib/pg_sql_triggers/version.rb +1 -1
- data/lib/pg_sql_triggers.rb +12 -0
- data/lib/tasks/trigger_migrations.rake +33 -0
- metadata +35 -5
data/README.md
CHANGED
|
@@ -21,37 +21,28 @@ Rails teams use PostgreSQL triggers for data integrity, performance, and billing
|
|
|
21
21
|
- UI control
|
|
22
22
|
- Emergency SQL escape hatches
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## Requirements
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
- **Ruby 3.0+**
|
|
27
|
+
- **Rails 6.1+**
|
|
28
|
+
- **PostgreSQL** (any supported version)
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
gem 'pg_sql_triggers'
|
|
30
|
-
```
|
|
30
|
+
## Quick Start
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
### Installation
|
|
33
33
|
|
|
34
|
-
```
|
|
35
|
-
|
|
34
|
+
```ruby
|
|
35
|
+
# Gemfile
|
|
36
|
+
gem 'pg_sql_triggers'
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
Run the installer:
|
|
39
|
-
|
|
40
39
|
```bash
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
bundle install
|
|
41
|
+
rails generate pg_sql_triggers:install
|
|
42
|
+
rails db:migrate
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
1. Create an initializer at `config/initializers/pg_sql_triggers.rb`
|
|
47
|
-
2. Create migrations for registry table
|
|
48
|
-
3. Mount the engine at `/pg_sql_triggers`
|
|
49
|
-
|
|
50
|
-
## Usage
|
|
51
|
-
|
|
52
|
-
### 1. Declaring Triggers
|
|
53
|
-
|
|
54
|
-
Create trigger definitions using the Ruby DSL:
|
|
45
|
+
### Define a Trigger
|
|
55
46
|
|
|
56
47
|
```ruby
|
|
57
48
|
# app/triggers/users_email_validation.rb
|
|
@@ -59,222 +50,59 @@ PgSqlTriggers::DSL.pg_sql_trigger "users_email_validation" do
|
|
|
59
50
|
table :users
|
|
60
51
|
on :insert, :update
|
|
61
52
|
function :validate_user_email
|
|
62
|
-
|
|
63
53
|
version 1
|
|
64
54
|
enabled false
|
|
65
|
-
|
|
66
55
|
when_env :production
|
|
67
56
|
end
|
|
68
57
|
```
|
|
69
58
|
|
|
70
|
-
###
|
|
71
|
-
|
|
72
|
-
Generate and run trigger migrations similar to Rails schema migrations:
|
|
59
|
+
### Create and Run Migration
|
|
73
60
|
|
|
74
61
|
```bash
|
|
75
|
-
|
|
76
|
-
rails generate trigger:migration add_validation_trigger
|
|
77
|
-
|
|
78
|
-
# Run pending trigger migrations
|
|
62
|
+
rails generate trigger:migration add_email_validation
|
|
79
63
|
rake trigger:migrate
|
|
80
|
-
|
|
81
|
-
# Rollback last trigger migration
|
|
82
|
-
rake trigger:rollback
|
|
83
|
-
|
|
84
|
-
# Rollback multiple steps
|
|
85
|
-
rake trigger:rollback STEP=3
|
|
86
|
-
|
|
87
|
-
# Check migration status
|
|
88
|
-
rake trigger:migrate:status
|
|
89
|
-
|
|
90
|
-
# Run a specific migration up
|
|
91
|
-
rake trigger:migrate:up VERSION=20231215120000
|
|
92
|
-
|
|
93
|
-
# Run a specific migration down
|
|
94
|
-
rake trigger:migrate:down VERSION=20231215120000
|
|
95
|
-
|
|
96
|
-
# Redo last migration
|
|
97
|
-
rake trigger:migrate:redo
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**Web UI Migration Management:**
|
|
101
|
-
|
|
102
|
-
You can also manage migrations directly from the web dashboard:
|
|
103
|
-
|
|
104
|
-
- **Apply All Pending Migrations**: Click the "Apply All Pending Migrations" button to run all pending migrations at once
|
|
105
|
-
- **Rollback Last Migration**: Use the "Rollback Last Migration" button to undo the most recent migration
|
|
106
|
-
- **Redo Last Migration**: Click "Redo Last Migration" to rollback and re-apply the last migration
|
|
107
|
-
- **Individual Migration Actions**: Each migration in the status table has individual "Up", "Down", or "Redo" buttons for granular control
|
|
108
|
-
|
|
109
|
-
All migration actions include confirmation dialogs and provide feedback via flash messages.
|
|
110
|
-
|
|
111
|
-
Trigger migrations are stored in `db/triggers/` and follow the same naming convention as Rails migrations (`YYYYMMDDHHMMSS_name.rb`).
|
|
112
|
-
|
|
113
|
-
Example trigger migration:
|
|
114
|
-
|
|
115
|
-
```ruby
|
|
116
|
-
# db/triggers/20231215120000_add_validation_trigger.rb
|
|
117
|
-
class AddValidationTrigger < PgSqlTriggers::Migration
|
|
118
|
-
def up
|
|
119
|
-
execute <<-SQL
|
|
120
|
-
CREATE OR REPLACE FUNCTION validate_user_email()
|
|
121
|
-
RETURNS TRIGGER AS $$
|
|
122
|
-
BEGIN
|
|
123
|
-
IF NEW.email !~ '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' THEN
|
|
124
|
-
RAISE EXCEPTION 'Invalid email format';
|
|
125
|
-
END IF;
|
|
126
|
-
RETURN NEW;
|
|
127
|
-
END;
|
|
128
|
-
$$ LANGUAGE plpgsql;
|
|
129
|
-
|
|
130
|
-
CREATE TRIGGER user_email_validation
|
|
131
|
-
BEFORE INSERT OR UPDATE ON users
|
|
132
|
-
FOR EACH ROW
|
|
133
|
-
EXECUTE FUNCTION validate_user_email();
|
|
134
|
-
SQL
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def down
|
|
138
|
-
execute <<-SQL
|
|
139
|
-
DROP TRIGGER IF EXISTS user_email_validation ON users;
|
|
140
|
-
DROP FUNCTION IF EXISTS validate_user_email();
|
|
141
|
-
SQL
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### 3. Combined Schema and Trigger Migrations
|
|
147
|
-
|
|
148
|
-
Run both schema and trigger migrations together:
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
# Run both schema and trigger migrations
|
|
152
|
-
rake db:migrate:with_triggers
|
|
153
|
-
|
|
154
|
-
# Rollback both (rolls back the most recent migration)
|
|
155
|
-
rake db:rollback:with_triggers
|
|
156
|
-
|
|
157
|
-
# Check status of both
|
|
158
|
-
rake db:migrate:status:with_triggers
|
|
159
|
-
|
|
160
|
-
# Get versions of both
|
|
161
|
-
rake db:version:with_triggers
|
|
162
64
|
```
|
|
163
65
|
|
|
164
|
-
###
|
|
165
|
-
|
|
166
|
-
Access trigger information from the Rails console:
|
|
167
|
-
|
|
168
|
-
```ruby
|
|
169
|
-
# List all triggers
|
|
170
|
-
PgSqlTriggers::Registry.list
|
|
171
|
-
|
|
172
|
-
# List enabled triggers
|
|
173
|
-
PgSqlTriggers::Registry.enabled
|
|
174
|
-
|
|
175
|
-
# List disabled triggers
|
|
176
|
-
PgSqlTriggers::Registry.disabled
|
|
177
|
-
|
|
178
|
-
# Get triggers for a specific table
|
|
179
|
-
PgSqlTriggers::Registry.for_table(:users)
|
|
180
|
-
|
|
181
|
-
# Check for drift
|
|
182
|
-
PgSqlTriggers::Registry.diff
|
|
183
|
-
|
|
184
|
-
# Validate all triggers
|
|
185
|
-
PgSqlTriggers::Registry.validate!
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### 5. Web UI
|
|
189
|
-
|
|
190
|
-
Access the web UI at `http://localhost:3000/pg_sql_triggers` to:
|
|
191
|
-
|
|
192
|
-
- View all triggers and their status
|
|
193
|
-
- Enable/disable triggers
|
|
194
|
-
- View drift states
|
|
195
|
-
- Execute SQL capsules
|
|
196
|
-
- Manage trigger lifecycle
|
|
197
|
-
- **Run trigger migrations** (up/down/redo) directly from the dashboard
|
|
198
|
-
- Apply all pending migrations with a single click
|
|
199
|
-
- Rollback the last migration
|
|
200
|
-
- Redo the last migration
|
|
201
|
-
- Individual migration controls for each migration in the status table
|
|
202
|
-
|
|
203
|
-
<img width="3360" height="2506" alt="screencapture-localhost-3000-pg-triggers-2025-12-27-17_04_29" src="https://github.com/user-attachments/assets/a7f5904b-1172-41fc-ba3f-c05587cb1fe8" />
|
|
66
|
+
### Access the Web UI
|
|
204
67
|
|
|
205
|
-
|
|
68
|
+
Navigate to `http://localhost:3000/pg_sql_triggers` to manage triggers visually.
|
|
206
69
|
|
|
70
|
+
Screenshots are available in the [docs/screenshots](docs/screenshots/) directory.
|
|
207
71
|
|
|
208
|
-
|
|
72
|
+
## Documentation
|
|
209
73
|
|
|
210
|
-
|
|
74
|
+
Comprehensive documentation is available in the [docs](docs/) directory:
|
|
211
75
|
|
|
212
|
-
- **
|
|
213
|
-
- **
|
|
214
|
-
- **
|
|
76
|
+
- **[Getting Started](docs/getting-started.md)** - Installation and basic setup
|
|
77
|
+
- **[Usage Guide](docs/usage-guide.md)** - DSL syntax, migrations, and drift detection
|
|
78
|
+
- **[Web UI](docs/web-ui.md)** - Using the web dashboard
|
|
79
|
+
- **[Kill Switch](docs/kill-switch.md)** - Production safety features
|
|
80
|
+
- **[Configuration](docs/configuration.md)** - Complete configuration reference
|
|
81
|
+
- **[API Reference](docs/api-reference.md)** - Console API and programmatic access
|
|
215
82
|
|
|
216
|
-
|
|
83
|
+
## Key Features
|
|
217
84
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
PgSqlTriggers.configure do |config|
|
|
221
|
-
config.permission_checker = ->(actor, action, environment) {
|
|
222
|
-
# Your custom permission logic
|
|
223
|
-
user = User.find(actor[:id])
|
|
224
|
-
user.has_permission?(action)
|
|
225
|
-
}
|
|
226
|
-
end
|
|
227
|
-
```
|
|
85
|
+
### Trigger DSL
|
|
86
|
+
Define triggers using a Rails-native Ruby DSL with versioning and environment control.
|
|
228
87
|
|
|
229
|
-
###
|
|
88
|
+
### Migration System
|
|
89
|
+
Manage trigger functions and definitions with a migration system similar to Rails schema migrations.
|
|
230
90
|
|
|
231
|
-
|
|
91
|
+
### Drift Detection
|
|
92
|
+
Automatically detect when database triggers drift from your DSL definitions.
|
|
232
93
|
|
|
233
|
-
|
|
234
|
-
-
|
|
235
|
-
- **Manual Override**: Trigger was modified outside of PgSqlTriggers
|
|
236
|
-
- **Disabled**: Trigger is disabled
|
|
237
|
-
- **Dropped**: Trigger was dropped but still in registry
|
|
238
|
-
- **Unknown**: Trigger exists in DB but not in registry
|
|
94
|
+
### Production Kill Switch
|
|
95
|
+
Multi-layered safety mechanism preventing accidental destructive operations in production environments.
|
|
239
96
|
|
|
240
|
-
###
|
|
97
|
+
### Web Dashboard
|
|
98
|
+
Visual interface for managing triggers, running migrations, and executing SQL capsules.
|
|
241
99
|
|
|
242
|
-
|
|
100
|
+
### Permissions
|
|
101
|
+
Three-tier permission system (Viewer, Operator, Admin) with customizable authorization.
|
|
243
102
|
|
|
244
|
-
|
|
245
|
-
# config/initializers/pg_sql_triggers.rb
|
|
246
|
-
PgSqlTriggers.configure do |config|
|
|
247
|
-
# Enable production kill switch (default: true)
|
|
248
|
-
config.kill_switch_enabled = true
|
|
249
|
-
end
|
|
250
|
-
```
|
|
103
|
+
## Examples
|
|
251
104
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
```ruby
|
|
255
|
-
PgSqlTriggers::SQL.override_kill_switch do
|
|
256
|
-
# Dangerous operation here
|
|
257
|
-
end
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## Configuration
|
|
261
|
-
|
|
262
|
-
```ruby
|
|
263
|
-
# config/initializers/pg_sql_triggers.rb
|
|
264
|
-
PgSqlTriggers.configure do |config|
|
|
265
|
-
# Kill switch for production (default: true)
|
|
266
|
-
config.kill_switch_enabled = true
|
|
267
|
-
|
|
268
|
-
# Environment detection (default: -> { Rails.env })
|
|
269
|
-
config.default_environment = -> { Rails.env }
|
|
270
|
-
|
|
271
|
-
# Custom permission checker
|
|
272
|
-
config.permission_checker = ->(actor, action, environment) {
|
|
273
|
-
# Return true/false based on your authorization logic
|
|
274
|
-
true
|
|
275
|
-
}
|
|
276
|
-
end
|
|
277
|
-
```
|
|
105
|
+
For working examples and complete demonstrations, check out the [example repository](https://github.com/samaswin87/pg_triggers_example).
|
|
278
106
|
|
|
279
107
|
## Core Principles
|
|
280
108
|
|
|
@@ -285,10 +113,14 @@ end
|
|
|
285
113
|
|
|
286
114
|
## Development
|
|
287
115
|
|
|
288
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
|
116
|
+
After checking out the repo, run `bin/setup` to install dependencies. Run `rake spec` to run tests. Run `bin/console` for an interactive prompt.
|
|
289
117
|
|
|
290
|
-
To install this gem
|
|
118
|
+
To install this gem locally, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and run `bundle exec rake release`.
|
|
291
119
|
|
|
292
120
|
## Contributing
|
|
293
121
|
|
|
294
122
|
Bug reports and pull requests are welcome on GitHub at https://github.com/samaswin87/pg_sql_triggers.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
See [LICENSE](LICENSE) file for details.
|
|
@@ -9,6 +9,9 @@ module PgSqlTriggers
|
|
|
9
9
|
|
|
10
10
|
before_action :check_permissions?
|
|
11
11
|
|
|
12
|
+
# Helper methods available in views
|
|
13
|
+
helper_method :current_environment, :kill_switch_active?, :expected_confirmation_text
|
|
14
|
+
|
|
12
15
|
private
|
|
13
16
|
|
|
14
17
|
def check_permissions?
|
|
@@ -31,5 +34,48 @@ module PgSqlTriggers
|
|
|
31
34
|
def current_user_id
|
|
32
35
|
"unknown"
|
|
33
36
|
end
|
|
37
|
+
|
|
38
|
+
# ========== Kill Switch Helpers ==========
|
|
39
|
+
|
|
40
|
+
# Returns the current environment
|
|
41
|
+
def current_environment
|
|
42
|
+
Rails.env
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Checks if kill switch is active for the current environment
|
|
46
|
+
def kill_switch_active?
|
|
47
|
+
PgSqlTriggers::SQL::KillSwitch.active?(environment: current_environment)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Checks kill switch before executing a dangerous operation
|
|
51
|
+
# Raises KillSwitchError if the operation is blocked
|
|
52
|
+
#
|
|
53
|
+
# @param operation [Symbol] The operation being performed
|
|
54
|
+
# @param confirmation [String, nil] Optional confirmation text from params
|
|
55
|
+
def check_kill_switch(operation:, confirmation: nil)
|
|
56
|
+
PgSqlTriggers::SQL::KillSwitch.check!(
|
|
57
|
+
operation: operation,
|
|
58
|
+
environment: current_environment,
|
|
59
|
+
confirmation: confirmation,
|
|
60
|
+
actor: current_actor
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Before action to require kill switch override for an action
|
|
65
|
+
# Add to specific controller actions that need protection:
|
|
66
|
+
# before_action -> { require_kill_switch_override(:operation_name) }, only: [:dangerous_action]
|
|
67
|
+
def require_kill_switch_override(operation, confirmation: nil)
|
|
68
|
+
check_kill_switch(operation: operation, confirmation: confirmation)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Returns the expected confirmation text for an operation (for use in views)
|
|
72
|
+
def expected_confirmation_text(operation)
|
|
73
|
+
if PgSqlTriggers.respond_to?(:kill_switch_confirmation_pattern) &&
|
|
74
|
+
PgSqlTriggers.kill_switch_confirmation_pattern.respond_to?(:call)
|
|
75
|
+
PgSqlTriggers.kill_switch_confirmation_pattern.call(operation)
|
|
76
|
+
else
|
|
77
|
+
"EXECUTE #{operation.to_s.upcase}"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
34
80
|
end
|
|
35
81
|
end
|
|
@@ -36,6 +36,9 @@ module PgSqlTriggers
|
|
|
36
36
|
# POST /generator/create
|
|
37
37
|
# Actually create the files and register in TriggerRegistry
|
|
38
38
|
def create
|
|
39
|
+
# Check kill switch before generating trigger
|
|
40
|
+
check_kill_switch(operation: :ui_trigger_generate, confirmation: params[:confirmation_text])
|
|
41
|
+
|
|
39
42
|
@form = PgSqlTriggers::Generator::Form.new(generator_params)
|
|
40
43
|
|
|
41
44
|
if @form.valid?
|
|
@@ -67,6 +70,9 @@ module PgSqlTriggers
|
|
|
67
70
|
@available_tables = fetch_available_tables
|
|
68
71
|
render :new
|
|
69
72
|
end
|
|
73
|
+
rescue PgSqlTriggers::KillSwitchError => e
|
|
74
|
+
flash[:error] = e.message
|
|
75
|
+
redirect_to root_path
|
|
70
76
|
end
|
|
71
77
|
|
|
72
78
|
# POST /generator/validate_table (AJAX)
|
|
@@ -96,10 +102,10 @@ module PgSqlTriggers
|
|
|
96
102
|
private
|
|
97
103
|
|
|
98
104
|
def generator_params
|
|
99
|
-
params.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
params.require(:pg_sql_triggers_generator_form).permit(
|
|
106
|
+
:trigger_name, :table_name, :function_name, :version,
|
|
107
|
+
:enabled, :condition, :generate_function_stub, :function_body,
|
|
108
|
+
events: [], environments: []
|
|
103
109
|
)
|
|
104
110
|
end
|
|
105
111
|
|
|
@@ -5,6 +5,9 @@ module PgSqlTriggers
|
|
|
5
5
|
# Provides actions to run migrations up, down, and redo
|
|
6
6
|
class MigrationsController < ApplicationController
|
|
7
7
|
def up
|
|
8
|
+
# Check kill switch before running migration
|
|
9
|
+
check_kill_switch(operation: :ui_migration_up, confirmation: params[:confirmation_text])
|
|
10
|
+
|
|
8
11
|
target_version = params[:version]&.to_i
|
|
9
12
|
PgSqlTriggers::Migrator.ensure_migrations_table!
|
|
10
13
|
|
|
@@ -22,6 +25,9 @@ module PgSqlTriggers
|
|
|
22
25
|
end
|
|
23
26
|
end
|
|
24
27
|
redirect_to root_path
|
|
28
|
+
rescue PgSqlTriggers::KillSwitchError => e
|
|
29
|
+
flash[:error] = e.message
|
|
30
|
+
redirect_to root_path
|
|
25
31
|
rescue StandardError => e
|
|
26
32
|
Rails.logger.error("Migration up failed: #{e.message}\n#{e.backtrace.join("\n")}")
|
|
27
33
|
flash[:error] = "Failed to apply migration: #{e.message}"
|
|
@@ -29,6 +35,9 @@ module PgSqlTriggers
|
|
|
29
35
|
end
|
|
30
36
|
|
|
31
37
|
def down
|
|
38
|
+
# Check kill switch before rolling back migration
|
|
39
|
+
check_kill_switch(operation: :ui_migration_down, confirmation: params[:confirmation_text])
|
|
40
|
+
|
|
32
41
|
target_version = params[:version]&.to_i
|
|
33
42
|
PgSqlTriggers::Migrator.ensure_migrations_table!
|
|
34
43
|
|
|
@@ -48,6 +57,9 @@ module PgSqlTriggers
|
|
|
48
57
|
flash[:success] = "Rolled back last migration successfully."
|
|
49
58
|
end
|
|
50
59
|
redirect_to root_path
|
|
60
|
+
rescue PgSqlTriggers::KillSwitchError => e
|
|
61
|
+
flash[:error] = e.message
|
|
62
|
+
redirect_to root_path
|
|
51
63
|
rescue StandardError => e
|
|
52
64
|
Rails.logger.error("Migration down failed: #{e.message}\n#{e.backtrace.join("\n")}")
|
|
53
65
|
flash[:error] = "Failed to rollback migration: #{e.message}"
|
|
@@ -55,6 +67,9 @@ module PgSqlTriggers
|
|
|
55
67
|
end
|
|
56
68
|
|
|
57
69
|
def redo
|
|
70
|
+
# Check kill switch before redoing migration
|
|
71
|
+
check_kill_switch(operation: :ui_migration_redo, confirmation: params[:confirmation_text])
|
|
72
|
+
|
|
58
73
|
target_version = params[:version]&.to_i
|
|
59
74
|
PgSqlTriggers::Migrator.ensure_migrations_table!
|
|
60
75
|
|
|
@@ -75,6 +90,9 @@ module PgSqlTriggers
|
|
|
75
90
|
flash[:success] = "Last migration redone successfully."
|
|
76
91
|
end
|
|
77
92
|
redirect_to root_path
|
|
93
|
+
rescue PgSqlTriggers::KillSwitchError => e
|
|
94
|
+
flash[:error] = e.message
|
|
95
|
+
redirect_to root_path
|
|
78
96
|
rescue StandardError => e
|
|
79
97
|
Rails.logger.error("Migration redo failed: #{e.message}\n#{e.backtrace.join("\n")}")
|
|
80
98
|
flash[:error] = "Failed to redo migration: #{e.message}"
|
|
@@ -24,7 +24,16 @@ module PgSqlTriggers
|
|
|
24
24
|
PgSqlTriggers::Drift.detect(trigger_name)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def enable!
|
|
27
|
+
def enable!(confirmation: nil)
|
|
28
|
+
# Check kill switch before enabling trigger
|
|
29
|
+
# Use Rails.env for kill switch check, not the trigger's environment field
|
|
30
|
+
PgSqlTriggers::SQL::KillSwitch.check!(
|
|
31
|
+
operation: :trigger_enable,
|
|
32
|
+
environment: Rails.env,
|
|
33
|
+
confirmation: confirmation,
|
|
34
|
+
actor: { type: "Console", id: "TriggerRegistry#enable!" }
|
|
35
|
+
)
|
|
36
|
+
|
|
28
37
|
# Check if trigger exists in database before trying to enable it
|
|
29
38
|
trigger_exists = false
|
|
30
39
|
begin
|
|
@@ -50,7 +59,16 @@ module PgSqlTriggers
|
|
|
50
59
|
update!(enabled: true)
|
|
51
60
|
end
|
|
52
61
|
|
|
53
|
-
def disable!
|
|
62
|
+
def disable!(confirmation: nil)
|
|
63
|
+
# Check kill switch before disabling trigger
|
|
64
|
+
# Use Rails.env for kill switch check, not the trigger's environment field
|
|
65
|
+
PgSqlTriggers::SQL::KillSwitch.check!(
|
|
66
|
+
operation: :trigger_disable,
|
|
67
|
+
environment: Rails.env,
|
|
68
|
+
confirmation: confirmation,
|
|
69
|
+
actor: { type: "Console", id: "TriggerRegistry#disable!" }
|
|
70
|
+
)
|
|
71
|
+
|
|
54
72
|
# Check if trigger exists in database before trying to disable it
|
|
55
73
|
trigger_exists = false
|
|
56
74
|
begin
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
</nav>
|
|
25
25
|
|
|
26
26
|
<main style="max-width: 1200px; margin: 2rem auto; padding: 0 1rem;">
|
|
27
|
+
<%= render 'pg_sql_triggers/shared/kill_switch_status' %>
|
|
28
|
+
|
|
27
29
|
<% if flash[:success] %>
|
|
28
30
|
<div style="background: #d4edda; color: #155724; padding: 1rem; margin-bottom: 1rem; border-radius: 4px; border-left: 4px solid #28a745;">
|
|
29
31
|
<%= flash[:success] %>
|
|
@@ -32,7 +34,38 @@
|
|
|
32
34
|
|
|
33
35
|
<% if flash[:error] %>
|
|
34
36
|
<div style="background: #f8d7da; color: #721c24; padding: 1rem; margin-bottom: 1rem; border-radius: 4px; border-left: 4px solid #dc3545;">
|
|
35
|
-
|
|
37
|
+
<% error_message = flash[:error].to_s %>
|
|
38
|
+
<% if error_message.include?("Kill switch is active") %>
|
|
39
|
+
<%# Format kill switch error messages nicely %>
|
|
40
|
+
<% lines = error_message.split("\n") %>
|
|
41
|
+
|
|
42
|
+
<%# Main error header with clear start %>
|
|
43
|
+
<div style="display: flex; align-items: flex-start; margin-bottom: 1rem; padding-bottom: 1rem; border-bottom: 2px solid #f5c6cb;">
|
|
44
|
+
<span style="font-size: 1.8em; margin-right: 0.75rem; line-height: 1.2;">⚠️</span>
|
|
45
|
+
<div style="flex: 1;">
|
|
46
|
+
<div style="font-weight: bold; font-size: 1.15em; margin-bottom: 0.5rem;">
|
|
47
|
+
Operation Blocked
|
|
48
|
+
</div>
|
|
49
|
+
<% lines[0..1].each do |line| %>
|
|
50
|
+
<% next if line.strip.empty? %>
|
|
51
|
+
<div style="margin: 0.25rem 0;"><%= line.strip %></div>
|
|
52
|
+
<% end %>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<%# Instructions section with preserved formatting %>
|
|
57
|
+
<div style="margin-top: 0.5rem;">
|
|
58
|
+
<%# Extract and format the instructions portion %>
|
|
59
|
+
<% instructions_start = error_message.index("To override") || 0 %>
|
|
60
|
+
<% instructions_text = error_message[instructions_start..-1] %>
|
|
61
|
+
<div style="white-space: pre-wrap; word-wrap: break-word; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; line-height: 1.6;">
|
|
62
|
+
<%= instructions_text.strip %>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
<% else %>
|
|
66
|
+
<%# Regular error message - preserve formatting %>
|
|
67
|
+
<div style="white-space: pre-wrap; word-wrap: break-word;"><%= error_message %></div>
|
|
68
|
+
<% end %>
|
|
36
69
|
</div>
|
|
37
70
|
<% end %>
|
|
38
71
|
|