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 +4 -4
- data/app/controllers/rails_vitals/application_controller.rb +2 -2
- data/app/controllers/rails_vitals/mcp_controller.rb +3 -2
- data/app/controllers/rails_vitals/playgrounds_controller.rb +28 -1
- data/app/views/rails_vitals/playgrounds/index.html.erb +12 -0
- data/lib/rails_vitals/analyzers/explain_analyzer.rb +3 -4
- data/lib/rails_vitals/configuration.rb +7 -1
- data/lib/rails_vitals/engine.rb +9 -1
- data/lib/rails_vitals/playground/sandbox.rb +8 -1
- data/lib/rails_vitals/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7fb9a7c51b933da864e0f8ce0cfce6b0035cd1b47d90bf438115338cdb64cba2
|
|
4
|
+
data.tar.gz: c0a6a58e6ca56c35708a5132a9352fed34552d8a3ae33fc7033c7604b7fa6cf2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
17
|
-
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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) &&
|
|
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
|
data/lib/rails_vitals/engine.rb
CHANGED
|
@@ -16,7 +16,15 @@ module RailsVitals
|
|
|
16
16
|
|
|
17
17
|
initializer "rails_vitals.mcp" do
|
|
18
18
|
if RailsVitals.config.mcp_enabled
|
|
19
|
-
|
|
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/
|
data/lib/rails_vitals/version.rb
CHANGED