startback 1.2.4 → 2.1.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/CHANGELOG.md +954 -0
- data/README.md +45 -2
- data/UPGRADING.md +460 -0
- data/lib/startback/caching/entity_cache.rb +2 -2
- data/lib/startback/event/bus/bunny/async.rb +131 -9
- data/lib/startback/security/rate_limiter.rb +1 -1
- data/lib/startback/version.rb +3 -3
- data/lib/startback/web/auto_caching.rb +10 -4
- data/lib/startback/web/cors_headers.rb +8 -2
- data/lib/startback/web/health_check.rb +1 -1
- data/spec/spec_helper.rb +7 -0
- data/spec/support/bunny_broker.rb +145 -0
- data/spec/unit/event/bus/bunny/test_async.rb +296 -0
- data/spec/unit/web/test_auto_caching.rb +19 -0
- data/spec/unit/web/test_cors_headers.rb +21 -0
- metadata +142 -58
data/README.md
CHANGED
|
@@ -14,10 +14,53 @@ Currently,
|
|
|
14
14
|
|
|
15
15
|
## Public API
|
|
16
16
|
|
|
17
|
-
This gem uses
|
|
18
|
-
API is defined as follows:
|
|
17
|
+
This gem uses semantic versioning. The public API is defined as follows:
|
|
19
18
|
|
|
20
19
|
* All ruby classes, require path, constructor arguments, and public methods.
|
|
21
20
|
|
|
22
21
|
* The `enspirit/startback:api` and `enspirit/startback:web` docker images and
|
|
23
22
|
main `CMD`.
|
|
23
|
+
|
|
24
|
+
Upgrading across a major version? See [UPGRADING.md](UPGRADING.md).
|
|
25
|
+
|
|
26
|
+
## Supported rubies
|
|
27
|
+
|
|
28
|
+
CI runs the suite on **Ruby 3.2, 3.3, 3.4 and 4.0** -- the whole range
|
|
29
|
+
`required_ruby_version` allows. Docker images are released for 3.4 and 4.0.
|
|
30
|
+
|
|
31
|
+
## Running the tests
|
|
32
|
+
|
|
33
|
+
make tests
|
|
34
|
+
|
|
35
|
+
The `Startback::Event::Bus::Bunny::Async` specs need a real RabbitMQ broker --
|
|
36
|
+
mocking bunny would only assert that Startback calls the methods Startback
|
|
37
|
+
calls. Start one and point the suite at it:
|
|
38
|
+
|
|
39
|
+
make rabbitmq.up
|
|
40
|
+
export STARTBACK_BUS_BUNNY_ASYNC_URL=amqp://guest:guest@localhost:5672
|
|
41
|
+
make tests
|
|
42
|
+
make rabbitmq.down
|
|
43
|
+
|
|
44
|
+
Without a broker those specs **skip**, and the suite is still green. CI sets
|
|
45
|
+
`STARTBACK_SPEC_REQUIRE_BUNNY=1`, which turns "no broker" into a failure, so
|
|
46
|
+
that a broken service container cannot quietly take the coverage away.
|
|
47
|
+
|
|
48
|
+
## Docker images
|
|
49
|
+
|
|
50
|
+
docker pull enspirit/startback:api # ruby 3.4
|
|
51
|
+
docker pull enspirit/startback:web # ruby 3.4, plus nodejs and yarn
|
|
52
|
+
|
|
53
|
+
The tags that name no ruby version -- `:api`, `:api-2.1.0`, `:api-2.1` -- are
|
|
54
|
+
built with `DEFAULT_MRI_VERSION`, currently **3.4**. Every ruby version listed
|
|
55
|
+
in `RELEASE_MRI_VERSIONS` is also reachable by name:
|
|
56
|
+
|
|
57
|
+
docker pull enspirit/startback:api-ruby4.0
|
|
58
|
+
docker pull enspirit/startback:api-2.1.0-ruby4.0
|
|
59
|
+
|
|
60
|
+
Both variables live at the bottom of the [Makefile](Makefile). Adding a ruby
|
|
61
|
+
version to the release matrix means listing it there and in the
|
|
62
|
+
`ruby-version` matrix of the tests and release-images workflows.
|
|
63
|
+
|
|
64
|
+
`make images` builds and pushes one ruby version (`MRI_VERSION`, defaulting to
|
|
65
|
+
`DEFAULT_MRI_VERSION`); `make images.all` walks the whole matrix, as the
|
|
66
|
+
release workflow does with one job per version.
|
data/UPGRADING.md
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
# Upgrading Startback
|
|
2
|
+
|
|
3
|
+
## From 2.0.x to 2.1.0
|
|
4
|
+
|
|
5
|
+
**There is next to nothing to do.** Startback's API is unchanged and the
|
|
6
|
+
event bus upgrade needs no broker-side migration. One thing does move: the
|
|
7
|
+
un-suffixed docker tags go from Ruby 3.3 to Ruby 3.4. This section exists so
|
|
8
|
+
you know *why*, and so you can spot the one thing that might bite you later.
|
|
9
|
+
|
|
10
|
+
| | |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Ruby | Unchanged, still `>= 3.2`. Ruby 4.0 is now supported and tested. |
|
|
13
|
+
| Docker images | `enspirit/startback:api` and `:web` move from Ruby 3.3 to **Ruby 3.4**. Ruby 4.0 is opt-in by name. |
|
|
14
|
+
| Event bus | Durable topology now, adopted automatically. **But see the RabbitMQ 4.3 wall below.** |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
### The one thing to know: RabbitMQ 4.3
|
|
19
|
+
|
|
20
|
+
This is the only item here with a deadline, and it is not really about
|
|
21
|
+
Startback.
|
|
22
|
+
|
|
23
|
+
`queue_options` used to default to `{}`, declaring a *transient
|
|
24
|
+
non-exclusive* queue. RabbitMQ deprecated that and flips it to denied in 4.3:
|
|
25
|
+
|
|
26
|
+
| RabbitMQ | transient non-exclusive queues | Startback <= 2.0 bus |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| 4.0, 4.1, 4.2 | permitted | works |
|
|
29
|
+
| **4.3+** | **denied** | **`listen` receives nothing, then `Timeout::Error`** |
|
|
30
|
+
|
|
31
|
+
So on 4.2 or earlier nothing is on fire today -- but 4.3 is a wall you hit
|
|
32
|
+
whether or not you upgrade Startback. 2.1.0 is what gets you over it: the
|
|
33
|
+
exchange and queue are now declared `durable: true`.
|
|
34
|
+
|
|
35
|
+
### Why the durable switch costs you nothing
|
|
36
|
+
|
|
37
|
+
AMQP refuses to redeclare an exchange or queue with different properties. On
|
|
38
|
+
a broker that has been up continuously since an older Startback declared its
|
|
39
|
+
topology, the new durable declaration is rejected with
|
|
40
|
+
`PRECONDITION_FAILED`. Startback now **adopts** what is already there rather
|
|
41
|
+
than failing on it, logging:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
Adopting an existing fanout whose properties differ from the requested ones.
|
|
45
|
+
It will be declared as requested after the next broker restart.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
So deploy in any order, with or without restarting the broker. There is
|
|
49
|
+
nothing to drain and nothing to delete: a transient queue holds no durable
|
|
50
|
+
state, and does not survive a broker restart in the first place. You become
|
|
51
|
+
durable by yourself the next time the broker restarts.
|
|
52
|
+
|
|
53
|
+
Restarting the broker before deploying gets you there immediately, but it is
|
|
54
|
+
an option, not a requirement.
|
|
55
|
+
|
|
56
|
+
Applications already passing their own `queue_options`/`fanout_options` are
|
|
57
|
+
unaffected: explicit options still win.
|
|
58
|
+
|
|
59
|
+
### Two bus bugs fixed, in case you saw them
|
|
60
|
+
|
|
61
|
+
Both predate 2.1.0 and neither announced itself. If you have ever seen the
|
|
62
|
+
bus "just stop" until a restart, this is likely why:
|
|
63
|
+
|
|
64
|
+
* **A dead channel was cached forever.** A channel-level error closes the
|
|
65
|
+
channel, and the bus kept one per thread without checking it was still
|
|
66
|
+
open. One such error broke the bus for that thread permanently -- every
|
|
67
|
+
later `emit` failing with `cannot use a closed channel`, for *any* event
|
|
68
|
+
type. Since `emit` runs inside `stop_errors`, the application kept
|
|
69
|
+
returning 200s while dropping every event.
|
|
70
|
+
|
|
71
|
+
* **Declaring could unsubscribe your listeners.** A rejected declaration
|
|
72
|
+
closes the channel it happened on, which was the shared one carrying your
|
|
73
|
+
consumers. Topology is now probed on a scratch channel.
|
|
74
|
+
|
|
75
|
+
### Bus listeners still receive a String
|
|
76
|
+
|
|
77
|
+
Not a change, but now documented and pinned by a spec, because it bites
|
|
78
|
+
people moving a listener between busses:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
bus.listen("My::Event::Type", "my-processor") do |body|
|
|
82
|
+
# Bus::Memory::Async hands over a Startback::Event here.
|
|
83
|
+
# Bus::Bunny::Async hands over the raw JSON String.
|
|
84
|
+
event = Startback::Event.json(body, nil)
|
|
85
|
+
end
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Docker images, if you build on them
|
|
89
|
+
|
|
90
|
+
`enspirit/startback:api` and `:web` are built from `DEFAULT_MRI_VERSION`,
|
|
91
|
+
now **Ruby 3.4**. 2.0.0 published them from Ruby 3.3, so tracking those tags
|
|
92
|
+
moves you one ruby minor version -- not a major, and 3.3 reaches end of life
|
|
93
|
+
in March 2027. Ruby 4.0 stays opt-in, asked for by name:
|
|
94
|
+
|
|
95
|
+
```dockerfile
|
|
96
|
+
FROM enspirit/startback:api-ruby4.0 # tracks 2.x on ruby 4.0
|
|
97
|
+
FROM enspirit/startback:api-2.1.0-ruby4.0 # pinned
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The `web` target now installs **nodejs 22** instead of 20, node 20 being end
|
|
101
|
+
of life since April 2026. Applications pinning a node version in their own
|
|
102
|
+
layer are unaffected.
|
|
103
|
+
|
|
104
|
+
**Moving your own application to Ruby 4.0** is a separate exercise, and worth
|
|
105
|
+
doing separately. `benchmark`, `logger` and `ostruct` stop being default gems
|
|
106
|
+
there: if your code requires them without declaring them, add them to your
|
|
107
|
+
Gemfile. Startback already declares all three for itself.
|
|
108
|
+
|
|
109
|
+
### Checklist
|
|
110
|
+
|
|
111
|
+
- [ ] Nothing, unless you are heading for RabbitMQ 4.3 -- in which case 2.1.0
|
|
112
|
+
is what you need, and it is enough
|
|
113
|
+
- [ ] `:api` / `:web` move from Ruby 3.3 to 3.4. 2.1.0 publishes no Ruby 3.3
|
|
114
|
+
image: ask for `-ruby4.0` if you want 4.0, or stay on
|
|
115
|
+
`:api-2.0.0-ruby3.3` if you are not ready to leave 3.3
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## From 1.2.x to 2.0.0
|
|
120
|
+
|
|
121
|
+
**Startback's own API has not changed.** Every class, require path, constructor
|
|
122
|
+
argument and public method behaves as it did in 1.2.x. What changed is the
|
|
123
|
+
dependency floor: Sinatra 4, and therefore Rack 3, are now required, and the
|
|
124
|
+
other dependencies moved to their latest major.
|
|
125
|
+
|
|
126
|
+
So almost everything below is about *your* application code meeting Rack 3 and
|
|
127
|
+
Sinatra 4, not about Startback. Each section is written as: what you will see,
|
|
128
|
+
why, and what to do.
|
|
129
|
+
|
|
130
|
+
Rough budget: a small API service usually needs **two changes** -- setting
|
|
131
|
+
`RACK_ENV`, and lowercasing any response triples it builds by hand. The rest
|
|
132
|
+
depends on what you use.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Before you start
|
|
137
|
+
|
|
138
|
+
| | |
|
|
139
|
+
|---|---|
|
|
140
|
+
| Ruby | **>= 3.2** is now enforced by the gemspec. 3.1 is end of life. |
|
|
141
|
+
| webspicy | **Must move to 1.x.** See [webspicy](#10-webspicy-must-move-to-1x) -- this one fails to install, it does not degrade quietly. |
|
|
142
|
+
| Everything else | Installs fine; behaviour changes are listed below. |
|
|
143
|
+
|
|
144
|
+
Start with:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
bundle update startback
|
|
148
|
+
bundle exec rake test # or whatever runs your suite
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Most failures will be issue 1 or issue 2.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 1. Every request returns `403 Host not permitted`
|
|
156
|
+
|
|
157
|
+
**You will see** every request failing with status 403 and a `text/plain` body
|
|
158
|
+
reading `Host not permitted` -- in your test suite first, and in local
|
|
159
|
+
development if you reach the app through anything other than `localhost`.
|
|
160
|
+
|
|
161
|
+
**Why.** Sinatra 4.1 added `Rack::Protection::HostAuthorization` (for
|
|
162
|
+
CVE-2024-21510). In the `development` environment it only accepts `localhost`,
|
|
163
|
+
`*.localhost`, `*.test` and IP literals as `Host`. `development` is the
|
|
164
|
+
environment Sinatra picks when **neither `RACK_ENV` nor `APP_ENV` is set**,
|
|
165
|
+
which is the common case in test suites and docker-compose.
|
|
166
|
+
|
|
167
|
+
Test suites are hit systematically because `Rack::Test` sends requests to
|
|
168
|
+
`example.org`, and so does webspicy's `RackTestClient`.
|
|
169
|
+
|
|
170
|
+
**Production is not affected**: outside `development`, the permitted list is
|
|
171
|
+
empty, which means "allow everything".
|
|
172
|
+
|
|
173
|
+
**Fix, for test suites** -- set the environment before Sinatra is loaded, i.e.
|
|
174
|
+
at the very top of `spec_helper.rb` (or your webspicy `config.rb`), *above* the
|
|
175
|
+
`require`s:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
ENV['RACK_ENV'] ||= 'test'
|
|
179
|
+
|
|
180
|
+
require 'startback'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Fix, for local development behind a custom hostname** -- either set
|
|
184
|
+
`RACK_ENV` in your docker-compose/`.env`, or declare the hosts:
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
class MyApi < Startback::Web::Api
|
|
188
|
+
set :host_authorization, { permitted_hosts: ['.my-app.internal', '.localhost'] }
|
|
189
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
A leading dot matches subdomains. Passing an empty list disables the check
|
|
193
|
+
entirely -- reasonable for a service that only ever sits behind a trusted
|
|
194
|
+
reverse proxy, but it is opting out of a CVE fix, so do it deliberately.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## 2. A response header appears twice, or a middleware stops seeing it
|
|
199
|
+
|
|
200
|
+
**You will see** responses carrying, say, both `Cache-Control` and
|
|
201
|
+
`cache-control` with different values; or a middleware that used to read a
|
|
202
|
+
header no longer finding it; or a caching proxy behaving oddly.
|
|
203
|
+
|
|
204
|
+
**Why.** The Rack 3 SPEC states that response header keys *"must not contain
|
|
205
|
+
uppercase ASCII characters (A-Z)"*. Rack 3 middleware therefore looks headers
|
|
206
|
+
up in lowercase. A triple you build by hand with `"Content-Type"` is a
|
|
207
|
+
different key from the `"content-type"` everything else uses, so instead of
|
|
208
|
+
overriding, it coexists.
|
|
209
|
+
|
|
210
|
+
Nothing raises. This is a silent behaviour change, which is what makes it worth
|
|
211
|
+
hunting for deliberately.
|
|
212
|
+
|
|
213
|
+
**Fix.** Lowercase the header names in any response triple your code builds:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
# before
|
|
217
|
+
[200, { "Content-Type" => "application/json" }, [body]]
|
|
218
|
+
|
|
219
|
+
# after
|
|
220
|
+
[200, { "content-type" => "application/json" }, [body]]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Grep for it:
|
|
224
|
+
|
|
225
|
+
```sh
|
|
226
|
+
grep -rnE '"(Content-Type|Cache-Control|Location|Content-Length|X-[A-Za-z-]+)"\s*=>' app lib
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
You do **not** need to change:
|
|
230
|
+
|
|
231
|
+
* `content_type :json` and friends inside a Sinatra route -- Sinatra normalizes.
|
|
232
|
+
* Reading headers from a response object (`response['Content-Type']`) --
|
|
233
|
+
`Rack::Headers` is case-insensitive on read.
|
|
234
|
+
* Startback's own middlewares. `AutoCaching`, `CorsHeaders`, `HealthCheck`,
|
|
235
|
+
`Shield` and `CatchAll` were all fixed in this release; `AutoCaching` and
|
|
236
|
+
`CorsHeaders` had exactly this duplication bug.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 3. `undefined method 'each' for an instance of String`
|
|
241
|
+
|
|
242
|
+
**You will see** that error, or a blank response body.
|
|
243
|
+
|
|
244
|
+
**Why.** Rack 3 requires a response body to respond to `each` or `call`. A bare
|
|
245
|
+
String is no longer a valid body.
|
|
246
|
+
|
|
247
|
+
**Fix.** Wrap it:
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
# before
|
|
251
|
+
[404, { "content-type" => "text/plain" }, "NotFound"]
|
|
252
|
+
|
|
253
|
+
# after
|
|
254
|
+
[404, { "content-type" => "text/plain" }, ["NotFound"]]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 4. `uninitialized constant` for a Rack 2 class
|
|
260
|
+
|
|
261
|
+
Rack 3 removed a number of constants. If your app or a third-party middleware
|
|
262
|
+
uses one, it fails at load time:
|
|
263
|
+
|
|
264
|
+
| Removed | Use instead |
|
|
265
|
+
|---|---|
|
|
266
|
+
| `Rack::Utils::HeaderHash` | `Rack::Headers` |
|
|
267
|
+
| `Rack::File` | `Rack::Files` |
|
|
268
|
+
| `Rack::Session::Cookie` | the `rack-session` gem (Sinatra already depends on it) |
|
|
269
|
+
| `Rack::Handler` | `Rackup::Handler`, from the `rackup` gem |
|
|
270
|
+
|
|
271
|
+
If the failure comes from a gem rather than your code, check whether it has a
|
|
272
|
+
Rack 3 compatible release. This is the most common reason an upgrade stalls,
|
|
273
|
+
and it is nothing Startback can shield you from.
|
|
274
|
+
|
|
275
|
+
Sinatra 4 also dropped the `IndifferentHash` initializer, disabled
|
|
276
|
+
`session_hijacking` protection by default, and removed
|
|
277
|
+
`Rack::Protection::EncryptedCookie` (cookies are still encrypted, by
|
|
278
|
+
`Rack::Session::Cookie`). And if you start the server by running the app file
|
|
279
|
+
directly rather than through `config.ru` + puma, you now need the `rackup` gem
|
|
280
|
+
in your Gemfile.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## 5. Puma: lifecycle hooks renamed, and a new default bind
|
|
285
|
+
|
|
286
|
+
Puma goes from 6 to 8, crossing two majors. Startback never loads puma itself
|
|
287
|
+
-- it ships it for you -- so nothing here is detectable by Startback's tests.
|
|
288
|
+
|
|
289
|
+
**Puma 7 renamed every lifecycle hook.** If your `puma.rb` uses the old names
|
|
290
|
+
they are simply not called, silently:
|
|
291
|
+
|
|
292
|
+
| Before | After |
|
|
293
|
+
|---|---|
|
|
294
|
+
| `on_worker_boot` | `before_worker_boot` |
|
|
295
|
+
| `on_worker_shutdown` | `before_worker_shutdown` |
|
|
296
|
+
| `on_restart` | `before_restart` |
|
|
297
|
+
| `on_booted` | `after_booted` |
|
|
298
|
+
| `on_stopped` | `after_stopped` |
|
|
299
|
+
| `on_refork` | `before_refork` |
|
|
300
|
+
| `on_thread_start` | `before_thread_start` |
|
|
301
|
+
|
|
302
|
+
This matters most for database connection handling, which is usually exactly
|
|
303
|
+
what those hooks do.
|
|
304
|
+
|
|
305
|
+
**Puma 7 also** made `preload_app!` the default in clustered mode, and requires
|
|
306
|
+
a config instance to be `clamp`-ed before values are read.
|
|
307
|
+
|
|
308
|
+
**Puma 8** changed the default production bind from `0.0.0.0` to `::` when an
|
|
309
|
+
IPv6 interface is available. In a container that publishes ports over IPv4
|
|
310
|
+
only, this can make the service unreachable. Bind explicitly if you care:
|
|
311
|
+
|
|
312
|
+
```ruby
|
|
313
|
+
# puma.rb
|
|
314
|
+
bind 'tcp://0.0.0.0:3000'
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Not ready?** `gem 'puma', '~> 6.0'` in your Gemfile. Startback accepts
|
|
318
|
+
`>= 6.0.2, < 9.0`.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 6. `undefined method 'fast_generate' for module JSON`
|
|
323
|
+
|
|
324
|
+
**Why.** json 3 removed `JSON.fast_generate`.
|
|
325
|
+
|
|
326
|
+
**Fix.** `JSON.generate`. It is the same output; `fast_generate` only skipped
|
|
327
|
+
the circular-reference check.
|
|
328
|
+
|
|
329
|
+
Startback used it internally in `Security::RateLimiter` and
|
|
330
|
+
`Caching::EntityCache#encode_key`, and both now use `JSON.generate`. **The
|
|
331
|
+
generated strings are identical**, so cache entries and rate-limit counters
|
|
332
|
+
survive the upgrade -- no cache flush needed.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 7. jwt 2 to 3
|
|
337
|
+
|
|
338
|
+
Only relevant if your application uses JWT; Startback ships the gem but never
|
|
339
|
+
loads it. jwt 3 is a real break:
|
|
340
|
+
|
|
341
|
+
* RSA keys must be **at least 2048 bits**. Shorter keys now raise.
|
|
342
|
+
* Base64 decoding follows RFC 4648 strictly; tolerantly-encoded tokens that
|
|
343
|
+
used to decode now fail.
|
|
344
|
+
* The payload cannot be read before the signature is verified.
|
|
345
|
+
* `HS512256` is gone.
|
|
346
|
+
* Custom algorithms must include `JWT::JWA::SigningAlgorithm`.
|
|
347
|
+
* Since 3.3: if you rescue `JWT::DecodeError`, `JWT::IncorrectAlgorithm` or
|
|
348
|
+
`ArgumentError` **around `JWT.encode`**, rescue `JWT::EncodeError` instead.
|
|
349
|
+
Decoding is unaffected.
|
|
350
|
+
|
|
351
|
+
Read jwt's own `UPGRADING.md` before taking it. **Not ready?**
|
|
352
|
+
`gem 'jwt', '~> 2.1'`. Startback accepts `>= 2.1, < 4.0`.
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## 8. finitio 0.12 to 1.0: check your `.fio` schemas
|
|
357
|
+
|
|
358
|
+
Two removals affect schemas, and one of them changes meaning silently:
|
|
359
|
+
|
|
360
|
+
* `Fixnum` and `Bignum` are gone from `finitio/data`. Use `Integer`. This one
|
|
361
|
+
fails loudly.
|
|
362
|
+
* **`FalseClass` was a bug and is now fixed.** It used to be an alias of
|
|
363
|
+
`.TrueClass`, so it accepted `true` and rejected `false`. If a schema of
|
|
364
|
+
yours worked around that -- writing `FalseClass` where it meant a *true*
|
|
365
|
+
value -- it now means the opposite.
|
|
366
|
+
|
|
367
|
+
Grep before upgrading:
|
|
368
|
+
|
|
369
|
+
```sh
|
|
370
|
+
grep -rn "Fixnum\|Bignum\|FalseClass" --include=*.fio .
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Not ready?** `gem 'finitio', '~> 0.12'`. Startback accepts `>= 0.12, < 2.0`.
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## 9. bunny 2 to 3, if you use the event bus
|
|
378
|
+
|
|
379
|
+
Applies to `Startback::Event::Bus::Bunny::Async` only.
|
|
380
|
+
|
|
381
|
+
* Versioned delivery tags are removed.
|
|
382
|
+
* Passive declarations (`passive: true`) are no longer replayed by topology
|
|
383
|
+
recovery.
|
|
384
|
+
* The `openssl` gem >= 3.3 is now required, which means a native build --
|
|
385
|
+
watch slim/alpine images.
|
|
386
|
+
|
|
387
|
+
**Heads up on coverage:** Startback's test matrix has no RabbitMQ, so the Bunny
|
|
388
|
+
bus is upgraded but *unverified by the suite*. If you use it, exercise it in a
|
|
389
|
+
staging environment rather than trusting the green build. *(Fixed in 2.1.0 --
|
|
390
|
+
and it found a RabbitMQ 4.3 incompatibility. See the 2.1.0 section above.)*
|
|
391
|
+
|
|
392
|
+
**Not ready?** `gem 'bunny', '~> 2.14'`. Startback accepts `>= 2.14, < 4.0`.
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
## 10. webspicy must move to 1.x
|
|
398
|
+
|
|
399
|
+
**You will see** `bundle install` fail outright:
|
|
400
|
+
|
|
401
|
+
```
|
|
402
|
+
Because every version of startback depends on rack-robustness >= 2.0, < 3.0
|
|
403
|
+
and webspicy >= 0.25.0 depends on rack-robustness >= 1.2, < 2.0,
|
|
404
|
+
every version of startback is incompatible with webspicy >= 0.25.0.
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Why.** Every webspicy 0.27.x release caps `finitio < 0.13`, `http < 6.0` and
|
|
408
|
+
`rack-robustness < 2.0`. webspicy 1.0 widened all three.
|
|
409
|
+
|
|
410
|
+
**Fix.** `gem 'webspicy', '>= 1.0', '< 2.0'`.
|
|
411
|
+
|
|
412
|
+
There is no way around this one, and no quiet degradation: bundler refuses to
|
|
413
|
+
resolve.
|
|
414
|
+
|
|
415
|
+
Coming from 0.26 or earlier, note that webspicy validates unstructured
|
|
416
|
+
response bodies against `output_schema` since 0.27, where it used to skip
|
|
417
|
+
them. A content-negotiating endpoint may need its schema widened accordingly
|
|
418
|
+
(e.g. `[Todo]|Csv` for one serving both JSON and CSV).
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Opting out, gem by gem
|
|
423
|
+
|
|
424
|
+
Startback deliberately declares **wide ranges** for the dependencies it does
|
|
425
|
+
not use itself, so you can stay on an older major while still upgrading
|
|
426
|
+
Startback. Add the pin to your own Gemfile:
|
|
427
|
+
|
|
428
|
+
| Gem | Startback accepts | Pin to stay put |
|
|
429
|
+
|---|---|---|
|
|
430
|
+
| puma | `>= 6.0.2, < 9.0` | `gem 'puma', '~> 6.0'` |
|
|
431
|
+
| jwt | `>= 2.1, < 4.0` | `gem 'jwt', '~> 2.1'` |
|
|
432
|
+
| http | `>= 5.0, < 7.0` | `gem 'http', '~> 5.0'` |
|
|
433
|
+
| bunny | `>= 2.14, < 4.0` | `gem 'bunny', '~> 2.14'` |
|
|
434
|
+
| finitio | `>= 0.12, < 2.0` | `gem 'finitio', '~> 0.12'` |
|
|
435
|
+
| json | `>= 2.6, < 4.0` | `gem 'json', '~> 2.6'` |
|
|
436
|
+
|
|
437
|
+
These cannot be opted out of, because Startback's own code depends on them:
|
|
438
|
+
|
|
439
|
+
| Gem | Required |
|
|
440
|
+
|---|---|
|
|
441
|
+
| sinatra | `>= 4.0, < 5.0` -- the middlewares use `Rack::Headers`, Rack 3 only |
|
|
442
|
+
| rack-robustness | `>= 2.0, < 3.0` -- `Shield` and `CatchAll` subclass it |
|
|
443
|
+
| Ruby | `>= 3.2` |
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Checklist
|
|
448
|
+
|
|
449
|
+
- [ ] Ruby >= 3.2
|
|
450
|
+
- [ ] `RACK_ENV` set in the test suite, at the top of `spec_helper.rb`
|
|
451
|
+
- [ ] Response triples built by hand use lowercase header names
|
|
452
|
+
- [ ] Response bodies are arrays, not bare Strings
|
|
453
|
+
- [ ] No `Rack::Utils::HeaderHash` / `Rack::File` / `Rack::Handler` left, in
|
|
454
|
+
your code or your gems
|
|
455
|
+
- [ ] `puma.rb` lifecycle hooks renamed; bind address checked
|
|
456
|
+
- [ ] No `JSON.fast_generate` left
|
|
457
|
+
- [ ] `.fio` schemas grepped for `Fixnum`, `Bignum`, `FalseClass`
|
|
458
|
+
- [ ] webspicy on 1.x
|
|
459
|
+
- [ ] jwt / bunny reviewed, or pinned
|
|
460
|
+
- [ ] Bunny event bus exercised somewhere real, since CI does not cover it
|
|
@@ -144,10 +144,10 @@ module Startback
|
|
|
144
144
|
|
|
145
145
|
# Encodes a context free key to an actual cache key.
|
|
146
146
|
#
|
|
147
|
-
# Default implementation uses JSON.
|
|
147
|
+
# Default implementation uses JSON.generate but MAY be
|
|
148
148
|
# overriden.
|
|
149
149
|
def encode_key(context_free_key)
|
|
150
|
-
JSON.
|
|
150
|
+
JSON.generate(context_free_key)
|
|
151
151
|
end
|
|
152
152
|
|
|
153
153
|
# Returns whether `cached` entity seems fresh enough to
|