stitches 3.8.2 → 4.1.0RC2
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/.circleci/config.yml +131 -28
- data/.github/CODEOWNERS +1 -1
- data/.ruby-version +1 -1
- data/Gemfile.rails-6.1 +7 -0
- data/README.md +55 -25
- data/lib/stitches/allowlist_middleware.rb +0 -1
- data/lib/stitches/api_client_access_wrapper.rb +42 -0
- data/lib/stitches/api_generator.rb +3 -2
- data/lib/stitches/api_key.rb +1 -8
- data/lib/stitches/configuration.rb +35 -6
- data/lib/stitches/generator_files/config/initializers/stitches.rb +10 -0
- data/lib/stitches/railtie.rb +2 -0
- data/lib/stitches/render_timestamps_in_iso8601_in_json.rb +6 -2
- data/lib/stitches/valid_mime_type.rb +11 -4
- data/lib/stitches/version.rb +3 -1
- data/lib/stitches_norailtie.rb +0 -1
- data/owners.json +1 -1
- data/spec/api_client_access_wrapper_spec.rb +52 -0
- data/spec/api_key_spec.rb +7 -8
- data/spec/configuration_spec.rb +39 -10
- data/spec/integration/add_to_rails_app_spec.rb +0 -29
- data/spec/valid_mime_type_spec.rb +16 -0
- data/stitches.gemspec +1 -0
- metadata +26 -10
- data/lib/stitches/update_configuration_generator.rb +0 -16
- data/lib/stitches/whitelisting_middleware.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 181e2199d9e7f15ef933d3c3b87262f83894e02c25821d53aa23191db16c6a7a
|
4
|
+
data.tar.gz: 8f90ed0f8e39e94715f77f2708f1fe87da31318f97708dfd50692f8408ec9d71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4043849fc0c7da16cd1a87216897a6bf696b0cf82adf18d5a2d0e0277fd8ba7881e6af75e1c6451ee9fece50902bb1088166ac46c40eddc74cc4b3c01f5ecc5
|
7
|
+
data.tar.gz: 2e2310a95b713fe859ce309cac4d03552fd094ac03d2526045095980f488204a27a04da5c459b90719af9f947af13f1d70301b9eddb21f90a742470198760bd2
|
data/.circleci/config.yml
CHANGED
@@ -3,9 +3,33 @@
|
|
3
3
|
---
|
4
4
|
version: 2
|
5
5
|
jobs:
|
6
|
+
generate-and-push-docs:
|
7
|
+
docker:
|
8
|
+
- image: circleci/ruby:3.0.0
|
9
|
+
auth:
|
10
|
+
username: "$DOCKERHUB_USERNAME"
|
11
|
+
password: "$DOCKERHUB_PASSWORD"
|
12
|
+
steps:
|
13
|
+
- checkout
|
14
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
15
|
+
- run: bundle install --full-index
|
16
|
+
- run:
|
17
|
+
name: Generate documentation
|
18
|
+
command: ' if [[ $(bundle exec rake -T docs:generate:custom) ]]; then echo
|
19
|
+
"Generating docs using rake task docs:generate:custom" ; bundle exec rake
|
20
|
+
docs:generate:custom ; elif [[ $(bundle exec rake -T docs:generate) ]];
|
21
|
+
then echo "Generating docs using rake task docs:generate" ; bundle exec
|
22
|
+
rake docs:generate ; else echo "Skipping doc generation" ; exit 0 ; fi '
|
23
|
+
- run:
|
24
|
+
name: Push documentation to Unwritten
|
25
|
+
command: if [[ $(bundle exec rake -T docs:push) ]]; then bundle exec rake
|
26
|
+
docs:push; fi
|
6
27
|
release:
|
7
28
|
docker:
|
8
|
-
- image: circleci/ruby:
|
29
|
+
- image: circleci/ruby:3.0.0
|
30
|
+
auth:
|
31
|
+
username: "$DOCKERHUB_USERNAME"
|
32
|
+
password: "$DOCKERHUB_PASSWORD"
|
9
33
|
steps:
|
10
34
|
- checkout
|
11
35
|
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
@@ -17,14 +41,52 @@ jobs:
|
|
17
41
|
- run:
|
18
42
|
name: Build/release gem to artifactory
|
19
43
|
command: bundle exec rake push_artifactory
|
20
|
-
ruby-
|
44
|
+
ruby-3.0.0-rails-6.1:
|
21
45
|
docker:
|
22
|
-
- image: circleci/ruby:
|
46
|
+
- image: circleci/ruby:3.0.0
|
47
|
+
auth:
|
48
|
+
username: "$DOCKERHUB_USERNAME"
|
49
|
+
password: "$DOCKERHUB_PASSWORD"
|
23
50
|
environment:
|
24
|
-
BUNDLE_GEMFILE: Gemfile.rails-6.
|
51
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.1
|
52
|
+
working_directory: "~/stitches"
|
53
|
+
steps:
|
54
|
+
- checkout
|
55
|
+
- run:
|
56
|
+
name: Check for Gemfile.lock presence
|
57
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
58
|
+
https://github.com/stitchfix/eng-wiki/blob/master/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
59
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
60
|
+
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
61
|
+
- run: bundle install --full-index
|
62
|
+
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
63
|
+
--format=doc
|
64
|
+
- run:
|
65
|
+
name: Run Additional CI Steps
|
66
|
+
command: if [ -e bin/additional-ci-steps ]; then bin/additional-ci-steps;
|
67
|
+
fi
|
68
|
+
- run:
|
69
|
+
name: Notify Pager Duty
|
70
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
71
|
+
when: on_fail
|
72
|
+
- store_test_results:
|
73
|
+
path: "/tmp/test-results"
|
74
|
+
ruby-2.7.2-rails-6.1:
|
75
|
+
docker:
|
76
|
+
- image: circleci/ruby:2.7.2
|
77
|
+
auth:
|
78
|
+
username: "$DOCKERHUB_USERNAME"
|
79
|
+
password: "$DOCKERHUB_PASSWORD"
|
80
|
+
environment:
|
81
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.1
|
25
82
|
working_directory: "~/stitches"
|
26
83
|
steps:
|
27
84
|
- checkout
|
85
|
+
- run:
|
86
|
+
name: Check for Gemfile.lock presence
|
87
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
88
|
+
https://github.com/stitchfix/eng-wiki/blob/master/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
89
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
28
90
|
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
29
91
|
- run: bundle install --full-index
|
30
92
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
@@ -35,18 +97,26 @@ jobs:
|
|
35
97
|
fi
|
36
98
|
- run:
|
37
99
|
name: Notify Pager Duty
|
38
|
-
command: bundle exec y-notify "#
|
100
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
39
101
|
when: on_fail
|
40
102
|
- store_test_results:
|
41
103
|
path: "/tmp/test-results"
|
42
|
-
ruby-
|
104
|
+
ruby-3.0.0-rails-6.0:
|
43
105
|
docker:
|
44
|
-
- image: circleci/ruby:
|
106
|
+
- image: circleci/ruby:3.0.0
|
107
|
+
auth:
|
108
|
+
username: "$DOCKERHUB_USERNAME"
|
109
|
+
password: "$DOCKERHUB_PASSWORD"
|
45
110
|
environment:
|
46
111
|
BUNDLE_GEMFILE: Gemfile.rails-6.0
|
47
112
|
working_directory: "~/stitches"
|
48
113
|
steps:
|
49
114
|
- checkout
|
115
|
+
- run:
|
116
|
+
name: Check for Gemfile.lock presence
|
117
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
118
|
+
https://github.com/stitchfix/eng-wiki/blob/master/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
119
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
50
120
|
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
51
121
|
- run: bundle install --full-index
|
52
122
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
@@ -57,18 +127,26 @@ jobs:
|
|
57
127
|
fi
|
58
128
|
- run:
|
59
129
|
name: Notify Pager Duty
|
60
|
-
command: bundle exec y-notify "#
|
130
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
61
131
|
when: on_fail
|
62
132
|
- store_test_results:
|
63
133
|
path: "/tmp/test-results"
|
64
|
-
ruby-2.7.
|
134
|
+
ruby-2.7.2-rails-6.0:
|
65
135
|
docker:
|
66
|
-
- image: circleci/ruby:2.7.
|
136
|
+
- image: circleci/ruby:2.7.2
|
137
|
+
auth:
|
138
|
+
username: "$DOCKERHUB_USERNAME"
|
139
|
+
password: "$DOCKERHUB_PASSWORD"
|
67
140
|
environment:
|
68
|
-
BUNDLE_GEMFILE: Gemfile.rails-
|
141
|
+
BUNDLE_GEMFILE: Gemfile.rails-6.0
|
69
142
|
working_directory: "~/stitches"
|
70
143
|
steps:
|
71
144
|
- checkout
|
145
|
+
- run:
|
146
|
+
name: Check for Gemfile.lock presence
|
147
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
148
|
+
https://github.com/stitchfix/eng-wiki/blob/master/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
149
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
72
150
|
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
73
151
|
- run: bundle install --full-index
|
74
152
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
@@ -79,18 +157,26 @@ jobs:
|
|
79
157
|
fi
|
80
158
|
- run:
|
81
159
|
name: Notify Pager Duty
|
82
|
-
command: bundle exec y-notify "#
|
160
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
83
161
|
when: on_fail
|
84
162
|
- store_test_results:
|
85
163
|
path: "/tmp/test-results"
|
86
|
-
ruby-2.
|
164
|
+
ruby-2.7.2-rails-5.2:
|
87
165
|
docker:
|
88
|
-
- image: circleci/ruby:2.
|
166
|
+
- image: circleci/ruby:2.7.2
|
167
|
+
auth:
|
168
|
+
username: "$DOCKERHUB_USERNAME"
|
169
|
+
password: "$DOCKERHUB_PASSWORD"
|
89
170
|
environment:
|
90
171
|
BUNDLE_GEMFILE: Gemfile.rails-5.2
|
91
172
|
working_directory: "~/stitches"
|
92
173
|
steps:
|
93
174
|
- checkout
|
175
|
+
- run:
|
176
|
+
name: Check for Gemfile.lock presence
|
177
|
+
command: ' if (test -f Gemfile.lock) then echo "Dont commit Gemfile.lock (see
|
178
|
+
https://github.com/stitchfix/eng-wiki/blob/master/architecture-decisions/0009-rubygem-dependencies-will-be-managed-more-explicitly.md)"
|
179
|
+
1>&2 ; exit 1 ; else exit 0 ; fi '
|
94
180
|
- run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
|
95
181
|
- run: bundle install --full-index
|
96
182
|
- run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
|
@@ -101,7 +187,7 @@ jobs:
|
|
101
187
|
fi
|
102
188
|
- run:
|
103
189
|
name: Notify Pager Duty
|
104
|
-
command: bundle exec y-notify "#
|
190
|
+
command: bundle exec y-notify "#eng-runtime-alerts"
|
105
191
|
when: on_fail
|
106
192
|
- store_test_results:
|
107
193
|
path: "/tmp/test-results"
|
@@ -112,31 +198,46 @@ workflows:
|
|
112
198
|
- release:
|
113
199
|
context: org-global
|
114
200
|
requires:
|
115
|
-
- ruby-
|
116
|
-
- ruby-2.
|
117
|
-
- ruby-
|
118
|
-
- ruby-2.
|
201
|
+
- ruby-3.0.0-rails-6.1
|
202
|
+
- ruby-2.7.2-rails-6.1
|
203
|
+
- ruby-3.0.0-rails-6.0
|
204
|
+
- ruby-2.7.2-rails-6.0
|
205
|
+
- ruby-2.7.2-rails-5.2
|
119
206
|
filters:
|
120
207
|
tags:
|
121
|
-
only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?RC[-\.]?\
|
208
|
+
only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
|
122
209
|
branches:
|
123
210
|
ignore: /.*/
|
124
|
-
-
|
211
|
+
- generate-and-push-docs:
|
212
|
+
context: org-global
|
213
|
+
requires:
|
214
|
+
- release
|
215
|
+
filters:
|
216
|
+
tags:
|
217
|
+
only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\w*)?$/
|
218
|
+
branches:
|
219
|
+
ignore: /.*/
|
220
|
+
- ruby-3.0.0-rails-6.1:
|
125
221
|
context: org-global
|
126
222
|
filters:
|
127
223
|
tags:
|
128
224
|
only: &1 /.*/
|
129
|
-
- ruby-2.
|
225
|
+
- ruby-2.7.2-rails-6.1:
|
130
226
|
context: org-global
|
131
227
|
filters:
|
132
228
|
tags:
|
133
229
|
only: *1
|
134
|
-
- ruby-
|
230
|
+
- ruby-3.0.0-rails-6.0:
|
135
231
|
context: org-global
|
136
232
|
filters:
|
137
233
|
tags:
|
138
234
|
only: *1
|
139
|
-
- ruby-2.
|
235
|
+
- ruby-2.7.2-rails-6.0:
|
236
|
+
context: org-global
|
237
|
+
filters:
|
238
|
+
tags:
|
239
|
+
only: *1
|
240
|
+
- ruby-2.7.2-rails-5.2:
|
140
241
|
context: org-global
|
141
242
|
filters:
|
142
243
|
tags:
|
@@ -150,11 +251,13 @@ workflows:
|
|
150
251
|
only:
|
151
252
|
- master
|
152
253
|
jobs:
|
153
|
-
- ruby-
|
254
|
+
- ruby-3.0.0-rails-6.1:
|
255
|
+
context: org-global
|
256
|
+
- ruby-2.7.2-rails-6.1:
|
154
257
|
context: org-global
|
155
|
-
- ruby-
|
258
|
+
- ruby-3.0.0-rails-6.0:
|
156
259
|
context: org-global
|
157
|
-
- ruby-2.7.
|
260
|
+
- ruby-2.7.2-rails-6.0:
|
158
261
|
context: org-global
|
159
|
-
- ruby-2.
|
262
|
+
- ruby-2.7.2-rails-5.2:
|
160
263
|
context: org-global
|
data/.github/CODEOWNERS
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.7.
|
1
|
+
ruby-2.7.2
|
data/Gemfile.rails-6.1
ADDED
data/README.md
CHANGED
@@ -4,13 +4,13 @@ Create Microservices in Rails by pretty much just writing regular Rails code.
|
|
4
4
|
|
5
5
|
This gem provides:
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
- transparent API key authentication.
|
8
|
+
- router-level API version based on headers.
|
9
|
+
- a way to document your microservice endpoints via acceptance tests.
|
10
|
+
- structured errors, buildable from invalid Active Records, Exceptions, or by hand.
|
11
11
|
|
12
12
|
This, plus much of what you get from Rails already, means you can create a microservice Rails application by just writing the
|
13
|
-
same Rails code you write today.
|
13
|
+
same Rails code you write today. Instead of rendering web views, you render JSON (which is built into Rails).
|
14
14
|
|
15
15
|
## To install
|
16
16
|
|
@@ -35,14 +35,26 @@ Then, set it up:
|
|
35
35
|
|
36
36
|
### Upgrading from an older version
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
- When upgrading to version 4.0.0 you may now take advantage of an in-memory cache
|
39
|
+
|
40
|
+
You can enabled it like so
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Stitches.configure do |config|
|
44
|
+
config.max_cache_ttl = 5 # seconds
|
45
|
+
config.max_cache_size = 100 # how many keys to cache
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
- If you have a version lower than 3.3.0, you need to run two generators, one of which creates a new database migration on your
|
50
|
+
`api_clients` table:
|
40
51
|
|
41
52
|
```
|
42
53
|
> bin/rails generate stitches:add_enabled_to_api_clients
|
43
54
|
> bin/rails generate stitches:add_deprecation
|
44
55
|
```
|
45
|
-
|
56
|
+
|
57
|
+
- If you have a version lower than 3.6.0, you need to run one generator:
|
46
58
|
|
47
59
|
```
|
48
60
|
> bin/rails generate stitches:add_deprecation
|
@@ -59,8 +71,8 @@ class Api::V1::WidgetsController < ApiController
|
|
59
71
|
if widget.valid?
|
60
72
|
head 201
|
61
73
|
else
|
62
|
-
render json: {
|
63
|
-
errors: Stitches::Errors.from_active_record_object(widget)
|
74
|
+
render json: {
|
75
|
+
errors: Stitches::Errors.from_active_record_object(widget)
|
64
76
|
}, status: 422
|
65
77
|
end
|
66
78
|
end
|
@@ -73,44 +85,62 @@ private
|
|
73
85
|
end
|
74
86
|
```
|
75
87
|
|
76
|
-
If you think there's nothing special about this—you are correct.
|
88
|
+
If you think there's nothing special about this—you are correct. This is the vanillaest of vanilla Rails controllers, with a few
|
77
89
|
notable exceptions:
|
78
90
|
|
79
|
-
|
80
|
-
you, so there's zero need to use `respond_to` and friends.
|
81
|
-
|
82
|
-
|
83
|
-
about it in your code.
|
84
|
-
|
85
|
-
routed here.
|
91
|
+
- We aren't checking content type. A stitches-based microservice always uses JSON and refuses to route requests for non-JSON to
|
92
|
+
you, so there's zero need to use `respond_to` and friends.
|
93
|
+
- The error-building is structured and reliable.
|
94
|
+
- This is an authenticated request. No request without proper authentication will be routed here, so you don't have to worry
|
95
|
+
about it in your code.
|
96
|
+
- This is a versioned request. While the URL will _not_ contain `v1` in it, the `Accept` header will require a version and get
|
97
|
+
routed here. If you make a V2, it's just a new controller and this concern is handled at the routing layer.
|
86
98
|
|
87
|
-
All this means that the Rails skills of you and your team can be directly applied to building microservices.
|
99
|
+
All this means that the Rails skills of you and your team can be directly applied to building microservices. You don't have to make a bunch of boring decisions about auth, versioning, or content-types. It also means you can start deploying and creating microservices with little friction. No need to deal with a complex DSL or new programming language to get yourselves going with Microservices.
|
88
100
|
|
89
101
|
## More Info
|
90
102
|
|
91
103
|
See [the wiki](https://github.com/stitchfix/stitches/wiki/Setup) for how to setup stitches.
|
92
104
|
|
93
|
-
|
105
|
+
- [Stitches Features](https://github.com/stitchfix/stitches/wiki/Features-of-Stitches) include:
|
94
106
|
- Authorization via API key
|
95
107
|
- Versioned requests via HTTP content types
|
96
108
|
- Structured Errors
|
97
109
|
- ISO 8601-formatted dates
|
98
110
|
- Deprecation using the `Sunset` header
|
99
|
-
|
100
|
-
|
111
|
+
- An optional ApiKey cache to allow mostly DB free APIs
|
112
|
+
- The [Generator](https://github.com/stitchfix/stitches/wiki/Generator) sets up some code in your app, so you can start writing
|
113
|
+
APIs using vanilla Rails idioms:
|
101
114
|
- a "ping" controller that can validate your app is working
|
102
115
|
- version routing based on content-type (requests for V2 use the same URL, but are serviced by a different controller)
|
103
116
|
- An ApiClient Active Record
|
104
117
|
- Acceptance tests that can produce API documentation as they test your app.
|
105
|
-
|
118
|
+
- Stitches provides [testing support](https://github.com/stitchfix/stitches/wiki/Testing)
|
119
|
+
|
120
|
+
## API Key Caching
|
121
|
+
|
122
|
+
Since version 4.0.0, stitches now has the ability to cache API keys in
|
123
|
+
memory for a configurable amount of time. This may be an improvement for
|
124
|
+
some applications.
|
125
|
+
|
126
|
+
You must configure the API Cache for it be used.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
Stitches.configure do |config|
|
130
|
+
config.max_cache_ttl = 5 # seconds
|
131
|
+
config.max_cache_size = 100 # how many keys to cache
|
132
|
+
end
|
133
|
+
```
|
106
134
|
|
135
|
+
Your cache size should be
|
136
|
+
larger then the number of consumer keys your service has.
|
107
137
|
|
108
138
|
## Developing
|
109
139
|
|
110
|
-
Although `Stitches.configuration` is global, do not depend directly on that in your logic.
|
140
|
+
Although `Stitches.configuration` is global, do not depend directly on that in your logic. Instead, allow all classes to receive a configuration object in their constructor. This makes the classes easier to deal with and change, without incurring much of a real cost to development. Global symbols suck, but are convenient. This is how you make the most of it.
|
111
141
|
|
112
142
|
Also, the integration test does a lot of "testing the implementation", but since Rails generators are notorious for silently
|
113
|
-
failing with a successful result, we have to make sure that the various `inject_into_file` calls are actually working.
|
143
|
+
failing with a successful result, we have to make sure that the various `inject_into_file` calls are actually working. Do not do
|
114
144
|
any fancy refactors here, just keep it up to date.
|
115
145
|
|
116
146
|
---
|
@@ -2,7 +2,6 @@ module Stitches
|
|
2
2
|
# A middleware that will skip its behavior if the path matches an allowed URL
|
3
3
|
class AllowlistMiddleware
|
4
4
|
def initialize(app, options={})
|
5
|
-
|
6
5
|
@app = app
|
7
6
|
@configuration = options[:configuration] || Stitches.configuration
|
8
7
|
@except = options[:except] || @configuration.allowlist_regexp
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'lru_redux'
|
2
|
+
|
3
|
+
module Stitches::ApiClientAccessWrapper
|
4
|
+
|
5
|
+
def self.fetch_for_key(key)
|
6
|
+
if cache_enabled
|
7
|
+
fetch_for_key_from_cache(key)
|
8
|
+
else
|
9
|
+
fetch_for_key_from_db(key)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.fetch_for_key_from_cache(key)
|
14
|
+
api_key_cache.getset(key) do
|
15
|
+
fetch_for_key_from_db(key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.fetch_for_key_from_db(key)
|
20
|
+
if ::ApiClient.column_names.include?("enabled")
|
21
|
+
::ApiClient.find_by(key: key, enabled: true)
|
22
|
+
else
|
23
|
+
ActiveSupport::Deprecation.warn('api_keys is missing "enabled" column. Run "rails g stitches:add_enabled_to_api_clients"')
|
24
|
+
::ApiClient.find_by(key: key)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.clear_api_cache
|
29
|
+
api_key_cache.clear if cache_enabled
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.api_key_cache
|
33
|
+
@api_key_cache ||= LruRedux::TTL::ThreadSafeCache.new(
|
34
|
+
Stitches.configuration.max_cache_size,
|
35
|
+
Stitches.configuration.max_cache_ttl,
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.cache_enabled
|
40
|
+
Stitches.configuration.max_cache_ttl.positive?
|
41
|
+
end
|
42
|
+
end
|
@@ -12,7 +12,6 @@ module Stitches
|
|
12
12
|
|
13
13
|
desc "Bootstraps your API service with a basic ping controller and spec to ensure everything is setup properly"
|
14
14
|
def bootstrap_api
|
15
|
-
gem "stitches"
|
16
15
|
gem "apitome"
|
17
16
|
gem_group :development, :test do
|
18
17
|
gem "rspec"
|
@@ -20,7 +19,9 @@ module Stitches
|
|
20
19
|
gem "rspec_api_documentation"
|
21
20
|
end
|
22
21
|
|
23
|
-
|
22
|
+
Bundler.with_clean_env do
|
23
|
+
run "bundle install"
|
24
|
+
end
|
24
25
|
generate "apitome:install"
|
25
26
|
generate "rspec:install"
|
26
27
|
|
data/lib/stitches/api_key.rb
CHANGED
@@ -27,14 +27,7 @@ module Stitches
|
|
27
27
|
if authorization
|
28
28
|
if authorization =~ /#{@configuration.custom_http_auth_scheme}\s+key=(.*)\s*$/
|
29
29
|
key = $1
|
30
|
-
|
31
|
-
if ApiClient.column_names.include?("enabled")
|
32
|
-
client = ApiClient.where(key: key, enabled: true).first
|
33
|
-
else
|
34
|
-
ActiveSupport::Deprecation.warn('api_keys is missing "enabled" column. Run "rails g stitches:add_enabled_to_api_clients"')
|
35
|
-
client = ApiClient.where(key: key).first
|
36
|
-
end
|
37
|
-
|
30
|
+
client = Stitches::ApiClientAccessWrapper.fetch_for_key(key)
|
38
31
|
if client.present?
|
39
32
|
env[@configuration.env_var_to_hold_api_client_primary_key] = client.id
|
40
33
|
env[@configuration.env_var_to_hold_api_client] = client
|
@@ -13,6 +13,8 @@ class Stitches::Configuration
|
|
13
13
|
@custom_http_auth_scheme = UnsetString.new("custom_http_auth_scheme")
|
14
14
|
@env_var_to_hold_api_client_primary_key = NonNullString.new("env_var_to_hold_api_client_primary_key","STITCHES_API_CLIENT_ID")
|
15
15
|
@env_var_to_hold_api_client= NonNullString.new("env_var_to_hold_api_client","STITCHES_API_CLIENT")
|
16
|
+
@max_cache_ttl = NonNullInteger.new("max_cache_ttl", 0)
|
17
|
+
@max_cache_size = NonNullInteger.new("max_cache_size", 0)
|
16
18
|
end
|
17
19
|
|
18
20
|
# A RegExp that allows URLS around the mime type and api key requirements.
|
@@ -25,11 +27,6 @@ class Stitches::Configuration
|
|
25
27
|
@allowlist_regexp = new_allowlist_regexp
|
26
28
|
end
|
27
29
|
|
28
|
-
def whitelist_regexp=(new_allowlist_regexp)
|
29
|
-
self.allowlist_regexp = new_allowlist_regexp
|
30
|
-
warn("⚠️ 'whitelist' is deprecated in stitches configuration, please use 'allowlist' or auto-update with:\n\n bin/rails g stitches:update_configuration\n\n⚠️ 'whitelist' will be removed in 4.0")
|
31
|
-
end
|
32
|
-
|
33
30
|
# The name of your custom http auth scheme. This must be set, and has no default
|
34
31
|
def custom_http_auth_scheme
|
35
32
|
@custom_http_auth_scheme.to_s
|
@@ -39,7 +36,7 @@ class Stitches::Configuration
|
|
39
36
|
@custom_http_auth_scheme = NonNullString.new("custom_http_auth_scheme",new_custom_http_auth_scheme)
|
40
37
|
end
|
41
38
|
|
42
|
-
# The name of the environment variable that the ApiKey middleware should use to
|
39
|
+
# The name of the environment variable that the ApiKey middleware should use to
|
43
40
|
# place the primary key of the authenticated ApiKey. For example, if a user provides
|
44
41
|
# the api key 1234-1234-1234-1234, and that maps to the primary key 42 in your database,
|
45
42
|
# the environment will contain "42" in the key provided here.
|
@@ -59,8 +56,40 @@ class Stitches::Configuration
|
|
59
56
|
@env_var_to_hold_api_client= NonNullString.new("env_var_to_hold_api_client",new_env_var_to_hold_api_client)
|
60
57
|
end
|
61
58
|
|
59
|
+
def max_cache_ttl
|
60
|
+
@max_cache_ttl.to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
def max_cache_ttl=(new_max_cache_ttl)
|
64
|
+
@max_cache_ttl = NonNullInteger.new("max_cache_ttl", new_max_cache_ttl)
|
65
|
+
end
|
66
|
+
|
67
|
+
def max_cache_size
|
68
|
+
@max_cache_size.to_i
|
69
|
+
end
|
70
|
+
|
71
|
+
def max_cache_size=(new_max_cache_size)
|
72
|
+
@max_cache_size = NonNullInteger.new("max_cache_size", new_max_cache_size)
|
73
|
+
end
|
74
|
+
|
62
75
|
private
|
63
76
|
|
77
|
+
class NonNullInteger
|
78
|
+
def initialize(name, value)
|
79
|
+
unless value.is_a?(Integer)
|
80
|
+
raise "#{name} must be an Integer, not a #{value.class}"
|
81
|
+
end
|
82
|
+
|
83
|
+
@value = value
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_i
|
87
|
+
@value
|
88
|
+
end
|
89
|
+
|
90
|
+
alias to_integer to_i
|
91
|
+
end
|
92
|
+
|
64
93
|
class NonNullString
|
65
94
|
def initialize(name,string)
|
66
95
|
unless string.nil? || string.is_a?(String)
|
@@ -11,4 +11,14 @@ Stitches.configure do |configuration|
|
|
11
11
|
# Env var that gets the primary key of the authenticated ApiKey
|
12
12
|
# for access in your controllers, so they don't need to re-parse the header
|
13
13
|
# configuration.env_var_to_hold_api_client_primary_key = "YOUR_ENV_VAR"
|
14
|
+
|
15
|
+
# Configures how long to cache ApiKeys in memory (In Seconds)
|
16
|
+
# A value of 0 will disable the cache entierly
|
17
|
+
# Default is 0
|
18
|
+
# configuration.max_cache_ttl = 5
|
19
|
+
|
20
|
+
# Configures how many ApiKeys to cache at one time
|
21
|
+
# This should be larger then the number of clients
|
22
|
+
# Default is 0
|
23
|
+
# configuration.max_cache_size = 100
|
14
24
|
end
|
data/lib/stitches/railtie.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'stitches/api_key'
|
2
2
|
require 'stitches/valid_mime_type'
|
3
|
+
require 'stitches/api_client_access_wrapper'
|
3
4
|
|
4
5
|
module Stitches
|
5
6
|
class Railtie < Rails::Railtie
|
6
7
|
config.app_middleware.use Stitches::ApiKey
|
7
8
|
config.app_middleware.use Stitches::ValidMimeType
|
9
|
+
|
8
10
|
end
|
9
11
|
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
require 'active_support/time_with_zone'
|
2
2
|
|
3
3
|
class ActiveSupport::TimeWithZone
|
4
|
-
# We want dates to be
|
4
|
+
# We want dates to always be in UTC
|
5
5
|
def as_json(options = {})
|
6
|
-
utc
|
6
|
+
if utc?
|
7
|
+
super
|
8
|
+
else
|
9
|
+
utc.as_json(options)
|
10
|
+
end
|
7
11
|
end
|
8
12
|
end
|
9
13
|
|
@@ -1,19 +1,26 @@
|
|
1
1
|
require_relative 'allowlist_middleware'
|
2
2
|
module Stitches
|
3
|
-
# A middleware that requires all API calls to be for versioned JSON
|
4
|
-
#
|
3
|
+
# A middleware that requires all API calls to be for versioned JSON or Protobuf.
|
4
|
+
#
|
5
|
+
# This means that the Accept header (available to Rack apps as HTTP_ACCEPT) should be like so:
|
5
6
|
#
|
6
7
|
# application/json; version=1
|
7
8
|
#
|
8
9
|
# This just checks that you've specified some numeric version. ApiVersionConstraint should be used
|
9
10
|
# to "lock down" the versions you accept.
|
11
|
+
#
|
12
|
+
# Or in the case of a protobuf encoded payload the header should be like so:
|
13
|
+
#
|
14
|
+
# application/protobuf
|
15
|
+
#
|
16
|
+
# There isn't an accepted standard for protobuf encoded payloads but this form is common.
|
10
17
|
class ValidMimeType < Stitches::AllowlistMiddleware
|
11
18
|
|
12
19
|
protected
|
13
20
|
|
14
21
|
def do_call(env)
|
15
22
|
accept = String(env["HTTP_ACCEPT"])
|
16
|
-
if accept =~ %r{application/json} && accept =~ %r{version=\d+}
|
23
|
+
if (accept =~ %r{application/json} && accept =~ %r{version=\d+}) || accept =~ %r{application/protobuf}
|
17
24
|
@app.call(env)
|
18
25
|
else
|
19
26
|
not_acceptable_response(accept)
|
@@ -24,7 +31,7 @@ module Stitches
|
|
24
31
|
|
25
32
|
def not_acceptable_response(accept_header)
|
26
33
|
status = 406
|
27
|
-
body = "Not Acceptable - '#{accept_header}' didn't have the right mime type or version number. We only accept application/json with a version"
|
34
|
+
body = "Not Acceptable - '#{accept_header}' didn't have the right mime type or version number. We only accept application/json with a version or application/protobuf"
|
28
35
|
header = { "WWW-Authenticate" => accept_header }
|
29
36
|
Rack::Response.new(body, status, header).finish
|
30
37
|
end
|
data/lib/stitches/version.rb
CHANGED
data/lib/stitches_norailtie.rb
CHANGED
@@ -14,7 +14,6 @@ require 'stitches/errors'
|
|
14
14
|
require 'stitches/api_generator'
|
15
15
|
require 'stitches/add_deprecation_generator'
|
16
16
|
require 'stitches/add_enabled_to_api_clients_generator'
|
17
|
-
require 'stitches/update_configuration_generator'
|
18
17
|
require 'stitches/api_version_constraint'
|
19
18
|
require 'stitches/api_key'
|
20
19
|
require 'stitches/deprecation'
|
data/owners.json
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
module MyApp
|
4
|
+
class Application
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
unless defined? ApiClient
|
9
|
+
class ApiClient
|
10
|
+
def self.column_names
|
11
|
+
["enabled"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe Stitches::ApiClientAccessWrapper do
|
17
|
+
let(:api_client) {
|
18
|
+
double(ApiClient, id: 42)
|
19
|
+
}
|
20
|
+
before do
|
21
|
+
Stitches.configuration.reset_to_defaults!
|
22
|
+
end
|
23
|
+
describe '#fetch_by_key' do
|
24
|
+
context "cache is disabled" do
|
25
|
+
before do
|
26
|
+
expect(ApiClient).to receive(:find_by).and_return(api_client).twice
|
27
|
+
end
|
28
|
+
|
29
|
+
it "fetchs object from db twice" do
|
30
|
+
expect(described_class.fetch_for_key("123").id).to eq(42)
|
31
|
+
expect(described_class.fetch_for_key("123").id).to eq(42)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "cache is configured" do
|
36
|
+
before do
|
37
|
+
Stitches.configure do |config|
|
38
|
+
config.max_cache_ttl = 5
|
39
|
+
config.max_cache_size = 10
|
40
|
+
end
|
41
|
+
|
42
|
+
expect(ApiClient).to receive(:find_by).and_return(api_client).once
|
43
|
+
end
|
44
|
+
|
45
|
+
it "fetchs object from cache" do
|
46
|
+
expect(described_class.fetch_for_key("123").id).to eq(42)
|
47
|
+
# This should hit the cache
|
48
|
+
expect(described_class.fetch_for_key("123").id).to eq(42)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/api_key_spec.rb
CHANGED
@@ -15,10 +15,8 @@ end
|
|
15
15
|
|
16
16
|
describe Stitches::ApiKey do
|
17
17
|
let(:app) { double("rack app") }
|
18
|
-
let(:
|
19
|
-
|
20
|
-
double(ApiClient, id: 42)
|
21
|
-
]
|
18
|
+
let(:api_client) {
|
19
|
+
double(ApiClient, id: 42)
|
22
20
|
}
|
23
21
|
|
24
22
|
before do
|
@@ -27,7 +25,8 @@ describe Stitches::ApiKey do
|
|
27
25
|
fake_rails_app = MyApp::Application.new
|
28
26
|
allow(Rails).to receive(:application).and_return(fake_rails_app)
|
29
27
|
allow(app).to receive(:call).with(env)
|
30
|
-
allow(ApiClient).to receive(:
|
28
|
+
allow(ApiClient).to receive(:find_by).and_return(api_client)
|
29
|
+
Stitches::ApiClientAccessWrapper.clear_api_cache
|
31
30
|
end
|
32
31
|
|
33
32
|
subject(:middleware) { described_class.new(app, namespace: "/api") }
|
@@ -158,11 +157,11 @@ describe Stitches::ApiKey do
|
|
158
157
|
end
|
159
158
|
|
160
159
|
it "sets the api_client's ID in the environment" do
|
161
|
-
expect(env[Stitches.configuration.env_var_to_hold_api_client_primary_key]).to eq(
|
160
|
+
expect(env[Stitches.configuration.env_var_to_hold_api_client_primary_key]).to eq(api_client.id)
|
162
161
|
end
|
163
162
|
|
164
163
|
it "sets the api_client itself in the environment" do
|
165
|
-
expect(env[Stitches.configuration.env_var_to_hold_api_client]).to eq(
|
164
|
+
expect(env[Stitches.configuration.env_var_to_hold_api_client]).to eq(api_client)
|
166
165
|
end
|
167
166
|
end
|
168
167
|
|
@@ -177,7 +176,7 @@ describe Stitches::ApiKey do
|
|
177
176
|
"HTTP_AUTHORIZATION" => "MyAwesomeInternalScheme key=foobar",
|
178
177
|
}
|
179
178
|
}
|
180
|
-
let(:
|
179
|
+
let(:api_client) { nil }
|
181
180
|
|
182
181
|
it_behaves_like "an unauthorized response" do
|
183
182
|
let(:expected_body) { "Unauthorized - key invalid" }
|
data/spec/configuration_spec.rb
CHANGED
@@ -9,17 +9,23 @@ describe Stitches::Configuration do
|
|
9
9
|
let(:allowlist_regexp) { %r{foo} }
|
10
10
|
let(:custom_http_auth_scheme) { "Blah" }
|
11
11
|
let(:env_var_to_hold_api_client_primary_key) { "FOOBAR" }
|
12
|
+
let(:max_cache_ttl) { 11 }
|
13
|
+
let(:max_cache_size) { 111 }
|
12
14
|
|
13
15
|
it "can be configured globally" do
|
14
16
|
Stitches.configure do |config|
|
15
17
|
config.allowlist_regexp = allowlist_regexp
|
16
18
|
config.custom_http_auth_scheme = custom_http_auth_scheme
|
17
19
|
config.env_var_to_hold_api_client_primary_key = env_var_to_hold_api_client_primary_key
|
20
|
+
config.max_cache_ttl = max_cache_ttl
|
21
|
+
config.max_cache_size = max_cache_size
|
18
22
|
end
|
19
23
|
|
20
24
|
expect(Stitches.configuration.allowlist_regexp).to eq(allowlist_regexp)
|
21
25
|
expect(Stitches.configuration.custom_http_auth_scheme).to eq(custom_http_auth_scheme)
|
22
26
|
expect(Stitches.configuration.env_var_to_hold_api_client_primary_key).to eq(env_var_to_hold_api_client_primary_key)
|
27
|
+
expect(Stitches.configuration.max_cache_ttl).to eq(max_cache_ttl)
|
28
|
+
expect(Stitches.configuration.max_cache_size).to eq(max_cache_size)
|
23
29
|
end
|
24
30
|
|
25
31
|
it "defaults to nil for allowlist_regexp" do
|
@@ -30,6 +36,14 @@ describe Stitches::Configuration do
|
|
30
36
|
expect(Stitches.configuration.env_var_to_hold_api_client_primary_key).to eq("STITCHES_API_CLIENT_ID")
|
31
37
|
end
|
32
38
|
|
39
|
+
it "defaults to 0 for max_cache_ttl" do
|
40
|
+
expect(Stitches.configuration.max_cache_ttl).to eq(0)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "sets a default for max_cache_size" do
|
44
|
+
expect(Stitches.configuration.max_cache_size).to eq(0)
|
45
|
+
end
|
46
|
+
|
33
47
|
it "blows up if you try to use custom_http_auth_scheme without having set it" do
|
34
48
|
expect {
|
35
49
|
Stitches.configuration.custom_http_auth_scheme
|
@@ -102,19 +116,34 @@ describe Stitches::Configuration do
|
|
102
116
|
}.not_to raise_error
|
103
117
|
end
|
104
118
|
end
|
105
|
-
context "deprecated options we want to support for backwards compatibility" do
|
106
119
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
120
|
+
describe "max_cache_ttl" do
|
121
|
+
let(:config) { Stitches::Configuration.new }
|
122
|
+
it "must be an integer" do
|
123
|
+
expect {
|
124
|
+
config.max_cache_ttl = ""
|
125
|
+
}.to raise_error(/max_cache_ttl must be an Integer, not a String/)
|
111
126
|
end
|
112
127
|
|
113
|
-
it "
|
114
|
-
|
115
|
-
config.
|
116
|
-
|
117
|
-
|
128
|
+
it "may not be nil" do
|
129
|
+
expect {
|
130
|
+
config.max_cache_ttl = nil
|
131
|
+
}.to raise_error(/max_cache_ttl must be an Integer, not a NilClass/)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "max_cache_size" do
|
136
|
+
let(:config) { Stitches::Configuration.new }
|
137
|
+
it "must be an integer" do
|
138
|
+
expect {
|
139
|
+
config.max_cache_size = ""
|
140
|
+
}.to raise_error(/max_cache_size must be an Integer, not a String/)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "may not be nil" do
|
144
|
+
expect {
|
145
|
+
config.max_cache_size = nil
|
146
|
+
}.to raise_error(/max_cache_size must be an Integer, not a NilClass/)
|
118
147
|
end
|
119
148
|
end
|
120
149
|
end
|
@@ -109,35 +109,6 @@ RSpec.describe "Adding Stitches to a New Rails App", :integration do
|
|
109
109
|
expect(include_line).to_not be_nil,lines.inspect
|
110
110
|
end
|
111
111
|
|
112
|
-
it "inserts can update old configuration" do
|
113
|
-
run "bin/rails generate stitches:api"
|
114
|
-
|
115
|
-
initializer = rails_root / "config" / "initializers" / "stitches.rb"
|
116
|
-
|
117
|
-
initializer_contents = File.read(initializer).split(/\n/)
|
118
|
-
found_initializer = false
|
119
|
-
File.open(initializer,"w") do |file|
|
120
|
-
initializer_contents.each do |line|
|
121
|
-
if line =~ /allowlist/
|
122
|
-
line = line.gsub("allowlist","whitelist")
|
123
|
-
found_initializer = true
|
124
|
-
end
|
125
|
-
file.puts line
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
raise "Didn't find 'allowlist' in the initializer?!" if !found_initializer
|
130
|
-
|
131
|
-
run "bin/rails generate stitches:update_configuration"
|
132
|
-
|
133
|
-
lines = File.read(initializer).split(/\n/)
|
134
|
-
include_line = lines.detect { |line|
|
135
|
-
line =~ /whitelist/
|
136
|
-
}
|
137
|
-
|
138
|
-
expect(include_line).to be_nil,lines.inspect
|
139
|
-
end
|
140
|
-
|
141
112
|
class RoutesFileAnalysis
|
142
113
|
attr_reader :routes_file
|
143
114
|
def initialize(routes_file, namespace: nil, module_scope: nil, resource: nil, mounted_engine: nil)
|
@@ -132,6 +132,22 @@ describe Stitches::ValidMimeType do
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
+
context "protbuf mime type" do
|
136
|
+
let(:env) {
|
137
|
+
{
|
138
|
+
"PATH_INFO" => "/api/ping",
|
139
|
+
"HTTP_ACCEPT" => "application/protobuf",
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
before do
|
144
|
+
@response = middleware.call(env)
|
145
|
+
end
|
146
|
+
it "calls through to the rest of the chain" do
|
147
|
+
expect(app).to have_received(:call).with(env)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
135
151
|
context "unacceptable responses" do
|
136
152
|
before do
|
137
153
|
@response = middleware.call(env)
|
data/stitches.gemspec
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stitches
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.1.0RC2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stitch Fix Engineering
|
8
8
|
- Andrew Peterson
|
9
9
|
- Dave Copeland
|
10
10
|
- Jonathan Dean
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2021-03-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -41,6 +41,20 @@ dependencies:
|
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '0'
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: lru_redux
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
44
58
|
- !ruby/object:Gem::Dependency
|
45
59
|
name: rspec
|
46
60
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +123,7 @@ files:
|
|
109
123
|
- Gemfile.rails-5.1
|
110
124
|
- Gemfile.rails-5.2
|
111
125
|
- Gemfile.rails-6.0
|
126
|
+
- Gemfile.rails-6.1
|
112
127
|
- LICENSE.txt
|
113
128
|
- README.md
|
114
129
|
- Rakefile
|
@@ -117,6 +132,7 @@ files:
|
|
117
132
|
- lib/stitches/add_deprecation_generator.rb
|
118
133
|
- lib/stitches/add_enabled_to_api_clients_generator.rb
|
119
134
|
- lib/stitches/allowlist_middleware.rb
|
135
|
+
- lib/stitches/api_client_access_wrapper.rb
|
120
136
|
- lib/stitches/api_generator.rb
|
121
137
|
- lib/stitches/api_key.rb
|
122
138
|
- lib/stitches/api_version_constraint.rb
|
@@ -147,12 +163,11 @@ files:
|
|
147
163
|
- lib/stitches/spec/have_api_error.rb
|
148
164
|
- lib/stitches/spec/show_deprecation.rb
|
149
165
|
- lib/stitches/spec/test_headers.rb
|
150
|
-
- lib/stitches/update_configuration_generator.rb
|
151
166
|
- lib/stitches/valid_mime_type.rb
|
152
167
|
- lib/stitches/version.rb
|
153
|
-
- lib/stitches/whitelisting_middleware.rb
|
154
168
|
- lib/stitches_norailtie.rb
|
155
169
|
- owners.json
|
170
|
+
- spec/api_client_access_wrapper_spec.rb
|
156
171
|
- spec/api_key_spec.rb
|
157
172
|
- spec/api_version_constraint_spec.rb
|
158
173
|
- spec/configuration_spec.rb
|
@@ -170,7 +185,7 @@ homepage: https://github.com/stitchfix/stitches
|
|
170
185
|
licenses:
|
171
186
|
- MIT
|
172
187
|
metadata: {}
|
173
|
-
post_install_message:
|
188
|
+
post_install_message:
|
174
189
|
rdoc_options: []
|
175
190
|
require_paths:
|
176
191
|
- lib
|
@@ -181,15 +196,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
181
196
|
version: '0'
|
182
197
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
198
|
requirements:
|
184
|
-
- - "
|
199
|
+
- - ">"
|
185
200
|
- !ruby/object:Gem::Version
|
186
|
-
version:
|
201
|
+
version: 1.3.1
|
187
202
|
requirements: []
|
188
|
-
rubygems_version: 3.
|
189
|
-
signing_key:
|
203
|
+
rubygems_version: 3.1.4
|
204
|
+
signing_key:
|
190
205
|
specification_version: 4
|
191
206
|
summary: You'll be in stitches at how easy it is to create a service at Stitch Fix
|
192
207
|
test_files:
|
208
|
+
- spec/api_client_access_wrapper_spec.rb
|
193
209
|
- spec/api_key_spec.rb
|
194
210
|
- spec/api_version_constraint_spec.rb
|
195
211
|
- spec/configuration_spec.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'rails/generators'
|
2
|
-
|
3
|
-
module Stitches
|
4
|
-
class UpdateConfigurationGenerator < Rails::Generators::Base
|
5
|
-
include Rails::Generators::Migration
|
6
|
-
|
7
|
-
source_root(File.expand_path(File.join(File.dirname(__FILE__),"generator_files")))
|
8
|
-
|
9
|
-
desc "Change your configuration to use 'allowlist' so you'll be ready for 4.x"
|
10
|
-
def update_to_allowlist
|
11
|
-
gsub_file "config/initializers/stitches.rb", /whitelist/, "allowlist"
|
12
|
-
puts "🎉 You are now good to go!"
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|