Module: RailsConsoleAi::BuiltinGuards
- Defined in:
- lib/rails_console_ai/safety_guards.rb
Overview
Built-in guard: database write prevention
Works on all Rails versions (5+) and all database adapters.
Prepends a write-intercepting module once, controlled by a thread-local flag.
Defined Under Namespace
Modules: EngineCallBlocker, HttpBlocker, InProcessRequestBlocker, WriteBlocker
Class Method Summary
collapse
Class Method Details
.check_in_process_request!(http_method, path) ⇒ Object
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
|
# File 'lib/rails_console_ai/safety_guards.rb', line 390
def self.check_in_process_request!(http_method, path)
return unless Thread.current[:rails_console_ai_block_in_process_requests]
return if Thread.current[:rails_console_ai_bypass_guards]
key = path.to_s
guards = RailsConsoleAi.configuration.safety_guards
return if !key.empty? && guards.allowed?(:in_process_requests, key)
label = [http_method.to_s.upcase, key].reject(&:empty?).join(' ')
raise RailsConsoleAi::SafetyError.new(
"In-process HTTP request blocked (#{label.empty? ? 'app dispatch' : label}). " \
"Dispatching a request through the app's own middleware stack from this session " \
"can hang the process indefinitely, even for GET. Do not retry via another route " \
"or Rack — call the controller's underlying service or model code directly instead.",
guard: :in_process_requests,
blocked_key: key.empty? ? nil : key
)
end
|
.database_writes ⇒ Object
295
296
297
298
299
300
301
302
303
304
305
|
# File 'lib/rails_console_ai/safety_guards.rb', line 295
def self.database_writes
->(& block) {
ensure_write_blocker_installed!
Thread.current[:rails_console_ai_block_writes] = true
begin
block.call
ensure
Thread.current[:rails_console_ai_block_writes] = false
end
}
end
|
.ensure_http_blocker_installed! ⇒ Object
442
443
444
445
446
447
448
449
450
|
# File 'lib/rails_console_ai/safety_guards.rb', line 442
def self.ensure_http_blocker_installed!
return if @http_blocker_installed
require 'net/http'
unless Net::HTTP.ancestors.include?(HttpBlocker)
Net::HTTP.prepend(HttpBlocker)
end
@http_blocker_installed = true
end
|
.ensure_in_process_blocker_installed! ⇒ Object
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
|
# File 'lib/rails_console_ai/safety_guards.rb', line 422
def self.ensure_in_process_blocker_installed!
return if @in_process_blocker_installed
begin
require 'action_dispatch'
require 'action_dispatch/testing/integration'
rescue LoadError, NameError
nil end
if defined?(ActionDispatch::Integration::Session) &&
!ActionDispatch::Integration::Session.ancestors.include?(InProcessRequestBlocker)
ActionDispatch::Integration::Session.prepend(InProcessRequestBlocker)
end
if defined?(Rails::Engine) && !Rails::Engine.ancestors.include?(EngineCallBlocker)
Rails::Engine.prepend(EngineCallBlocker)
end
@in_process_blocker_installed = true
end
|
.ensure_write_blocker_installed! ⇒ Object
307
308
309
310
311
312
313
314
315
|
# File 'lib/rails_console_ai/safety_guards.rb', line 307
def self.ensure_write_blocker_installed!
return if @write_blocker_installed
connection = ActiveRecord::Base.connection
unless connection.class.ancestors.include?(WriteBlocker)
connection.class.prepend(WriteBlocker)
end
@write_blocker_installed = true
end
|
.http_mutations ⇒ Object
341
342
343
344
345
346
347
348
349
350
351
|
# File 'lib/rails_console_ai/safety_guards.rb', line 341
def self.http_mutations
->(&block) {
ensure_http_blocker_installed!
Thread.current[:rails_console_ai_block_http] = true
begin
block.call
ensure
Thread.current[:rails_console_ai_block_http] = false
end
}
end
|
.in_process_requests ⇒ Object
409
410
411
412
413
414
415
416
417
418
419
420
|
# File 'lib/rails_console_ai/safety_guards.rb', line 409
def self.in_process_requests
->(&block) {
ensure_in_process_blocker_installed!
prev = Thread.current[:rails_console_ai_block_in_process_requests]
Thread.current[:rails_console_ai_block_in_process_requests] = true
begin
block.call
ensure
Thread.current[:rails_console_ai_block_in_process_requests] = prev
end
}
end
|
.mailers ⇒ Object
353
354
355
356
357
358
359
360
361
362
363
364
365
|
# File 'lib/rails_console_ai/safety_guards.rb', line 353
def self.mailers
->(&block) {
return block.call if Thread.current[:rails_console_ai_bypass_guards]
old_value = ActionMailer::Base.perform_deliveries
ActionMailer::Base.perform_deliveries = false
begin
block.call
ensure
ActionMailer::Base.perform_deliveries = old_value
end
}
end
|