jets 2.1.7 → 2.2.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 +3 -0
- data/jets.gemspec +1 -0
- data/lib/jets.rb +2 -1
- data/lib/jets/application/defaults.rb +3 -0
- data/lib/jets/authorizer/base.rb +36 -0
- data/lib/jets/authorizer/dsl.rb +64 -0
- data/lib/jets/authorizer/helpers/iam_helper.rb +50 -0
- data/lib/jets/camelizer.rb +3 -70
- data/lib/jets/cfn/builders/api_deployment_builder.rb +0 -2
- data/lib/jets/cfn/builders/api_gateway_builder.rb +0 -2
- data/lib/jets/cfn/builders/api_resources_builder.rb +0 -2
- data/lib/jets/cfn/builders/authorizer_builder.rb +67 -0
- data/lib/jets/cfn/builders/base_child_builder.rb +2 -2
- data/lib/jets/cfn/builders/controller_builder.rb +4 -1
- data/lib/jets/cfn/builders/interface.rb +6 -4
- data/lib/jets/cfn/builders/parent_builder.rb +22 -10
- data/lib/jets/commands/build.rb +126 -103
- data/lib/jets/controller/authorization.rb +72 -0
- data/lib/jets/controller/base.rb +25 -43
- data/lib/jets/controller/middleware/cors.rb +1 -1
- data/lib/jets/klass.rb +3 -3
- data/lib/jets/naming.rb +12 -2
- data/lib/jets/resource/api_gateway/authorizer.rb +82 -0
- data/lib/jets/resource/api_gateway/method.rb +23 -38
- data/lib/jets/resource/api_gateway/method/authorization.rb +32 -0
- data/lib/jets/resource/child_stack/app_class.rb +16 -5
- data/lib/jets/resource/child_stack/authorizer.rb +46 -0
- data/lib/jets/resource/child_stack/common_parameters.rb +14 -0
- data/lib/jets/resource/child_stack/shared.rb +2 -9
- data/lib/jets/router/route.rb +1 -8
- data/lib/jets/router/route/authorization.rb +48 -0
- data/lib/jets/rule/dsl.rb +0 -1
- data/lib/jets/version.rb +1 -1
- metadata +26 -2
data/lib/jets/commands/build.rb
CHANGED
@@ -40,8 +40,9 @@ module Jets::Commands
|
|
40
40
|
|
41
41
|
def build_all_templates
|
42
42
|
# CloudFormation templates
|
43
|
-
# 1. Shared templates - child templates needs them
|
43
|
+
# 1. Shared and authorizer templates - child templates needs them
|
44
44
|
build_api_gateway_templates
|
45
|
+
build_authorizer_templates # controllers can use these
|
45
46
|
# 2. Child templates - parent template needs them
|
46
47
|
build_app_child_templates
|
47
48
|
# 2. Child templates - parent template needs them
|
@@ -51,7 +52,7 @@ module Jets::Commands
|
|
51
52
|
end
|
52
53
|
|
53
54
|
def build_minimal_template
|
54
|
-
Jets::Cfn::Builders::ParentBuilder.new(@options).build
|
55
|
+
Jets::Cfn::Builders::ParentBuilder.new(@options).build(parent=true)
|
55
56
|
end
|
56
57
|
|
57
58
|
def build_api_gateway_templates
|
@@ -59,6 +60,12 @@ module Jets::Commands
|
|
59
60
|
Jets::Cfn::Builders::ApiDeploymentBuilder.new(@options).build
|
60
61
|
end
|
61
62
|
|
63
|
+
def build_authorizer_templates
|
64
|
+
authorizer_files.each do |path|
|
65
|
+
Jets::Cfn::Builders::AuthorizerBuilder.new(path).build
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
62
69
|
def build_app_child_templates
|
63
70
|
app_files.each do |path|
|
64
71
|
build_child_template(path)
|
@@ -74,6 +81,8 @@ module Jets::Commands
|
|
74
81
|
# path: app/controllers/comments_controller.rb
|
75
82
|
# path: app/jobs/easy_job.rb
|
76
83
|
def build_child_template(path)
|
84
|
+
return if authorizer?(path) # AuthorizerBuilder is built earlier
|
85
|
+
|
77
86
|
md = path.match(%r{app/(.*?)/}) # extract: controller, job or function
|
78
87
|
process_class = md[1].classify
|
79
88
|
builder_class = "Jets::Cfn::Builders::#{process_class}Builder".constantize
|
@@ -85,14 +94,20 @@ module Jets::Commands
|
|
85
94
|
# Jets::Cfn::Builders::FunctionBuilder.new(Hello)
|
86
95
|
# Jets::Cfn::Builders::FunctionBuilder.new(HelloFunction)
|
87
96
|
app_class = Jets::Klass.from_path(path)
|
88
|
-
|
89
|
-
|
90
|
-
builder.build
|
97
|
+
if Jets.poly_only? && app_class == Jets::PreheatJob
|
98
|
+
return # No prewarm when there's only poly functions
|
91
99
|
end
|
100
|
+
|
101
|
+
builder = builder_class.new(app_class)
|
102
|
+
builder.build
|
103
|
+
end
|
104
|
+
|
105
|
+
def authorizer?(path)
|
106
|
+
path.include?("app/authorizers")
|
92
107
|
end
|
93
108
|
|
94
109
|
def build_parent_template
|
95
|
-
Jets::Cfn::Builders::ParentBuilder.new(@options).build
|
110
|
+
Jets::Cfn::Builders::ParentBuilder.new(@options).build(parent=true)
|
96
111
|
end
|
97
112
|
|
98
113
|
def clean_templates
|
@@ -103,126 +118,134 @@ module Jets::Commands
|
|
103
118
|
self.class.app_files
|
104
119
|
end
|
105
120
|
|
106
|
-
# Crucial that the Dir.pwd is in the tmp_code because for
|
107
|
-
# because Jets.boot set ups autoload_paths and this is how project
|
108
|
-
# classes are loaded.
|
109
|
-
# TODO: rework code so that Dir.pwd does not have to be in tmp_code for build to work.
|
110
|
-
def self.app_files
|
111
|
-
paths = []
|
112
|
-
expression = "#{Jets.root}/app/**/**/*.rb"
|
113
|
-
Dir.glob(expression).each do |path|
|
114
|
-
return false unless File.file?(path)
|
115
|
-
next unless app_file?(path)
|
116
|
-
next if concerns?(path)
|
117
|
-
|
118
|
-
relative_path = path.sub("#{Jets.root}/", '')
|
119
|
-
# Rids of the Jets.root at beginning
|
120
|
-
paths << relative_path
|
121
|
-
end
|
122
|
-
paths += internal_app_files
|
123
|
-
paths
|
124
|
-
end
|
125
|
-
|
126
121
|
def shared_files
|
127
122
|
self.class.shared_files
|
128
123
|
end
|
129
124
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
125
|
+
def authorizer_files
|
126
|
+
self.class.authorizer_files
|
127
|
+
end
|
128
|
+
|
129
|
+
class << self
|
130
|
+
# Crucial that the Dir.pwd is in the tmp_code because for because Jets.boot set ups autoload_paths and this is
|
131
|
+
# how project classes are loaded.
|
132
|
+
# TODO: rework code so that Dir.pwd does not have to be in tmp_code for build to work.
|
133
|
+
#
|
134
|
+
# app_files method is mainly used to determine what templates to build.
|
135
|
+
# app_files method is also used to determine what handlers to build.
|
136
|
+
def app_files
|
137
|
+
paths = []
|
138
|
+
expression = "#{Jets.root}/app/**/**/*.rb"
|
139
|
+
Dir.glob(expression).each do |path|
|
140
|
+
next unless app_file?(path)
|
141
|
+
relative_path = path.sub("#{Jets.root}/", '') # rid of the Jets.root at beginning
|
142
|
+
paths << relative_path
|
143
|
+
end
|
144
|
+
paths += internal_app_files
|
145
|
+
paths
|
146
|
+
end
|
136
147
|
|
137
|
-
|
138
|
-
|
139
|
-
|
148
|
+
APP_FOLDERS = %w[authorizers controllers functions jobs rules]
|
149
|
+
def app_file?(path)
|
150
|
+
return false unless File.extname(path) == ".rb"
|
151
|
+
return false unless File.file?(path) unless Jets.env.test?
|
152
|
+
return false if application_abstract_classes.detect { |p| path.include?(p) }
|
153
|
+
return false if concerns?(path)
|
154
|
+
return true if APP_FOLDERS.detect { |p| path.include?("app/#{p}") }
|
155
|
+
false
|
140
156
|
end
|
141
|
-
paths
|
142
|
-
end
|
143
157
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
158
|
+
# Do not define lamda functions for abstract application parent classes. Examples:
|
159
|
+
#
|
160
|
+
# application_controller.rb
|
161
|
+
# application_job.rb
|
162
|
+
# application_authorizer.rb
|
163
|
+
def application_abstract_classes
|
164
|
+
APP_FOLDERS.map { |a| "application_#{a.singularize}.rb" }
|
165
|
+
end
|
150
166
|
|
151
|
-
|
152
|
-
|
153
|
-
app_class = Jets::Klass.from_path(path) # IE: PostsController, Jets::PublicController
|
154
|
-
langs = app_class.tasks.map(&:lang)
|
155
|
-
langs.include?(:ruby) && app_class != Jets::PreheatJob
|
167
|
+
def concerns?(path)
|
168
|
+
path =~ %r{app/\w+/concerns/}
|
156
169
|
end
|
157
|
-
!!has_ruby
|
158
|
-
end
|
159
170
|
|
160
|
-
|
161
|
-
|
162
|
-
Jets::Stack.subclasses.each do |klass|
|
163
|
-
klass.functions.each do |fun|
|
164
|
-
if fun.lang == :ruby
|
165
|
-
has_ruby = true
|
166
|
-
break
|
167
|
-
end
|
168
|
-
end
|
171
|
+
def authorizer_files
|
172
|
+
app_files.select { |p| p.include?("app/authorizers") }
|
169
173
|
end
|
170
|
-
has_ruby
|
171
|
-
end
|
172
174
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
# The copying of other internal files like views is done in builders/code_builder.rb copy_internal_jets_code
|
177
|
-
def self.internal_app_files
|
178
|
-
paths = []
|
179
|
-
controllers = File.expand_path("../../internal/app/controllers/jets", __FILE__)
|
175
|
+
def shared_files
|
176
|
+
find_app_paths("shared/resources")
|
177
|
+
end
|
180
178
|
|
181
|
-
|
182
|
-
|
179
|
+
def find_app_paths(app_path)
|
180
|
+
paths = []
|
181
|
+
expression = "#{Jets.root}/app/#{app_path}/**/*.rb"
|
182
|
+
Dir.glob(expression).each do |path|
|
183
|
+
return false unless File.file?(path)
|
183
184
|
|
184
|
-
|
185
|
-
|
185
|
+
relative_path = path.sub("#{Jets.root}/", '')
|
186
|
+
# Rids of the Jets.root at beginning
|
187
|
+
paths << relative_path
|
188
|
+
end
|
189
|
+
paths
|
190
|
+
end
|
186
191
|
|
187
|
-
|
188
|
-
|
192
|
+
# Finds out of the app has polymorphic functions only and zero ruby functions.
|
193
|
+
# In this case, we can skip a lot of the ruby related building and speed up the
|
194
|
+
# deploy process.
|
195
|
+
def poly_only?
|
196
|
+
!app_has_ruby? && !shared_has_ruby?
|
197
|
+
end
|
189
198
|
|
190
|
-
|
191
|
-
|
192
|
-
|
199
|
+
def app_has_ruby?
|
200
|
+
has_ruby = app_files.detect do |path|
|
201
|
+
app_class = Jets::Klass.from_path(path) # IE: PostsController, Jets::PublicController
|
202
|
+
langs = app_class.tasks.map(&:lang)
|
203
|
+
langs.include?(:ruby) && app_class != Jets::PreheatJob
|
204
|
+
end
|
205
|
+
!!has_ruby
|
193
206
|
end
|
194
207
|
|
195
|
-
|
196
|
-
|
208
|
+
def shared_has_ruby?
|
209
|
+
has_ruby = false
|
210
|
+
Jets::Stack.subclasses.each do |klass|
|
211
|
+
klass.functions.each do |fun|
|
212
|
+
if fun.lang == :ruby
|
213
|
+
has_ruby = true
|
214
|
+
break
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
has_ruby
|
219
|
+
end
|
197
220
|
|
198
|
-
|
199
|
-
|
200
|
-
#
|
201
|
-
#
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
]
|
206
|
-
return false if excludes.detect { |p| path.include?(p) }
|
221
|
+
# Add internal Jets controllers if they are being used
|
222
|
+
# TODO: Interesting, this eventually just used to generate handlers and controllers only.
|
223
|
+
# Maybe rename to make that clear.
|
224
|
+
# The copying of other internal files like views is done in builders/code_builder.rb copy_internal_jets_code
|
225
|
+
def internal_app_files
|
226
|
+
paths = []
|
227
|
+
controllers = File.expand_path("../../internal/app/controllers/jets", __FILE__)
|
207
228
|
|
208
|
-
|
209
|
-
|
210
|
-
app/jobs
|
211
|
-
app/functions
|
212
|
-
app/rules
|
213
|
-
]
|
214
|
-
return true if includes.detect { |p| path.include?(p) }
|
229
|
+
public_catchall = Jets::Router.has_controller?("Jets::PublicController")
|
230
|
+
paths << "#{controllers}/public_controller.rb" if public_catchall
|
215
231
|
|
216
|
-
|
217
|
-
|
232
|
+
rack_catchall = Jets::Router.has_controller?("Jets::RackController")
|
233
|
+
paths << "#{controllers}/rack_controller.rb" if rack_catchall
|
218
234
|
|
219
|
-
|
220
|
-
|
221
|
-
end
|
235
|
+
mailer_controller = Jets::Router.has_controller?("Jets::MailersController")
|
236
|
+
paths << "#{controllers}/mailers_controller.rb" if mailer_controller
|
222
237
|
|
223
|
-
|
224
|
-
|
225
|
-
|
238
|
+
if Jets.config.prewarm.enable
|
239
|
+
jobs = File.expand_path("../../internal/app/jobs/jets", __FILE__)
|
240
|
+
paths << "#{jobs}/preheat_job.rb"
|
241
|
+
end
|
226
242
|
|
243
|
+
paths
|
244
|
+
end
|
245
|
+
|
246
|
+
def tmp_code(full_build_path=false)
|
247
|
+
full_build_path ? "#{Jets.build_root}/stage/code" : "stage/code"
|
248
|
+
end
|
249
|
+
end
|
227
250
|
end
|
228
251
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Jets::Controller
|
2
|
+
module Authorization
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :auth_type,
|
7
|
+
:auth_to,
|
8
|
+
:auth_options, # for only and except filters
|
9
|
+
:api_key_needed
|
10
|
+
end
|
11
|
+
|
12
|
+
class_methods do
|
13
|
+
def controller_path
|
14
|
+
name.sub(/Controller$/, "".freeze).underscore
|
15
|
+
end
|
16
|
+
|
17
|
+
def authorization_type(value=nil)
|
18
|
+
if !value.nil?
|
19
|
+
self.auth_type = value
|
20
|
+
else
|
21
|
+
self.auth_type
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def authorizer(value=nil, options={})
|
26
|
+
if !value.nil?
|
27
|
+
self.auth_to = value # IE: main#protect
|
28
|
+
self.auth_options = options # IE: only: %w[index] or expect: [:show]
|
29
|
+
else
|
30
|
+
self.auth_to
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def authorizer_logical_id(action_name)
|
35
|
+
return unless auth_to
|
36
|
+
|
37
|
+
only = auth_options[:only].map(&:to_s) if auth_options && auth_options[:only]
|
38
|
+
except = auth_options[:except].map(&:to_s) if auth_options && auth_options[:except]
|
39
|
+
|
40
|
+
if except and !except.include?(action_name)
|
41
|
+
logical_id = Jets::Router::Route.authorizer_logical_id(auth_to)
|
42
|
+
end
|
43
|
+
|
44
|
+
# only overrides except
|
45
|
+
if only and only.include?(action_name)
|
46
|
+
logical_id = Jets::Router::Route.authorizer_logical_id(auth_to)
|
47
|
+
end
|
48
|
+
|
49
|
+
# if both only and except are not set then always set the logical_id
|
50
|
+
if !only && !except
|
51
|
+
logical_id = Jets::Router::Route.authorizer_logical_id(auth_to)
|
52
|
+
end
|
53
|
+
|
54
|
+
logical_id
|
55
|
+
end
|
56
|
+
|
57
|
+
# Autoamtically sets authorization_type for the specific route based on the controller authorizer
|
58
|
+
def infer_authorization_type_for(action_name)
|
59
|
+
return unless authorizer_logical_id(action_name)
|
60
|
+
Jets::Authorizer::Base.authorization_type(auth_to)
|
61
|
+
end
|
62
|
+
|
63
|
+
def api_key_required(value=nil)
|
64
|
+
if !value.nil?
|
65
|
+
self.api_key_needed = value
|
66
|
+
else
|
67
|
+
self.api_key_needed
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/jets/controller/base.rb
CHANGED
@@ -4,14 +4,15 @@ require "rack/utils" # Rack::Utils.parse_nested_query
|
|
4
4
|
# Controller public methods get turned into Lambda functions.
|
5
5
|
class Jets::Controller
|
6
6
|
class Base < Jets::Lambda::Functions
|
7
|
+
include ActiveSupport::Rescuable
|
8
|
+
include Authorization
|
7
9
|
include Callbacks
|
8
10
|
include Cookies
|
11
|
+
include ForgeryProtection
|
12
|
+
include Jets::Router::Helpers
|
9
13
|
include Layout
|
10
14
|
include Params
|
11
15
|
include Rendering
|
12
|
-
include ActiveSupport::Rescuable
|
13
|
-
include Jets::Router::Helpers
|
14
|
-
include ForgeryProtection
|
15
16
|
|
16
17
|
delegate :headers, to: :request
|
17
18
|
delegate :set_header, to: :response
|
@@ -23,6 +24,16 @@ class Jets::Controller
|
|
23
24
|
@response = Response.new
|
24
25
|
end
|
25
26
|
|
27
|
+
# Overrides Base.process
|
28
|
+
def self.process(event, context={}, meth)
|
29
|
+
controller = new(event, context, meth)
|
30
|
+
# Using send because process! is private method in Jets::RackController so
|
31
|
+
# it doesnt create a lambda function. It's doesnt matter what scope process!
|
32
|
+
# is in Controller::Base because Jets lambda functions inheritance doesnt
|
33
|
+
# include methods in Controller::Base.
|
34
|
+
controller.send(:process!)
|
35
|
+
end
|
36
|
+
|
26
37
|
# One key difference between process! vs dispatch!
|
27
38
|
#
|
28
39
|
# process! - takes the request through the middleware stack
|
@@ -101,49 +112,20 @@ class Jets::Controller
|
|
101
112
|
@meth
|
102
113
|
end
|
103
114
|
|
104
|
-
def self.controller_path
|
105
|
-
name.sub(/Controller$/, "".freeze).underscore
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.process(event, context={}, meth)
|
109
|
-
controller = new(event, context, meth)
|
110
|
-
# Using send because process! is private method in Jets::RackController so
|
111
|
-
# it doesnt create a lambda function. It's doesnt matter what scope process!
|
112
|
-
# is in Controller::Base because Jets lambda functions inheritance doesnt
|
113
|
-
# include methods in Controller::Base.
|
114
|
-
controller.send(:process!)
|
115
|
-
end
|
116
|
-
|
117
115
|
class_attribute :internal_controller
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
class_attribute :auth_type
|
127
|
-
def self.authorization_type(value=nil)
|
128
|
-
if !value.nil?
|
129
|
-
self.auth_type = value
|
130
|
-
else
|
131
|
-
self.auth_type
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
class_attribute :api_key_needed
|
136
|
-
def self.api_key_required(value=nil)
|
137
|
-
if !value.nil?
|
138
|
-
self.api_key_needed = value
|
139
|
-
else
|
140
|
-
self.api_key_needed
|
116
|
+
class << self
|
117
|
+
def internal(value=nil)
|
118
|
+
if !value.nil?
|
119
|
+
self.internal_controller = value
|
120
|
+
else
|
121
|
+
self.internal_controller
|
122
|
+
end
|
141
123
|
end
|
142
|
-
end
|
143
124
|
|
144
|
-
|
145
|
-
|
146
|
-
|
125
|
+
def helper_method(*meths)
|
126
|
+
meths.each do |meth|
|
127
|
+
Jets::Router::Helpers.define_helper_method(meth)
|
128
|
+
end
|
147
129
|
end
|
148
130
|
end
|
149
131
|
end
|