marty 2.4.0 → 2.4.1
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 +5 -5
- data/Gemfile.lock +1 -1
- data/app/components/marty/api_auth_view.rb +4 -27
- data/app/components/marty/extras/layout.rb +7 -1
- data/app/components/marty/grid.rb +10 -9
- data/app/controllers/marty/rpc_controller.rb +4 -2
- data/app/models/marty/api_auth.rb +1 -80
- data/app/models/marty/api_config.rb +4 -4
- data/app/models/marty/delorean_rule.rb +2 -3
- data/config/routes.rb +1 -1
- data/db/migrate/{501_add_api_class_to_marty_api_config.rb → 500_add_api_class_to_marty_api_config.rb} +0 -0
- data/lib/marty/aws/base.rb +98 -0
- data/lib/marty/util.rb +15 -0
- data/lib/marty/version.rb +1 -1
- data/other/marty/api/base.rb +3 -0
- data/spec/controllers/job_controller_spec.rb +1 -1
- data/spec/dummy/app/components/gemini/xyz_rule_view.rb +0 -1
- data/spec/dummy/config/application.rb +0 -1
- data/spec/features/enum_spec.rb +100 -35
- data/spec/features/log_view_spec.rb +5 -5
- data/spec/features/rule_spec.rb +30 -30
- data/spec/features/user_view_spec.rb +2 -0
- data/spec/lib/logger_spec.rb +1 -1
- data/spec/models/event_spec.rb +1 -1
- data/spec/models/promise_spec.rb +1 -1
- data/spec/models/user_spec.rb +6 -6
- data/spec/spec_helper.rb +9 -69
- data/spec/support/chromedriver.rb +41 -0
- data/spec/support/components/netzke_combobox.rb +57 -0
- data/spec/support/components/netzke_grid.rb +356 -0
- data/spec/support/custom_matchers.rb +18 -0
- data/spec/support/custom_selectors.rb +49 -0
- data/spec/support/delayed_job_helpers.rb +4 -5
- data/spec/support/download_helper.rb +52 -0
- data/spec/support/helper.rb +20 -0
- data/spec/support/netzke.rb +306 -0
- data/spec/support/performance_helper.rb +26 -0
- data/spec/support/post_run_logger.rb +32 -0
- data/spec/support/{spec_setup.rb → setup.rb} +19 -6
- data/spec/support/shared_connection.rb +31 -0
- data/spec/support/{clean_db_helpers.rb → shared_connection_db_helpers.rb} +2 -2
- data/spec/support/structure_compare.rb +62 -0
- data/spec/support/suite.rb +27 -0
- data/spec/support/{integration_helpers.rb → users.rb} +11 -9
- metadata +20 -8
- data/db/migrate/502_add_parameters_to_marty_api_auth.rb +0 -5
- data/spec/support/user_helpers.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c3db866b4afffd7cef3f93ecdaf8698dc45bf169
|
4
|
+
data.tar.gz: f1ba792e54124bd28c8a50a5080a3ea556dfe4bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d40dc1b4535d794f22bd51916449cf48738030780b37a7392abf7ee95ed3ee7f890415090c5b189e271a6f26fa519bf60f8075e9912ff0861896deb73531a366
|
7
|
+
data.tar.gz: 59c87e1a2e69ba55ad37a0b43ae5876487a3226ca1f34b060bf3b889b318f8616cfa3d10f511450a806223a31107d84b4fa5a142af089da7a206ebad1c0151a5
|
data/Gemfile.lock
CHANGED
@@ -7,37 +7,14 @@ class Marty::ApiAuthView < Marty::McflyGridPanel
|
|
7
7
|
def configure(c)
|
8
8
|
super
|
9
9
|
|
10
|
-
c.title
|
11
|
-
c.
|
12
|
-
c.
|
13
|
-
c.model = "Marty::ApiAuth"
|
14
|
-
c.attributes = [:aws, :entity_name, :api_key, :script_name]
|
10
|
+
c.title = I18n.t('api_auth', default: "API Authorization")
|
11
|
+
c.model = "Marty::ApiAuth"
|
12
|
+
c.attributes = [:app_name, :api_key, :script_name]
|
15
13
|
c.store_config.merge!({sorters: [{property: :app_name, direction: 'ASC'}]})
|
16
14
|
end
|
17
15
|
|
18
|
-
attribute :
|
19
|
-
c.width = 60
|
20
|
-
c.read_only = true
|
21
|
-
c.text = "AWS"
|
22
|
-
c.type = :boolean
|
23
|
-
c.getter = lambda do |r|
|
24
|
-
!!r.parameters['aws_api_key']
|
25
|
-
end
|
26
|
-
c.sorting_scope = get_json_sorter('parameters', 'aws_api_key')
|
27
|
-
c.filterable = true
|
28
|
-
c.filter_with = lambda do |rel, value, op|
|
29
|
-
rel.where("parameters->>'aws_api_key' IS #{value ? 'NOT' : ''} NULL")
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
attribute :entity_name do |c|
|
16
|
+
attribute :app_name do |c|
|
34
17
|
c.flex = 1
|
35
|
-
c.text = "Entity Name"
|
36
|
-
c.getter = lambda do |r|
|
37
|
-
aws = !!r.parameters['aws_api_key']
|
38
|
-
entity = r.entity
|
39
|
-
entity ? entity.name : (aws ? nil : r.app_name)
|
40
|
-
end
|
41
18
|
end
|
42
19
|
|
43
20
|
attribute :api_key do |c|
|
@@ -73,7 +73,8 @@ module Layout
|
|
73
73
|
######################################################################
|
74
74
|
# PG ENUM field handling
|
75
75
|
|
76
|
-
def enum_column(c, class_or_array)
|
76
|
+
def enum_column(c, class_or_array, col=nil)
|
77
|
+
col ||= c.name.demodulize.tableize.singularize
|
77
78
|
vals = class_or_array.is_a?(Array) ? class_or_array : class_or_array::VALUES
|
78
79
|
editor_config = {
|
79
80
|
trigger_action: :all,
|
@@ -91,6 +92,7 @@ module Layout
|
|
91
92
|
field_config: editor_config,
|
92
93
|
type: :string,
|
93
94
|
setter: enum_setter(c.name),
|
95
|
+
sorting_scope: get_sorter(col)
|
94
96
|
)
|
95
97
|
end
|
96
98
|
|
@@ -112,6 +114,10 @@ module Layout
|
|
112
114
|
lambda {|r, v| r.send("#{name}=", v.blank? || v == '---' ? nil : v)}
|
113
115
|
end
|
114
116
|
|
117
|
+
def get_sorter(col)
|
118
|
+
lambda {|rel, dir| rel.order("#{col}::text #{dir.to_s}")}
|
119
|
+
end
|
120
|
+
|
115
121
|
######################################################################
|
116
122
|
# employ lots of hakery to implement NULLable boolean field in
|
117
123
|
# Netzke 8.x.
|
@@ -25,7 +25,7 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
25
25
|
}
|
26
26
|
JS
|
27
27
|
|
28
|
-
c.
|
28
|
+
c.set_disable_component_actions = l(<<-JS)
|
29
29
|
function(prefix, flag) {
|
30
30
|
for (var key in this.actions) {
|
31
31
|
if (key.substring(0, prefix.length) == prefix) {
|
@@ -87,14 +87,14 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
87
87
|
}
|
88
88
|
|
89
89
|
me.serverConfig.selected = rid;
|
90
|
-
me.
|
90
|
+
me.setDisableComponentActions('do', !has_sel);
|
91
91
|
|
92
92
|
for (var child of children) {
|
93
|
-
var comp = me.
|
93
|
+
var comp = me.findComponent(child)
|
94
94
|
if (comp) {
|
95
95
|
comp.serverConfig.parent_id = rid;
|
96
|
-
if (comp.
|
97
|
-
comp.
|
96
|
+
if (comp.setDisableComponentActions) {
|
97
|
+
comp.setDisableComponentActions('parent', !has_sel);
|
98
98
|
}
|
99
99
|
if (comp.reload) { comp.reload() }
|
100
100
|
}
|
@@ -117,9 +117,7 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
117
117
|
c.on_selection_change = l(<<-JS)
|
118
118
|
function(f) {
|
119
119
|
var me = this;
|
120
|
-
me.getSelectionModel().on('selectionchange',
|
121
|
-
f(m);
|
122
|
-
});
|
120
|
+
me.getSelectionModel().on('selectionchange', f);
|
123
121
|
}
|
124
122
|
JS
|
125
123
|
|
@@ -150,7 +148,7 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
150
148
|
var children = me.serverConfig.child_components || [];
|
151
149
|
this.store.reload();
|
152
150
|
for (child of children) {
|
153
|
-
var comp = me.
|
151
|
+
var comp = me.findComponent(child);
|
154
152
|
if (comp && comp.reload) { comp.reload() }
|
155
153
|
}
|
156
154
|
}
|
@@ -182,6 +180,9 @@ class Marty::Grid < ::Netzke::Grid::Base
|
|
182
180
|
c.editing = :both
|
183
181
|
c.store_config = {page_size: 30}
|
184
182
|
c.view_config = {preserve_scroll_on_reload: true}
|
183
|
+
|
184
|
+
# disable buffered renderer plugin to avoid white space on reload
|
185
|
+
c.buffered_renderer = false
|
185
186
|
end
|
186
187
|
|
187
188
|
def has_search_action?
|
@@ -20,8 +20,8 @@ class Marty::RpcController < ActionController::Base
|
|
20
20
|
|
21
21
|
api_params = api.process_params(massaged_params)
|
22
22
|
api.before_evaluate(api_params)
|
23
|
-
result = api.evaluate(api_params
|
24
|
-
api.after_evaluate(api_params
|
23
|
+
result = api.evaluate(api_params, request, api_config)
|
24
|
+
api.after_evaluate(api_params, result)
|
25
25
|
|
26
26
|
log_params = {start_time: start_time, auth: auth}
|
27
27
|
api.log(result, api_params + log_params, request) if
|
@@ -67,6 +67,8 @@ class Marty::RpcController < ActionController::Base
|
|
67
67
|
when String
|
68
68
|
params = ActiveSupport::JSON.decode(params)
|
69
69
|
when ActionController::Parameters
|
70
|
+
# must permit params before conversion to_h
|
71
|
+
# convert hash to json and parse to get expected hash (not indifferent)
|
70
72
|
params.permit!
|
71
73
|
params = JSON.parse(params.to_h.to_json)
|
72
74
|
when nil
|
@@ -1,8 +1,6 @@
|
|
1
1
|
class Marty::ApiAuth < Marty::Base
|
2
2
|
has_mcfly
|
3
3
|
|
4
|
-
belongs_to :entity, polymorphic: true, optional: true
|
5
|
-
|
6
4
|
KEY_SIZE = 19
|
7
5
|
|
8
6
|
validates_presence_of :app_name, :api_key, :script_name
|
@@ -26,87 +24,10 @@ class Marty::ApiAuth < Marty::Base
|
|
26
24
|
|
27
25
|
before_validation do
|
28
26
|
self.api_key = Marty::ApiAuth.generate_key if
|
29
|
-
self.api_key.
|
30
|
-
end
|
31
|
-
|
32
|
-
before_save do
|
33
|
-
return unless changed.include?(:entity_id) && !parameters['aws_api_key']
|
34
|
-
|
35
|
-
msg = 'API Auth must be associated with an AWS API KEY before '\
|
36
|
-
'it can be associated with an entity'
|
37
|
-
|
38
|
-
errors.add(:base, msg)
|
39
|
-
end
|
40
|
-
|
41
|
-
before_destroy do
|
42
|
-
next unless aws = parameters['aws_api_key']
|
43
|
-
begin
|
44
|
-
client = Marty::Aws::Apigateway.new
|
45
|
-
resp = client.delete_usage_plan_key(aws['api_usage_plan_id'],
|
46
|
-
aws['aid'])
|
47
|
-
client.delete_api_key(aws['aid']) if resp
|
48
|
-
rescue => e
|
49
|
-
Marty::Logger.log('api_test', 'error', e.message)
|
50
|
-
throw :abort unless e.message.include?('Invalid API Key')
|
51
|
-
end
|
27
|
+
self.api_key.blank?
|
52
28
|
end
|
53
29
|
|
54
30
|
def self.generate_key
|
55
31
|
SecureRandom.hex(KEY_SIZE)
|
56
32
|
end
|
57
|
-
|
58
|
-
def create_aws_api_key api_id, api_usage_plan_id
|
59
|
-
client = Marty::Aws::Apigateway.new
|
60
|
-
app_id = Marty::Config['AWS_APP_IDENTIFIER'] || 'marty'
|
61
|
-
name = "#{app_id}-#{api_id}-#{api_key[0..3]}"
|
62
|
-
|
63
|
-
key = nil
|
64
|
-
begin
|
65
|
-
key = client.create_api_key(name, 'marty_api_key', api_key)
|
66
|
-
rescue => e
|
67
|
-
#Marty::Logger.log('api_test', 'error', e.message)
|
68
|
-
end
|
69
|
-
|
70
|
-
upkey = nil
|
71
|
-
begin
|
72
|
-
upkey = key &&
|
73
|
-
client.create_usage_plan_key(api_usage_plan_id, key.id)
|
74
|
-
rescue => e
|
75
|
-
#Marty::Logger.log('api_test', 'error', e.message)
|
76
|
-
# remove api key we created
|
77
|
-
client.delete_api_key(key.id)
|
78
|
-
end
|
79
|
-
|
80
|
-
raise "Unable to create AWS API Key" unless key && upkey
|
81
|
-
|
82
|
-
parameters['aws_api_key'] = {
|
83
|
-
'aid' => key.id,
|
84
|
-
'api_usage_plan_id' => api_usage_plan_id,
|
85
|
-
'api_id' => api_id,
|
86
|
-
}
|
87
|
-
|
88
|
-
save!
|
89
|
-
end
|
90
|
-
|
91
|
-
def move_aws_key usage_plan_id
|
92
|
-
return unless aws = parameters['aws_api_key']
|
93
|
-
return if aws['api_usage_plan_id'] == usage_plan_id
|
94
|
-
|
95
|
-
begin
|
96
|
-
client = Marty::Aws::Apigateway.new
|
97
|
-
resp = client.delete_usage_plan_key(aws['api_usage_plan_id'],
|
98
|
-
aws['aid'])
|
99
|
-
rescue => e
|
100
|
-
# on fail recreate usage plan key
|
101
|
-
Marty::Logger.log('api', 'api_test', aws)
|
102
|
-
client.create_usage_plan_key(aws['api_usage_plan_id'], aws['aid']) if
|
103
|
-
client
|
104
|
-
return
|
105
|
-
else
|
106
|
-
client.create_usage_plan_key(usage_plan_id, aws['aid']) if resp
|
107
|
-
end
|
108
|
-
|
109
|
-
parameters['aws_api_key'] += {'api_usage_plan_id' => usage_plan_id}
|
110
|
-
save!
|
111
|
-
end
|
112
33
|
end
|
@@ -2,10 +2,10 @@ class Marty::ApiConfig < Marty::Base
|
|
2
2
|
validates_presence_of :script
|
3
3
|
|
4
4
|
def self.lookup(script, node, attr)
|
5
|
-
res = where(
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
res = where('node IS NULL OR node = ?', node).
|
6
|
+
where('attr IS NULL OR attr = ?', attr).
|
7
|
+
order('node nulls last, attr nulls last').
|
8
|
+
find_by(script: script)
|
9
9
|
|
10
10
|
res && res.as_json.except('id',
|
11
11
|
'created_at',
|
@@ -152,10 +152,9 @@ class Marty::DeloreanRule < Marty::BaseRule
|
|
152
152
|
estack_full = resh.delete(:err_stack)
|
153
153
|
estack = estack_full && {
|
154
154
|
err_stack: estack_full.select{ |l| l.starts_with?('DELOREAN')}} || {}
|
155
|
+
detail = { input: params, dgparams: dgparams} + resh + estack
|
155
156
|
Marty::Logger.info("Rule Log #{ruleh['name']}",
|
156
|
-
|
157
|
-
dgparams: dgparams } + resh + estack
|
158
|
-
)
|
157
|
+
Marty::Util.scrub_obj(detail))
|
159
158
|
end
|
160
159
|
end
|
161
160
|
end
|
data/config/routes.rb
CHANGED
@@ -6,5 +6,5 @@ Marty::Engine.routes.draw do
|
|
6
6
|
match via: [:get, :post], "rpc/evaluate(.:format)" => "rpc", as: :rpc
|
7
7
|
match via: [:get, :post], "report(.:format)" => "report#index", as: :report
|
8
8
|
get 'job/download' => 'job', as: :job
|
9
|
-
get 'diag',
|
9
|
+
get 'diag', to: 'diagnostic/#op'
|
10
10
|
end
|
File without changes
|
@@ -0,0 +1,98 @@
|
|
1
|
+
class Marty::Aws::Base
|
2
|
+
# aws reserved host used to get instance meta-data
|
3
|
+
META_DATA_HOST = '169.254.169.254'
|
4
|
+
|
5
|
+
attr_reader :id,
|
6
|
+
:doc,
|
7
|
+
:role,
|
8
|
+
:creds,
|
9
|
+
:version,
|
10
|
+
:host,
|
11
|
+
|
12
|
+
def self.get url
|
13
|
+
uri = URI.parse(url)
|
14
|
+
req = Net::HTTP.new(uri.host, uri.port)
|
15
|
+
req.read_timeout = req.open_timeout = ENV['AWS_REQUEST_TIMEOUT'] || 0.25
|
16
|
+
req.start {|http| http.get(uri.to_s) }.body
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.is_aws?
|
20
|
+
response = get("http://#{META_DATA_HOST}") rescue nil
|
21
|
+
response.present?
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@id = get_instance_id
|
26
|
+
@doc = get_document
|
27
|
+
@role = get_role
|
28
|
+
@creds = get_credentials
|
29
|
+
@version = '2016-11-15'
|
30
|
+
end
|
31
|
+
|
32
|
+
def query_meta_data query
|
33
|
+
self.class.get("http://#{META_DATA_HOST}/latest/meta-data/#{query}/")
|
34
|
+
end
|
35
|
+
|
36
|
+
def query_dynamic query
|
37
|
+
self.class.get("http://#{META_DATA_HOST}/latest/dynamic/#{query}/")
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def get_instance_id
|
42
|
+
query_meta_data('instance-id').to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_role
|
46
|
+
query_meta_data('iam/security-credentials').to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_credentials
|
50
|
+
res = JSON.parse(query_meta_data("iam/security-credentials/#{@role}"))
|
51
|
+
res.symbolize_keys
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_document
|
55
|
+
res = JSON.parse(query_dynamic('instance-identity/document'))
|
56
|
+
res.symbolize_keys
|
57
|
+
end
|
58
|
+
|
59
|
+
def request info, params = {}
|
60
|
+
action = info[:action]
|
61
|
+
endpoint = info[:endpoint]
|
62
|
+
method = info[:method] || :get
|
63
|
+
|
64
|
+
default = action ? {'Action' => action, 'Version' => @version} : {}
|
65
|
+
|
66
|
+
host = "#{@service}.#{@doc[:region]}.amazonaws.com"
|
67
|
+
|
68
|
+
url = "https://#{host}/"
|
69
|
+
url += endpoint if endpoint
|
70
|
+
url += '?' + (default + params).map{|a, v| "#{a}=#{v}"}.join('&') unless
|
71
|
+
params.empty?
|
72
|
+
|
73
|
+
sig = Aws::Sigv4::Signer.new(service: @service,
|
74
|
+
region: @doc[:region],
|
75
|
+
access_key_id: @creds[:access_key_id],
|
76
|
+
secret_access_key: @creds[:secret_access_key],
|
77
|
+
session_token: @creds[:token])
|
78
|
+
signed_url = sig.presign_url(http_method:'GET', url: url)
|
79
|
+
|
80
|
+
http = Net::HTTP.new(host, 443)
|
81
|
+
http.use_ssl = true
|
82
|
+
Net::HTTP.send(method, signed_url)
|
83
|
+
end
|
84
|
+
|
85
|
+
def ensure_resp path, obj
|
86
|
+
if path == []
|
87
|
+
obj.is_a?(Array) ? obj : [obj]
|
88
|
+
elsif obj.is_a?(Hash)
|
89
|
+
key = path.shift
|
90
|
+
raise "Unexpected AWS Response: #{key} missing" unless
|
91
|
+
(obj.is_a?(Hash) && obj[key])
|
92
|
+
|
93
|
+
ensure_resp(path, obj[key])
|
94
|
+
else
|
95
|
+
obj.map{|s| ensure_resp(path.clone, s)}.flatten(1)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/marty/util.rb
CHANGED
@@ -132,4 +132,19 @@ module Marty::Util
|
|
132
132
|
URI.encode("#{Marty::Util.marty_path}/report?data=#{data}"\
|
133
133
|
"&reptitle=#{title}&format=#{format}")
|
134
134
|
end
|
135
|
+
|
136
|
+
def self.scrub_obj(obj)
|
137
|
+
trav = lambda {|o|
|
138
|
+
if o.is_a?(Hash)
|
139
|
+
return o.each_with_object({}) {|(k, v), h| h[k] = trav.call(v)}
|
140
|
+
elsif o.is_a?(Array)
|
141
|
+
return o.map {|v| trav.call(v)}
|
142
|
+
elsif o.to_s.length > 10000
|
143
|
+
o.class.to_s
|
144
|
+
else
|
145
|
+
o
|
146
|
+
end
|
147
|
+
}
|
148
|
+
trav.call(obj)
|
149
|
+
end
|
135
150
|
end
|
data/lib/marty/version.rb
CHANGED
data/other/marty/api/base.rb
CHANGED