route_500_check 0.2.0
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 +7 -0
- data/CHANGELOG.md +68 -0
- data/LICENSE +3 -0
- data/README.md +255 -0
- data/SECURITY.md +119 -0
- data/exe/route500check +8 -0
- data/lib/generators/route_500_check/install_generator.rb +11 -0
- data/lib/generators/route_500_check/templates/route_500_check.rb +57 -0
- data/lib/route_500_check/checker.rb +71 -0
- data/lib/route_500_check/cli.rb +21 -0
- data/lib/route_500_check/dsl/route_definition.rb +10 -0
- data/lib/route_500_check/dsl/validator.rb +23 -0
- data/lib/route_500_check/dsl.rb +95 -0
- data/lib/route_500_check/errors.rb +26 -0
- data/lib/route_500_check/executor/request_runner.rb +12 -0
- data/lib/route_500_check/only_public_builder.rb +45 -0
- data/lib/route_500_check/railtie.rb +9 -0
- data/lib/route_500_check/reporter/json.rb +27 -0
- data/lib/route_500_check/result/result.rb +5 -0
- data/lib/route_500_check/result/summary.rb +10 -0
- data/lib/route_500_check/route_param_builder.rb +108 -0
- data/lib/route_500_check/runner.rb +130 -0
- data/lib/route_500_check/version.rb +3 -0
- data/lib/route_500_check.rb +31 -0
- metadata +83 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6b15f117febf23b2ce99b03f0a0177aeca8aa24e1c4d1c71d0730b1bdaca5391
|
|
4
|
+
data.tar.gz: 941a95a6427a6f92b759d481be967ea01de4d6df909817c5ad5c9282e29dd397
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 86b6c5cd56e13f8c360a1d63b5d6ef80e59ccf659b34029b33840ec1593ee72379d81c12384a2de2845fa1bed94f734a07eec3ab393f1d12e7853197a419c190
|
|
7
|
+
data.tar.gz: 9aa0293e93bde3be504edd57f4eb87df565f9910fe2fb5592245b30494b49bbbcb34fb2f486e82b97e12e535c288fb4cf83ebdf77509f8b217493e9574d05556
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.2.0
|
|
4
|
+
|
|
5
|
+
### Summary
|
|
6
|
+
|
|
7
|
+
This release focuses on **stability, safety, and operational clarity**.
|
|
8
|
+
No new features were added. Existing functionality was refined to ensure
|
|
9
|
+
predictable behavior in production cron jobs and CI environments.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
* Explicit **exit code semantics** to distinguish:
|
|
16
|
+
|
|
17
|
+
* HTTP 500 detection
|
|
18
|
+
* Configuration / safety stops
|
|
19
|
+
* Runtime failures
|
|
20
|
+
* `SECURITY.md` documenting intended usage, safety guarantees, and non-goals
|
|
21
|
+
* Validation layer (`DSL::Validator`) executed **before any HTTP requests**
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
* Entry point unified through CLI (`exe/route500check` → `Route500Check.run`)
|
|
28
|
+
* DSL evaluation stabilized using instance-scoped execution
|
|
29
|
+
* Route expansion logic centralized in `RouteParamBuilder`
|
|
30
|
+
* Safety limit violations now raise a dedicated configuration exception
|
|
31
|
+
* Human-readable configuration errors clearly separated from runtime failures
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### Safety Improvements
|
|
36
|
+
|
|
37
|
+
* Route expansion is fully deterministic and validated prior to execution
|
|
38
|
+
* No HTTP requests are sent when configuration validation fails
|
|
39
|
+
* Global and per-route limits are enforced consistently
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### Exit Codes
|
|
44
|
+
|
|
45
|
+
| Code | Meaning |
|
|
46
|
+
| ---- | -------------------------------------------------------------- |
|
|
47
|
+
| 0 | No HTTP 500 errors detected |
|
|
48
|
+
| 1 | Configuration or safety limit triggered (no requests executed) |
|
|
49
|
+
| 2 | Runtime error or HTTP 500 detected |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### Compatibility Notes
|
|
54
|
+
|
|
55
|
+
* No changes to DSL syntax
|
|
56
|
+
* Existing configurations continue to work as-is
|
|
57
|
+
* Behavior is stricter where misconfiguration previously led to silent over-execution
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
### Notes
|
|
62
|
+
|
|
63
|
+
This version intentionally avoids feature expansion.
|
|
64
|
+
Future releases will prioritize correctness and maintainability over additional DSL features.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
© mntkst
|
data/LICENSE
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Route500Check
|
|
2
|
+
|
|
3
|
+
Route500Check is a lightweight checker focused on **HTTP 500 errors** in Rails applications.
|
|
4
|
+
It does not depend on Rails internals and checks pages via real HTTP requests, just like end users.
|
|
5
|
+
|
|
6
|
+
* Focused on HTTP 500 detection
|
|
7
|
+
* Safe for large-scale sites (anti-runaway design)
|
|
8
|
+
* Suitable for CI / cron jobs
|
|
9
|
+
|
|
10
|
+
Route500Check is designed as a **safety-focused operational tool**, not a crawler or scanner.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem "route_500_check"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bundle install
|
|
22
|
+
bundle exec rails generate route500_check:install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Basic Usage
|
|
28
|
+
|
|
29
|
+
### config/route_500_check.rb
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
base_url "http://localhost:3000"
|
|
33
|
+
default_limit 100
|
|
34
|
+
|
|
35
|
+
route "/"
|
|
36
|
+
|
|
37
|
+
route "/foo/:id" do
|
|
38
|
+
id 1000..9999
|
|
39
|
+
sample 10
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Run
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
bundle exec route500check
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Production (recommended)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
ROUTE500CHECK_BASE_URL=https://example.com ONLY=public bundle exec route500check
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## base_url Priority
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
ENV["ROUTE500CHECK_BASE_URL"]
|
|
61
|
+
↓
|
|
62
|
+
DSL base_url
|
|
63
|
+
↓
|
|
64
|
+
error
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
In production environments, it is recommended to use environment variables
|
|
68
|
+
instead of modifying the DSL configuration.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## ONLY=public
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
ONLY=public bundle exec route500check
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Runs checks only for public-facing pages.
|
|
79
|
+
|
|
80
|
+
Default excluded prefixes:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
/admin
|
|
84
|
+
/api
|
|
85
|
+
/internal
|
|
86
|
+
/rails
|
|
87
|
+
/assets
|
|
88
|
+
/health
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Custom prefixes:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
only_public do
|
|
95
|
+
exclude_prefix "/admin"
|
|
96
|
+
exclude_prefix "/api"
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Safety Guards
|
|
103
|
+
|
|
104
|
+
Route500Check includes multiple safety mechanisms to prevent accidental overload
|
|
105
|
+
or misuse.
|
|
106
|
+
|
|
107
|
+
### default_limit (global hard limit)
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
default_limit 100
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Absolute upper bound for the total number of expanded routes.
|
|
114
|
+
|
|
115
|
+
If the expanded route count exceeds this limit, execution stops **before any HTTP
|
|
116
|
+
requests are sent**.
|
|
117
|
+
|
|
118
|
+
### route limit
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
limit 20
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Effective rule:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
min(route_limit, default_limit)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## sample
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
sample 10
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
* Random selection per route
|
|
139
|
+
* No duplicate URLs within the same route
|
|
140
|
+
* Applied before global limits
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## ignore_status
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
ignore_status [502, 503]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Affects exit code determination only.
|
|
151
|
+
Statuses are still logged and written to JSON output.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Output
|
|
156
|
+
|
|
157
|
+
### STDOUT
|
|
158
|
+
|
|
159
|
+
Human-readable logs intended for operators.
|
|
160
|
+
|
|
161
|
+
### JSON (always generated)
|
|
162
|
+
|
|
163
|
+
File: `route_500_check_result.json`
|
|
164
|
+
Location: current working directory
|
|
165
|
+
|
|
166
|
+
Includes:
|
|
167
|
+
|
|
168
|
+
* Summary (status counts, latency)
|
|
169
|
+
* Detailed per-route results
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Exit Codes
|
|
174
|
+
|
|
175
|
+
Route500Check separates exit codes by intent, making it safe for automation.
|
|
176
|
+
|
|
177
|
+
| Exit code | Meaning |
|
|
178
|
+
| --------- | -------------------------------------------------------------- |
|
|
179
|
+
| `0` | No HTTP 500 errors detected |
|
|
180
|
+
| `1` | Configuration or safety limit triggered (no requests executed) |
|
|
181
|
+
| `2` | Runtime error or HTTP 500 detected |
|
|
182
|
+
|
|
183
|
+
### Exit code `1` (Configuration / Safety)
|
|
184
|
+
|
|
185
|
+
Exit code `1` indicates that Route500Check stopped **before sending any HTTP
|
|
186
|
+
requests**, for example:
|
|
187
|
+
|
|
188
|
+
* Expanded route count exceeds `default_limit`
|
|
189
|
+
* Route sampling or limit configuration prevents safe execution
|
|
190
|
+
|
|
191
|
+
Example output:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
[route_500_check][CONFIG] Route expansion exceeded safety limit.
|
|
195
|
+
- expanded routes: 122
|
|
196
|
+
- default_limit: 10
|
|
197
|
+
|
|
198
|
+
This is NOT a runtime error.
|
|
199
|
+
Adjust default_limit or route sample/limit settings.
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
This exit code does **not** indicate HTTP 500 errors.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Security Considerations
|
|
207
|
+
|
|
208
|
+
Route500Check is intended for **site owners and operators** to monitor their own
|
|
209
|
+
applications.
|
|
210
|
+
|
|
211
|
+
### Controlled Request Expansion
|
|
212
|
+
|
|
213
|
+
To prevent accidental overload or abuse:
|
|
214
|
+
|
|
215
|
+
* All routes must be explicitly defined
|
|
216
|
+
* Total request count is validated **before execution**
|
|
217
|
+
* Execution stops immediately if safety limits are exceeded
|
|
218
|
+
* No HTTP requests are sent when validation fails
|
|
219
|
+
|
|
220
|
+
### Not a Scanning Tool
|
|
221
|
+
|
|
222
|
+
Route500Check intentionally avoids features common in scanning or crawling tools:
|
|
223
|
+
|
|
224
|
+
* No automatic discovery
|
|
225
|
+
* No recursive crawling
|
|
226
|
+
* No parallel request amplification
|
|
227
|
+
* No authentication or authorization bypass
|
|
228
|
+
|
|
229
|
+
### Clear Failure Semantics
|
|
230
|
+
|
|
231
|
+
Configuration and safety stops are clearly distinguished from runtime failures:
|
|
232
|
+
|
|
233
|
+
* Configuration / safety violations return exit code `1`
|
|
234
|
+
* Runtime errors and HTTP 500 detection return exit code `2`
|
|
235
|
+
|
|
236
|
+
This separation reduces the risk of misinterpretation in CI, cron jobs, and
|
|
237
|
+
monitoring systems.
|
|
238
|
+
|
|
239
|
+
### Intended Usage
|
|
240
|
+
|
|
241
|
+
Route500Check is suitable for:
|
|
242
|
+
|
|
243
|
+
* Verifying critical user-facing routes
|
|
244
|
+
* Detecting HTTP 500 regressions
|
|
245
|
+
* Safe execution in production cron jobs and CI pipelines
|
|
246
|
+
|
|
247
|
+
It is **not intended for penetration testing, stress testing, or content
|
|
248
|
+
discovery**.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
MIT
|
|
255
|
+
© mntkst
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Route500Check is designed as a **safety-focused operational tool** for site owners and operators.
|
|
6
|
+
Its primary purpose is to detect HTTP 500 errors on explicitly defined routes using real HTTP requests,
|
|
7
|
+
while preventing accidental overload or misuse.
|
|
8
|
+
|
|
9
|
+
This document explains the security-related design principles and intended usage of Route500Check.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Intended Usage
|
|
14
|
+
|
|
15
|
+
Route500Check is intended for:
|
|
16
|
+
|
|
17
|
+
* Monitoring critical user-facing routes
|
|
18
|
+
* Detecting HTTP 500 regressions in Rails applications
|
|
19
|
+
* Safe execution in production cron jobs and CI pipelines
|
|
20
|
+
|
|
21
|
+
It is **not intended** for:
|
|
22
|
+
|
|
23
|
+
* Penetration testing
|
|
24
|
+
* Stress testing or load testing
|
|
25
|
+
* Crawling or content discovery
|
|
26
|
+
* Scanning systems you do not own or operate
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Controlled Request Execution
|
|
31
|
+
|
|
32
|
+
Route500Check includes multiple safeguards to ensure controlled execution:
|
|
33
|
+
|
|
34
|
+
* All routes must be explicitly defined by the user
|
|
35
|
+
* No automatic discovery or recursive crawling is performed
|
|
36
|
+
* Route expansion is deterministic and predictable
|
|
37
|
+
* Total request count is validated **before execution**
|
|
38
|
+
|
|
39
|
+
If safety validation fails, execution stops immediately and **no HTTP requests are sent**.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Safety Limits
|
|
44
|
+
|
|
45
|
+
### Global Limit (`default_limit`)
|
|
46
|
+
|
|
47
|
+
The `default_limit` setting defines an absolute upper bound for the total number of HTTP requests
|
|
48
|
+
that can be generated from all routes.
|
|
49
|
+
|
|
50
|
+
If the expanded route count exceeds this limit:
|
|
51
|
+
|
|
52
|
+
* Route500Check stops before sending any requests
|
|
53
|
+
* Exit code `1` is returned
|
|
54
|
+
* A clear configuration-related message is displayed
|
|
55
|
+
|
|
56
|
+
This mechanism prevents accidental overload due to misconfiguration.
|
|
57
|
+
|
|
58
|
+
### Per-route Limits
|
|
59
|
+
|
|
60
|
+
Each route may define its own:
|
|
61
|
+
|
|
62
|
+
* `limit`
|
|
63
|
+
* `sample`
|
|
64
|
+
|
|
65
|
+
Effective limits are calculated safely, and always respect the global `default_limit`.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Exit Code Semantics
|
|
70
|
+
|
|
71
|
+
Route500Check separates exit codes by intent to reduce operational risk:
|
|
72
|
+
|
|
73
|
+
| Exit code | Meaning |
|
|
74
|
+
| --------- | -------------------------------------------------------------- |
|
|
75
|
+
| `0` | No HTTP 500 errors detected |
|
|
76
|
+
| `1` | Configuration or safety limit triggered (no requests executed) |
|
|
77
|
+
| `2` | Runtime error or HTTP 500 detected |
|
|
78
|
+
|
|
79
|
+
Exit code `1` indicates a **safety stop**, not a runtime failure and not an HTTP 500 detection.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Non-goals and Explicit Limitations
|
|
84
|
+
|
|
85
|
+
To avoid misuse, Route500Check intentionally does **not** provide:
|
|
86
|
+
|
|
87
|
+
* Parallel or high-volume request execution
|
|
88
|
+
* Automatic endpoint discovery
|
|
89
|
+
* Authentication or authorization bypass mechanisms
|
|
90
|
+
* Rate limit evasion or throttling circumvention
|
|
91
|
+
|
|
92
|
+
Any use outside the intended scope may violate laws, regulations, or terms of service.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Responsible Use
|
|
97
|
+
|
|
98
|
+
Users are responsible for ensuring that Route500Check is executed only against systems they own
|
|
99
|
+
or are authorized to operate.
|
|
100
|
+
|
|
101
|
+
The authors and maintainers of Route500Check assume no responsibility for misuse of this tool
|
|
102
|
+
outside its intended operational scope.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Reporting Security Issues
|
|
107
|
+
|
|
108
|
+
If you believe you have found a security vulnerability in Route500Check itself (not in a target
|
|
109
|
+
application), please report it responsibly.
|
|
110
|
+
|
|
111
|
+
At this time, please open a GitHub issue with a clear description of the problem and steps to
|
|
112
|
+
reproduce it. Sensitive details should be minimized.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Policy Updates
|
|
117
|
+
|
|
118
|
+
This security policy may be updated as the project evolves. Please review it periodically to
|
|
119
|
+
stay informed about Route500Check's security posture.
|
data/exe/route500check
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Route500Check configuration file
|
|
2
|
+
#
|
|
3
|
+
# This file defines which routes should be checked for HTTP 500 errors.
|
|
4
|
+
# Routes are expanded and validated before execution to ensure safe operation.
|
|
5
|
+
#
|
|
6
|
+
# No HTTP requests are sent if validation fails.
|
|
7
|
+
|
|
8
|
+
# Base URL for requests.
|
|
9
|
+
# In production, it is recommended to use the environment variable
|
|
10
|
+
# ROUTE500CHECK_BASE_URL instead of hard-coding this value.
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
# ROUTE500CHECK_BASE_URL=https://example.com bundle exec route500check
|
|
14
|
+
#
|
|
15
|
+
base_url "http://localhost:3000"
|
|
16
|
+
|
|
17
|
+
# Global safety limit.
|
|
18
|
+
# This is an absolute upper bound for the total number of HTTP requests
|
|
19
|
+
# after route expansion.
|
|
20
|
+
#
|
|
21
|
+
default_limit 50
|
|
22
|
+
|
|
23
|
+
# Run checks only for public-facing pages.
|
|
24
|
+
# Useful when executing against production environments.
|
|
25
|
+
#
|
|
26
|
+
# only_public do
|
|
27
|
+
# exclude_prefix "/admin"
|
|
28
|
+
# exclude_prefix "/api"
|
|
29
|
+
# end
|
|
30
|
+
|
|
31
|
+
# -----------------------
|
|
32
|
+
# Route definitions
|
|
33
|
+
# -----------------------
|
|
34
|
+
|
|
35
|
+
# Simple static route
|
|
36
|
+
route "/"
|
|
37
|
+
|
|
38
|
+
# Route with path parameters
|
|
39
|
+
route "/items/:id" do
|
|
40
|
+
id 1..100
|
|
41
|
+
sample 10
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Route with explicit limit
|
|
45
|
+
route "/categories/:category_id" do
|
|
46
|
+
category_id [1, 2, 3, 4, 5]
|
|
47
|
+
limit 5
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# -----------------------
|
|
51
|
+
# Optional settings
|
|
52
|
+
# -----------------------
|
|
53
|
+
|
|
54
|
+
# Ignore specific HTTP status codes when determining exit code.
|
|
55
|
+
# These statuses are still logged and written to JSON output.
|
|
56
|
+
#
|
|
57
|
+
# ignore_status [502, 503]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# lib/route_500_check/checker.rb
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "uri"
|
|
5
|
+
|
|
6
|
+
module Route500Check
|
|
7
|
+
class Checker
|
|
8
|
+
def initialize(base_url)
|
|
9
|
+
@base_url = base_url
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def check(path)
|
|
13
|
+
uri = build_uri(path)
|
|
14
|
+
start = now
|
|
15
|
+
|
|
16
|
+
response = Net::HTTP.get_response(uri)
|
|
17
|
+
finish = now
|
|
18
|
+
|
|
19
|
+
build_success_result(
|
|
20
|
+
path: path,
|
|
21
|
+
uri: uri,
|
|
22
|
+
response: response,
|
|
23
|
+
start: start,
|
|
24
|
+
finish: finish
|
|
25
|
+
)
|
|
26
|
+
rescue => e
|
|
27
|
+
finish = now rescue nil
|
|
28
|
+
|
|
29
|
+
build_error_result(
|
|
30
|
+
path: path,
|
|
31
|
+
uri: uri,
|
|
32
|
+
error: e,
|
|
33
|
+
start: start,
|
|
34
|
+
finish: finish
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def build_uri(path)
|
|
41
|
+
URI.join(@base_url, path)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def now
|
|
45
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def elapsed_ms(start, finish)
|
|
49
|
+
return nil unless start && finish
|
|
50
|
+
((finish - start) * 1000).round(1)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def build_success_result(path:, uri:, response:, start:, finish:)
|
|
54
|
+
{
|
|
55
|
+
path: path,
|
|
56
|
+
url: uri.to_s,
|
|
57
|
+
status: response.code.to_i,
|
|
58
|
+
elapsed_ms: elapsed_ms(start, finish)
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def build_error_result(path:, uri:, error:, start:, finish:)
|
|
63
|
+
{
|
|
64
|
+
path: path,
|
|
65
|
+
url: uri.to_s,
|
|
66
|
+
error: error.message,
|
|
67
|
+
elapsed_ms: elapsed_ms(start, finish)
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# lib/route500_check/cli.rb
|
|
2
|
+
|
|
3
|
+
module Route500Check
|
|
4
|
+
class CLI
|
|
5
|
+
EXIT_OK = 0
|
|
6
|
+
EXIT_500 = 2
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
config = DSL.load!
|
|
10
|
+
DSL::Validator.validate!(config)
|
|
11
|
+
|
|
12
|
+
Runner.run
|
|
13
|
+
rescue Route500Check::Errors::RouteLimitExceeded => e
|
|
14
|
+
warn "[route_500_check][CONFIG] #{e.message}"
|
|
15
|
+
exit 1
|
|
16
|
+
rescue => e
|
|
17
|
+
warn "[route_500_check][FATAL] #{e.class}: #{e.message}"
|
|
18
|
+
exit 2
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# lib/route_500_check/dsl/validator.rb
|
|
2
|
+
module Route500Check
|
|
3
|
+
class DSL::Validator
|
|
4
|
+
def self.validate!(config)
|
|
5
|
+
expanded =
|
|
6
|
+
RouteParamBuilder.expand(
|
|
7
|
+
config.routes,
|
|
8
|
+
config.default_limit
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
total = expanded.size
|
|
12
|
+
limit = config.default_limit
|
|
13
|
+
|
|
14
|
+
return unless limit
|
|
15
|
+
return if total <= limit
|
|
16
|
+
|
|
17
|
+
raise Route500Check::Errors::RouteLimitExceeded.new(
|
|
18
|
+
actual: total,
|
|
19
|
+
limit: limit
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# lib/route_500_check/dsl.rb
|
|
2
|
+
require "route_500_check/route_param_builder"
|
|
3
|
+
require "route_500_check/only_public_builder"
|
|
4
|
+
|
|
5
|
+
module Route500Check
|
|
6
|
+
RouteDef = Struct.new(:template, :params)
|
|
7
|
+
|
|
8
|
+
class DSL
|
|
9
|
+
CONFIG_PATH = "config/route_500_check.rb"
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
attr_accessor :current
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :routes, :ignore_statuses
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@routes = []
|
|
19
|
+
@default_limit = nil
|
|
20
|
+
@ignore_statuses = []
|
|
21
|
+
@only_public_prefixes = nil
|
|
22
|
+
@base_url = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# ==========
|
|
26
|
+
# Load config
|
|
27
|
+
# ==========
|
|
28
|
+
def self.load!
|
|
29
|
+
unless File.exist?(CONFIG_PATH)
|
|
30
|
+
raise <<~MSG
|
|
31
|
+
[route_500_check] Config file not found: #{CONFIG_PATH}
|
|
32
|
+
|
|
33
|
+
Please run:
|
|
34
|
+
rails generate route500_check:install
|
|
35
|
+
MSG
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
self.current = new
|
|
39
|
+
|
|
40
|
+
begin
|
|
41
|
+
DSL.current.instance_eval(File.read(CONFIG_PATH))
|
|
42
|
+
rescue Exception => e
|
|
43
|
+
raise "[route_500_check] Failed to load config: #{e.message}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
current
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# ==========
|
|
50
|
+
# Global settings
|
|
51
|
+
# ==========
|
|
52
|
+
def base_url(value = nil)
|
|
53
|
+
value ? (@base_url = value) : @base_url
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def default_limit(value = nil)
|
|
57
|
+
value ? (@default_limit = value) : @default_limit
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def ignore_status(values = nil)
|
|
61
|
+
if values
|
|
62
|
+
@ignore_statuses = Array(values).map(&:to_i)
|
|
63
|
+
else
|
|
64
|
+
@ignore_statuses
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# ==========
|
|
69
|
+
# ONLY=public DSL
|
|
70
|
+
# ==========
|
|
71
|
+
def only_public(&block)
|
|
72
|
+
builder = ::Route500Check::OnlyPublicBuilder.new
|
|
73
|
+
builder.instance_eval(&block)
|
|
74
|
+
@only_public_prefixes = builder.prefixes
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def only_public_prefixes
|
|
78
|
+
@only_public_prefixes
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# ==========
|
|
82
|
+
# route DSL
|
|
83
|
+
# ==========
|
|
84
|
+
def route(path, &block)
|
|
85
|
+
params = {}
|
|
86
|
+
|
|
87
|
+
if block
|
|
88
|
+
builder = ::Route500Check::RouteParamBuilder.new(params)
|
|
89
|
+
builder.instance_eval(&block)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
@routes << RouteDef.new(path, params)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Route500Check
|
|
2
|
+
module Errors
|
|
3
|
+
class RouteLimitExceeded < StandardError
|
|
4
|
+
attr_reader :actual, :limit
|
|
5
|
+
|
|
6
|
+
def initialize(actual:, limit:)
|
|
7
|
+
@actual = actual
|
|
8
|
+
@limit = limit
|
|
9
|
+
super(build_message)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def build_message
|
|
15
|
+
<<~MSG.strip
|
|
16
|
+
Route expansion exceeded safety limit.
|
|
17
|
+
- expanded routes: #{actual}
|
|
18
|
+
- default_limit: #{limit}
|
|
19
|
+
|
|
20
|
+
This is NOT a runtime error.
|
|
21
|
+
Adjust default_limit or route sample/limit settings.
|
|
22
|
+
MSG
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# lib/route_500_check/only_public_builder.rb
|
|
2
|
+
|
|
3
|
+
module Route500Check
|
|
4
|
+
class OnlyPublicBuilder
|
|
5
|
+
DEFAULT_EXCLUDE_PREFIXES = %w[
|
|
6
|
+
/admin
|
|
7
|
+
/api
|
|
8
|
+
/internal
|
|
9
|
+
/rails
|
|
10
|
+
/assets
|
|
11
|
+
/health
|
|
12
|
+
].freeze
|
|
13
|
+
|
|
14
|
+
# ======================
|
|
15
|
+
# DSL 用(既存仕様そのまま)
|
|
16
|
+
# ======================
|
|
17
|
+
def initialize
|
|
18
|
+
@prefixes = []
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def exclude_prefix(prefix)
|
|
22
|
+
@prefixes << prefix
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prefixes
|
|
26
|
+
@prefixes
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# ======================
|
|
30
|
+
# 実行用(Runner から利用)
|
|
31
|
+
# ======================
|
|
32
|
+
def self.filter(paths, prefixes = nil)
|
|
33
|
+
effective_prefixes =
|
|
34
|
+
if prefixes && !prefixes.empty?
|
|
35
|
+
prefixes
|
|
36
|
+
else
|
|
37
|
+
DEFAULT_EXCLUDE_PREFIXES
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
paths.reject do |path|
|
|
41
|
+
effective_prefixes.any? { |prefix| path.start_with?(prefix) }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# lib/route_500_check/reporter/json.rb
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "time"
|
|
5
|
+
|
|
6
|
+
module Route500Check
|
|
7
|
+
module Reporter
|
|
8
|
+
class Json
|
|
9
|
+
DEFAULT_OUTPUT_PATH = "route500check.json"
|
|
10
|
+
|
|
11
|
+
def self.write(results:, summary:, output_path: nil)
|
|
12
|
+
payload = build_payload(results: results, summary: summary)
|
|
13
|
+
File.write(output_path || DEFAULT_OUTPUT_PATH, JSON.pretty_generate(payload))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def self.build_payload(results:, summary:)
|
|
19
|
+
{
|
|
20
|
+
generated_at: Time.now.utc.iso8601,
|
|
21
|
+
summary: summary,
|
|
22
|
+
results: results
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# lib/route_500_check/route_param_builder.rb
|
|
2
|
+
|
|
3
|
+
module Route500Check
|
|
4
|
+
class RouteParamBuilder
|
|
5
|
+
# ======================
|
|
6
|
+
# DSL 用
|
|
7
|
+
# ======================
|
|
8
|
+
def initialize(params)
|
|
9
|
+
@params = params
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def sample(n)
|
|
13
|
+
@params[:__sample__] = n
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def limit(n)
|
|
17
|
+
@params[:__limit__] = n
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def method_missing(name, *args, &block)
|
|
21
|
+
@params[name.to_sym] =
|
|
22
|
+
if args.length <= 1
|
|
23
|
+
args.first
|
|
24
|
+
else
|
|
25
|
+
args
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def respond_to_missing?(_name, _include_private = false)
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# ======================
|
|
34
|
+
# 実行用(Runner が呼ぶ)
|
|
35
|
+
# ======================
|
|
36
|
+
def self.expand(route_defs, default_limit)
|
|
37
|
+
route_defs.flat_map do |route|
|
|
38
|
+
template = route.template
|
|
39
|
+
params = route.params || {}
|
|
40
|
+
|
|
41
|
+
placeholders =
|
|
42
|
+
template.scan(/:(\w+)/).flatten.map(&:to_sym)
|
|
43
|
+
|
|
44
|
+
# placeholder が無い場合
|
|
45
|
+
if placeholders.empty?
|
|
46
|
+
paths = [template]
|
|
47
|
+
else
|
|
48
|
+
values_map =
|
|
49
|
+
placeholders.map do |key|
|
|
50
|
+
raw = params[key]
|
|
51
|
+
values =
|
|
52
|
+
case raw
|
|
53
|
+
when Range
|
|
54
|
+
raw.to_a
|
|
55
|
+
when Array
|
|
56
|
+
raw.flat_map { |v| v.is_a?(Range) ? v.to_a : v }
|
|
57
|
+
else
|
|
58
|
+
[raw]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
[key, values]
|
|
62
|
+
end.to_h
|
|
63
|
+
|
|
64
|
+
combinations = cartesian_product(values_map)
|
|
65
|
+
|
|
66
|
+
# sample
|
|
67
|
+
if params[:__sample__]
|
|
68
|
+
combinations = combinations.sample(params[:__sample__])
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# limit(route → global の順で適用)
|
|
72
|
+
route_limit = params[:__limit__]
|
|
73
|
+
global_limit = default_limit
|
|
74
|
+
|
|
75
|
+
effective_limit =
|
|
76
|
+
if route_limit && global_limit
|
|
77
|
+
[route_limit, global_limit].min
|
|
78
|
+
else
|
|
79
|
+
route_limit || global_limit
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
if effective_limit
|
|
83
|
+
combinations = combinations.take(effective_limit)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
paths =
|
|
87
|
+
combinations.map do |combo|
|
|
88
|
+
path = template.dup
|
|
89
|
+
combo.each { |k, v| path.sub!(":#{k}", v.to_s) }
|
|
90
|
+
path
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
paths
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.cartesian_product(values_map)
|
|
99
|
+
keys = values_map.keys
|
|
100
|
+
values = values_map.values
|
|
101
|
+
|
|
102
|
+
values
|
|
103
|
+
.shift
|
|
104
|
+
.product(*values)
|
|
105
|
+
.map { |combo| keys.zip(combo).to_h }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# lib/route_500_check/runner.rb
|
|
2
|
+
|
|
3
|
+
require "route_500_check/route_param_builder"
|
|
4
|
+
require "route_500_check/only_public_builder"
|
|
5
|
+
|
|
6
|
+
module Route500Check
|
|
7
|
+
class Runner
|
|
8
|
+
EXIT_OK = 0
|
|
9
|
+
EXIT_500 = 2
|
|
10
|
+
|
|
11
|
+
def self.run(_options = {})
|
|
12
|
+
config = DSL.load!
|
|
13
|
+
|
|
14
|
+
runtime_base_url =
|
|
15
|
+
ENV["ROUTE500CHECK_BASE_URL"] ||
|
|
16
|
+
config.base_url
|
|
17
|
+
|
|
18
|
+
unless runtime_base_url
|
|
19
|
+
abort "[route_500_check] base_url is required (ENV or DSL)"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
puts "[route_500_check] base_url=#{runtime_base_url}"
|
|
23
|
+
|
|
24
|
+
checker = Checker.new(runtime_base_url)
|
|
25
|
+
|
|
26
|
+
# ---- route expansion ----
|
|
27
|
+
paths =
|
|
28
|
+
RouteParamBuilder.expand(
|
|
29
|
+
config.routes,
|
|
30
|
+
config.default_limit
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# ---- ONLY=public ----
|
|
34
|
+
if ENV["ONLY"] == "public"
|
|
35
|
+
paths =
|
|
36
|
+
OnlyPublicBuilder.filter(
|
|
37
|
+
paths,
|
|
38
|
+
config.only_public_prefixes
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# ---- execute ----
|
|
43
|
+
results = []
|
|
44
|
+
|
|
45
|
+
paths.each do |path|
|
|
46
|
+
result = checker.check(path)
|
|
47
|
+
results << result
|
|
48
|
+
|
|
49
|
+
if result[:error]
|
|
50
|
+
puts "[route_500_check] ERROR #{result[:url]} #{result[:error]}"
|
|
51
|
+
else
|
|
52
|
+
puts "[route_500_check] GET #{result[:url]} -> #{result[:status]} (#{result[:elapsed_ms]}ms)"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# ---- summary ----
|
|
57
|
+
summary = build_summary(results)
|
|
58
|
+
print_summary(summary)
|
|
59
|
+
|
|
60
|
+
ignored = config.ignore_status || []
|
|
61
|
+
|
|
62
|
+
has_500 = results.any? do |r|
|
|
63
|
+
s = r[:status]
|
|
64
|
+
s && s >= 500 && !ignored.include?(s)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Reporter::Json.write(
|
|
68
|
+
results: results,
|
|
69
|
+
summary: summary
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
exit(has_500 ? EXIT_500 : EXIT_OK)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# ==========
|
|
76
|
+
# summary helpers
|
|
77
|
+
# ==========
|
|
78
|
+
def self.print_summary(s)
|
|
79
|
+
puts "[route_500_check] Result summary:"
|
|
80
|
+
puts " total_routes: #{s[:total_routes]}"
|
|
81
|
+
puts " success: #{s[:success]}"
|
|
82
|
+
puts " errors: #{s[:errors]}"
|
|
83
|
+
puts " http_2xx: #{s[:http_2xx]}"
|
|
84
|
+
puts " http_3xx: #{s[:http_3xx]}"
|
|
85
|
+
puts " http_4xx: #{s[:http_4xx]}"
|
|
86
|
+
puts " http_5xx: #{s[:http_5xx]}"
|
|
87
|
+
puts " max_latency: #{s[:max_latency_ms] ? "#{s[:max_latency_ms]}ms" : '-'}"
|
|
88
|
+
puts " avg_latency: #{s[:avg_latency_ms] ? "#{s[:avg_latency_ms]}ms" : '-'}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.build_summary(results)
|
|
92
|
+
total = results.size
|
|
93
|
+
|
|
94
|
+
error_count = results.count { |r| r[:error] }
|
|
95
|
+
|
|
96
|
+
statuses = results.map { |r| r[:status] }.compact
|
|
97
|
+
|
|
98
|
+
http_2xx = statuses.count { |s| s >= 200 && s < 300 }
|
|
99
|
+
http_3xx = statuses.count { |s| s >= 300 && s < 400 }
|
|
100
|
+
http_4xx = statuses.count { |s| s >= 400 && s < 500 }
|
|
101
|
+
http_5xx = statuses.count { |s| s >= 500 }
|
|
102
|
+
|
|
103
|
+
http_4xx_breakdown =
|
|
104
|
+
statuses
|
|
105
|
+
.select { |s| s >= 400 && s < 500 }
|
|
106
|
+
.tally
|
|
107
|
+
.transform_keys(&:to_s)
|
|
108
|
+
|
|
109
|
+
success = total - error_count - http_5xx
|
|
110
|
+
|
|
111
|
+
elapsed = results.map { |r| r[:elapsed_ms] }.compact
|
|
112
|
+
|
|
113
|
+
{
|
|
114
|
+
total_routes: total,
|
|
115
|
+
success: success,
|
|
116
|
+
errors: error_count,
|
|
117
|
+
|
|
118
|
+
http_2xx: http_2xx,
|
|
119
|
+
http_3xx: http_3xx,
|
|
120
|
+
http_4xx: http_4xx,
|
|
121
|
+
http_5xx: http_5xx,
|
|
122
|
+
|
|
123
|
+
http_4xx_breakdown: http_4xx_breakdown,
|
|
124
|
+
|
|
125
|
+
max_latency_ms: elapsed.max,
|
|
126
|
+
avg_latency_ms: elapsed.any? ? (elapsed.sum / elapsed.size.to_f).round(1) : nil
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# lib/route_500_check.rb
|
|
2
|
+
|
|
3
|
+
require "route_500_check/version"
|
|
4
|
+
|
|
5
|
+
# DSL 関連
|
|
6
|
+
require "route_500_check/route_param_builder"
|
|
7
|
+
require "route_500_check/only_public_builder"
|
|
8
|
+
require "route_500_check/dsl"
|
|
9
|
+
require "route_500_check/dsl/validator"
|
|
10
|
+
require "route_500_check/errors"
|
|
11
|
+
|
|
12
|
+
# 実行系
|
|
13
|
+
require "route_500_check/checker"
|
|
14
|
+
require "route_500_check/reporter/json"
|
|
15
|
+
require "route_500_check/runner"
|
|
16
|
+
require "route_500_check/cli"
|
|
17
|
+
|
|
18
|
+
module Route500Check
|
|
19
|
+
def self.define(&block)
|
|
20
|
+
DSL.current ||= DSL.new
|
|
21
|
+
DSL.current.instance_eval(&block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.run
|
|
25
|
+
CLI.new.run
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
if defined?(Rails)
|
|
30
|
+
require "route_500_check/railtie"
|
|
31
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: route_500_check
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- mntkst
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-12-31 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.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '6.0'
|
|
27
|
+
description: DSL-based HTTP 500 error detector for Rails applications
|
|
28
|
+
email:
|
|
29
|
+
executables:
|
|
30
|
+
- route500check
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- CHANGELOG.md
|
|
35
|
+
- LICENSE
|
|
36
|
+
- README.md
|
|
37
|
+
- SECURITY.md
|
|
38
|
+
- exe/route500check
|
|
39
|
+
- lib/generators/route_500_check/install_generator.rb
|
|
40
|
+
- lib/generators/route_500_check/templates/route_500_check.rb
|
|
41
|
+
- lib/route_500_check.rb
|
|
42
|
+
- lib/route_500_check/checker.rb
|
|
43
|
+
- lib/route_500_check/cli.rb
|
|
44
|
+
- lib/route_500_check/dsl.rb
|
|
45
|
+
- lib/route_500_check/dsl/route_definition.rb
|
|
46
|
+
- lib/route_500_check/dsl/validator.rb
|
|
47
|
+
- lib/route_500_check/errors.rb
|
|
48
|
+
- lib/route_500_check/executor/request_runner.rb
|
|
49
|
+
- lib/route_500_check/only_public_builder.rb
|
|
50
|
+
- lib/route_500_check/railtie.rb
|
|
51
|
+
- lib/route_500_check/reporter/json.rb
|
|
52
|
+
- lib/route_500_check/result/result.rb
|
|
53
|
+
- lib/route_500_check/result/summary.rb
|
|
54
|
+
- lib/route_500_check/route_param_builder.rb
|
|
55
|
+
- lib/route_500_check/runner.rb
|
|
56
|
+
- lib/route_500_check/version.rb
|
|
57
|
+
homepage: https://github.com/mntkst/route_500_check
|
|
58
|
+
licenses:
|
|
59
|
+
- MIT
|
|
60
|
+
metadata:
|
|
61
|
+
homepage_uri: https://github.com/mntkst/route_500_check
|
|
62
|
+
source_code_uri: https://github.com/mntkst/route_500_check
|
|
63
|
+
changelog_uri: https://github.com/mntkst/route_500_check/releases
|
|
64
|
+
post_install_message:
|
|
65
|
+
rdoc_options: []
|
|
66
|
+
require_paths:
|
|
67
|
+
- lib
|
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - ">="
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '0'
|
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
|
+
requirements:
|
|
75
|
+
- - ">="
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '0'
|
|
78
|
+
requirements: []
|
|
79
|
+
rubygems_version: 3.4.19
|
|
80
|
+
signing_key:
|
|
81
|
+
specification_version: 4
|
|
82
|
+
summary: Detect HTTP 500 errors by scanning selected Rails routes
|
|
83
|
+
test_files: []
|