otto 2.0.0.pre8 → 2.0.0.pre10
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/.github/workflows/ci.yml +1 -1
- data/.github/workflows/claude-code-review.yml +1 -1
- data/.github/workflows/claude.yml +1 -1
- data/.github/workflows/code-smells.yml +2 -2
- data/CHANGELOG.rst +73 -35
- data/CLAUDE.md +44 -0
- data/Gemfile.lock +7 -7
- data/README.md +20 -0
- data/docs/.gitignore +2 -0
- data/docs/modern-authentication-authorization-landscape.md +558 -0
- data/docs/multi-strategy-authentication-design.md +1401 -0
- data/lib/otto/core/error_handler.rb +104 -10
- data/lib/otto/core/freezable.rb +0 -2
- data/lib/otto/core/helper_registry.rb +135 -0
- data/lib/otto/core/lifecycle_hooks.rb +63 -0
- data/lib/otto/core/middleware_management.rb +70 -0
- data/lib/otto/core/middleware_stack.rb +12 -8
- data/lib/otto/core/router.rb +25 -31
- data/lib/otto/core.rb +3 -0
- data/lib/otto/errors.rb +92 -0
- data/lib/otto/helpers.rb +2 -2
- data/lib/otto/locale/middleware.rb +1 -1
- data/lib/otto/mcp/core.rb +33 -0
- data/lib/otto/mcp/protocol.rb +1 -1
- data/lib/otto/mcp/rate_limiting.rb +6 -2
- data/lib/otto/mcp/schema_validation.rb +2 -2
- data/lib/otto/mcp.rb +1 -0
- data/lib/otto/privacy/core.rb +82 -0
- data/lib/otto/privacy.rb +1 -0
- data/lib/otto/{helpers/request.rb → request.rb} +17 -6
- data/lib/otto/{helpers/response.rb → response.rb} +20 -7
- data/lib/otto/response_handlers/json.rb +1 -3
- data/lib/otto/response_handlers/view.rb +1 -1
- data/lib/otto/route.rb +2 -4
- data/lib/otto/route_handlers/base.rb +88 -5
- data/lib/otto/route_handlers/class_method.rb +9 -67
- data/lib/otto/route_handlers/instance_method.rb +10 -57
- data/lib/otto/route_handlers/lambda.rb +2 -2
- data/lib/otto/route_handlers/logic_class.rb +85 -90
- data/lib/otto/security/authentication/auth_strategy.rb +2 -2
- data/lib/otto/security/authentication/strategies/api_key_strategy.rb +1 -1
- data/lib/otto/security/authentication/strategy_result.rb +9 -9
- data/lib/otto/security/authorization_error.rb +1 -1
- data/lib/otto/security/config.rb +3 -3
- data/lib/otto/security/core.rb +167 -0
- data/lib/otto/security/middleware/csrf_middleware.rb +1 -1
- data/lib/otto/security/middleware/validation_middleware.rb +1 -1
- data/lib/otto/security/rate_limiter.rb +7 -3
- data/lib/otto/security.rb +1 -0
- data/lib/otto/version.rb +1 -1
- data/lib/otto.rb +29 -404
- metadata +12 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5e7fb7a7177b6488a5a3cdacc8e3a929d58f92d44fb03bb506effca3f6c3550
|
|
4
|
+
data.tar.gz: 351a23a9c8e12aff50296cde108e73478dac7cf052d687deb5855f3ccb35cd79
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 651edcf79562877a2046132ccc876f747545d1bed8f4821352af4c16f8e795bec5d02e82afcf27320b368af9e25853df3c71d26c4fa6b6f81878704322d0f29d
|
|
7
|
+
data.tar.gz: e763f2d28e2ff4dd0d16a98ff8ab9eda6d495d32e7be10b31a1c21516a075fb1f49a44464eeaf66d92f701821ab3fce91ab72c25d18430efa70e65b2a435cb94
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -21,7 +21,7 @@ jobs:
|
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
23
|
- name: Checkout code
|
|
24
|
-
uses: actions/checkout@
|
|
24
|
+
uses: actions/checkout@v6
|
|
25
25
|
|
|
26
26
|
- name: Set up Ruby
|
|
27
27
|
uses: ruby/setup-ruby@v1
|
|
@@ -88,7 +88,7 @@ jobs:
|
|
|
88
88
|
|
|
89
89
|
steps:
|
|
90
90
|
- name: Checkout code
|
|
91
|
-
uses: actions/checkout@
|
|
91
|
+
uses: actions/checkout@v6
|
|
92
92
|
|
|
93
93
|
- name: Set up Ruby
|
|
94
94
|
uses: ruby/setup-ruby@v1
|
data/CHANGELOG.rst
CHANGED
|
@@ -7,71 +7,109 @@ The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.1.0/>`
|
|
|
7
7
|
|
|
8
8
|
<!--scriv-insert-here-->
|
|
9
9
|
|
|
10
|
-
.. _changelog-2.0.0.
|
|
10
|
+
.. _changelog-2.0.0.pre10:
|
|
11
11
|
|
|
12
|
-
2.0.0.
|
|
13
|
-
|
|
12
|
+
2.0.0.pre10 — 2025-12-09
|
|
13
|
+
========================
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Added
|
|
16
16
|
-----
|
|
17
17
|
|
|
18
|
-
-
|
|
18
|
+
- ``Otto::Request`` and ``Otto::Response`` classes extending Rack equivalents
|
|
19
|
+
- ``register_request_helpers`` and ``register_response_helpers`` for application-specific helpers
|
|
20
|
+
- Helper modules included at class level (not per-request extension)
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
Changed
|
|
23
|
+
-------
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
- Moved ``lib/otto/helpers/request.rb`` → ``lib/otto/request.rb``
|
|
26
|
+
- Moved ``lib/otto/helpers/response.rb`` → ``lib/otto/response.rb``
|
|
27
|
+
- All internal code now uses ``Otto::Request``/``Otto::Response`` instead of ``Rack::Request``/``Rack::Response``
|
|
28
|
+
|
|
29
|
+
.. _changelog-2.0.0.pre9:
|
|
30
|
+
|
|
31
|
+
2.0.0.pre9 — 2025-12-06
|
|
23
32
|
=======================
|
|
24
33
|
|
|
25
34
|
Added
|
|
26
35
|
-----
|
|
27
36
|
|
|
28
|
-
-
|
|
37
|
+
- Base HTTP error classes (``Otto::NotFoundError``, ``Otto::BadRequestError``, ``Otto::ForbiddenError``, ``Otto::UnauthorizedError``, ``Otto::PayloadTooLargeError``) that implementing projects can subclass for consistent error handling
|
|
38
|
+
- Auto-registration of all framework error classes during ``Otto#initialize`` - framework errors now automatically return correct HTTP status codes without manual registration
|
|
29
39
|
|
|
30
40
|
Changed
|
|
31
41
|
-------
|
|
32
42
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
43
|
+
- Framework error classes now inherit from new base classes: ``Otto::Security::AuthorizationError`` < ``Otto::ForbiddenError``, ``Otto::Security::CSRFError`` < ``Otto::ForbiddenError``, ``Otto::Security::RequestTooLargeError`` < ``Otto::PayloadTooLargeError``, ``Otto::Security::ValidationError`` < ``Otto::BadRequestError``, ``Otto::MCP::ValidationError`` < ``Otto::BadRequestError``
|
|
44
|
+
- ``Otto::Security::RequestTooLargeError`` now returns HTTP 413 (Payload Too Large) instead of 500, semantically correct per RFC 7231
|
|
45
|
+
|
|
46
|
+
- Consolidated route handler implementation using Template Method pattern, reducing duplication by ~120 lines while improving maintainability
|
|
47
|
+
|
|
48
|
+
Fixed
|
|
49
|
+
-----
|
|
50
|
+
|
|
51
|
+
- Error handlers now respect route's ``response=json`` parameter for content
|
|
52
|
+
negotiation, ensuring API routes always return JSON error responses regardless
|
|
53
|
+
of the Accept header.
|
|
54
|
+
|
|
55
|
+
- Rate limiters now respect route ``response=json`` declarations when returning
|
|
56
|
+
throttled responses, matching the error handler fix for consistent content
|
|
57
|
+
negotiation across all error paths.
|
|
58
|
+
|
|
59
|
+
- ClassMethodHandler direct testing context now respects route ``response_type``
|
|
60
|
+
when generating error responses.
|
|
61
|
+
|
|
62
|
+
- Unified error handling across ClassMethodHandler and InstanceMethodHandler to consistently support JSON content negotiation
|
|
35
63
|
|
|
36
64
|
AI Assistance
|
|
37
65
|
-------------
|
|
38
66
|
|
|
39
|
-
-
|
|
67
|
+
- Implementation design and architecture developed with AI pair programming
|
|
68
|
+
- Comprehensive test coverage (31 new base class tests, 12 auto-registration tests) developed with AI assistance
|
|
69
|
+
- Error class hierarchy and inheritance patterns refined through AI-guided architectural discussion
|
|
40
70
|
|
|
41
|
-
|
|
42
|
-
--------------------------------------------------------
|
|
71
|
+
.. _changelog-2.0.0.pre8:
|
|
43
72
|
|
|
44
|
-
|
|
73
|
+
2.0.0.pre8 — 2025-11-27
|
|
74
|
+
=======================
|
|
45
75
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
|
|
76
|
+
Fixed
|
|
77
|
+
-----
|
|
78
|
+
|
|
79
|
+
- Routes declaring ``response=json`` now return 401 JSON errors instead of 302 redirects when authentication fails, regardless of Accept header. The route's explicit configuration takes precedence over content negotiation.
|
|
80
|
+
|
|
81
|
+
.. _changelog-2.0.0.pre7:
|
|
82
|
+
|
|
83
|
+
2.0.0.pre7 — 2025-11-24
|
|
84
|
+
=======================
|
|
85
|
+
|
|
86
|
+
Added
|
|
87
|
+
-----
|
|
88
|
+
|
|
89
|
+
- Error handler registration system for expected business logic errors via ``otto.register_error_handler(ErrorClass, status:, log_level:)``. Supports custom response handlers via blocks.
|
|
51
90
|
|
|
52
|
-
|
|
91
|
+
Changed
|
|
92
|
+
-------
|
|
93
|
+
|
|
94
|
+
- Backtrace logging now always logs at ERROR level with sanitized file paths (was DEBUG level with full paths)
|
|
95
|
+
- Increased backtrace limit from 10 to 20 lines for better debugging context
|
|
96
|
+
- Improved gem path formatting in backtraces (e.g., ``[GEM] rack/lib/rack.rb:20``)
|
|
97
|
+
|
|
98
|
+
Fixed
|
|
99
|
+
-----
|
|
53
100
|
|
|
54
|
-
-
|
|
55
|
-
- Regular gems show cleaner output: ``[GEM] rack/lib/rack.rb:20`` instead of ``[GEM] rack-3.2.4/lib/rack.rb:20``
|
|
56
|
-
- Multi-hyphenated gem names handled correctly (``active-record-import-1.5.0`` → ``active-record-import``)
|
|
57
|
-
- Better handling of version-only directory names in gem paths
|
|
101
|
+
- Fixed path sanitization for bundler git-based gems and multi-hyphenated gem names
|
|
58
102
|
|
|
59
|
-
|
|
103
|
+
Documentation
|
|
104
|
+
-------------
|
|
60
105
|
|
|
61
|
-
- Added comprehensive backtrace sanitization section to CLAUDE.md
|
|
62
106
|
- Documented security guarantees and sanitization rules
|
|
63
107
|
- Added examples showing before/after path transformations
|
|
64
|
-
- Created comprehensive test suite for backtrace sanitization
|
|
65
|
-
|
|
66
|
-
**Rationale:**
|
|
67
108
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
- Project structure and internal organization
|
|
71
|
-
- Gem installation paths and Ruby versions
|
|
72
|
-
- System architecture details
|
|
109
|
+
AI Assistance
|
|
110
|
+
-------------
|
|
73
111
|
|
|
74
|
-
|
|
112
|
+
- Implemented error handler registration architecture with comprehensive test coverage (17 test cases) using sequential thinking to work through security implications and design decisions. AI assisted with path sanitization strategy, error classification patterns, and ensuring backward compatibility with existing error handling.
|
|
75
113
|
|
|
76
114
|
.. _changelog-2.0.0.pre6:
|
|
77
115
|
|
data/CLAUDE.md
CHANGED
|
@@ -14,6 +14,40 @@ otto.register_error_handler(YourApp::RateLimited, status: 429, log_level: :warn)
|
|
|
14
14
|
|
|
15
15
|
Must be registered before first request (before configuration freezing).
|
|
16
16
|
|
|
17
|
+
## Request/Response Helper Registration
|
|
18
|
+
|
|
19
|
+
Register application helpers that integrate with Otto features (authentication, privacy, locale):
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
module YourApp::RequestHelpers
|
|
23
|
+
def current_customer
|
|
24
|
+
user = strategy_result&.user
|
|
25
|
+
user.is_a?(YourApp::Customer) ? user : YourApp::Customer.anonymous
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
otto = Otto.new('routes.txt')
|
|
30
|
+
otto.register_request_helpers(YourApp::RequestHelpers)
|
|
31
|
+
otto.register_response_helpers(YourApp::ResponseHelpers)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Must be registered before first request.
|
|
35
|
+
|
|
36
|
+
> [!NOTE]
|
|
37
|
+
> **Helper availability by context:** The base `Otto::Request` and `Otto::Response` classes (with Otto's built-in helpers like `masked_ip`, `geo_country`) are available everywhere, including Rack middleware. However, custom helpers registered via `register_request_helpers` and `register_response_helpers` are only available in route handlers, error handlers, and components that have access to the Otto instance's dynamic request/response classes.
|
|
38
|
+
|
|
39
|
+
### Reserved Method Names
|
|
40
|
+
|
|
41
|
+
Helper modules should avoid overriding these methods inherited from Rack::Request/Rack::Response:
|
|
42
|
+
|
|
43
|
+
**Request reserved methods**: `env`, `params`, `cookies`, `session`, `path`, `path_info`, `query_string`, `request_method`, `content_type`, `content_length`, `media_type`, `get?`, `post?`, `put?`, `delete?`, `head?`, `options?`, `patch?`, `xhr?`, `referer`, `user_agent`, `base_url`, `url`, `fullpath`, `ip`, `host`, `port`, `ssl?`, `scheme`
|
|
44
|
+
|
|
45
|
+
**Response reserved methods**: `status`, `headers`, `body`, `finish`, `write`, `close`, `set_cookie`, `delete_cookie`, `redirect`, `content_type`, `content_length`, `location`
|
|
46
|
+
|
|
47
|
+
**Otto-specific methods**: `request` (on Response), `app_path`, `masked_ip`, `hashed_ip`, `client_ipaddress`, `secure?`, `local?`, `ajax?`
|
|
48
|
+
|
|
49
|
+
No runtime validation is performed for performance reasons. Overriding these methods will cause undefined behavior.
|
|
50
|
+
|
|
17
51
|
## Authentication Architecture
|
|
18
52
|
|
|
19
53
|
Authentication is handled by `RouteAuthWrapper` at the handler level, NOT by middleware.
|
|
@@ -115,6 +149,16 @@ bundle exec rubocop
|
|
|
115
149
|
bundle exec rspec
|
|
116
150
|
```
|
|
117
151
|
|
|
152
|
+
## Git Commands
|
|
153
|
+
|
|
154
|
+
Always use `--no-pager` with git commands to avoid interactive pager issues:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
git --no-pager diff
|
|
158
|
+
git --no-pager log
|
|
159
|
+
git --no-pager show
|
|
160
|
+
```
|
|
161
|
+
|
|
118
162
|
## Key Architecture Principles
|
|
119
163
|
|
|
120
164
|
- **Security by Default**: IP privacy, configuration freezing, backtrace sanitization
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
otto (2.0.0.
|
|
4
|
+
otto (2.0.0.pre10)
|
|
5
5
|
concurrent-ruby (~> 1.3, < 2.0)
|
|
6
6
|
facets (~> 3.1)
|
|
7
7
|
ipaddr (~> 1, < 2.0)
|
|
@@ -62,7 +62,7 @@ GEM
|
|
|
62
62
|
pp (>= 0.6.0)
|
|
63
63
|
rdoc (>= 4.0.0)
|
|
64
64
|
reline (>= 0.4.2)
|
|
65
|
-
json (2.
|
|
65
|
+
json (2.16.0)
|
|
66
66
|
json_schemer (2.4.0)
|
|
67
67
|
bigdecimal
|
|
68
68
|
hana (~> 1.3)
|
|
@@ -113,7 +113,7 @@ GEM
|
|
|
113
113
|
rack
|
|
114
114
|
rack-test (2.2.0)
|
|
115
115
|
rack (>= 1.3)
|
|
116
|
-
rackup (2.
|
|
116
|
+
rackup (2.3.1)
|
|
117
117
|
rack (>= 3)
|
|
118
118
|
rainbow (3.1.1)
|
|
119
119
|
rbs (3.9.5)
|
|
@@ -156,21 +156,21 @@ GEM
|
|
|
156
156
|
rubocop-ast (>= 1.47.1, < 2.0)
|
|
157
157
|
ruby-progressbar (~> 1.7)
|
|
158
158
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
159
|
-
rubocop-ast (1.
|
|
159
|
+
rubocop-ast (1.48.0)
|
|
160
160
|
parser (>= 3.3.7.2)
|
|
161
161
|
prism (~> 1.4)
|
|
162
162
|
rubocop-performance (1.26.1)
|
|
163
163
|
lint_roller (~> 1.1)
|
|
164
164
|
rubocop (>= 1.75.0, < 2.0)
|
|
165
165
|
rubocop-ast (>= 1.47.1, < 2.0)
|
|
166
|
-
rubocop-rspec (3.
|
|
166
|
+
rubocop-rspec (3.8.0)
|
|
167
167
|
lint_roller (~> 1.1)
|
|
168
|
-
rubocop (~> 1.
|
|
168
|
+
rubocop (~> 1.81)
|
|
169
169
|
rubocop-thread_safety (0.7.3)
|
|
170
170
|
lint_roller (~> 1.1)
|
|
171
171
|
rubocop (~> 1.72, >= 1.72.1)
|
|
172
172
|
rubocop-ast (>= 1.44.0, < 2.0)
|
|
173
|
-
ruby-lsp (0.26.
|
|
173
|
+
ruby-lsp (0.26.4)
|
|
174
174
|
language_server-protocol (~> 3.17.0)
|
|
175
175
|
prism (>= 1.2, < 2.0)
|
|
176
176
|
rbs (>= 3, < 5)
|
data/README.md
CHANGED
|
@@ -84,6 +84,26 @@ app = Otto.new("./routes", {
|
|
|
84
84
|
|
|
85
85
|
Security features include CSRF protection, input validation, security headers, and trusted proxy configuration.
|
|
86
86
|
|
|
87
|
+
## Error Handling
|
|
88
|
+
|
|
89
|
+
Otto provides base error classes that automatically return correct HTTP status codes:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
# Use built-in error classes directly
|
|
93
|
+
raise Otto::NotFoundError, "Product not found" # Returns 404
|
|
94
|
+
raise Otto::BadRequestError, "Invalid parameter" # Returns 400
|
|
95
|
+
raise Otto::UnauthorizedError, "Login required" # Returns 401
|
|
96
|
+
raise Otto::ForbiddenError, "Access denied" # Returns 403
|
|
97
|
+
|
|
98
|
+
# Or subclass them for your application
|
|
99
|
+
class MyApp::ResourceNotFound < Otto::NotFoundError; end
|
|
100
|
+
|
|
101
|
+
# Optionally customize status or logging (overrides auto-registration)
|
|
102
|
+
app.register_error_handler(MyApp::ResourceNotFound, status: 410, log_level: :warn)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
All framework errors are auto-registered during initialization. No manual registration required unless you want custom behavior.
|
|
106
|
+
|
|
87
107
|
## Privacy by Default
|
|
88
108
|
|
|
89
109
|
Otto automatically masks public IP addresses and anonymizes user agents to comply with GDPR, CCPA, and other privacy regulations:
|