otto 2.8.1 → 2.10.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 +4 -4
- data/.github/dependabot.yml +5 -0
- data/.github/workflows/ci.yml +11 -8
- data/.github/workflows/claude-code-review.yml +38 -13
- data/.github/workflows/claude.yml +10 -8
- data/.github/workflows/code-smells.yml +5 -5
- data/.github/workflows/release-gem.yml +2 -2
- data/.github/workflows/ruby-lint.yml +3 -3
- data/.github/workflows/yardoc.yml +5 -5
- data/.gitignore +1 -5
- data/.rubocop_todo.yml +7 -5
- data/AGENTS.md +22 -1
- data/CHANGELOG.rst +239 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +11 -15
- data/README.md +139 -38
- data/docs/README.md +166 -0
- data/docs/adr/README.md +16 -0
- data/docs/adr/adr-001-route-authentication-at-handler-boundary.md +38 -0
- data/docs/adr/adr-002-multi-strategy-authentication-and-authorization.md +50 -0
- data/docs/adr/adr-003-caddy-tls-route-based-integration.md +48 -0
- data/docs/adr/adr-004-separate-compatibility-from-security-maintenance.md +58 -0
- data/docs/guides/authentication.md +377 -0
- data/docs/guides/caddy-tls.md +205 -0
- data/docs/guides/configuration_freezing.md +146 -0
- data/docs/guides/enrichment.md +161 -0
- data/docs/guides/forwarded-authority.md +249 -0
- data/docs/guides/geo-country.md +168 -0
- data/docs/guides/ip_privacy.md +39 -0
- data/docs/guides/ipaddr-encoding-quirk.md +56 -0
- data/docs/guides/mcp.md +282 -0
- data/docs/guides/privacy.md +193 -0
- data/docs/guides/routing.md +181 -0
- data/docs/guides/structured_logging.md +281 -0
- data/docs/guides/testing-guide.md +391 -0
- data/docs/maintainers/github-actions.md +41 -0
- data/docs/maintainers/investigations/.gitignore +2 -0
- data/docs/migrating/v2.0.0.md +337 -0
- data/docs/reference/authentication.md +290 -0
- data/docs/reference/route-syntax.md +181 -0
- data/docs/reference/runtime-and-dependency-security.md +86 -0
- data/examples/advanced_routes/README.md +43 -57
- data/examples/authentication_strategies/README.md +37 -196
- data/examples/basic/README.md +24 -39
- data/examples/basic/config.ru +0 -1
- data/examples/caddy_tls_demo/README.md +8 -2
- data/examples/lambda_handlers/README.md +11 -2
- data/examples/mcp_demo/README.md +75 -161
- data/examples/mcp_demo/config.ru +1 -0
- data/examples/security_features/README.md +36 -234
- data/lib/otto/caddy_tls/localhost_guard.rb +22 -24
- data/lib/otto/core/configuration.rb +36 -22
- data/lib/otto/core/file_safety.rb +89 -31
- data/lib/otto/core/middleware_stack.rb +36 -36
- data/lib/otto/core/router.rb +62 -19
- data/lib/otto/env_keys.rb +42 -2
- data/lib/otto/mcp/auth/token.rb +10 -4
- data/lib/otto/mcp/core.rb +23 -5
- data/lib/otto/mcp/endpoint.rb +41 -0
- data/lib/otto/mcp/errors.rb +15 -0
- data/lib/otto/mcp/options.rb +292 -0
- data/lib/otto/mcp/protocol.rb +52 -22
- data/lib/otto/mcp/rate_limiting.rb +175 -97
- data/lib/otto/mcp/registry.rb +14 -14
- data/lib/otto/mcp/schema_validation.rb +20 -12
- data/lib/otto/mcp/server.rb +131 -32
- data/lib/otto/optional_dependency.rb +57 -0
- data/lib/otto/privacy/config.rb +10 -8
- data/lib/otto/response.rb +7 -1
- data/lib/otto/security/authentication/route_auth_wrapper/role_authorization.rb +22 -5
- data/lib/otto/security/authentication/strategies/api_key_strategy.rb +181 -18
- data/lib/otto/security/authentication/strategies/permission_strategy.rb +1 -0
- data/lib/otto/security/authentication/strategies/role_strategy.rb +1 -0
- data/lib/otto/security/authentication/strategies/session_strategy.rb +1 -0
- data/lib/otto/security/authentication/strategy_result.rb +58 -28
- data/lib/otto/security/config.rb +379 -20
- data/lib/otto/security/configurator.rb +36 -6
- data/lib/otto/security/core.rb +19 -1
- data/lib/otto/security/csp/emit_middleware.rb +2 -1
- data/lib/otto/security/csp/policy.rb +159 -7
- data/lib/otto/security/csp/request_extras.rb +256 -0
- data/lib/otto/security/csp/writer.rb +153 -12
- data/lib/otto/security/csp.rb +5 -0
- data/lib/otto/security/middleware/ip_privacy_middleware.rb +105 -4
- data/lib/otto/security/middleware/rate_limit_middleware.rb +1 -6
- data/lib/otto/security/rate_limiter.rb +81 -46
- data/lib/otto/utils.rb +50 -0
- data/lib/otto/version.rb +1 -1
- data/lib/otto.rb +9 -11
- data/otto.gemspec +0 -2
- metadata +32 -41
- data/docs/.gitignore +0 -10
- data/docs/1108-STREAMING_ARCHITECTURE_ANALYSIS.md +0 -1105
- data/docs/1108-STREAMING_SUPPORT_SUMMARY.md +0 -376
- data/docs/enrichment.md +0 -128
- data/docs/geo-country.md +0 -181
- data/docs/ipaddr-encoding-quirk.md +0 -34
- data/docs/migrating/v2.0.0-pre1.md +0 -276
- data/docs/migrating/v2.0.0-pre2.md +0 -338
- data/docs/modern-authentication-authorization-landscape.md +0 -558
- data/docs/multi-strategy-authentication-design.md +0 -1401
- data/docs/reverse-proxy-network-services.md +0 -371
data/lib/otto.rb
CHANGED
|
@@ -76,7 +76,7 @@ class Otto
|
|
|
76
76
|
end
|
|
77
77
|
@logger = Logger.new($stdout, Logger::INFO)
|
|
78
78
|
|
|
79
|
-
attr_reader :routes, :routes_literal, :
|
|
79
|
+
attr_reader :routes, :routes_literal, :route_definitions,
|
|
80
80
|
:routes_by_definition, :option,
|
|
81
81
|
:static_route, :security_config, :locale_config, :auth_config,
|
|
82
82
|
:route_handler_factory, :mcp_server, :caddy_tls_server, :security, :middleware,
|
|
@@ -84,6 +84,7 @@ class Otto
|
|
|
84
84
|
attr_accessor :not_found, :server_error
|
|
85
85
|
|
|
86
86
|
def initialize(path = nil, opts = {})
|
|
87
|
+
constructed = false
|
|
87
88
|
initialize_core_state
|
|
88
89
|
initialize_options(path, opts)
|
|
89
90
|
initialize_configurations(opts)
|
|
@@ -106,6 +107,13 @@ class Otto
|
|
|
106
107
|
# but before processing requests.
|
|
107
108
|
@freeze_mutex = Mutex.new
|
|
108
109
|
@configuration_frozen = false
|
|
110
|
+
constructed = true
|
|
111
|
+
ensure
|
|
112
|
+
# A config that committed to a forwarding family during configure_security
|
|
113
|
+
# is held process-wide; withdraw it if construction failed afterwards
|
|
114
|
+
# (e.g. a bad routes path), or the dead app would keep vetoing other
|
|
115
|
+
# families for the life of the process.
|
|
116
|
+
Otto::Security::Config.release_rack_forwarding_family!(@security_config) if @security_config && !constructed
|
|
109
117
|
end
|
|
110
118
|
alias options option
|
|
111
119
|
|
|
@@ -172,16 +180,6 @@ class Otto
|
|
|
172
180
|
private
|
|
173
181
|
|
|
174
182
|
def initialize_core_state
|
|
175
|
-
# The GET cache is a Concurrent::Map, not a plain Hash: lazy static-file
|
|
176
|
-
# discovery (Core::Router#handle_request, Core::FileSafety#add_static_path)
|
|
177
|
-
# writes into it at request time, after freeze_configuration! has already
|
|
178
|
-
# deep-frozen the rest of the routing state. Deep-freezing this cache too
|
|
179
|
-
# would turn every as-yet-uncached static file request into a 500
|
|
180
|
-
# (FrozenError) in production (issue #185), so it is intentionally excluded
|
|
181
|
-
# from deep_freeze_value in Configuration#freeze_configuration! and kept as
|
|
182
|
-
# a structure that is both mutable post-freeze and safe under concurrent
|
|
183
|
-
# request threads.
|
|
184
|
-
@routes_static = { GET: Concurrent::Map.new }
|
|
185
183
|
@routes = { GET: [] }
|
|
186
184
|
@routes_literal = { GET: {} }
|
|
187
185
|
@route_definitions = {}
|
data/otto.gemspec
CHANGED
|
@@ -34,8 +34,6 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.add_dependency 'logger', '~> 1', '< 2.0'
|
|
35
35
|
|
|
36
36
|
spec.add_dependency 'rack', '~> 3.1', '< 4.0'
|
|
37
|
-
spec.add_dependency 'rack-parser', '~> 0.7'
|
|
38
|
-
spec.add_dependency 'rexml', '~> 3.4'
|
|
39
37
|
|
|
40
38
|
# Security dependencies
|
|
41
39
|
spec.add_dependency 'loofah', '~> 2.20'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: otto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Delano Mandelbaum
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -70,34 +70,6 @@ dependencies:
|
|
|
70
70
|
- - "<"
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
72
|
version: '4.0'
|
|
73
|
-
- !ruby/object:Gem::Dependency
|
|
74
|
-
name: rack-parser
|
|
75
|
-
requirement: !ruby/object:Gem::Requirement
|
|
76
|
-
requirements:
|
|
77
|
-
- - "~>"
|
|
78
|
-
- !ruby/object:Gem::Version
|
|
79
|
-
version: '0.7'
|
|
80
|
-
type: :runtime
|
|
81
|
-
prerelease: false
|
|
82
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
83
|
-
requirements:
|
|
84
|
-
- - "~>"
|
|
85
|
-
- !ruby/object:Gem::Version
|
|
86
|
-
version: '0.7'
|
|
87
|
-
- !ruby/object:Gem::Dependency
|
|
88
|
-
name: rexml
|
|
89
|
-
requirement: !ruby/object:Gem::Requirement
|
|
90
|
-
requirements:
|
|
91
|
-
- - "~>"
|
|
92
|
-
- !ruby/object:Gem::Version
|
|
93
|
-
version: '3.4'
|
|
94
|
-
type: :runtime
|
|
95
|
-
prerelease: false
|
|
96
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
97
|
-
requirements:
|
|
98
|
-
- - "~>"
|
|
99
|
-
- !ruby/object:Gem::Version
|
|
100
|
-
version: '3.4'
|
|
101
73
|
- !ruby/object:Gem::Dependency
|
|
102
74
|
name: loofah
|
|
103
75
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -144,18 +116,32 @@ files:
|
|
|
144
116
|
- bin/rspec
|
|
145
117
|
- changelog.d/README.md
|
|
146
118
|
- changelog.d/scriv.ini
|
|
147
|
-
- docs
|
|
148
|
-
- docs/
|
|
149
|
-
- docs/
|
|
150
|
-
- docs/
|
|
151
|
-
- docs/
|
|
152
|
-
- docs/
|
|
153
|
-
- docs/
|
|
154
|
-
- docs/
|
|
119
|
+
- docs/README.md
|
|
120
|
+
- docs/adr/README.md
|
|
121
|
+
- docs/adr/adr-001-route-authentication-at-handler-boundary.md
|
|
122
|
+
- docs/adr/adr-002-multi-strategy-authentication-and-authorization.md
|
|
123
|
+
- docs/adr/adr-003-caddy-tls-route-based-integration.md
|
|
124
|
+
- docs/adr/adr-004-separate-compatibility-from-security-maintenance.md
|
|
125
|
+
- docs/guides/authentication.md
|
|
126
|
+
- docs/guides/caddy-tls.md
|
|
127
|
+
- docs/guides/configuration_freezing.md
|
|
128
|
+
- docs/guides/enrichment.md
|
|
129
|
+
- docs/guides/forwarded-authority.md
|
|
130
|
+
- docs/guides/geo-country.md
|
|
131
|
+
- docs/guides/ip_privacy.md
|
|
132
|
+
- docs/guides/ipaddr-encoding-quirk.md
|
|
133
|
+
- docs/guides/mcp.md
|
|
134
|
+
- docs/guides/privacy.md
|
|
135
|
+
- docs/guides/routing.md
|
|
136
|
+
- docs/guides/structured_logging.md
|
|
137
|
+
- docs/guides/testing-guide.md
|
|
138
|
+
- docs/maintainers/github-actions.md
|
|
139
|
+
- docs/maintainers/investigations/.gitignore
|
|
140
|
+
- docs/migrating/v2.0.0.md
|
|
155
141
|
- docs/migrating/v2.3.0.md
|
|
156
|
-
- docs/
|
|
157
|
-
- docs/
|
|
158
|
-
- docs/
|
|
142
|
+
- docs/reference/authentication.md
|
|
143
|
+
- docs/reference/route-syntax.md
|
|
144
|
+
- docs/reference/runtime-and-dependency-security.md
|
|
159
145
|
- examples/.gitignore
|
|
160
146
|
- examples/advanced_routes/README.md
|
|
161
147
|
- examples/advanced_routes/app.rb
|
|
@@ -251,12 +237,16 @@ files:
|
|
|
251
237
|
- lib/otto/mcp.rb
|
|
252
238
|
- lib/otto/mcp/auth/token.rb
|
|
253
239
|
- lib/otto/mcp/core.rb
|
|
240
|
+
- lib/otto/mcp/endpoint.rb
|
|
241
|
+
- lib/otto/mcp/errors.rb
|
|
242
|
+
- lib/otto/mcp/options.rb
|
|
254
243
|
- lib/otto/mcp/protocol.rb
|
|
255
244
|
- lib/otto/mcp/rate_limiting.rb
|
|
256
245
|
- lib/otto/mcp/registry.rb
|
|
257
246
|
- lib/otto/mcp/route_parser.rb
|
|
258
247
|
- lib/otto/mcp/schema_validation.rb
|
|
259
248
|
- lib/otto/mcp/server.rb
|
|
249
|
+
- lib/otto/optional_dependency.rb
|
|
260
250
|
- lib/otto/privacy.rb
|
|
261
251
|
- lib/otto/privacy/anonymizer_resolver.rb
|
|
262
252
|
- lib/otto/privacy/asn_resolver.rb
|
|
@@ -312,6 +302,7 @@ files:
|
|
|
312
302
|
- lib/otto/security/csp/policy.rb
|
|
313
303
|
- lib/otto/security/csp/report.rb
|
|
314
304
|
- lib/otto/security/csp/report_middleware.rb
|
|
305
|
+
- lib/otto/security/csp/request_extras.rb
|
|
315
306
|
- lib/otto/security/csp/writer.rb
|
|
316
307
|
- lib/otto/security/csrf.rb
|
|
317
308
|
- lib/otto/security/csrf_enforcement_wrapper.rb
|
data/docs/.gitignore
DELETED