otto 2.0.0.pre3 → 2.0.0.pre8
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/code-smells.yml +143 -0
- data/.gitignore +4 -0
- data/.pre-commit-config.yaml +2 -2
- data/.reek.yml +99 -0
- data/CHANGELOG.rst +156 -0
- data/CLAUDE.md +74 -540
- data/Gemfile +4 -2
- data/Gemfile.lock +58 -19
- data/README.md +49 -1
- data/examples/advanced_routes/README.md +137 -20
- data/examples/authentication_strategies/README.md +212 -19
- data/examples/backtrace_sanitization_demo.rb +86 -0
- data/examples/basic/README.md +61 -10
- data/examples/error_handler_registration.rb +136 -0
- data/examples/logging_improvements.rb +76 -0
- data/examples/mcp_demo/README.md +187 -27
- data/examples/security_features/README.md +249 -30
- data/examples/simple_geo_resolver.rb +107 -0
- data/lib/otto/core/configuration.rb +15 -20
- data/lib/otto/core/error_handler.rb +138 -8
- data/lib/otto/core/file_safety.rb +2 -2
- data/lib/otto/core/freezable.rb +2 -2
- data/lib/otto/core/middleware_stack.rb +2 -2
- data/lib/otto/core/router.rb +61 -8
- data/lib/otto/core/uri_generator.rb +2 -2
- data/lib/otto/core.rb +2 -0
- data/lib/otto/design_system.rb +2 -2
- data/lib/otto/env_keys.rb +61 -12
- data/lib/otto/helpers/base.rb +2 -2
- data/lib/otto/helpers/request.rb +8 -3
- data/lib/otto/helpers/response.rb +2 -2
- data/lib/otto/helpers/validation.rb +2 -2
- data/lib/otto/helpers.rb +2 -0
- data/lib/otto/locale/config.rb +2 -2
- data/lib/otto/locale/middleware.rb +160 -0
- data/lib/otto/locale.rb +10 -0
- data/lib/otto/logging_helpers.rb +273 -0
- data/lib/otto/mcp/auth/token.rb +2 -2
- data/lib/otto/mcp/protocol.rb +2 -2
- data/lib/otto/mcp/rate_limiting.rb +2 -2
- data/lib/otto/mcp/registry.rb +2 -2
- data/lib/otto/mcp/route_parser.rb +2 -2
- data/lib/otto/mcp/schema_validation.rb +2 -2
- data/lib/otto/mcp/server.rb +2 -2
- data/lib/otto/mcp.rb +2 -0
- data/lib/otto/privacy/config.rb +2 -0
- data/lib/otto/privacy/geo_resolver.rb +199 -29
- data/lib/otto/privacy/ip_privacy.rb +2 -0
- data/lib/otto/privacy/redacted_fingerprint.rb +18 -8
- data/lib/otto/privacy.rb +2 -0
- data/lib/otto/response_handlers/auto.rb +2 -0
- data/lib/otto/response_handlers/base.rb +2 -0
- data/lib/otto/response_handlers/default.rb +2 -0
- data/lib/otto/response_handlers/factory.rb +2 -0
- data/lib/otto/response_handlers/json.rb +2 -0
- data/lib/otto/response_handlers/redirect.rb +2 -0
- data/lib/otto/response_handlers/view.rb +2 -0
- data/lib/otto/response_handlers.rb +2 -2
- data/lib/otto/route.rb +4 -4
- data/lib/otto/route_definition.rb +42 -15
- data/lib/otto/route_handlers/base.rb +2 -0
- data/lib/otto/route_handlers/class_method.rb +26 -26
- data/lib/otto/route_handlers/factory.rb +2 -2
- data/lib/otto/route_handlers/instance_method.rb +16 -6
- data/lib/otto/route_handlers/lambda.rb +8 -20
- data/lib/otto/route_handlers/logic_class.rb +33 -8
- data/lib/otto/route_handlers.rb +2 -2
- data/lib/otto/security/authentication/auth_failure.rb +2 -2
- data/lib/otto/security/authentication/auth_strategy.rb +11 -4
- data/lib/otto/security/authentication/route_auth_wrapper/response_builder.rb +123 -0
- data/lib/otto/security/authentication/route_auth_wrapper/role_authorization.rb +120 -0
- data/lib/otto/security/authentication/route_auth_wrapper/strategy_resolver.rb +69 -0
- data/lib/otto/security/authentication/route_auth_wrapper.rb +185 -195
- data/lib/otto/security/authentication/strategies/api_key_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategies/noauth_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategies/permission_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategies/role_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategies/session_strategy.rb +2 -0
- data/lib/otto/security/authentication/strategy_result.rb +6 -5
- data/lib/otto/security/authentication.rb +2 -2
- data/lib/otto/security/authorization_error.rb +73 -0
- data/lib/otto/security/config.rb +2 -2
- data/lib/otto/security/configurator.rb +17 -2
- data/lib/otto/security/csrf.rb +2 -2
- data/lib/otto/security/middleware/csrf_middleware.rb +11 -1
- data/lib/otto/security/middleware/ip_privacy_middleware.rb +31 -11
- data/lib/otto/security/middleware/rate_limit_middleware.rb +2 -0
- data/lib/otto/security/middleware/validation_middleware.rb +15 -0
- data/lib/otto/security/rate_limiter.rb +2 -2
- data/lib/otto/security/rate_limiting.rb +2 -2
- data/lib/otto/security/validator.rb +2 -2
- data/lib/otto/security.rb +3 -0
- data/lib/otto/static.rb +2 -2
- data/lib/otto/utils.rb +27 -2
- data/lib/otto/version.rb +3 -3
- data/lib/otto.rb +174 -14
- data/otto.gemspec +7 -3
- metadata +25 -15
- data/benchmark_middleware_wrap.rb +0 -163
- data/changelog.d/20251014_144317_delano_54_thats_a_wrapper.rst +0 -36
- data/changelog.d/20251014_161526_delano_54_thats_a_wrapper.rst +0 -5
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: otto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.0.
|
|
4
|
+
version: 2.0.0.pre8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Delano Mandelbaum
|
|
@@ -10,12 +10,12 @@ cert_chain: []
|
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
|
-
name:
|
|
13
|
+
name: concurrent-ruby
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '1'
|
|
18
|
+
version: '1.3'
|
|
19
19
|
- - "<"
|
|
20
20
|
- !ruby/object:Gem::Version
|
|
21
21
|
version: '2.0'
|
|
@@ -25,17 +25,17 @@ dependencies:
|
|
|
25
25
|
requirements:
|
|
26
26
|
- - "~>"
|
|
27
27
|
- !ruby/object:Gem::Version
|
|
28
|
-
version: '1'
|
|
28
|
+
version: '1.3'
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: '2.0'
|
|
32
32
|
- !ruby/object:Gem::Dependency
|
|
33
|
-
name:
|
|
33
|
+
name: ipaddr
|
|
34
34
|
requirement: !ruby/object:Gem::Requirement
|
|
35
35
|
requirements:
|
|
36
36
|
- - "~>"
|
|
37
37
|
- !ruby/object:Gem::Version
|
|
38
|
-
version: '1
|
|
38
|
+
version: '1'
|
|
39
39
|
- - "<"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
41
|
version: '2.0'
|
|
@@ -45,7 +45,7 @@ dependencies:
|
|
|
45
45
|
requirements:
|
|
46
46
|
- - "~>"
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: '1
|
|
48
|
+
version: '1'
|
|
49
49
|
- - "<"
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: '2.0'
|
|
@@ -107,16 +107,16 @@ dependencies:
|
|
|
107
107
|
name: rexml
|
|
108
108
|
requirement: !ruby/object:Gem::Requirement
|
|
109
109
|
requirements:
|
|
110
|
-
- - "
|
|
110
|
+
- - "~>"
|
|
111
111
|
- !ruby/object:Gem::Version
|
|
112
|
-
version: 3.
|
|
112
|
+
version: '3.4'
|
|
113
113
|
type: :runtime
|
|
114
114
|
prerelease: false
|
|
115
115
|
version_requirements: !ruby/object:Gem::Requirement
|
|
116
116
|
requirements:
|
|
117
|
-
- - "
|
|
117
|
+
- - "~>"
|
|
118
118
|
- !ruby/object:Gem::Version
|
|
119
|
-
version: 3.
|
|
119
|
+
version: '3.4'
|
|
120
120
|
- !ruby/object:Gem::Dependency
|
|
121
121
|
name: facets
|
|
122
122
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -155,9 +155,11 @@ files:
|
|
|
155
155
|
- ".github/workflows/ci.yml"
|
|
156
156
|
- ".github/workflows/claude-code-review.yml"
|
|
157
157
|
- ".github/workflows/claude.yml"
|
|
158
|
+
- ".github/workflows/code-smells.yml"
|
|
158
159
|
- ".gitignore"
|
|
159
160
|
- ".pre-commit-config.yaml"
|
|
160
161
|
- ".pre-push-config.yaml"
|
|
162
|
+
- ".reek.yml"
|
|
161
163
|
- ".rspec"
|
|
162
164
|
- ".rubocop.yml"
|
|
163
165
|
- CHANGELOG.rst
|
|
@@ -166,10 +168,7 @@ files:
|
|
|
166
168
|
- Gemfile.lock
|
|
167
169
|
- LICENSE.txt
|
|
168
170
|
- README.md
|
|
169
|
-
- benchmark_middleware_wrap.rb
|
|
170
171
|
- bin/rspec
|
|
171
|
-
- changelog.d/20251014_144317_delano_54_thats_a_wrapper.rst
|
|
172
|
-
- changelog.d/20251014_161526_delano_54_thats_a_wrapper.rst
|
|
173
172
|
- changelog.d/README.md
|
|
174
173
|
- changelog.d/scriv.ini
|
|
175
174
|
- docs/.gitignore
|
|
@@ -217,10 +216,13 @@ files:
|
|
|
217
216
|
- examples/authentication_strategies/app/controllers/main_controller.rb
|
|
218
217
|
- examples/authentication_strategies/config.ru
|
|
219
218
|
- examples/authentication_strategies/routes
|
|
219
|
+
- examples/backtrace_sanitization_demo.rb
|
|
220
220
|
- examples/basic/README.md
|
|
221
221
|
- examples/basic/app.rb
|
|
222
222
|
- examples/basic/config.ru
|
|
223
223
|
- examples/basic/routes
|
|
224
|
+
- examples/error_handler_registration.rb
|
|
225
|
+
- examples/logging_improvements.rb
|
|
224
226
|
- examples/mcp_demo/README.md
|
|
225
227
|
- examples/mcp_demo/app.rb
|
|
226
228
|
- examples/mcp_demo/config.ru
|
|
@@ -229,6 +231,7 @@ files:
|
|
|
229
231
|
- examples/security_features/app.rb
|
|
230
232
|
- examples/security_features/config.ru
|
|
231
233
|
- examples/security_features/routes
|
|
234
|
+
- examples/simple_geo_resolver.rb
|
|
232
235
|
- lib/otto.rb
|
|
233
236
|
- lib/otto/core.rb
|
|
234
237
|
- lib/otto/core/configuration.rb
|
|
@@ -245,7 +248,10 @@ files:
|
|
|
245
248
|
- lib/otto/helpers/request.rb
|
|
246
249
|
- lib/otto/helpers/response.rb
|
|
247
250
|
- lib/otto/helpers/validation.rb
|
|
251
|
+
- lib/otto/locale.rb
|
|
248
252
|
- lib/otto/locale/config.rb
|
|
253
|
+
- lib/otto/locale/middleware.rb
|
|
254
|
+
- lib/otto/logging_helpers.rb
|
|
249
255
|
- lib/otto/mcp.rb
|
|
250
256
|
- lib/otto/mcp/auth/token.rb
|
|
251
257
|
- lib/otto/mcp/protocol.rb
|
|
@@ -281,12 +287,16 @@ files:
|
|
|
281
287
|
- lib/otto/security/authentication/auth_failure.rb
|
|
282
288
|
- lib/otto/security/authentication/auth_strategy.rb
|
|
283
289
|
- lib/otto/security/authentication/route_auth_wrapper.rb
|
|
290
|
+
- lib/otto/security/authentication/route_auth_wrapper/response_builder.rb
|
|
291
|
+
- lib/otto/security/authentication/route_auth_wrapper/role_authorization.rb
|
|
292
|
+
- lib/otto/security/authentication/route_auth_wrapper/strategy_resolver.rb
|
|
284
293
|
- lib/otto/security/authentication/strategies/api_key_strategy.rb
|
|
285
294
|
- lib/otto/security/authentication/strategies/noauth_strategy.rb
|
|
286
295
|
- lib/otto/security/authentication/strategies/permission_strategy.rb
|
|
287
296
|
- lib/otto/security/authentication/strategies/role_strategy.rb
|
|
288
297
|
- lib/otto/security/authentication/strategies/session_strategy.rb
|
|
289
298
|
- lib/otto/security/authentication/strategy_result.rb
|
|
299
|
+
- lib/otto/security/authorization_error.rb
|
|
290
300
|
- lib/otto/security/config.rb
|
|
291
301
|
- lib/otto/security/configurator.rb
|
|
292
302
|
- lib/otto/security/csrf.rb
|
|
@@ -325,7 +335,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
325
335
|
- !ruby/object:Gem::Version
|
|
326
336
|
version: '0'
|
|
327
337
|
requirements: []
|
|
328
|
-
rubygems_version: 3.
|
|
338
|
+
rubygems_version: 3.7.2
|
|
329
339
|
specification_version: 4
|
|
330
340
|
summary: Auto-define your rack-apps in plaintext.
|
|
331
341
|
test_files: []
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Benchmark to measure real-world Otto performance with actual routes and middleware
|
|
5
|
-
# Usage: ruby benchmark_middleware_wrap.rb
|
|
6
|
-
|
|
7
|
-
require 'bundler/setup'
|
|
8
|
-
require 'benchmark'
|
|
9
|
-
require 'stringio'
|
|
10
|
-
require 'tempfile'
|
|
11
|
-
|
|
12
|
-
require_relative 'lib/otto'
|
|
13
|
-
|
|
14
|
-
REQUEST_COUNT = 50_000
|
|
15
|
-
MIDDLEWARE_COUNT = 40
|
|
16
|
-
|
|
17
|
-
# Create a temporary routes file
|
|
18
|
-
routes_content = <<~ROUTES
|
|
19
|
-
GET / TestApp.index
|
|
20
|
-
GET /users/:id TestApp.show
|
|
21
|
-
POST /users TestApp.create
|
|
22
|
-
GET /health TestApp.health
|
|
23
|
-
ROUTES
|
|
24
|
-
|
|
25
|
-
routes_file = Tempfile.new(['routes', '.txt'])
|
|
26
|
-
routes_file.write(routes_content)
|
|
27
|
-
routes_file.close
|
|
28
|
-
|
|
29
|
-
# Define test application
|
|
30
|
-
class TestApp
|
|
31
|
-
def self.index(_env, _params = {})
|
|
32
|
-
[200, { 'Content-Type' => 'text/html' }, ['Welcome']]
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def self.show(env, params = {})
|
|
36
|
-
user_id = params[:id] || env.dig('otto.params', :id) || '123'
|
|
37
|
-
[200, { 'Content-Type' => 'text/html' }, ["User #{user_id}"]]
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def self.create(_env, _params = {})
|
|
41
|
-
[201, { 'Content-Type' => 'application/json' }, ['{"id": 123}']]
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def self.health(_env, _params = {})
|
|
45
|
-
[200, { 'Content-Type' => 'text/plain' }, ['OK']]
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Create real Rack middleware
|
|
50
|
-
class BenchmarkMiddleware
|
|
51
|
-
def initialize(app, _config = nil)
|
|
52
|
-
@app = app
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def call(env)
|
|
56
|
-
@app.call(env)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Create Otto instance with real configuration
|
|
61
|
-
otto = Otto.new(routes_file.path)
|
|
62
|
-
|
|
63
|
-
# Add real Otto security middleware
|
|
64
|
-
otto.enable_csrf_protection!
|
|
65
|
-
otto.enable_request_validation!
|
|
66
|
-
|
|
67
|
-
# Add custom middleware to reach target count
|
|
68
|
-
current_count = otto.middleware.size
|
|
69
|
-
(MIDDLEWARE_COUNT - current_count).times do
|
|
70
|
-
otto.use(Class.new(BenchmarkMiddleware))
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Suppress error logging for benchmark
|
|
74
|
-
Otto.logger.level = Logger::FATAL
|
|
75
|
-
|
|
76
|
-
puts "\n" + ("=" * 70)
|
|
77
|
-
puts "Otto Performance Benchmark"
|
|
78
|
-
puts ("=" * 70)
|
|
79
|
-
puts "Configuration:"
|
|
80
|
-
puts " Routes: #{otto.instance_variable_get(:@route_definitions).size}"
|
|
81
|
-
actual_app = otto.instance_variable_get(:@app)
|
|
82
|
-
puts " Middleware: #{otto.middleware.size} (#{MIDDLEWARE_COUNT} total in stack, app built: #{!actual_app.nil?})"
|
|
83
|
-
puts " Requests: #{REQUEST_COUNT.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse}"
|
|
84
|
-
puts ("=" * 70)
|
|
85
|
-
|
|
86
|
-
# Create realistic Rack environments for different routes
|
|
87
|
-
def make_env(method, path)
|
|
88
|
-
{
|
|
89
|
-
'REQUEST_METHOD' => method,
|
|
90
|
-
'PATH_INFO' => path,
|
|
91
|
-
'QUERY_STRING' => '',
|
|
92
|
-
'SERVER_NAME' => 'example.com',
|
|
93
|
-
'SERVER_PORT' => '80',
|
|
94
|
-
'rack.version' => [1, 3],
|
|
95
|
-
'rack.url_scheme' => 'http',
|
|
96
|
-
'rack.input' => StringIO.new,
|
|
97
|
-
'rack.errors' => StringIO.new,
|
|
98
|
-
'rack.multithread' => false,
|
|
99
|
-
'rack.multiprocess' => true,
|
|
100
|
-
'rack.run_once' => false,
|
|
101
|
-
'REMOTE_ADDR' => '192.168.1.100',
|
|
102
|
-
'HTTP_USER_AGENT' => 'Benchmark/1.0',
|
|
103
|
-
'rack.session' => {}
|
|
104
|
-
}
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Test different routes
|
|
108
|
-
routes = [
|
|
109
|
-
['GET', '/'],
|
|
110
|
-
['GET', '/users/123'],
|
|
111
|
-
['POST', '/users'],
|
|
112
|
-
['GET', '/health']
|
|
113
|
-
]
|
|
114
|
-
|
|
115
|
-
# Warmup
|
|
116
|
-
puts "\nWarming up (1,000 requests)..."
|
|
117
|
-
1_000.times do |i|
|
|
118
|
-
method, path = routes[i % routes.size]
|
|
119
|
-
env = make_env(method, path)
|
|
120
|
-
otto.call(env)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
puts "\n" + ("=" * 70)
|
|
124
|
-
puts "Running benchmark..."
|
|
125
|
-
puts ("=" * 70)
|
|
126
|
-
|
|
127
|
-
# Benchmark
|
|
128
|
-
result = Benchmark.measure do
|
|
129
|
-
REQUEST_COUNT.times do |i|
|
|
130
|
-
method, path = routes[i % routes.size]
|
|
131
|
-
env = make_env(method, path)
|
|
132
|
-
otto.call(env)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
total_time = result.real
|
|
137
|
-
per_request = (total_time / REQUEST_COUNT * 1_000_000).round(2)
|
|
138
|
-
requests_per_sec = (REQUEST_COUNT / total_time).round(0)
|
|
139
|
-
|
|
140
|
-
puts "\nResults:"
|
|
141
|
-
puts ("=" * 70)
|
|
142
|
-
puts " Total time: #{(total_time * 1000).round(2)}ms"
|
|
143
|
-
puts " Time per request: #{per_request}µs"
|
|
144
|
-
puts " Requests/sec: #{requests_per_sec.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse}"
|
|
145
|
-
puts ("=" * 70)
|
|
146
|
-
|
|
147
|
-
# Performance analysis
|
|
148
|
-
puts "\nPerformance Analysis:"
|
|
149
|
-
if per_request < 20
|
|
150
|
-
puts " ✓ Excellent performance (< 20µs per request)"
|
|
151
|
-
elsif per_request < 50
|
|
152
|
-
puts " ✓ Good performance (< 50µs per request)"
|
|
153
|
-
elsif per_request < 100
|
|
154
|
-
puts " ~ Acceptable performance (< 100µs per request)"
|
|
155
|
-
else
|
|
156
|
-
puts " ⚠ May need optimization (#{per_request}µs per request)"
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
puts "\nMiddleware overhead: ~#{((per_request - 2.5) / MIDDLEWARE_COUNT).round(3)}µs per middleware"
|
|
160
|
-
puts
|
|
161
|
-
|
|
162
|
-
# Cleanup
|
|
163
|
-
routes_file.unlink
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
Changed
|
|
2
|
-
-------
|
|
3
|
-
|
|
4
|
-
- Authentication now handled by RouteAuthWrapper at handler level instead of middleware
|
|
5
|
-
- RouteAuthWrapper enhanced with session persistence, security headers, strategy caching, and sophisticated pattern matching
|
|
6
|
-
- env['otto.strategy_result'] now GUARANTEED to be present on all routes (authenticated or anonymous)
|
|
7
|
-
- RouteAuthWrapper now wraps all route handlers, not just routes with auth requirements
|
|
8
|
-
|
|
9
|
-
Removed
|
|
10
|
-
-------
|
|
11
|
-
|
|
12
|
-
- Removed AuthenticationMiddleware (architecturally broken - executed before routing)
|
|
13
|
-
- Removed enable_authentication! (no longer needed - RouteAuthWrapper handles auth automatically)
|
|
14
|
-
- Removed defensive nil fallback from LogicClassHandler (no longer needed)
|
|
15
|
-
|
|
16
|
-
Fixed
|
|
17
|
-
-----
|
|
18
|
-
|
|
19
|
-
- Session persistence now works correctly (env['rack.session'] references same object as strategy_result.session)
|
|
20
|
-
- Security headers now included on all authentication failure responses (401/302)
|
|
21
|
-
- Strategy lookups now cached for performance
|
|
22
|
-
- env['otto.strategy_result'] is now guaranteed to be present (anonymous StrategyResult for public routes)
|
|
23
|
-
- Routes without auth requirements now get anonymous StrategyResult with IP metadata
|
|
24
|
-
|
|
25
|
-
Security
|
|
26
|
-
--------
|
|
27
|
-
|
|
28
|
-
- Authentication strategies now execute after routing when route_definition is available
|
|
29
|
-
- Supports exact match, prefix match (role:admin), and fallback patterns for strategies
|
|
30
|
-
|
|
31
|
-
Documentation
|
|
32
|
-
-------------
|
|
33
|
-
|
|
34
|
-
- Updated CLAUDE.md with RouteAuthWrapper architecture overview
|
|
35
|
-
- Updated env_keys.rb to document guaranteed presence of strategy_result
|
|
36
|
-
- Added comprehensive tests for anonymous route handling
|