otto 2.9.0 → 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 +203 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +11 -15
- data/README.md +75 -37
- 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 +20 -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/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 +328 -14
- data/lib/otto/security/configurator.rb +36 -6
- data/lib/otto/security/core.rb +19 -1
- 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 +31 -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
|
@@ -1,225 +1,66 @@
|
|
|
1
|
-
# Otto
|
|
1
|
+
# Otto Authentication Strategies Example
|
|
2
2
|
|
|
3
|
-
This example
|
|
3
|
+
This source-checkout example shows four route-level authentication strategies:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- `authenticated` accepts `demo_token`.
|
|
6
|
+
- `role:admin` accepts `admin_token`.
|
|
7
|
+
- `permission:write` accepts `demo_token` or `admin_token`.
|
|
8
|
+
- `api_key` accepts `demo_api_key_123`.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
- Token-based authentication with session validation
|
|
9
|
-
- API key authentication for programmatic access
|
|
10
|
-
- Role and permission-based access control
|
|
11
|
-
- How to protect routes with authentication requirements
|
|
12
|
-
- Handling authentication failures and redirects
|
|
10
|
+
The strategies are registered in `app/auth.rb` before the application handles its first request. The protected routes are defined in `routes`.
|
|
13
11
|
|
|
14
|
-
##
|
|
12
|
+
## Prerequisites
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
- `routes`: Application routes with authentication requirements
|
|
18
|
-
- `app/auth.rb`: Authentication strategy definitions and token setup
|
|
19
|
-
- `app/controllers/`: Handler classes for protected and public routes
|
|
14
|
+
Run this example from an Otto source checkout. Its `config.ru` loads Otto from `../../lib`, rather than from an installed gem.
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
### Token-Based Auth
|
|
24
|
-
Validates user tokens for web applications:
|
|
25
|
-
```
|
|
26
|
-
GET /profile HomeController#profile auth=token
|
|
27
|
-
```
|
|
28
|
-
Requires: `?token=demo_token`
|
|
29
|
-
|
|
30
|
-
### Admin Role Auth
|
|
31
|
-
Validates admin-level access:
|
|
32
|
-
```
|
|
33
|
-
GET /admin AdminController#dashboard auth=admin
|
|
34
|
-
```
|
|
35
|
-
Requires: `?token=admin_token`
|
|
36
|
-
|
|
37
|
-
### Permission-Based Auth
|
|
38
|
-
Validates specific permissions:
|
|
39
|
-
```
|
|
40
|
-
POST /edit ArticleController#update auth=can_write
|
|
41
|
-
```
|
|
42
|
-
Requires: `?token=demo_token` (with write permission)
|
|
43
|
-
|
|
44
|
-
### API Key Auth
|
|
45
|
-
Validates API keys for programmatic access:
|
|
46
|
-
```
|
|
47
|
-
GET /api/data ApiController#show auth=api_key
|
|
48
|
-
```
|
|
49
|
-
Requires: `?api_key=demo_api_key_123`
|
|
50
|
-
|
|
51
|
-
## How to Run
|
|
52
|
-
|
|
53
|
-
### Using rackup (recommended)
|
|
16
|
+
You need a supported Ruby version and Bundler. `rackup` is a development dependency in the root `Gemfile`, so enable the `development` group before installing dependencies:
|
|
54
17
|
|
|
55
18
|
```sh
|
|
56
|
-
|
|
57
|
-
|
|
19
|
+
# From the repository root
|
|
20
|
+
bundle config set with development
|
|
21
|
+
bundle install
|
|
58
22
|
```
|
|
59
23
|
|
|
60
|
-
|
|
24
|
+
## Run the example
|
|
61
25
|
|
|
62
26
|
```sh
|
|
63
|
-
|
|
64
|
-
|
|
27
|
+
# From the repository root
|
|
28
|
+
cd examples/authentication_strategies
|
|
29
|
+
bundle exec rackup config.ru
|
|
65
30
|
```
|
|
66
31
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
## Testing Authentication
|
|
70
|
-
|
|
71
|
-
### Web Browser (Token-based)
|
|
32
|
+
The server listens on `http://127.0.0.1:9292` by default. Leave it running and use a second terminal for the checks below.
|
|
72
33
|
|
|
73
|
-
|
|
34
|
+
## Verify the configured credentials
|
|
74
35
|
|
|
75
|
-
-
|
|
76
|
-
- **Authenticated user**: [http://localhost:9292/profile?token=demo_token](http://localhost:9292/profile?token=demo_token)
|
|
77
|
-
- **Admin user**: [http://localhost:9292/admin?token=admin_token](http://localhost:9292/admin?token=admin_token)
|
|
78
|
-
- **User with write permission**: [http://localhost:9292/edit?token=demo_token](http://localhost:9292/edit?token=demo_token)
|
|
79
|
-
|
|
80
|
-
### curl Commands (API Key)
|
|
36
|
+
The strategies read the token from the query string or the exact `Authorization` header value. The API-key strategy reads the key from the query string or `X-API-Key`:
|
|
81
37
|
|
|
82
38
|
```sh
|
|
83
|
-
|
|
84
|
-
curl http://
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
curl "http://localhost:9292/api/data?api_key=demo_api_key_123"
|
|
39
|
+
curl -i "http://127.0.0.1:9292/profile?token=demo_token"
|
|
40
|
+
curl -i -H 'Authorization: demo_token' http://127.0.0.1:9292/profile
|
|
41
|
+
curl -i "http://127.0.0.1:9292/api/data?api_key=demo_api_key_123"
|
|
42
|
+
curl -i -H 'X-API-Key: demo_api_key_123' http://127.0.0.1:9292/api/data
|
|
88
43
|
```
|
|
89
44
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
Try accessing protected routes without valid credentials:
|
|
45
|
+
Use an omitted or invalid credential to exercise the authentication-failure path:
|
|
93
46
|
|
|
94
47
|
```sh
|
|
95
|
-
|
|
96
|
-
curl http://
|
|
97
|
-
|
|
98
|
-
# Invalid token - returns 401
|
|
99
|
-
curl "http://localhost:9292/profile?token=invalid"
|
|
100
|
-
|
|
101
|
-
# Wrong token type - returns 401
|
|
102
|
-
curl "http://localhost:9292/admin?api_key=demo_api_key_123"
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Expected Output
|
|
106
|
-
|
|
107
|
-
### Successful Authentication
|
|
108
|
-
```
|
|
109
|
-
HTTP/1.1 200 OK
|
|
110
|
-
Content-Type: text/html
|
|
111
|
-
|
|
112
|
-
<h1>Welcome, alice!</h1>
|
|
113
|
-
<p>This is your profile.</p>
|
|
48
|
+
curl -i http://127.0.0.1:9292/profile
|
|
49
|
+
curl -i "http://127.0.0.1:9292/api/data?api_key=invalid"
|
|
114
50
|
```
|
|
115
51
|
|
|
116
|
-
###
|
|
117
|
-
```
|
|
118
|
-
HTTP/1.1 401 Unauthorized
|
|
119
|
-
Content-Type: text/plain
|
|
120
|
-
|
|
121
|
-
Unauthorized
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Redirect to Login
|
|
125
|
-
```
|
|
126
|
-
HTTP/1.1 302 Found
|
|
127
|
-
Location: http://localhost:9292/?login=required
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## File Structure Details
|
|
131
|
-
|
|
132
|
-
### Routes File
|
|
133
|
-
- Public routes (no `auth=` requirement)
|
|
134
|
-
- Protected routes with different auth strategies
|
|
135
|
-
- Admin-only routes
|
|
136
|
-
- API routes with API key authentication
|
|
137
|
-
|
|
138
|
-
### Auth Strategies (`app/auth.rb`)
|
|
139
|
-
- Token validation logic with demo tokens
|
|
140
|
-
- Admin role checking
|
|
141
|
-
- Permission validation (read, write, admin)
|
|
142
|
-
- API key validation for programmatic access
|
|
143
|
-
|
|
144
|
-
### Controllers (`app/controllers/`)
|
|
145
|
-
- Welcome controller for public pages
|
|
146
|
-
- Profile controller for authenticated users
|
|
147
|
-
- Admin controller for admin-only pages
|
|
148
|
-
- Article controller for permission-based access
|
|
149
|
-
- API controller for programmatic access
|
|
150
|
-
|
|
151
|
-
## Key Concepts
|
|
152
|
-
|
|
153
|
-
### Strategy Registration
|
|
154
|
-
Strategies are registered in `config.ru` before the first request:
|
|
155
|
-
|
|
156
|
-
```ruby
|
|
157
|
-
app.add_auth_strategy('token', TokenStrategy.new)
|
|
158
|
-
app.add_auth_strategy('admin', AdminStrategy.new)
|
|
159
|
-
app.add_auth_strategy('api_key', APIKeyStrategy.new)
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Route Protection
|
|
163
|
-
Routes specify their auth requirement in the routes file:
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
GET /protected Controller#method auth=token
|
|
167
|
-
POST /admin Controller#admin auth=admin
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### User Context
|
|
171
|
-
After successful authentication, `req.user_context` contains user info:
|
|
172
|
-
|
|
173
|
-
```ruby
|
|
174
|
-
def profile
|
|
175
|
-
user_id = @req.user_context[:user_id]
|
|
176
|
-
@res.body = "Welcome, #{user_id}!"
|
|
177
|
-
end
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Demo Credentials
|
|
181
|
-
|
|
182
|
-
### Tokens
|
|
183
|
-
- `demo_token` - Regular user (Alice)
|
|
184
|
-
- Permissions: read, write
|
|
185
|
-
- Roles: user
|
|
186
|
-
- `admin_token` - Administrator
|
|
187
|
-
- Permissions: read, write, admin
|
|
188
|
-
- Roles: admin, user
|
|
189
|
-
|
|
190
|
-
### API Keys
|
|
191
|
-
- `demo_api_key_123` - Demo API access
|
|
192
|
-
- Additional keys can be added to `app/auth.rb`
|
|
193
|
-
|
|
194
|
-
## Customizing Authentication
|
|
195
|
-
|
|
196
|
-
To add your own authentication:
|
|
197
|
-
|
|
198
|
-
1. **Create a strategy class**:
|
|
199
|
-
```ruby
|
|
200
|
-
class MyStrategy < Otto::Security::Authentication::AuthStrategy
|
|
201
|
-
def authenticate(env, requirement)
|
|
202
|
-
# Validate credentials
|
|
203
|
-
success_result(user_id: 'alice') # or failure_result
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
2. **Register it in config.ru**:
|
|
209
|
-
```ruby
|
|
210
|
-
app.add_auth_strategy('my_strategy', MyStrategy.new)
|
|
211
|
-
```
|
|
52
|
+
### Current limitation
|
|
212
53
|
|
|
213
|
-
|
|
214
|
-
```
|
|
215
|
-
GET /protected Controller#method auth=my_strategy
|
|
216
|
-
```
|
|
54
|
+
In this checkout, `app/controllers/main_controller.rb` and `app/controllers/auth_controller.rb` define class methods, while Otto instantiates route handlers with a request and response. Requests that reach those handlers therefore fail with an argument error. The commands above document the configured credential inputs, but they cannot currently verify a successful protected response until the controllers are made compatible with the handler interface.
|
|
217
55
|
|
|
218
|
-
##
|
|
56
|
+
## Files to inspect
|
|
219
57
|
|
|
220
|
-
-
|
|
221
|
-
-
|
|
58
|
+
- `config.ru` creates the Otto application, enables CSRF and request validation, and registers the strategies.
|
|
59
|
+
- `app/auth.rb` contains the demo credentials and strategy callbacks.
|
|
60
|
+
- `routes` associates each protected route with its `auth=` requirement.
|
|
61
|
+
- `app/controllers/auth_controller.rb` supplies the protected responses.
|
|
222
62
|
|
|
223
|
-
##
|
|
63
|
+
## Next steps
|
|
224
64
|
|
|
225
|
-
- [
|
|
65
|
+
- See the [security features example](../security_features/README.md) for CSRF and request-validation configuration.
|
|
66
|
+
- Read the [authentication guide](../../docs/guides/authentication.md) for application authentication design.
|
data/examples/basic/README.md
CHANGED
|
@@ -7,67 +7,52 @@ This example demonstrates a basic Otto application with a single route that acce
|
|
|
7
7
|
- How to define routes in plain-text format
|
|
8
8
|
- Creating a basic request handler class
|
|
9
9
|
- Working with Rack request and response objects
|
|
10
|
-
- Running an Otto application with
|
|
11
|
-
- Simple form handling and
|
|
10
|
+
- Running an Otto application with Rackup
|
|
11
|
+
- Simple form handling and validation
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Run it
|
|
14
14
|
|
|
15
|
-
###
|
|
15
|
+
### Prerequisites
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
cd examples/basic
|
|
19
|
-
rackup config.ru -p 10770
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
### Using thin
|
|
17
|
+
Run this example from an Otto source checkout with Ruby 3.2 through 4.0 and Bundler. `rackup` is a development dependency in the root `Gemfile`, so enable that optional group before installing the bundle.
|
|
23
18
|
|
|
24
19
|
```sh
|
|
20
|
+
git clone https://github.com/delano/otto.git
|
|
21
|
+
cd otto
|
|
22
|
+
bundle config set with development
|
|
23
|
+
bundle install
|
|
25
24
|
cd examples/basic
|
|
26
|
-
|
|
25
|
+
bundle exec rackup config.ru -p 10770
|
|
27
26
|
```
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
The server listens on `http://localhost:10770`.
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
cd examples/basic
|
|
33
|
-
puma config.ru -p 10770
|
|
34
|
-
```
|
|
30
|
+
> **Current limitation:** The checked-in app starts, but `GET /` currently returns `500` because `App#index` calls the undefined `otto_form_wrapper` helper. Until that source issue is fixed, the browser workflow below cannot be completed.
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
### Verify after fixing the source issue
|
|
37
33
|
|
|
38
|
-
|
|
34
|
+
In another terminal, confirm that the home page responds with HTML:
|
|
39
35
|
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
* Version 3.12.0 (ruby 3.2.0-p0), codename: Llama Litter Box
|
|
43
|
-
* Min threads: 0, max threads: 32
|
|
44
|
-
* Environment: development
|
|
45
|
-
* Listening on tcp://127.0.0.1:10770
|
|
46
|
-
|
|
47
|
-
[GET request to /]
|
|
48
|
-
GET / 200 OK
|
|
49
|
-
|
|
50
|
-
[Submitting feedback form]
|
|
51
|
-
POST /feedback 302 Found
|
|
52
|
-
Location: http://localhost:10770/
|
|
36
|
+
```sh
|
|
37
|
+
curl -i http://localhost:10770/
|
|
53
38
|
```
|
|
54
39
|
|
|
55
|
-
|
|
40
|
+
Expect `HTTP/1.1 200` and an HTML page containing `Otto Framework`. Open the same URL in a browser, enter a message, and submit the form. The form posts to `/` (not `/feedback`) and displays either the submitted message or the validation message for an empty submission.
|
|
56
41
|
|
|
57
42
|
## File Structure
|
|
58
43
|
|
|
59
44
|
* `README.md`: This file.
|
|
60
45
|
* `app.rb`: Contains the application logic with two methods:
|
|
61
46
|
- `index`: Displays the main page with a feedback form
|
|
62
|
-
- `receive_feedback`: Handles form submissions and
|
|
47
|
+
- `receive_feedback`: Handles form submissions and renders the result
|
|
63
48
|
* `config.ru`: The Rack configuration file that loads Otto and the application.
|
|
64
|
-
|
|
49
|
+
- `routes`: Maps `GET /` to `App#index` and `POST /` to `App#receive_feedback`.
|
|
65
50
|
|
|
66
|
-
## Trying
|
|
51
|
+
## Trying it out after resolving the limitation
|
|
67
52
|
|
|
68
|
-
1. **View the home page**: Open `http://localhost:10770` in your browser
|
|
69
|
-
2. **Submit feedback**: Enter text in the feedback form and click
|
|
70
|
-
3. **Check the
|
|
53
|
+
1. **View the home page**: Open `http://localhost:10770` in your browser.
|
|
54
|
+
2. **Submit feedback**: Enter text in the feedback form and click **Send Feedback**.
|
|
55
|
+
3. **Check the result**: The response shows the submitted message and a link back to the home page.
|
|
71
56
|
|
|
72
57
|
## Next Steps
|
|
73
58
|
|
|
@@ -77,4 +62,4 @@ Then visit `http://localhost:10770` and submit feedback to see it in action.
|
|
|
77
62
|
|
|
78
63
|
## Further Reading
|
|
79
64
|
|
|
80
|
-
- [
|
|
65
|
+
- [Project README](../../README.md) - Installation and framework overview
|
data/examples/basic/config.ru
CHANGED
|
@@ -19,9 +19,15 @@ config-only on Caddy's side.
|
|
|
19
19
|
|
|
20
20
|
## Run it
|
|
21
21
|
|
|
22
|
+
This is a source-checkout example: its Rackup file loads Otto from `../../lib`.
|
|
23
|
+
From the repository root, install the optional development dependencies (which
|
|
24
|
+
include `rackup`) and start the app:
|
|
25
|
+
|
|
22
26
|
```sh
|
|
27
|
+
bundle config set with development
|
|
28
|
+
bundle install
|
|
23
29
|
cd examples/caddy_tls_demo
|
|
24
|
-
rackup config.ru # serves on http://localhost:9292
|
|
30
|
+
bundle exec rackup config.ru # serves on http://localhost:9292
|
|
25
31
|
```
|
|
26
32
|
|
|
27
33
|
## Try it
|
|
@@ -97,4 +103,4 @@ your real data over whatever channel your app already trusts. Two more defenses:
|
|
|
97
103
|
respond @tls_permission 404
|
|
98
104
|
```
|
|
99
105
|
|
|
100
|
-
See [
|
|
106
|
+
See [ADR-003: Caddy TLS route-based integration](../../docs/adr/adr-003-caddy-tls-route-based-integration.md).
|
|
@@ -89,11 +89,20 @@ anything.
|
|
|
89
89
|
|
|
90
90
|
## How to Run
|
|
91
91
|
|
|
92
|
+
Run this example from an Otto source checkout. It requires Ruby 3.2 through
|
|
93
|
+
4.0, Bundler, and the development dependencies: `rackup` is a development
|
|
94
|
+
dependency in the root `Gemfile` and is not installed with the released `otto`
|
|
95
|
+
gem.
|
|
96
|
+
|
|
92
97
|
```sh
|
|
98
|
+
cd /path/to/otto
|
|
99
|
+
bundle config set with development
|
|
100
|
+
bundle install
|
|
93
101
|
cd examples/lambda_handlers
|
|
94
|
-
rackup config.ru -p 10780
|
|
102
|
+
bundle exec rackup config.ru -p 10780
|
|
95
103
|
```
|
|
96
104
|
|
|
105
|
+
|
|
97
106
|
Then, from another terminal:
|
|
98
107
|
|
|
99
108
|
```sh
|
|
@@ -125,4 +134,4 @@ curl -X POST --data 'hello' localhost:10780/webhook
|
|
|
125
134
|
|
|
126
135
|
## Further Reading
|
|
127
136
|
|
|
128
|
-
- [
|
|
137
|
+
- [Route syntax reference](../../docs/reference/route-syntax.md)
|