otto 2.0.0.pre3 → 2.0.0.pre7
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 +146 -0
- data/.gitignore +4 -0
- data/.pre-commit-config.yaml +2 -2
- data/.reek.yml +99 -0
- data/CHANGELOG.rst +90 -0
- data/CLAUDE.md +74 -540
- data/Gemfile +4 -2
- data/Gemfile.lock +58 -19
- data/README.md +49 -1
- data/changelog.d/20251103_235431_delano_86_improve_error_logging.rst +15 -0
- data/changelog.d/20251109_025012_claude_fix_backtrace_sanitization.rst +37 -0
- 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 +18 -25
- data/lib/otto/route_handlers/factory.rb +2 -2
- data/lib/otto/route_handlers/instance_method.rb +8 -5
- data/lib/otto/route_handlers/lambda.rb +8 -20
- data/lib/otto/route_handlers/logic_class.rb +23 -6
- 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.rb +230 -78
- 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 +24 -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
data/otto.gemspec
CHANGED
|
@@ -10,21 +10,25 @@ Gem::Specification.new do |spec|
|
|
|
10
10
|
spec.email = 'gems@solutious.com'
|
|
11
11
|
spec.authors = ['Delano Mandelbaum']
|
|
12
12
|
spec.license = 'MIT'
|
|
13
|
-
spec.files =
|
|
13
|
+
spec.files = if File.directory?('.git') && system('git --version > /dev/null 2>&1')
|
|
14
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
15
|
+
else
|
|
16
|
+
Dir['**/*'].select { |f| File.file?(f) }.reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
17
|
+
end
|
|
14
18
|
spec.homepage = 'https://github.com/delano/otto'
|
|
15
19
|
spec.require_paths = ['lib']
|
|
16
20
|
|
|
17
21
|
spec.required_ruby_version = ['>= 3.2', '< 4.0']
|
|
18
22
|
|
|
19
|
-
spec.add_dependency 'ipaddr', '~> 1', '< 2.0'
|
|
20
23
|
spec.add_dependency 'concurrent-ruby', '~> 1.3', '< 2.0'
|
|
24
|
+
spec.add_dependency 'ipaddr', '~> 1', '< 2.0'
|
|
21
25
|
|
|
22
26
|
# Logger is not part of the default gems as of Ruby 3.5.0
|
|
23
27
|
spec.add_dependency 'logger', '~> 1', '< 2.0'
|
|
24
28
|
|
|
25
29
|
spec.add_dependency 'rack', '~> 3.1', '< 4.0'
|
|
26
30
|
spec.add_dependency 'rack-parser', '~> 0.7'
|
|
27
|
-
spec.add_dependency 'rexml', '
|
|
31
|
+
spec.add_dependency 'rexml', '~> 3.4'
|
|
28
32
|
|
|
29
33
|
# Security dependencies
|
|
30
34
|
spec.add_dependency 'facets', '~> 3.1'
|
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.pre7
|
|
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,9 @@ 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/
|
|
172
|
-
- changelog.d/
|
|
172
|
+
- changelog.d/20251103_235431_delano_86_improve_error_logging.rst
|
|
173
|
+
- changelog.d/20251109_025012_claude_fix_backtrace_sanitization.rst
|
|
173
174
|
- changelog.d/README.md
|
|
174
175
|
- changelog.d/scriv.ini
|
|
175
176
|
- docs/.gitignore
|
|
@@ -217,10 +218,13 @@ files:
|
|
|
217
218
|
- examples/authentication_strategies/app/controllers/main_controller.rb
|
|
218
219
|
- examples/authentication_strategies/config.ru
|
|
219
220
|
- examples/authentication_strategies/routes
|
|
221
|
+
- examples/backtrace_sanitization_demo.rb
|
|
220
222
|
- examples/basic/README.md
|
|
221
223
|
- examples/basic/app.rb
|
|
222
224
|
- examples/basic/config.ru
|
|
223
225
|
- examples/basic/routes
|
|
226
|
+
- examples/error_handler_registration.rb
|
|
227
|
+
- examples/logging_improvements.rb
|
|
224
228
|
- examples/mcp_demo/README.md
|
|
225
229
|
- examples/mcp_demo/app.rb
|
|
226
230
|
- examples/mcp_demo/config.ru
|
|
@@ -229,6 +233,7 @@ files:
|
|
|
229
233
|
- examples/security_features/app.rb
|
|
230
234
|
- examples/security_features/config.ru
|
|
231
235
|
- examples/security_features/routes
|
|
236
|
+
- examples/simple_geo_resolver.rb
|
|
232
237
|
- lib/otto.rb
|
|
233
238
|
- lib/otto/core.rb
|
|
234
239
|
- lib/otto/core/configuration.rb
|
|
@@ -245,7 +250,10 @@ files:
|
|
|
245
250
|
- lib/otto/helpers/request.rb
|
|
246
251
|
- lib/otto/helpers/response.rb
|
|
247
252
|
- lib/otto/helpers/validation.rb
|
|
253
|
+
- lib/otto/locale.rb
|
|
248
254
|
- lib/otto/locale/config.rb
|
|
255
|
+
- lib/otto/locale/middleware.rb
|
|
256
|
+
- lib/otto/logging_helpers.rb
|
|
249
257
|
- lib/otto/mcp.rb
|
|
250
258
|
- lib/otto/mcp/auth/token.rb
|
|
251
259
|
- lib/otto/mcp/protocol.rb
|
|
@@ -287,6 +295,7 @@ files:
|
|
|
287
295
|
- lib/otto/security/authentication/strategies/role_strategy.rb
|
|
288
296
|
- lib/otto/security/authentication/strategies/session_strategy.rb
|
|
289
297
|
- lib/otto/security/authentication/strategy_result.rb
|
|
298
|
+
- lib/otto/security/authorization_error.rb
|
|
290
299
|
- lib/otto/security/config.rb
|
|
291
300
|
- lib/otto/security/configurator.rb
|
|
292
301
|
- lib/otto/security/csrf.rb
|
|
@@ -325,7 +334,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
325
334
|
- !ruby/object:Gem::Version
|
|
326
335
|
version: '0'
|
|
327
336
|
requirements: []
|
|
328
|
-
rubygems_version: 3.
|
|
337
|
+
rubygems_version: 3.7.2
|
|
329
338
|
specification_version: 4
|
|
330
339
|
summary: Auto-define your rack-apps in plaintext.
|
|
331
340
|
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
|