rails_pulse 0.3.3 → 0.4.0.pre.2

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 (169) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -0
  3. data/README.md +44 -3
  4. data/app/assets/stylesheets/rails_pulse/application.css +21 -32
  5. data/app/assets/stylesheets/rails_pulse/components/backtrace.css +238 -0
  6. data/app/assets/stylesheets/rails_pulse/components/badge.css +32 -0
  7. data/app/assets/stylesheets/rails_pulse/components/button.css +2 -36
  8. data/app/assets/stylesheets/rails_pulse/components/card.css +8 -11
  9. data/app/assets/stylesheets/rails_pulse/components/chart.css +16 -3
  10. data/app/assets/stylesheets/rails_pulse/components/csp_safe_positioning.css +5 -39
  11. data/app/assets/stylesheets/rails_pulse/components/dashboard.css +0 -52
  12. data/app/assets/stylesheets/rails_pulse/components/deployments.css +39 -0
  13. data/app/assets/stylesheets/rails_pulse/components/dialog.css +0 -5
  14. data/app/assets/stylesheets/rails_pulse/components/input.css +0 -14
  15. data/app/assets/stylesheets/rails_pulse/components/layouts.css +0 -20
  16. data/app/assets/stylesheets/rails_pulse/components/menu.css +0 -16
  17. data/app/assets/stylesheets/rails_pulse/components/sidebar_menu.css +0 -16
  18. data/app/assets/stylesheets/rails_pulse/components/storage.css +187 -0
  19. data/app/assets/stylesheets/rails_pulse/components/tags.css +0 -14
  20. data/app/assets/stylesheets/rails_pulse/components/time_range_selector.css +5 -5
  21. data/app/assets/stylesheets/rails_pulse/components/utilities.css +0 -17
  22. data/app/controllers/concerns/chart_table_concern.rb +15 -3
  23. data/app/controllers/concerns/ransack_params_concern.rb +18 -0
  24. data/app/controllers/concerns/response_range_concern.rb +1 -1
  25. data/app/controllers/concerns/time_range_concern.rb +28 -14
  26. data/app/controllers/rails_pulse/application_controller.rb +104 -31
  27. data/app/controllers/rails_pulse/dashboard_controller.rb +9 -0
  28. data/app/controllers/rails_pulse/deployments_controller.rb +26 -5
  29. data/app/controllers/rails_pulse/exception_occurrences_controller.rb +19 -0
  30. data/app/controllers/rails_pulse/exceptions_controller.rb +119 -0
  31. data/app/controllers/rails_pulse/job_runs_controller.rb +1 -1
  32. data/app/controllers/rails_pulse/requests_controller.rb +1 -1
  33. data/app/controllers/rails_pulse/routes_controller.rb +7 -1
  34. data/app/controllers/rails_pulse/storage_controller.rb +7 -0
  35. data/app/controllers/rails_pulse/tags_controller.rb +2 -2
  36. data/app/helpers/rails_pulse/application_helper.rb +1 -0
  37. data/app/helpers/rails_pulse/backtrace_helper.rb +85 -0
  38. data/app/helpers/rails_pulse/breadcrumbs_helper.rb +4 -1
  39. data/app/helpers/rails_pulse/chart_helper.rb +0 -3
  40. data/app/helpers/rails_pulse/route_helper.rb +8 -16
  41. data/app/javascript/rails_pulse/application.js +29 -8
  42. data/app/javascript/rails_pulse/controllers/clipboard_controller.js +58 -0
  43. data/app/javascript/rails_pulse/controllers/index_controller.js +16 -10
  44. data/app/javascript/rails_pulse/controllers/pagination_controller.js +6 -2
  45. data/app/javascript/rails_pulse/controllers/popover_controller.js +4 -0
  46. data/app/models/concerns/rails_pulse/taggable.rb +11 -6
  47. data/app/models/rails_pulse/cards/base.rb +53 -0
  48. data/app/models/rails_pulse/dashboard/health_summary.rb +52 -0
  49. data/app/models/rails_pulse/dashboard/needs_attention.rb +73 -1
  50. data/app/models/rails_pulse/dashboard/storage_status.rb +490 -0
  51. data/app/models/rails_pulse/deployment.rb +47 -1
  52. data/app/models/rails_pulse/exception_group.rb +37 -0
  53. data/app/models/rails_pulse/exception_occurrence.rb +27 -0
  54. data/app/models/rails_pulse/exceptions/cards/exception_rate.rb +116 -0
  55. data/app/models/rails_pulse/exceptions/cards/open_groups.rb +49 -0
  56. data/app/models/rails_pulse/exceptions/cards/total_occurrences.rb +62 -0
  57. data/app/models/rails_pulse/exceptions/charts/occurrence_volume.rb +56 -0
  58. data/app/models/rails_pulse/exceptions/raw_data.rb +216 -0
  59. data/app/models/rails_pulse/jobs/cards/p95_duration.rb +8 -2
  60. data/app/models/rails_pulse/operation.rb +13 -4
  61. data/app/models/rails_pulse/queries/cards/percentile_query_times.rb +8 -3
  62. data/app/models/rails_pulse/request.rb +5 -1
  63. data/app/models/rails_pulse/route.rb +71 -21
  64. data/app/models/rails_pulse/routes/cards/error_rates.rb +6 -3
  65. data/app/models/rails_pulse/routes/cards/percentile_response_times.rb +8 -3
  66. data/app/models/rails_pulse/routes/tables/index.rb +8 -6
  67. data/app/models/rails_pulse/summary.rb +21 -10
  68. data/app/models/rails_pulse/tables/base.rb +4 -2
  69. data/app/services/rails_pulse/analysis/explain_plan_analyzer.rb +47 -12
  70. data/app/services/rails_pulse/exception_capture_service.rb +228 -0
  71. data/app/services/rails_pulse/exception_message_sanitizer.rb +152 -0
  72. data/app/services/rails_pulse/operations/change_point.rb +144 -0
  73. data/app/services/rails_pulse/operations/compare.rb +92 -0
  74. data/app/services/rails_pulse/operations/comparison.rb +126 -0
  75. data/app/services/rails_pulse/operations/metric.rb +63 -0
  76. data/app/services/rails_pulse/operations/series.rb +84 -0
  77. data/app/services/rails_pulse/operations/subject.rb +77 -0
  78. data/app/services/rails_pulse/route_controller_action_backfiller.rb +110 -0
  79. data/app/services/rails_pulse/route_merger.rb +99 -0
  80. data/app/services/rails_pulse/route_migrator.rb +139 -0
  81. data/app/services/rails_pulse/route_path_normalizer.rb +79 -0
  82. data/app/services/rails_pulse/route_recognizer.rb +47 -0
  83. data/app/services/rails_pulse/summary_service.rb +45 -0
  84. data/app/services/rails_pulse/tag_filter_service.rb +5 -3
  85. data/app/views/layouts/rails_pulse/_menu_items.html.erb +7 -0
  86. data/app/views/layouts/rails_pulse/_onboarding_banner.html.erb +8 -0
  87. data/app/views/layouts/rails_pulse/_setup_screen.html.erb +5 -5
  88. data/app/views/layouts/rails_pulse/application.html.erb +4 -4
  89. data/app/views/rails_pulse/components/_empty_state.html.erb +1 -1
  90. data/app/views/rails_pulse/components/_panel.html.erb +16 -6
  91. data/app/views/rails_pulse/components/_raw_data.html.erb +34 -0
  92. data/app/views/rails_pulse/dashboard/_chart_panel.html.erb +6 -8
  93. data/app/views/rails_pulse/dashboard/_deployments_panel.html.erb +64 -0
  94. data/app/views/rails_pulse/dashboard/_health_badge.html.erb +21 -10
  95. data/app/views/rails_pulse/dashboard/_storage_panel.html.erb +67 -0
  96. data/app/views/rails_pulse/dashboard/index.html.erb +22 -1
  97. data/app/views/rails_pulse/deployments/_status_badge.html.erb +5 -0
  98. data/app/views/rails_pulse/deployments/_table.html.erb +29 -0
  99. data/app/views/rails_pulse/deployments/index.html.erb +15 -0
  100. data/app/views/rails_pulse/deployments/show.html.erb +62 -0
  101. data/app/views/rails_pulse/exception_occurrences/show.html.erb +45 -0
  102. data/app/views/rails_pulse/exceptions/_backtrace.html.erb +33 -0
  103. data/app/views/rails_pulse/exceptions/_metric_cards.html.erb +6 -0
  104. data/app/views/rails_pulse/exceptions/_occurrences_table.html.erb +23 -0
  105. data/app/views/rails_pulse/exceptions/_status_badge.html.erb +6 -0
  106. data/app/views/rails_pulse/exceptions/_table.html.erb +33 -0
  107. data/app/views/rails_pulse/exceptions/index.html.erb +66 -0
  108. data/app/views/rails_pulse/exceptions/show.html.erb +52 -0
  109. data/app/views/rails_pulse/queries/_raw_data.html.erb +1 -23
  110. data/app/views/rails_pulse/requests/_table.html.erb +1 -1
  111. data/app/views/rails_pulse/routes/_requests_table.html.erb +5 -0
  112. data/app/views/rails_pulse/routes/_table.html.erb +22 -8
  113. data/app/views/rails_pulse/routes/index.html.erb +5 -1
  114. data/app/views/rails_pulse/routes/show.html.erb +5 -0
  115. data/app/views/rails_pulse/storage/show.html.erb +123 -0
  116. data/config/routes.rb +13 -4
  117. data/db/rails_pulse_migrate/20260506000001_create_rails_pulse_exceptions.rb +50 -0
  118. data/db/rails_pulse_migrate/20260507000001_add_actual_query_to_operations.rb +10 -5
  119. data/db/rails_pulse_migrate/20260610000001_add_controller_action_to_rails_pulse_routes.rb +8 -0
  120. data/db/rails_pulse_migrate/20260610000002_change_rails_pulse_routes_to_multi_verb_model.rb +185 -0
  121. data/db/rails_pulse_migrate/20260610000003_add_null_action_unique_index_to_routes.rb +32 -0
  122. data/db/rails_pulse_migrate/20260823000001_add_location_to_exception_groups.rb +12 -0
  123. data/db/rails_pulse_schema.rb +54 -6
  124. data/lib/generators/rails_pulse/base_methods.rb +2 -0
  125. data/lib/generators/rails_pulse/install_generator.rb +5 -0
  126. data/lib/generators/rails_pulse/schema_parser.rb +22 -2
  127. data/lib/generators/rails_pulse/templates/db/rails_pulse_schema.rb +54 -6
  128. data/lib/generators/rails_pulse/templates/migrations/upgrade_rails_pulse_tables.rb +1 -1
  129. data/lib/generators/rails_pulse/templates/rails_pulse.rb +157 -16
  130. data/lib/generators/rails_pulse/upgrade_generator.rb +166 -38
  131. data/lib/rails_pulse/cleanup_service.rb +110 -15
  132. data/lib/rails_pulse/configuration.rb +125 -6
  133. data/lib/rails_pulse/engine.rb +32 -17
  134. data/lib/rails_pulse/installers/config_updater.rb +202 -0
  135. data/lib/rails_pulse/job_run_collector.rb +43 -16
  136. data/lib/rails_pulse/middleware/asset_server.rb +11 -0
  137. data/lib/rails_pulse/middleware/request_collector.rb +9 -4
  138. data/lib/rails_pulse/packaged_assets.rb +147 -0
  139. data/lib/rails_pulse/route_indexes.rb +66 -0
  140. data/lib/rails_pulse/subscribers/exception_subscriber.rb +36 -0
  141. data/lib/rails_pulse/tracker.rb +29 -10
  142. data/lib/rails_pulse/version.rb +1 -1
  143. data/lib/rails_pulse.rb +1 -0
  144. data/lib/rails_pulse_server.ru +16 -47
  145. data/lib/tasks/rails_pulse.rake +83 -4
  146. data/lib/tasks/rails_pulse_assets.rake +15 -0
  147. data/lib/tasks/rails_pulse_tasks.rake +29 -0
  148. data/public/rails-pulse-assets/rails-pulse-icons.js +6 -2
  149. data/public/rails-pulse-assets/rails-pulse.css +1 -1
  150. data/public/rails-pulse-assets/rails-pulse.js +18 -117
  151. metadata +78 -37
  152. data/Rakefile +0 -554
  153. data/app/javascript/rails_pulse/controllers/form_controller.js +0 -39
  154. data/app/javascript/rails_pulse/controllers/period_selector_controller.js +0 -19
  155. data/app/javascript/rails_pulse/controllers/timezone_controller.js +0 -89
  156. data/app/javascript/rails_pulse/theme.js +0 -416
  157. data/config/brakeman.ignore +0 -190
  158. data/config/brakeman.yml +0 -68
  159. data/config/initializers/rails_pulse.rb +0 -287
  160. data/public/rails-pulse-assets/csp-test.js +0 -120
  161. data/public/rails-pulse-assets/rails-pulse-icons.js.map +0 -13
  162. data/public/rails-pulse-assets/rails-pulse.css.map +0 -1
  163. data/public/rails-pulse-assets/rails-pulse.js.map +0 -7
  164. data/vendor/assets/javascripts/rails-pulse-icons.js +0 -93
  165. data/vendor/assets/javascripts/rails-pulse-icons.js.map +0 -13
  166. data/vendor/assets/javascripts/rails-pulse.js +0 -157
  167. data/vendor/assets/javascripts/rails-pulse.js.map +0 -7
  168. data/vendor/assets/stylesheets/rails-pulse.css +0 -1
  169. data/vendor/assets/stylesheets/rails-pulse.css.map +0 -1
@@ -1,416 +0,0 @@
1
-
2
- (function (root, factory) {
3
- if (typeof define === 'function' && define.amd) {
4
- // AMD. Register as an anonymous module.
5
- define(['exports', 'echarts'], factory);
6
- } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
7
- // CommonJS
8
- factory(exports, require('echarts'));
9
- } else {
10
- // Browser globals
11
- factory({}, root.echarts);
12
- }
13
- }(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this, function (exports, echarts) {
14
- var log = function (msg) {
15
- if (typeof console !== 'undefined') {
16
- console && console.error && console.error(msg);
17
- }
18
- };
19
- if (!echarts) {
20
- log('ECharts is not Loaded');
21
- return;
22
- }
23
- echarts.registerTheme('railspulse', {
24
- "color": [
25
- "#ffc91f",
26
- "#ffde66",
27
- "#fbedbf",
28
- "#ffc91f",
29
- "#ffc91f",
30
- "#ffc91f"
31
- ],
32
- "backgroundColor": "rgba(255,255,255,0)",
33
- "textStyle": {},
34
- "title": {
35
- "textStyle": {
36
- "color": "#666666"
37
- },
38
- "subtextStyle": {
39
- "color": "#999999"
40
- }
41
- },
42
- "line": {
43
- "itemStyle": {
44
- "borderWidth": "2"
45
- },
46
- "lineStyle": {
47
- "width": "3"
48
- },
49
- "symbolSize": "8",
50
- "symbol": "emptyCircle",
51
- "smooth": false
52
- },
53
- "radar": {
54
- "itemStyle": {
55
- "borderWidth": "2"
56
- },
57
- "lineStyle": {
58
- "width": "3"
59
- },
60
- "symbolSize": "8",
61
- "symbol": "emptyCircle",
62
- "smooth": false
63
- },
64
- "bar": {
65
- "itemStyle": {
66
- "barBorderWidth": 0,
67
- "barBorderColor": "#ccc"
68
- }
69
- },
70
- "pie": {
71
- "itemStyle": {
72
- "borderWidth": 0,
73
- "borderColor": "#ccc"
74
- }
75
- },
76
- "scatter": {
77
- "itemStyle": {
78
- "borderWidth": 0,
79
- "borderColor": "#ccc"
80
- }
81
- },
82
- "boxplot": {
83
- "itemStyle": {
84
- "borderWidth": 0,
85
- "borderColor": "#ccc"
86
- }
87
- },
88
- "parallel": {
89
- "itemStyle": {
90
- "borderWidth": 0,
91
- "borderColor": "#ccc"
92
- }
93
- },
94
- "sankey": {
95
- "itemStyle": {
96
- "borderWidth": 0,
97
- "borderColor": "#ccc"
98
- }
99
- },
100
- "funnel": {
101
- "itemStyle": {
102
- "borderWidth": 0,
103
- "borderColor": "#ccc"
104
- }
105
- },
106
- "gauge": {
107
- "itemStyle": {
108
- "borderWidth": 0,
109
- "borderColor": "#ccc"
110
- }
111
- },
112
- "candlestick": {
113
- "itemStyle": {
114
- "color": "#ffc91f",
115
- "color0": "transparent",
116
- "borderColor": "#ffc91f",
117
- "borderColor0": "#ffc91f",
118
- "borderWidth": "1"
119
- }
120
- },
121
- "graph": {
122
- "itemStyle": {
123
- "borderWidth": 0,
124
- "borderColor": "#ccc"
125
- },
126
- "lineStyle": {
127
- "width": "1",
128
- "color": "#cccccc"
129
- },
130
- "symbolSize": "8",
131
- "symbol": "emptyCircle",
132
- "smooth": false,
133
- "color": [
134
- "#ffc91f",
135
- "#ffde66",
136
- "#fbedbf",
137
- "#ffc91f",
138
- "#ffc91f",
139
- "#ffc91f"
140
- ],
141
- "label": {
142
- "color": "#ffffff"
143
- }
144
- },
145
- "map": {
146
- "itemStyle": {
147
- "areaColor": "#eeeeee",
148
- "borderColor": "#999999",
149
- "borderWidth": 0.5
150
- },
151
- "label": {
152
- "color": "#28544e"
153
- },
154
- "emphasis": {
155
- "itemStyle": {
156
- "areaColor": "rgba(34,195,170,0.25)",
157
- "borderColor": "#22c3aa",
158
- "borderWidth": 1
159
- },
160
- "label": {
161
- "color": "#349e8e"
162
- }
163
- }
164
- },
165
- "geo": {
166
- "itemStyle": {
167
- "areaColor": "#eeeeee",
168
- "borderColor": "#999999",
169
- "borderWidth": 0.5
170
- },
171
- "label": {
172
- "color": "#28544e"
173
- },
174
- "emphasis": {
175
- "itemStyle": {
176
- "areaColor": "rgba(34,195,170,0.25)",
177
- "borderColor": "#22c3aa",
178
- "borderWidth": 1
179
- },
180
- "label": {
181
- "color": "#349e8e"
182
- }
183
- }
184
- },
185
- "categoryAxis": {
186
- "axisLine": {
187
- "show": true,
188
- "lineStyle": {
189
- "color": "#cccccc"
190
- }
191
- },
192
- "axisTick": {
193
- "show": false,
194
- "lineStyle": {
195
- "color": "#333"
196
- }
197
- },
198
- "axisLabel": {
199
- "show": true,
200
- "color": "#999999"
201
- },
202
- "splitLine": {
203
- "show": true,
204
- "lineStyle": {
205
- "color": [
206
- "#eeeeee"
207
- ]
208
- }
209
- },
210
- "splitArea": {
211
- "show": false,
212
- "areaStyle": {
213
- "color": [
214
- "rgba(250,250,250,0.05)",
215
- "rgba(200,200,200,0.02)"
216
- ]
217
- }
218
- }
219
- },
220
- "valueAxis": {
221
- "axisLine": {
222
- "show": true,
223
- "lineStyle": {
224
- "color": "#cccccc"
225
- }
226
- },
227
- "axisTick": {
228
- "show": false,
229
- "lineStyle": {
230
- "color": "#333"
231
- }
232
- },
233
- "axisLabel": {
234
- "show": true,
235
- "color": "#999999"
236
- },
237
- "splitLine": {
238
- "show": true,
239
- "lineStyle": {
240
- "color": [
241
- "#eeeeee"
242
- ]
243
- }
244
- },
245
- "splitArea": {
246
- "show": false,
247
- "areaStyle": {
248
- "color": [
249
- "rgba(250,250,250,0.05)",
250
- "rgba(200,200,200,0.02)"
251
- ]
252
- }
253
- }
254
- },
255
- "logAxis": {
256
- "axisLine": {
257
- "show": true,
258
- "lineStyle": {
259
- "color": "#cccccc"
260
- }
261
- },
262
- "axisTick": {
263
- "show": false,
264
- "lineStyle": {
265
- "color": "#333"
266
- }
267
- },
268
- "axisLabel": {
269
- "show": true,
270
- "color": "#999999"
271
- },
272
- "splitLine": {
273
- "show": true,
274
- "lineStyle": {
275
- "color": [
276
- "#eeeeee"
277
- ]
278
- }
279
- },
280
- "splitArea": {
281
- "show": false,
282
- "areaStyle": {
283
- "color": [
284
- "rgba(250,250,250,0.05)",
285
- "rgba(200,200,200,0.02)"
286
- ]
287
- }
288
- }
289
- },
290
- "timeAxis": {
291
- "axisLine": {
292
- "show": true,
293
- "lineStyle": {
294
- "color": "#cccccc"
295
- }
296
- },
297
- "axisTick": {
298
- "show": false,
299
- "lineStyle": {
300
- "color": "#333"
301
- }
302
- },
303
- "axisLabel": {
304
- "show": true,
305
- "color": "#999999"
306
- },
307
- "splitLine": {
308
- "show": true,
309
- "lineStyle": {
310
- "color": [
311
- "#eeeeee"
312
- ]
313
- }
314
- },
315
- "splitArea": {
316
- "show": false,
317
- "areaStyle": {
318
- "color": [
319
- "rgba(250,250,250,0.05)",
320
- "rgba(200,200,200,0.02)"
321
- ]
322
- }
323
- }
324
- },
325
- "toolbox": {
326
- "iconStyle": {
327
- "borderColor": "#999999"
328
- },
329
- "emphasis": {
330
- "iconStyle": {
331
- "borderColor": "#666666"
332
- }
333
- }
334
- },
335
- "legend": {
336
- "textStyle": {
337
- "color": "#999999"
338
- }
339
- },
340
- "tooltip": {
341
- "axisPointer": {
342
- "lineStyle": {
343
- "color": "#cccccc",
344
- "width": 1
345
- },
346
- "crossStyle": {
347
- "color": "#cccccc",
348
- "width": 1
349
- }
350
- }
351
- },
352
- "timeline": {
353
- "lineStyle": {
354
- "color": "#ffc91f",
355
- "width": 1
356
- },
357
- "itemStyle": {
358
- "color": "#ffc91f",
359
- "borderWidth": 1
360
- },
361
- "controlStyle": {
362
- "color": "#ffc91f",
363
- "borderColor": "#ffc91f",
364
- "borderWidth": 0.5
365
- },
366
- "checkpointStyle": {
367
- "color": "#ffc91f",
368
- "borderColor": "#ffc91f"
369
- },
370
- "label": {
371
- "color": "#ffc91f"
372
- },
373
- "emphasis": {
374
- "itemStyle": {
375
- "color": "#ffc91f"
376
- },
377
- "controlStyle": {
378
- "color": "#ffc91f",
379
- "borderColor": "#ffc91f",
380
- "borderWidth": 0.5
381
- },
382
- "label": {
383
- "color": "#ffc91f"
384
- }
385
- }
386
- },
387
- "visualMap": {
388
- "color": [
389
- "#ffc91f",
390
- "#ffc91f",
391
- "#ffc91f"
392
- ]
393
- },
394
- "dataZoom": {
395
- "backgroundColor": "rgba(255,255,255,0)",
396
- "dataBackgroundColor": "rgba(222,222,222,1)",
397
- "fillerColor": "rgba(114,230,212,0.25)",
398
- "handleColor": "#cccccc",
399
- "handleSize": "100%",
400
- "textStyle": {
401
- "color": "#999999"
402
- }
403
- },
404
- "markPoint": {
405
- "label": {
406
- "color": "#ffffff"
407
- },
408
- "emphasis": {
409
- "label": {
410
- "color": "#ffffff"
411
- }
412
- }
413
- }
414
- });
415
- }));
416
-
@@ -1,190 +0,0 @@
1
- {
2
- "ignored_warnings": [
3
- {
4
- "warning_type": "SQL Injection",
5
- "warning_code": 0,
6
- "fingerprint": "3d4cff0f317df7445891a1fc467912f3ad09e869da9b3e8433d5897354f5d849",
7
- "check_name": "SQL",
8
- "message": "Possible SQL injection",
9
- "file": "app/models/rails_pulse/request.rb",
10
- "line": 40,
11
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
12
- "code": "Arel.sql(\"FLOOR(#{parent.table[:status].name} / 100)\")",
13
- "render_path": null,
14
- "location": {
15
- "type": "method",
16
- "class": "Request",
17
- "method": null
18
- },
19
- "user_input": "parent.table[:status].name",
20
- "confidence": "Medium",
21
- "cwe_id": [
22
- 89
23
- ],
24
- "note": "Reviewed: Using Arel.sql with column name from ActiveRecord table definition - safe, not user input"
25
- },
26
- {
27
- "warning_type": "SQL Injection",
28
- "warning_code": 0,
29
- "fingerprint": "dc13170579f824326ffcaf309858f90fc807c7bdc4bfe41df3bb5d2b8f719a12",
30
- "check_name": "SQL",
31
- "message": "Possible SQL injection",
32
- "file": "app/models/rails_pulse/request.rb",
33
- "line": 54,
34
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
35
- "code": "Arel.sql with configuration thresholds",
36
- "render_path": null,
37
- "location": {
38
- "type": "method",
39
- "class": "Request",
40
- "method": null
41
- },
42
- "user_input": "((RailsPulse.configuration rescue nil).request_thresholds or { :slow => 500, :very_slow => 1000, :critical => 2000 })[:slow]",
43
- "confidence": "Medium",
44
- "cwe_id": [
45
- 89
46
- ],
47
- "note": "Reviewed: Using Arel.sql with configuration values from RailsPulse.configuration - safe, not user input"
48
- },
49
- {
50
- "warning_type": "SQL Injection",
51
- "warning_code": 0,
52
- "fingerprint": "3c816cd9f565d6592595f5566cbd9d9a19ecb51ad704477f01a9bf2b4c1f29fb",
53
- "check_name": "SQL",
54
- "message": "Possible SQL injection",
55
- "file": "app/services/rails_pulse/analysis/explain_plan_analyzer.rb",
56
- "line": 191,
57
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
58
- "code": "RailsPulse::ApplicationRecord.connection.execute(\"EXPLAIN (ANALYZE, BUFFERS) #{sql}\")",
59
- "render_path": null,
60
- "location": {
61
- "type": "method",
62
- "class": "RailsPulse::Analysis::ExplainPlanAnalyzer",
63
- "method": "execute_postgres_explain"
64
- },
65
- "user_input": "sql",
66
- "confidence": "Medium",
67
- "cwe_id": [
68
- 89
69
- ],
70
- "note": "Reviewed: SQL comes from Rails' ActiveRecord instrumentation (payload[:sql]), not user input. This is internally-generated SQL that Rails has already executed safely. EXPLAIN is read-only."
71
- },
72
- {
73
- "warning_type": "SQL Injection",
74
- "warning_code": 0,
75
- "fingerprint": "a57a1c949d21de15d6b48e52bfc3077e3177a13ba1d703ddf48e241fb4e81c6e",
76
- "check_name": "SQL",
77
- "message": "Possible SQL injection",
78
- "file": "app/services/rails_pulse/analysis/explain_plan_analyzer.rb",
79
- "line": 196,
80
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
81
- "code": "RailsPulse::ApplicationRecord.connection.execute(\"EXPLAIN #{sql}\")",
82
- "render_path": null,
83
- "location": {
84
- "type": "method",
85
- "class": "RailsPulse::Analysis::ExplainPlanAnalyzer",
86
- "method": "execute_mysql_explain"
87
- },
88
- "user_input": "sql",
89
- "confidence": "Medium",
90
- "cwe_id": [
91
- 89
92
- ],
93
- "note": "Reviewed: SQL comes from Rails' ActiveRecord instrumentation (payload[:sql]), not user input. This is internally-generated SQL that Rails has already executed safely. EXPLAIN is read-only."
94
- },
95
- {
96
- "warning_type": "SQL Injection",
97
- "warning_code": 0,
98
- "fingerprint": "85c09ca9672d132fb206d0371e20087deaf381d89733f73d647129878b89f374",
99
- "check_name": "SQL",
100
- "message": "Possible SQL injection",
101
- "file": "app/services/rails_pulse/analysis/explain_plan_analyzer.rb",
102
- "line": 201,
103
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
104
- "code": "RailsPulse::ApplicationRecord.connection.execute(\"EXPLAIN QUERY PLAN #{sql}\")",
105
- "render_path": null,
106
- "location": {
107
- "type": "method",
108
- "class": "RailsPulse::Analysis::ExplainPlanAnalyzer",
109
- "method": "execute_sqlite_explain"
110
- },
111
- "user_input": "sql",
112
- "confidence": "Medium",
113
- "cwe_id": [
114
- 89
115
- ],
116
- "note": "Reviewed: SQL comes from Rails' ActiveRecord instrumentation (payload[:sql]), not user input. This is internally-generated SQL that Rails has already executed safely. EXPLAIN is read-only."
117
- },
118
- {
119
- "warning_type": "SQL Injection",
120
- "warning_code": 0,
121
- "fingerprint": "520c23ea14761b7f1c085eb07168e7b32c13ebc910c0cc8c261ae8a2ff5ca85d",
122
- "check_name": "SQL",
123
- "message": "Possible SQL injection",
124
- "file": "app/models/rails_pulse/jobs/cards/failure_rate.rb",
125
- "line": 26,
126
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
127
- "code": "quote(current_window_start)",
128
- "render_path": null,
129
- "location": {
130
- "type": "method",
131
- "class": "RailsPulse::Jobs::Cards::FailureRate",
132
- "method": "to_metric_card"
133
- },
134
- "user_input": "quote(current_window_start)",
135
- "confidence": "Medium",
136
- "cwe_id": [
137
- 89
138
- ],
139
- "note": "Reviewed: connection.quote() with internally computed Time objects (current_window_start, range_start) - safe, not user input. Used in SELECT CASE expressions where ? placeholders are not supported."
140
- },
141
- {
142
- "warning_type": "SQL Injection",
143
- "warning_code": 0,
144
- "fingerprint": "ab6c9e686a8555f338323c53a8e77cf860a21a33220c6f1f049653d955f25570",
145
- "check_name": "SQL",
146
- "message": "Possible SQL injection",
147
- "file": "app/models/rails_pulse/jobs/cards/p95_duration.rb",
148
- "line": 26,
149
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
150
- "code": "quote(current_window_start)",
151
- "render_path": null,
152
- "location": {
153
- "type": "method",
154
- "class": "RailsPulse::Jobs::Cards::P95Duration",
155
- "method": "to_metric_card"
156
- },
157
- "user_input": "quote(current_window_start)",
158
- "confidence": "Medium",
159
- "cwe_id": [
160
- 89
161
- ],
162
- "note": "Reviewed: connection.quote() with internally computed Time objects (current_window_start, range_start) - safe, not user input. Used in SELECT CASE expressions where ? placeholders are not supported."
163
- },
164
- {
165
- "warning_type": "SQL Injection",
166
- "warning_code": 0,
167
- "fingerprint": "ba1379d027867507f1b72031ceb57527c7503797ff2fe357604e903f9fcfb819",
168
- "check_name": "SQL",
169
- "message": "Possible SQL injection",
170
- "file": "app/models/rails_pulse/jobs/cards/total_runs.rb",
171
- "line": 25,
172
- "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
173
- "code": "quote(current_window_start)",
174
- "render_path": null,
175
- "location": {
176
- "type": "method",
177
- "class": "RailsPulse::Jobs::Cards::TotalRuns",
178
- "method": "to_metric_card"
179
- },
180
- "user_input": "quote(current_window_start)",
181
- "confidence": "Medium",
182
- "cwe_id": [
183
- 89
184
- ],
185
- "note": "Reviewed: connection.quote() with internally computed Time objects (current_window_start, range_start) - safe, not user input. Used in SELECT CASE expressions where ? placeholders are not supported."
186
- }
187
- ],
188
- "updated": "2026-04-14 21:59:41 +0700",
189
- "brakeman_version": "7.1.1"
190
- }
data/config/brakeman.yml DELETED
@@ -1,68 +0,0 @@
1
- ---
2
- # Brakeman configuration file for Rails Pulse Engine
3
- # https://brakemanscanner.org/docs/options/
4
-
5
- # Application path - scan the engine files
6
- :app_path: "."
7
-
8
- # This is a Rails engine, not a standalone app
9
- :engine_paths:
10
- - app
11
- - lib
12
-
13
- # Rails version - let Brakeman detect automatically from gemspec
14
- :rails7: true
15
-
16
- # Output format for reports (can be: text, json, html, csv, tabs, markdown)
17
- :output_format: :text
18
-
19
- # Paths to skip - don't scan dummy app or test files
20
- :skip_files:
21
- - test/dummy/**/*
22
- - node_modules/**/*
23
- - vendor/**/*
24
- - gemfiles/**/*
25
-
26
- # Paths to ignore - additional paths to skip
27
- :ignore_paths:
28
- - test/**/*
29
- - tmp/**/*
30
- - log/**/*
31
- - vendor/**/*
32
- - node_modules/**/*
33
- - public/**/*
34
- - gemfiles/**/*
35
-
36
- # Confidence levels: 0 = high only, 1 = high and medium, 2 = all
37
- :min_confidence: 1 # Report high and medium confidence warnings only
38
-
39
- # Exit code configuration
40
- :exit_on_warn: true # Exit with error code if warnings found
41
- :exit_on_error: true # Exit with error code if errors found
42
-
43
- # Interactive mode
44
- :interactive: false
45
-
46
- # Parallelization
47
- :parallel_checks: true
48
-
49
- # Report additional information
50
- :report_progress: true
51
- :highlight_user_input: true
52
- :message_limit: 100 # Maximum number of warnings to report per type
53
-
54
- # Ignore file for specific false positives
55
- :ignore_file: config/brakeman.ignore
56
-
57
- # Additional options
58
- :absolute_paths: false # Use relative paths in reports
59
- :summary_only: false # Show full details, not just summary
60
-
61
- # Engine-specific: Skip checks that don't apply to mountable engines
62
- # These checks are more relevant for standalone apps
63
- :skip_checks:
64
- # Skip checks that are handled by the host application
65
- - CheckForgerySetting # CSRF protection is handled by host app
66
-
67
- # Note: We're NOT skipping SQL injection checks - those should be reviewed
68
- # Note: We're NOT skipping file access checks - those should be reviewed