rails_vitals 0.6.2 → 0.6.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c655986f52ddc0e0848b8e67c28d603ccea2a97dc6b85d9157a7a670fd298fc6
4
- data.tar.gz: 49bbb1b8fc0041bd75edb7d3d990ed517dcd907f64b7f99af95eb2d33dbdee80
3
+ metadata.gz: 7fb9a7c51b933da864e0f8ce0cfce6b0035cd1b47d90bf438115338cdb64cba2
4
+ data.tar.gz: c0a6a58e6ca56c35708a5132a9352fed34552d8a3ae33fc7033c7604b7fa6cf2
5
5
  SHA512:
6
- metadata.gz: 7e905ff8aa217f398c7521b677c088f637b5483cd153af51db1453fbee560476d32b230a3a9d432d975910f60fd9992cd4368a79b6be07abb4a6f676cff5c866
7
- data.tar.gz: fcd80c62bc58c1adfed045eb3764f29918705d6b9e0952af68f0f2601197f3af5079ca5abbe62aa6361c950b188711102f96ba3e36b28fa2766138b1fb69ce1d
6
+ metadata.gz: f5d40cc9d798c5c5fa4f2a02d173ff8c9991b273c66e50a81e201b987b46d5ac642a9b1e64d2e578c2055ce29b69abacfa373eb8b7bab4d22e4d6dc5966804d7
7
+ data.tar.gz: 717c9ca8d3d1f6561325635be1df4c53bd1c758295b95f29150b022dc8ab81c219abb6c49762f090b5a74b0f9c3b37b91f97f57be33867fb3c4a3555f76a7491
@@ -13,8 +13,8 @@ module RailsVitals
13
13
  true
14
14
  when :basic
15
15
  authenticate_or_request_with_http_basic("RailsVitals") do |username, password|
16
- username == RailsVitals.config.basic_auth_username &&
17
- password == RailsVitals.config.basic_auth_password
16
+ ActiveSupport::SecurityUtils.secure_compare(username, RailsVitals.config.basic_auth_username.to_s) &
17
+ ActiveSupport::SecurityUtils.secure_compare(password, RailsVitals.config.basic_auth_password.to_s)
18
18
  end
19
19
  when Proc
20
20
  unless auth.call(self)
@@ -13,11 +13,12 @@ module RailsVitals
13
13
  private
14
14
 
15
15
  def verify_environment
16
- if Rails.env.production?
16
+ unless RailsVitals.config.permitted_environment?
17
17
  render json: ResponseBuilder.error(
18
18
  nil,
19
19
  ResponseBuilder::AUTH_ERROR,
20
- "RailsVitals MCP is not available in production"
20
+ "RailsVitals MCP is not available in this environment. " \
21
+ "Permitted: #{RailsVitals::Configuration::PERMITTED_ENVIRONMENTS.join(', ')}"
21
22
  ), status: :forbidden
22
23
  end
23
24
  end
@@ -10,6 +10,26 @@ module RailsVitals
10
10
  def create
11
11
  expression = params[:expression].to_s.strip
12
12
  clean_expr = clean_expression(expression)
13
+
14
+ unless params[:confirmed] == "1"
15
+ @expression = clean_expr
16
+ @result = Playground::Sandbox::Result.new(
17
+ error: "Please confirm that you understand this runs real queries",
18
+ queries: [], query_count: 0, duration_ms: 0,
19
+ model_name: nil, record_count: 0, score: nil, n1_patterns: []
20
+ )
21
+ model_name = Playground::Sandbox.extract_model_name(clean_expr)
22
+ if model_name
23
+ @available_assocs = associations_for_model(model_name)
24
+ @prechecked_assocs = Array(params[:access_associations]).reject(&:blank?)
25
+ else
26
+ build_index_data
27
+ end
28
+
29
+ render :index
30
+ return
31
+ end
32
+
13
33
  access_associations = Array(params[:access_associations]).reject(&:blank?)
14
34
 
15
35
  result = Playground::Sandbox.run(
@@ -17,7 +37,7 @@ module RailsVitals
17
37
  access_associations: access_associations
18
38
  )
19
39
 
20
- model_name = Playground::Sandbox.extract_model_name(expression)
40
+ model_name = Playground::Sandbox.extract_model_name(clean_expr)
21
41
  @available_assocs = associations_for_model(model_name)
22
42
  @prechecked_assocs = access_associations
23
43
 
@@ -116,5 +136,12 @@ module RailsVitals
116
136
  }
117
137
  end
118
138
  end
139
+
140
+ def build_index_data
141
+ @default_query = default_query
142
+ @default_model = default_model_name
143
+ @available_assocs = associations_for_model(@default_model)
144
+ @prechecked_assocs = prechecked_associations
145
+ end
119
146
  end
120
147
  end
@@ -57,6 +57,18 @@
57
57
  Queries run against real data with a 100-record cap and 2s timeout.
58
58
  </div>
59
59
 
60
+ <label class="flex items-center gap-8 mb-16" style="cursor:pointer;font-size:13px;color:#a0aec0;">
61
+ <% if params[:confirmed] %>
62
+ <input type="checkbox" name="confirmed" value="1"
63
+ style="accent-color:#68d391;width:16px;height:16px;"
64
+ checked>
65
+ <% else %>
66
+ <input type="checkbox" name="confirmed" value="1"
67
+ style="accent-color:#68d391;width:16px;height:16px;">
68
+ <% end %>
69
+ I understand this runs real queries against my database
70
+ </label>
71
+
60
72
  <button type="submit" class="run-btn" id="run-btn">▶ Run</button>
61
73
  <% end %>
62
74
  </div>
@@ -1,8 +1,6 @@
1
1
  module RailsVitals
2
2
  module Analyzers
3
3
  class ExplainAnalyzer
4
- SUPPORTED_ENVIRONMENTS = %w[development test].freeze
5
-
6
4
  COLOR_DANGER = "#fc8181"
7
5
  COLOR_HEALTHY = "#68d391"
8
6
  COLOR_WARNING = "#f6ad55"
@@ -225,7 +223,7 @@ module RailsVitals
225
223
  private
226
224
 
227
225
  def self.supported_environment?
228
- SUPPORTED_ENVIRONMENTS.include?(Rails.env.to_s)
226
+ RailsVitals.config&.permitted_environment? || false
229
227
  end
230
228
 
231
229
  def self.select_query?(sql)
@@ -393,7 +391,8 @@ module RailsVitals
393
391
 
394
392
  def self.unsupported_env
395
393
  Result.new(
396
- error: "EXPLAIN is only available in development and test environments.",
394
+ error: "EXPLAIN is only available in permitted environments: " \
395
+ "#{RailsVitals::Configuration::PERMITTED_ENVIRONMENTS.join(', ')}.",
397
396
  sql: nil, plan: nil, warnings: [], suggestions: [],
398
397
  total_cost: nil, actual_time_ms: nil, rows_examined: nil
399
398
  )
@@ -15,8 +15,10 @@ module RailsVitals
15
15
  :mcp_max_log_size,
16
16
  :mcp_slow_query_threshold_ms
17
17
 
18
+ PERMITTED_ENVIRONMENTS = %w[development test].freeze
19
+
18
20
  def initialize
19
- @enabled = defined?(Rails) && !Rails.env.production?
21
+ @enabled = defined?(Rails) && permitted_environment?
20
22
  @store_size = 200
21
23
  @store_enabled = true
22
24
  @auth = :none
@@ -33,5 +35,9 @@ module RailsVitals
33
35
  @mcp_max_log_size = 100
34
36
  @mcp_slow_query_threshold_ms = 100
35
37
  end
38
+
39
+ def permitted_environment?
40
+ PERMITTED_ENVIRONMENTS.include?(Rails.env.to_s)
41
+ end
36
42
  end
37
43
  end
@@ -16,7 +16,15 @@ module RailsVitals
16
16
 
17
17
  initializer "rails_vitals.mcp" do
18
18
  if RailsVitals.config.mcp_enabled
19
- raise "RailsVitals MCP cannot run in production" if Rails.env.production?
19
+ unless RailsVitals.config.permitted_environment?
20
+ raise "RailsVitals MCP cannot run in #{Rails.env} environment. " \
21
+ "Permitted: #{RailsVitals::Configuration::PERMITTED_ENVIRONMENTS.join(', ')}"
22
+ end
23
+
24
+ token = RailsVitals.config.mcp_auth_token
25
+ if token.blank? || token.length < 16
26
+ raise "RailsVitals MCP requires mcp_auth_token to be at least 16 characters"
27
+ end
20
28
 
21
29
  require "rails_vitals/mcp/auth"
22
30
  require "rails_vitals/mcp/response_builder"
@@ -4,7 +4,14 @@ module RailsVitals
4
4
  BLOCKED_PATTERNS = [
5
5
  /\b(insert|update|delete|destroy|drop|truncate|create|alter)\b/i,
6
6
  /\.save/i, /\.save!/i, /\.update/i, /\.delete/i,
7
- /\.destroy/i, /`/
7
+ /\.destroy/i, /`/,
8
+ /\.connection\b/i, /\.execute\b/i, /\.exec\b/i,
9
+ /\.send\b/i, /\.public_send\b/i, /\.__send__\b/i,
10
+ /\.send_data\b/i, /\.open\b/i,
11
+ /\.instance_eval\b/i, /\.class_eval\b/i, /\.module_eval\b/i,
12
+ /\.define_method\b/i, /\.method_missing\b/i,
13
+ /\bsystem\b/i, /\beval\b/i, /\bfork\b/i, /\bspawn\b/i,
14
+ /\bIO\b/i, /\bFile\b/i, /\bThread\b/i, /\bProcess\b/i
8
15
  ].freeze
9
16
 
10
17
  SAFE_EXPRESSION_PATTERN = /\A[a-zA-Z0-9_\.\s\(\),:\[\]{}'"!?=<>|&*+\-\/\\%]+\z/
@@ -1,3 +1,3 @@
1
1
  module RailsVitals
2
- VERSION = "0.6.2"
2
+ VERSION = "0.6.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_vitals
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Sanchez