stitches 4.1.0RC2 → 4.2.0.RC1

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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +0 -38
  3. data/.gitignore +1 -0
  4. data/README.md +36 -4
  5. data/lib/stitches/add_disabled_at_to_api_clients_generator.rb +18 -0
  6. data/lib/stitches/allowlist_middleware.rb +20 -6
  7. data/lib/stitches/api_client_access_wrapper.rb +42 -11
  8. data/lib/stitches/api_key.rb +5 -5
  9. data/lib/stitches/configuration.rb +4 -0
  10. data/lib/stitches/generator_files/db/migrate/add_disabled_at_to_api_clients.rb +9 -0
  11. data/lib/stitches/generator_files/db/migrate/create_api_clients.rb +1 -0
  12. data/lib/stitches/render_timestamps_in_iso8601_in_json.rb +2 -6
  13. data/lib/stitches/valid_mime_type.rb +1 -1
  14. data/lib/stitches/version.rb +1 -1
  15. data/lib/stitches_norailtie.rb +1 -0
  16. data/spec/api_key_middleware_spec.rb +368 -0
  17. data/spec/api_version_constraint_middleware_spec.rb +58 -0
  18. data/spec/configuration_spec.rb +1 -1
  19. data/spec/deprecation_spec.rb +1 -1
  20. data/spec/error_spec.rb +1 -1
  21. data/spec/errors_spec.rb +3 -3
  22. data/spec/fake_app/.rspec +1 -0
  23. data/spec/fake_app/.ruby-version +1 -0
  24. data/spec/fake_app/Gemfile +53 -0
  25. data/spec/fake_app/README.md +24 -0
  26. data/spec/fake_app/Rakefile +6 -0
  27. data/spec/fake_app/app/assets/config/manifest.js +2 -0
  28. data/spec/fake_app/app/assets/stylesheets/application.css +15 -0
  29. data/spec/fake_app/app/controllers/api.rb +2 -0
  30. data/spec/fake_app/app/controllers/api/api_controller.rb +31 -0
  31. data/spec/fake_app/app/controllers/api/v1.rb +2 -0
  32. data/spec/fake_app/app/controllers/api/v1/hellos_controller.rb +7 -0
  33. data/spec/fake_app/app/controllers/api/v1/pings_controller.rb +16 -0
  34. data/spec/fake_app/app/controllers/api/v2.rb +2 -0
  35. data/spec/fake_app/app/controllers/api/v2/hellos_controller.rb +7 -0
  36. data/spec/fake_app/app/controllers/api/v2/pings_controller.rb +16 -0
  37. data/spec/fake_app/app/controllers/application_controller.rb +2 -0
  38. data/spec/fake_app/app/helpers/application_helper.rb +2 -0
  39. data/spec/fake_app/app/models/api_client.rb +2 -0
  40. data/spec/fake_app/app/models/application_record.rb +3 -0
  41. data/spec/fake_app/bin/rails +4 -0
  42. data/spec/fake_app/bin/rake +4 -0
  43. data/spec/fake_app/bin/setup +33 -0
  44. data/spec/fake_app/config.ru +6 -0
  45. data/spec/fake_app/config/application.rb +35 -0
  46. data/spec/fake_app/config/boot.rb +3 -0
  47. data/spec/fake_app/config/credentials.yml.enc +1 -0
  48. data/spec/fake_app/config/database.yml +25 -0
  49. data/spec/fake_app/config/environment.rb +5 -0
  50. data/spec/fake_app/config/environments/development.rb +71 -0
  51. data/spec/fake_app/config/environments/production.rb +109 -0
  52. data/spec/fake_app/config/environments/test.rb +52 -0
  53. data/spec/fake_app/config/initializers/assets.rb +12 -0
  54. data/spec/fake_app/config/initializers/cookies_serializer.rb +5 -0
  55. data/spec/fake_app/config/initializers/filter_parameter_logging.rb +6 -0
  56. data/spec/fake_app/config/initializers/stitches.rb +24 -0
  57. data/spec/fake_app/config/locales/en.yml +33 -0
  58. data/spec/fake_app/config/master.key +1 -0
  59. data/spec/fake_app/config/puma.rb +43 -0
  60. data/spec/fake_app/config/routes.rb +17 -0
  61. data/spec/fake_app/config/storage.yml +34 -0
  62. data/spec/fake_app/db/development.sqlite3 +0 -0
  63. data/spec/fake_app/db/migrate/20210802153118_enable_uuid_ossp_extension.rb +7 -0
  64. data/spec/fake_app/db/migrate/20210802153119_create_api_clients.rb +14 -0
  65. data/spec/fake_app/db/schema_missing_disabled_at.rb +12 -0
  66. data/spec/fake_app/db/schema_missing_enabled.rb +11 -0
  67. data/spec/fake_app/db/schema_modern.rb +13 -0
  68. data/spec/fake_app/db/seeds.rb +7 -0
  69. data/spec/fake_app/db/test.sqlite3 +0 -0
  70. data/spec/fake_app/doc/api.md +4 -0
  71. data/spec/fake_app/lib/tasks/generate_api_key.rake +10 -0
  72. data/spec/fake_app/public/404.html +67 -0
  73. data/spec/fake_app/public/422.html +67 -0
  74. data/spec/fake_app/public/500.html +66 -0
  75. data/spec/fake_app/public/apple-touch-icon-precomposed.png +0 -0
  76. data/spec/fake_app/public/apple-touch-icon.png +0 -0
  77. data/spec/fake_app/public/favicon.ico +0 -0
  78. data/spec/fake_app/public/javascripts/apitome/application.js +31 -0
  79. data/spec/fake_app/public/robots.txt +1 -0
  80. data/spec/fake_app/public/stylesheets/apitome/application.css +269 -0
  81. data/spec/fake_app/test/application_system_test_case.rb +5 -0
  82. data/spec/fake_app/test/test_helper.rb +13 -0
  83. data/spec/fake_app/tmp/development_secret.txt +1 -0
  84. data/spec/integration/add_to_rails_app_spec.rb +9 -1
  85. data/spec/rails_helper.rb +64 -0
  86. data/spec/valid_mime_type_middleware_spec.rb +59 -0
  87. data/spec/valid_mime_type_spec.rb +6 -4
  88. data/stitches.gemspec +2 -0
  89. metadata +165 -9
  90. data/spec/api_client_access_wrapper_spec.rb +0 -52
  91. data/spec/api_key_spec.rb +0 -208
  92. data/spec/api_version_constraint_spec.rb +0 -33
@@ -1,52 +0,0 @@
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 DELETED
@@ -1,208 +0,0 @@
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::ApiKey do
17
- let(:app) { double("rack app") }
18
- let(:api_client) {
19
- double(ApiClient, id: 42)
20
- }
21
-
22
- before do
23
- Stitches.configuration.reset_to_defaults!
24
- Stitches.configuration.custom_http_auth_scheme = 'MyAwesomeInternalScheme'
25
- fake_rails_app = MyApp::Application.new
26
- allow(Rails).to receive(:application).and_return(fake_rails_app)
27
- allow(app).to receive(:call).with(env)
28
- allow(ApiClient).to receive(:find_by).and_return(api_client)
29
- Stitches::ApiClientAccessWrapper.clear_api_cache
30
- end
31
-
32
- subject(:middleware) { described_class.new(app, namespace: "/api") }
33
-
34
- shared_examples "an unauthorized response" do
35
- it "returns a 401" do
36
- status, _headers, _body = @response
37
- expect(status).to eq(401)
38
- end
39
- it "sets the proper header" do
40
- _status, headers, _body = @response
41
- expect(headers["WWW-Authenticate"]).to eq("MyAwesomeInternalScheme realm=MyApp")
42
- end
43
- it "stops the call chain preventing anything from happening" do
44
- expect(app).not_to have_received(:call)
45
- end
46
- it "sends a reasonable message" do
47
- _status, _headers, body = @response
48
- expect(body).to eq([expected_body])
49
- end
50
- end
51
-
52
- describe "#call" do
53
- context "not in namespace" do
54
- context "not allowlisted" do
55
- let(:env) {
56
- {
57
- "PATH_INFO" => "/index/apifoolingyou/home",
58
- }
59
- }
60
-
61
- before do
62
- @response = middleware.call(env)
63
- end
64
-
65
- it_behaves_like "an unauthorized response" do
66
- let(:expected_body) { "Unauthorized - no authorization header" }
67
- end
68
- end
69
- context "allowlisting" do
70
- context "allowlist is explicit in middleware usage" do
71
- before do
72
- @response = middleware.call(env)
73
- end
74
- context "passes the allowlist" do
75
- subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
76
- let(:env) {
77
- {
78
- "PATH_INFO" => "/resque/overview"
79
- }
80
- }
81
- it "calls through to the rest of the chain" do
82
- expect(app).to have_received(:call).with(env)
83
- end
84
- end
85
-
86
- context "fails the allowlist" do
87
- subject(:middleware) { described_class.new(app, except: %r{\A/resque\/.*\Z}) }
88
- let(:env) {
89
- {
90
- "PATH_INFO" => "//resque/overview" # subtle
91
- }
92
- }
93
- it_behaves_like "an unauthorized response" do
94
- let(:expected_body) { "Unauthorized - no authorization header" }
95
- end
96
- end
97
- context "except: is not given a regexp" do
98
- let(:env) {
99
- {
100
- "PATH_INFO" => "//resque/overview" # subtle
101
- }
102
- }
103
- it "blows up" do
104
- expect {
105
- described_class.new(app, except: "/resque")
106
- }.to raise_error(/must be a Regexp/i)
107
- end
108
- end
109
- end
110
- context "allowlist is implicit from the configuration" do
111
-
112
- before do
113
- Stitches.configuration.allowlist_regexp = %r{\A/resque/.*\Z}
114
- @response = middleware.call(env)
115
- end
116
-
117
- context "passes the allowlist" do
118
- subject(:middleware) { described_class.new(app) }
119
- let(:env) {
120
- {
121
- "PATH_INFO" => "/resque/overview"
122
- }
123
- }
124
- it "calls through to the rest of the chain" do
125
- expect(app).to have_received(:call).with(env)
126
- end
127
- end
128
-
129
- context "fails the allowlist" do
130
- subject(:middleware) { described_class.new(app) }
131
- let(:env) {
132
- {
133
- "PATH_INFO" => "//resque/overview" # subtle
134
- }
135
- }
136
- it_behaves_like "an unauthorized response" do
137
- let(:expected_body) { "Unauthorized - no authorization header" }
138
- end
139
- end
140
- end
141
- end
142
- end
143
-
144
- context "valid key" do
145
- let(:env) {
146
- {
147
- "PATH_INFO" => "/api/ping",
148
- "HTTP_AUTHORIZATION" => "MyAwesomeInternalScheme key=foobar",
149
- }
150
- }
151
-
152
- before do
153
- @response = middleware.call(env)
154
- end
155
- it "calls through to the rest of the chain" do
156
- expect(app).to have_received(:call).with(env)
157
- end
158
-
159
- it "sets the api_client's ID in the environment" do
160
- expect(env[Stitches.configuration.env_var_to_hold_api_client_primary_key]).to eq(api_client.id)
161
- end
162
-
163
- it "sets the api_client itself in the environment" do
164
- expect(env[Stitches.configuration.env_var_to_hold_api_client]).to eq(api_client)
165
- end
166
- end
167
-
168
- context "unauthorized responses" do
169
- before do
170
- @response = middleware.call(env)
171
- end
172
- context "invalid key" do
173
- let(:env) {
174
- {
175
- "PATH_INFO" => "/api/ping",
176
- "HTTP_AUTHORIZATION" => "MyAwesomeInternalScheme key=foobar",
177
- }
178
- }
179
- let(:api_client) { nil }
180
-
181
- it_behaves_like "an unauthorized response" do
182
- let(:expected_body) { "Unauthorized - key invalid" }
183
- end
184
- end
185
- context "bad authorization type" do
186
- let(:env) {
187
- {
188
- "PATH_INFO" => "/api/ping",
189
- "HTTP_AUTHORIZATION" => "foobar",
190
- }
191
- }
192
- it_behaves_like "an unauthorized response" do
193
- let(:expected_body) { "Unauthorized - bad authorization type" }
194
- end
195
- end
196
- context "no auth header" do
197
- let(:env) {
198
- {
199
- "PATH_INFO" => "/api/ping",
200
- }
201
- }
202
- it_behaves_like "an unauthorized response" do
203
- let(:expected_body) { "Unauthorized - no authorization header" }
204
- end
205
- end
206
- end
207
- end
208
- end
@@ -1,33 +0,0 @@
1
- require 'spec_helper.rb'
2
-
3
- describe Stitches::ApiVersionConstraint do
4
- let(:version) { 2 }
5
- let(:request) { double("request", headers: headers) }
6
-
7
- subject(:constraint) { described_class.new(version) }
8
-
9
- context "no accept header" do
10
- let(:headers) { {} }
11
- it "doesn't match" do
12
- expect(constraint.matches?(request)).to eq(false)
13
- end
14
- end
15
- context "accept header missing version" do
16
- let(:headers) { { accept: "application/json" } }
17
- it "doesn't match" do
18
- expect(constraint.matches?(request)).to eq(false)
19
- end
20
- end
21
- context "accept header has wrong version" do
22
- let(:headers) { { accept: "application/json; version=1" } }
23
- it "doesn't match" do
24
- expect(constraint.matches?(request)).to eq(false)
25
- end
26
- end
27
- context "accept header has correct version" do
28
- let(:headers) { { accept: "application/json; version=2" } }
29
- it "matcheds" do
30
- expect(constraint.matches?(request)).to eq(true)
31
- end
32
- end
33
- end