solidstats 0.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.
@@ -0,0 +1,26 @@
1
+ <%# filepath: /Users/mezbah/microstartup/infolily_organizer/gems/solidstats/app/views/solidstats/dashboard/_audit_summary.html.erb %>
2
+ <div class="audit-summary">
3
+ <div class="audit-summary-header">
4
+ <h3>Security Audit Summary</h3>
5
+ <% created_at = @audit_output.dig("created_at") %>
6
+ <span class="audit-date">Last updated: <%= created_at ? DateTime.parse(created_at).strftime("%B %d, %Y at %H:%M") : Time.now.strftime("%B %d, %Y at %H:%M") %></span>
7
+ </div>
8
+ <div class="audit-stats">
9
+ <div class="audit-stat">
10
+ <% results = @audit_output.dig("results") || [] %>
11
+ <% cve_count = results.map { |r| r.dig("advisory", "cve") }.compact.uniq.size %>
12
+ <span class="stat-value"><%= cve_count %></span>
13
+ <span class="stat-label">CVEs</span>
14
+ </div>
15
+ <div class="audit-stat">
16
+ <% gem_count = results.map { |r| r.dig("gem", "name") }.uniq.size %>
17
+ <span class="stat-value"><%= gem_count %></span>
18
+ <span class="stat-label">Affected Gems</span>
19
+ </div>
20
+ <div class="audit-stat">
21
+ <% high_severity = results.count { |r| %w[high critical].include?(r.dig("advisory", "criticality").to_s.downcase) } %>
22
+ <span class="stat-value"><%= high_severity %></span>
23
+ <span class="stat-label">High Severity</span>
24
+ </div>
25
+ </div>
26
+ </div>
@@ -0,0 +1,3 @@
1
+ <div class="no-vulnerabilities">
2
+ <p>✅ No vulnerabilities found in your dependencies.</p>
3
+ </div>
@@ -0,0 +1,37 @@
1
+ <div class="stat-card audit-card">
2
+ <h2><span class="icon">🔒</span> Security Audit</h2>
3
+ <div class="card-content">
4
+ <% results = @audit_output.dig("results") || [] %>
5
+ <% vulnerabilities_count = results.size %>
6
+ <% if vulnerabilities_count == 0 %>
7
+ <div class="status-badge success">All Clear</div>
8
+ <% else %>
9
+ <div class="status-badge warning"><%= vulnerabilities_count %> <%= "Vulnerability".pluralize(vulnerabilities_count) %> Found</div>
10
+ <% end %>
11
+
12
+ <div class="metrics-group">
13
+ <div class="metric">
14
+ <span class="metric-label">Affected Gems:</span>
15
+ <span class="metric-value"><%= results.map { |r| r.dig("gem", "name") }.uniq.size %></span>
16
+ </div>
17
+ <div class="metric">
18
+ <span class="metric-label">High Severity:</span>
19
+ <span class="metric-value"><%= results.count { |r| %w[high critical].include?(r.dig("advisory", "criticality").to_s.downcase) } %></span>
20
+ </div>
21
+ </div>
22
+
23
+ <a href="#" class="toggle-details" data-target="audit-details">Show Details</a>
24
+ </div>
25
+ <%= render 'solidstats/dashboard/audit/audit_details' %>
26
+ </div>
27
+
28
+ <% if Rails.env.development? %>
29
+ <!-- Debug info - hidden in production -->
30
+ <div style="margin-top: 20px; padding: 10px; border: 1px dashed #ccc; font-size: 12px; display: none;">
31
+ <h4>Debug Audit Data:</h4>
32
+ <p>Vulnerabilities count: <%= (@audit_output.dig("results") || []).size %></p>
33
+ <% if @audit_output.dig("results") %>
34
+ <p>First vulnerability gem: <%= @audit_output.dig("results", 0, "gem", "name") rescue "N/A" %></p>
35
+ <% end %>
36
+ </div>
37
+ <% end %>
@@ -0,0 +1,66 @@
1
+ <%# filepath: /Users/mezbah/microstartup/infolily_organizer/gems/solidstats/app/views/solidstats/audit/_vulnerabilities_table.html.erb %>
2
+ <div class="vulnerabilities-table">
3
+ <table class="table">
4
+ <thead>
5
+ <tr>
6
+ <th>Gem</th>
7
+ <th>Version</th>
8
+ <th>Criticality</th>
9
+ <th>CVE</th>
10
+ <th>Title</th>
11
+ <th>Solution</th>
12
+ </tr>
13
+ </thead>
14
+ <tbody>
15
+ <% results = @audit_output.dig("results") || [] %>
16
+ <% results.each_with_index do |result, index| %>
17
+ <%
18
+ gem = result.dig("gem") || {}
19
+ advisory = result.dig("advisory") || {}
20
+ criticality = advisory["criticality"] || "Unknown"
21
+ is_high = %w[high critical].include?(criticality.downcase)
22
+ %>
23
+ <tr class="vulnerability-row <%= is_high ? 'high-severity' : '' %>" data-index="<%= index %>">
24
+ <td><%= gem["name"] %></td>
25
+ <td><span class="version"><%= gem["version"] %></span></td>
26
+ <td>
27
+ <span class="severity <%= criticality.to_s.downcase %>">
28
+ <%= criticality %>
29
+ </span>
30
+ </td>
31
+ <td>
32
+ <% if advisory["cve"].present? %>
33
+ <a href="https://nvd.nist.gov/vuln/detail/CVE-<%= advisory["cve"] %>" target="_blank">
34
+ CVE-<%= advisory["cve"] %>
35
+ </a>
36
+ <% elsif advisory["ghsa"].present? %>
37
+ <a href="https://github.com/advisories/<%= advisory["ghsa"] %>" target="_blank">
38
+ GHSA-<%= advisory["ghsa"] %>
39
+ </a>
40
+ <% else %>
41
+ N/A
42
+ <% end %>
43
+ </td>
44
+ <td>
45
+ <%= advisory["title"] %>
46
+ <% if advisory["description"].present? %>
47
+ <a href="#vulnerability-<%= index %>" class="view-details-link">View details</a>
48
+ <% end %>
49
+ </td>
50
+ <td>
51
+ <div class="solution">
52
+ <% if advisory["patched_versions"].present? %>
53
+ <button class="copy-btn" data-solution="<%= "#{gem["name"]}, #{advisory["patched_versions"].join(", ")}" %>">
54
+ <span class="copy-icon">📋</span> Copy
55
+ </button>
56
+ <code><%= advisory["patched_versions"].join(", ") %></code>
57
+ <% else %>
58
+ <span class="no-patch">No patch available</span>
59
+ <% end %>
60
+ </div>
61
+ </td>
62
+ </tr>
63
+ <% end %>
64
+ </tbody>
65
+ </table>
66
+ </div>
@@ -0,0 +1,62 @@
1
+ <div class="vulnerabilities-details-section hidden">
2
+ <h3>
3
+ <span>Vulnerability Details</span>
4
+ <button class="toggle-details-btn" aria-expanded="false">Show Details</button>
5
+ </h3>
6
+ <%# TODO: Render Markdown in .erb using Redcarpet with sanitize for safe HTML output %>
7
+ <div class="md-container">
8
+ <% results.each_with_index do |result, index| %>
9
+ <%
10
+ gem = result.dig("gem") || {}
11
+ advisory = result.dig("advisory") || {}
12
+ criticality = advisory["criticality"] || "Unknown"
13
+ is_high = %w[high critical].include?(criticality.to_s.downcase)
14
+ %>
15
+ <% if advisory["description"].present? %>
16
+ <div id="vulnerability-<%= index %>" class="md-entry <%= is_high ? 'high-severity' : '' %>">
17
+ <h2 class="md-heading">
18
+ <%= gem["name"] %> <%= gem["version"] %> - <%= advisory["title"] %>
19
+ </h2>
20
+
21
+ <div class="md-metadata">
22
+ <% if advisory["cve"].present? %>
23
+ <div class="md-tag cve">CVE-<%= advisory["cve"] %></div>
24
+ <% elsif advisory["ghsa"].present? %>
25
+ <div class="md-tag ghsa">GHSA-<%= advisory["ghsa"] %></div>
26
+ <% end %>
27
+ <div class="md-tag severity <%= criticality.to_s.downcase %>"><%= criticality %></div>
28
+ <% if advisory["date"].present? %>
29
+ <div class="md-date"><%= advisory["date"] %></div>
30
+ <% end %>
31
+ </div>
32
+
33
+ <div class="md-divider"></div>
34
+
35
+ <div class="md-content">
36
+ <%= simple_format(advisory["description"]) %>
37
+ </div>
38
+
39
+ <% if advisory["patched_versions"].present? %>
40
+ <div class="md-code-block">
41
+ <div class="md-code-header">Patched Versions</div>
42
+ <pre class="md-code"><%= advisory["patched_versions"].join(", ") %></pre>
43
+ </div>
44
+ <% end %>
45
+
46
+ <% if advisory["url"].present? %>
47
+ <div class="md-link">
48
+ <span class="md-link-icon">🔗</span>
49
+ <a href="<%= advisory["url"] %>" target="_blank" rel="noopener">More information</a>
50
+ </div>
51
+ <% end %>
52
+
53
+ <div class="md-back">
54
+ <a href="#" class="back-to-top" onclick="window.scrollTo({top: document.querySelector('.vulnerabilities-table').offsetTop - 20, behavior: 'smooth'}); return false;">
55
+ ↑ Back to vulnerabilities table
56
+ </a>
57
+ </div>
58
+ </div>
59
+ <% end %>
60
+ <% end %>
61
+ </div>
62
+ </div>
@@ -0,0 +1,345 @@
1
+ <div class="solidstats-dashboard">
2
+ <header class="dashboard-header">
3
+ <h1><span class="icon">🚥</span> Solidstats Dashboard</h1>
4
+ <p class="dashboard-last-updated">Last updated: <%= Time.now.strftime("%B %d, %Y at %H:%M") %></p>
5
+ </header>
6
+
7
+ <div class="stats-cards">
8
+ <%= render 'solidstats/dashboard/audit/security_audit' %>
9
+
10
+ <div class="stat-card">
11
+ <h2><span class="icon">🧹</span> Code Quality</h2>
12
+ <div class="card-content">
13
+ <div class="metric">
14
+ <!-- Your code quality metrics -->
15
+ </div>
16
+ </div>
17
+ </div>
18
+
19
+ <div class="stat-card">
20
+ <h2><span class="icon">📝</span> Code Health</h2>
21
+ <div class="card-content">
22
+ <!-- Your code health metrics -->
23
+ </div>
24
+ </div>
25
+
26
+ <div class="stat-card <%= @coverage.to_f > 80 ? 'status-ok' : (@coverage.to_f > 60 ? 'status-warning' : 'status-danger') %>">
27
+ <h2><span class="icon">🧪</span> Test Coverage</h2>
28
+ <div class="card-content">
29
+ <div class="progress-container">
30
+ <div class="progress-bar" style="width: <%= @coverage %>%"></div>
31
+ </div>
32
+ <div class="metric">
33
+ <span class="metric-value"><%= @coverage %>%</span>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="dashboard-actions">
40
+ <a href="#" class="action-button" onclick="refreshAudit(); return false;">Refresh Security Audit</a>
41
+ <a href="#" class="action-button" onclick="exportReport(); return false;">Export Report</a>
42
+ </div>
43
+ </div>
44
+
45
+ <style>
46
+ /* Base styles for dashboard */
47
+ .solidstats-dashboard {
48
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
49
+ color: #333;
50
+ max-width: 1200px;
51
+ margin: 0 auto;
52
+ padding: 20px;
53
+ }
54
+
55
+ /* Header styles */
56
+ .dashboard-header {
57
+ margin-bottom: 2rem;
58
+ }
59
+
60
+ .dashboard-header h1 {
61
+ font-size: 1.8rem;
62
+ font-weight: 600;
63
+ margin: 0 0 0.5rem 0;
64
+ }
65
+
66
+ .dashboard-last-updated {
67
+ color: #666;
68
+ margin: 0;
69
+ font-size: 0.9rem;
70
+ }
71
+
72
+ /* Card grid layout */
73
+ .stats-cards {
74
+ display: grid;
75
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
76
+ gap: 1.5rem;
77
+ margin-bottom: 2rem;
78
+ }
79
+
80
+ /* Fix for audit card to span full width when details are shown */
81
+ .audit-card {
82
+ position: relative;
83
+ transition: all 0.3s ease;
84
+ }
85
+
86
+ .audit-card.expanded {
87
+ grid-column: 1 / -1;
88
+ width: 100%;
89
+ }
90
+
91
+ /* Card styles */
92
+ .stat-card {
93
+ background: #fff;
94
+ border-radius: 8px;
95
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
96
+ padding: 1.5rem;
97
+ overflow: visible;
98
+ }
99
+
100
+ .stat-card h2 {
101
+ font-size: 1.2rem;
102
+ font-weight: 600;
103
+ margin: 0 0 1rem 0;
104
+ display: flex;
105
+ align-items: center;
106
+ gap: 0.5rem;
107
+ }
108
+
109
+ .stat-card .icon {
110
+ font-size: 1.4rem;
111
+ }
112
+
113
+ /* Metrics styling */
114
+ .metric {
115
+ display: flex;
116
+ justify-content: space-between;
117
+ align-items: center;
118
+ margin-bottom: 0.75rem;
119
+ }
120
+
121
+ .metric-label {
122
+ color: #666;
123
+ font-size: 0.9rem;
124
+ }
125
+
126
+ .metric-value {
127
+ font-weight: 600;
128
+ font-size: 1.1rem;
129
+ }
130
+
131
+ /* Status badges */
132
+ .status-badge {
133
+ display: inline-block;
134
+ padding: 0.35rem 0.75rem;
135
+ border-radius: 20px;
136
+ font-size: 0.85rem;
137
+ font-weight: 500;
138
+ margin-bottom: 1rem;
139
+ }
140
+
141
+ .status-badge.success {
142
+ background-color: #d4edda;
143
+ color: #155724;
144
+ }
145
+
146
+ .status-badge.warning {
147
+ background-color: #fff3cd;
148
+ color: #856404;
149
+ }
150
+
151
+ .status-badge.danger {
152
+ background-color: #f8d7da;
153
+ color: #721c24;
154
+ }
155
+
156
+ /* Progress bar */
157
+ .progress-container {
158
+ width: 100%;
159
+ height: 8px;
160
+ background-color: #e9ecef;
161
+ border-radius: 4px;
162
+ overflow: hidden;
163
+ margin-bottom: 0.75rem;
164
+ }
165
+
166
+ .progress-bar {
167
+ height: 100%;
168
+ background-color: #28a745;
169
+ border-radius: 4px;
170
+ }
171
+
172
+ /* Status contextual colors */
173
+ .status-ok .progress-bar {
174
+ background-color: #28a745;
175
+ }
176
+
177
+ .status-warning .progress-bar {
178
+ background-color: #ffc107;
179
+ }
180
+
181
+ .status-danger .progress-bar {
182
+ background-color: #dc3545;
183
+ }
184
+
185
+ /* Details panel styling */
186
+ .details-panel {
187
+ background: #f9f9f9;
188
+ border-top: 1px solid #eaeaea;
189
+ padding: 1.5rem;
190
+ margin-top: 1.5rem;
191
+ border-radius: 0 0 8px 8px;
192
+ overflow: visible;
193
+ }
194
+
195
+ .details-panel.hidden {
196
+ display: none;
197
+ }
198
+
199
+ .details-panel:not(.hidden) {
200
+ display: block;
201
+ }
202
+
203
+ /* Toggle details button */
204
+ .toggle-details {
205
+ display: inline-block;
206
+ color: #007bff;
207
+ cursor: pointer;
208
+ font-size: 0.9rem;
209
+ text-decoration: none;
210
+ }
211
+
212
+ .toggle-details:hover {
213
+ text-decoration: underline;
214
+ }
215
+
216
+ /* Table styling for vulnerability list */
217
+ .vulnerabilities-table {
218
+ overflow-x: auto;
219
+ margin-top: 1rem;
220
+ }
221
+
222
+ .table {
223
+ width: 100%;
224
+ border-collapse: collapse;
225
+ font-size: 0.9rem;
226
+ }
227
+
228
+ .table th {
229
+ text-align: left;
230
+ padding: 0.75rem;
231
+ background-color: #f8f9fa;
232
+ border-bottom: 2px solid #dee2e6;
233
+ }
234
+
235
+ .table td {
236
+ padding: 0.75rem;
237
+ border-bottom: 1px solid #dee2e6;
238
+ vertical-align: middle;
239
+ }
240
+
241
+ /* Severity indicators */
242
+ .severity {
243
+ display: inline-block;
244
+ padding: 0.25rem 0.5rem;
245
+ border-radius: 4px;
246
+ font-size: 0.8rem;
247
+ font-weight: 500;
248
+ }
249
+
250
+ .severity.high, .severity.critical {
251
+ background-color: #f8d7da;
252
+ color: #721c24;
253
+ }
254
+
255
+ .severity.medium {
256
+ background-color: #fff3cd;
257
+ color: #856404;
258
+ }
259
+
260
+ .severity.low {
261
+ background-color: #d1ecf1;
262
+ color: #0c5460;
263
+ }
264
+
265
+ .severity.unknown {
266
+ background-color: #e9ecef;
267
+ color: #495057;
268
+ }
269
+
270
+ /* Dashboard actions */
271
+ .dashboard-actions {
272
+ display: flex;
273
+ gap: 1rem;
274
+ margin-top: 2rem;
275
+ }
276
+
277
+ .action-button {
278
+ display: inline-block;
279
+ padding: 0.5rem 1rem;
280
+ background-color: #007bff;
281
+ color: white;
282
+ text-decoration: none;
283
+ border-radius: 4px;
284
+ font-size: 0.9rem;
285
+ cursor: pointer;
286
+ transition: background-color 0.2s;
287
+ }
288
+
289
+ .action-button:hover {
290
+ background-color: #0069d9;
291
+ }
292
+
293
+ /* Responsive adjustments */
294
+ @media (max-width: 768px) {
295
+ .stats-cards {
296
+ grid-template-columns: 1fr;
297
+ }
298
+
299
+ .dashboard-actions {
300
+ flex-direction: column;
301
+ }
302
+
303
+ .action-button {
304
+ width: 100%;
305
+ text-align: center;
306
+ }
307
+ }
308
+ </style>
309
+
310
+ <script>
311
+ document.addEventListener('DOMContentLoaded', function() {
312
+ // Toggle details panels
313
+ document.querySelectorAll('.toggle-details').forEach(function(toggle) {
314
+ toggle.addEventListener('click', function(e) {
315
+ e.preventDefault();
316
+ const targetId = this.getAttribute('data-target');
317
+ const panel = document.getElementById(targetId);
318
+ const card = this.closest('.stat-card');
319
+
320
+ panel.classList.toggle('hidden');
321
+ card.classList.toggle('expanded');
322
+
323
+ this.textContent = panel.classList.contains('hidden') ? 'Show Details' : 'Hide Details';
324
+
325
+ // If showing details, scroll to it for better visibility
326
+ if (!panel.classList.contains('hidden')) {
327
+ setTimeout(() => {
328
+ panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
329
+ }, 100);
330
+ }
331
+ });
332
+ });
333
+ });
334
+
335
+ function refreshAudit() {
336
+ // Implement refresh functionality
337
+ alert('Refreshing audit data...');
338
+ location.reload();
339
+ }
340
+
341
+ function exportReport() {
342
+ // Implement export functionality
343
+ alert('Exporting report...');
344
+ }
345
+ </script>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Solidstats::Engine.routes.draw do
2
+ root to: "dashboard#index"
3
+ end
@@ -0,0 +1,11 @@
1
+ module Solidstats
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Solidstats
4
+
5
+ initializer "solidstats.only_in_dev" do
6
+ unless Rails.env.development?
7
+ raise "Solidstats can only be used in development mode."
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module Solidstats
2
+ VERSION = "0.0.1"
3
+ end
data/lib/solidstats.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "solidstats/version"
2
+ require "solidstats/engine"
3
+
4
+ module Solidstats
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :solidstats do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solidstats
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - MezbahAlam
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-05-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler-audit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: 'View local project health: secuiry, lints, performance, and more.'
42
+ email:
43
+ - mezbah@infolily.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - app/assets/stylesheets/solidstats/application.css
52
+ - app/controllers/solidstats/application_controller.rb
53
+ - app/controllers/solidstats/dashboard_controller.rb
54
+ - app/helpers/solidstats/application_helper.rb
55
+ - app/jobs/solidstats/application_job.rb
56
+ - app/mailers/solidstats/application_mailer.rb
57
+ - app/models/solidstats/application_record.rb
58
+ - app/views/layouts/solidstats/application.html.erb
59
+ - app/views/solidstats/dashboard/audit/_audit_badge.html.erb
60
+ - app/views/solidstats/dashboard/audit/_audit_details.html.erb
61
+ - app/views/solidstats/dashboard/audit/_audit_filters.html.erb
62
+ - app/views/solidstats/dashboard/audit/_audit_summary.html.erb
63
+ - app/views/solidstats/dashboard/audit/_no_vulnerabilities.html.erb
64
+ - app/views/solidstats/dashboard/audit/_security_audit.html.erb
65
+ - app/views/solidstats/dashboard/audit/_vulnerabilities_table.html.erb
66
+ - app/views/solidstats/dashboard/audit/_vulnerability_details.html.erb
67
+ - app/views/solidstats/dashboard/index.html.erb
68
+ - config/routes.rb
69
+ - lib/solidstats.rb
70
+ - lib/solidstats/engine.rb
71
+ - lib/solidstats/version.rb
72
+ - lib/tasks/solidstats_tasks.rake
73
+ homepage: https://solidstats.infolily.com
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.4.19
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Development dashboard for Rails apps
96
+ test_files: []