oso-cloud 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 460a79201e11b1f8e81db2eedea8bfd1c6651301336e1d31652a54a1ed537344
4
- data.tar.gz: bd3692528348f8e9e45a36c09a3df41cef74fc47258db81471b456e0f1297f32
3
+ metadata.gz: 0afcafa1d502f02d19ed93b21ad4606eaf59056114c496c5a9d8b72f55994c05
4
+ data.tar.gz: e9bc9ad6450429c9d2c5a1574e4451316e1f043b666da2cfbdc3ae69e1e449cf
5
5
  SHA512:
6
- metadata.gz: 360042f1cb0f076651160473ae092215f36773832c70aa042e26a58a2ebbd9aacf034ec7e0227136075fbe1bc000148c627629a6ddee3ca0ba91cc422b1f2818
7
- data.tar.gz: 79eeab9786a8358d12c3010648ab03f3fff454e69ae217e15122fbc5ebd5e2f4619111da3727e2bb60af14bd3f11e66989c8c74594243852ab131de0e8d1396d
6
+ metadata.gz: 8e837b4bd3d8c16aa1859c93453756a35c844c5371ab9cad18d2afb88748dfc413993be213da260f73bff9d9b83ef28a734e2cfd994e706220c92c4d2ce62df4
7
+ data.tar.gz: 179d6e9639dd2cf447c4c71c6f888b5474f633ad1f323f15b46a8729e8acb86419e2e5b4f628628a4c8655d874881ee6e938d379dbd794f68ea6a18b593c580d
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0.0
3
+ Exclude:
4
+ - "bin/**/*"
5
+ NewCops: enable
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oso-cloud (1.0.0)
4
+ oso-cloud (1.1.0)
5
5
  faraday (~> 2.5.2)
6
6
  faraday-retry (~> 2.0.0)
7
7
 
@@ -11,7 +11,7 @@ GEM
11
11
  faraday (2.5.2)
12
12
  faraday-net_http (>= 2.0, < 3.1)
13
13
  ruby2_keywords (>= 0.0.4)
14
- faraday-net_http (3.0.0)
14
+ faraday-net_http (3.0.2)
15
15
  faraday-retry (2.0.0)
16
16
  faraday (~> 2.0)
17
17
  minitest (5.15.0)
data/lib/oso/api.rb CHANGED
@@ -18,18 +18,15 @@ module OsoCloud
18
18
  end
19
19
 
20
20
  # @!visibility private
21
- class ApiError
22
- attr_reader :message
23
-
21
+ class ApiError < StandardError
24
22
  def initialize(message:)
25
- @message = message
23
+ super(message)
26
24
  end
27
25
  end
28
26
 
29
27
  # @!visibility private
30
28
  class Policy
31
- attr_reader :filename
32
- attr_reader :src
29
+ attr_reader :filename, :src
33
30
 
34
31
  def initialize(filename:, src:)
35
32
  @filename = filename
@@ -42,29 +39,27 @@ module OsoCloud
42
39
  attr_reader :policy
43
40
 
44
41
  def initialize(policy:)
45
- if policy.is_a? Policy
46
- @policy = policy
47
- else
48
- @policy = Policy.new(**policy)
49
- end
42
+ @policy = if policy.is_a? Policy
43
+ policy
44
+ else
45
+ Policy.new(**policy)
46
+ end
50
47
  end
51
48
  end
52
49
 
53
50
  # @!visibility private
54
51
  class Fact
55
- attr_reader :predicate
56
- attr_reader :args
52
+ attr_reader :predicate, :args
57
53
 
58
54
  def initialize(predicate:, args:)
59
55
  @predicate = predicate
60
- @args = args.map { |v| if v.is_a? Value then v else Value.new(**v) end }
56
+ @args = args.map { |v| (v.is_a? Value) ? v : Value.new(**v) }
61
57
  end
62
58
  end
63
59
 
64
60
  # @!visibility private
65
61
  class Value
66
- attr_reader :type
67
- attr_reader :id
62
+ attr_reader :type, :id
68
63
 
69
64
  def initialize(type:, id:)
70
65
  @type = type
@@ -74,12 +69,11 @@ module OsoCloud
74
69
 
75
70
  # @!visibility private
76
71
  class Bulk
77
- attr_reader :delete
78
- attr_reader :tell
72
+ attr_reader :delete, :tell
79
73
 
80
74
  def initialize(delete:, tell:)
81
- @delete = delete.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
82
- @tell = tell.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
75
+ @delete = delete.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
76
+ @tell = tell.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
83
77
  end
84
78
  end
85
79
 
@@ -94,12 +88,7 @@ module OsoCloud
94
88
 
95
89
  # @!visibility private
96
90
  class AuthorizeQuery
97
- attr_reader :actor_type
98
- attr_reader :actor_id
99
- attr_reader :action
100
- attr_reader :resource_type
101
- attr_reader :resource_id
102
- attr_reader :context_facts
91
+ attr_reader :actor_type, :actor_id, :action, :resource_type, :resource_id, :context_facts
103
92
 
104
93
  def initialize(actor_type:, actor_id:, action:, resource_type:, resource_id:, context_facts:)
105
94
  @actor_type = actor_type
@@ -107,7 +96,7 @@ module OsoCloud
107
96
  @action = action
108
97
  @resource_type = resource_type
109
98
  @resource_id = resource_id
110
- @context_facts = context_facts.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
99
+ @context_facts = context_facts.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
111
100
  end
112
101
  end
113
102
 
@@ -116,24 +105,20 @@ module OsoCloud
116
105
  attr_reader :results
117
106
 
118
107
  def initialize(results:)
119
- @results = results.map { |v| if v.is_a? Value then v else Value.new(**v) end }
108
+ @results = results.map { |v| (v.is_a? Value) ? v : Value.new(**v) }
120
109
  end
121
110
  end
122
111
 
123
112
  # @!visibility private
124
113
  class AuthorizeResourcesQuery
125
- attr_reader :actor_type
126
- attr_reader :actor_id
127
- attr_reader :action
128
- attr_reader :resources
129
- attr_reader :context_facts
114
+ attr_reader :actor_type, :actor_id, :action, :resources, :context_facts
130
115
 
131
116
  def initialize(actor_type:, actor_id:, action:, resources:, context_facts:)
132
117
  @actor_type = actor_type
133
118
  @actor_id = actor_id
134
119
  @action = action
135
- @resources = resources.map { |v| if v.is_a? Value then v else Value.new(**v) end }
136
- @context_facts = context_facts.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
120
+ @resources = resources.map { |v| (v.is_a? Value) ? v : Value.new(**v) }
121
+ @context_facts = context_facts.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
137
122
  end
138
123
  end
139
124
 
@@ -148,18 +133,14 @@ module OsoCloud
148
133
 
149
134
  # @!visibility private
150
135
  class ListQuery
151
- attr_reader :actor_type
152
- attr_reader :actor_id
153
- attr_reader :action
154
- attr_reader :resource_type
155
- attr_reader :context_facts
136
+ attr_reader :actor_type, :actor_id, :action, :resource_type, :context_facts
156
137
 
157
138
  def initialize(actor_type:, actor_id:, action:, resource_type:, context_facts:)
158
139
  @actor_type = actor_type
159
140
  @actor_id = actor_id
160
141
  @action = action
161
142
  @resource_type = resource_type
162
- @context_facts = context_facts.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
143
+ @context_facts = context_facts.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
163
144
  end
164
145
  end
165
146
 
@@ -174,18 +155,14 @@ module OsoCloud
174
155
 
175
156
  # @!visibility private
176
157
  class ActionsQuery
177
- attr_reader :actor_type
178
- attr_reader :actor_id
179
- attr_reader :resource_type
180
- attr_reader :resource_id
181
- attr_reader :context_facts
158
+ attr_reader :actor_type, :actor_id, :resource_type, :resource_id, :context_facts
182
159
 
183
160
  def initialize(actor_type:, actor_id:, resource_type:, resource_id:, context_facts:)
184
161
  @actor_type = actor_type
185
162
  @actor_id = actor_id
186
163
  @resource_type = resource_type
187
164
  @resource_id = resource_id
188
- @context_facts = context_facts.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
165
+ @context_facts = context_facts.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
189
166
  end
190
167
  end
191
168
 
@@ -194,30 +171,27 @@ module OsoCloud
194
171
  attr_reader :results
195
172
 
196
173
  def initialize(results:)
197
- @results = results.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
174
+ @results = results.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
198
175
  end
199
176
  end
200
177
 
201
178
  # @!visibility private
202
179
  class Query
203
- attr_reader :fact
204
- attr_reader :context_facts
180
+ attr_reader :fact, :context_facts
205
181
 
206
182
  def initialize(fact:, context_facts:)
207
- if fact.is_a? Fact
208
- @fact = fact
209
- else
210
- @fact = Fact.new(**fact)
211
- end
212
- @context_facts = context_facts.map { |v| if v.is_a? Fact then v else Fact.new(**v) end }
183
+ @fact = if fact.is_a? Fact
184
+ fact
185
+ else
186
+ Fact.new(**fact)
187
+ end
188
+ @context_facts = context_facts.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
213
189
  end
214
190
  end
215
191
 
216
192
  # @!visibility private
217
193
  class StatsResult
218
- attr_reader :num_roles
219
- attr_reader :num_relations
220
- attr_reader :num_facts
194
+ attr_reader :num_roles, :num_relations, :num_facts
221
195
 
222
196
  def initialize(num_roles:, num_relations:, num_facts:)
223
197
  @num_roles = num_roles
@@ -226,31 +200,61 @@ module OsoCloud
226
200
  end
227
201
  end
228
202
 
229
-
230
203
  # @!visibility private
231
204
  class Api
232
- def initialize(url: 'https://cloud.osohq.com', api_key: nil)
205
+ def initialize(url: 'https://cloud.osohq.com', api_key: nil, options: nil)
233
206
  @url = url
234
207
  @connection = Faraday.new(url: url) do |faraday|
208
+ faraday.request :json
209
+
210
+ # responses are processed in reverse order; this stack implies the
211
+ # retries are attempted before an error is raised, and the json
212
+ # parser is only applied if there are no errors
213
+ faraday.response :json, preserve_raw: true
214
+ faraday.response :raise_error
235
215
  faraday.request :retry, {
236
- max: 15,
237
- interval: 0.05,
238
- interval_randomness: 0.5,
216
+ max: (options && options[:max_retries]) || 10,
217
+ interval: 0.01,
218
+ interval_randomness: 0.005,
219
+ max_interval: 1,
239
220
  backoff_factor: 2,
240
221
  retry_statuses: [429, 500, 502, 503, 504],
222
+ # ensure authorize and related check functions are retried because
223
+ # they are POST requests, which are not retried automatically
224
+ retry_if: lambda { |env, _exc|
225
+ %w[
226
+ /api/authorize
227
+ /api/authorize_resources
228
+ /api/list
229
+ /api/actions
230
+ /api/query
231
+ ].include? env.url.path
232
+ }
241
233
  }
242
234
 
243
- faraday.request :json
244
- faraday.response :json, preserve_raw: true
245
- faraday.adapter :net_http
235
+ if options && options[:test_adapter]
236
+ faraday.adapter :test do |stub|
237
+ stub.post(options[:test_adapter][:path]) do |_env|
238
+ options[:test_adapter][:func].call
239
+ end
240
+ stub.get(options[:test_adapter][:path]) do |_env|
241
+ options[:test_adapter][:func].call
242
+ end
243
+ stub.delete(options[:test_adapter][:path]) do |_env|
244
+ options[:test_adapter][:func].call
245
+ end
246
+ end
247
+ else
248
+ faraday.adapter :net_http
249
+ end
246
250
  end
247
251
  @api_key = api_key
248
252
  end
249
253
 
250
- def get_policy()
254
+ def get_policy
251
255
  params = {}
252
256
  data = nil
253
- url = "/policy"
257
+ url = '/policy'
254
258
  result = GET(url, params, data)
255
259
  GetPolicyResult.new(**result)
256
260
  end
@@ -258,7 +262,7 @@ module OsoCloud
258
262
  def post_policy(data)
259
263
  params = {}
260
264
  data = OsoCloud::Helpers.to_hash(data)
261
- url = "/policy"
265
+ url = '/policy'
262
266
  result = POST(url, params, data)
263
267
  ApiResult.new(**result)
264
268
  end
@@ -266,7 +270,7 @@ module OsoCloud
266
270
  def post_facts(data)
267
271
  params = {}
268
272
  data = OsoCloud::Helpers.to_hash(data)
269
- url = "/facts"
273
+ url = '/facts'
270
274
  result = POST(url, params, data)
271
275
  Fact.new(**result)
272
276
  end
@@ -274,7 +278,7 @@ module OsoCloud
274
278
  def delete_facts(data)
275
279
  params = {}
276
280
  data = OsoCloud::Helpers.to_hash(data)
277
- url = "/facts"
281
+ url = '/facts'
278
282
  result = DELETE(url, params, data)
279
283
  ApiResult.new(**result)
280
284
  end
@@ -282,7 +286,7 @@ module OsoCloud
282
286
  def post_bulk_load(data)
283
287
  params = {}
284
288
  data = OsoCloud::Helpers.to_hash(data)
285
- url = "/bulk_load"
289
+ url = '/bulk_load'
286
290
  result = POST(url, params, data)
287
291
  ApiResult.new(**result)
288
292
  end
@@ -290,7 +294,7 @@ module OsoCloud
290
294
  def post_bulk_delete(data)
291
295
  params = {}
292
296
  data = OsoCloud::Helpers.to_hash(data)
293
- url = "/bulk_delete"
297
+ url = '/bulk_delete'
294
298
  result = POST(url, params, data)
295
299
  ApiResult.new(**result)
296
300
  end
@@ -298,7 +302,7 @@ module OsoCloud
298
302
  def post_bulk(data)
299
303
  params = {}
300
304
  data = OsoCloud::Helpers.to_hash(data)
301
- url = "/bulk"
305
+ url = '/bulk'
302
306
  result = POST(url, params, data)
303
307
  ApiResult.new(**result)
304
308
  end
@@ -306,7 +310,7 @@ module OsoCloud
306
310
  def post_authorize(data)
307
311
  params = {}
308
312
  data = OsoCloud::Helpers.to_hash(data)
309
- url = "/authorize"
313
+ url = '/authorize'
310
314
  result = POST(url, params, data)
311
315
  AuthorizeResult.new(**result)
312
316
  end
@@ -314,7 +318,7 @@ module OsoCloud
314
318
  def post_authorize_resources(data)
315
319
  params = {}
316
320
  data = OsoCloud::Helpers.to_hash(data)
317
- url = "/authorize_resources"
321
+ url = '/authorize_resources'
318
322
  result = POST(url, params, data)
319
323
  AuthorizeResourcesResult.new(**result)
320
324
  end
@@ -322,7 +326,7 @@ module OsoCloud
322
326
  def post_list(data)
323
327
  params = {}
324
328
  data = OsoCloud::Helpers.to_hash(data)
325
- url = "/list"
329
+ url = '/list'
326
330
  result = POST(url, params, data)
327
331
  ListResult.new(**result)
328
332
  end
@@ -330,7 +334,7 @@ module OsoCloud
330
334
  def post_actions(data)
331
335
  params = {}
332
336
  data = OsoCloud::Helpers.to_hash(data)
333
- url = "/actions"
337
+ url = '/actions'
334
338
  result = POST(url, params, data)
335
339
  ActionsResult.new(**result)
336
340
  end
@@ -338,33 +342,34 @@ module OsoCloud
338
342
  def post_query(data)
339
343
  params = {}
340
344
  data = OsoCloud::Helpers.to_hash(data)
341
- url = "/query"
345
+ url = '/query'
342
346
  result = POST(url, params, data)
343
347
  QueryResult.new(**result)
344
348
  end
345
349
 
346
- def get_stats()
350
+ def get_stats
347
351
  params = {}
348
352
  data = nil
349
- url = "/stats"
353
+ url = '/stats'
350
354
  result = GET(url, params, data)
351
355
  StatsResult.new(**result)
352
356
  end
353
357
 
354
- def clear_data()
358
+ def clear_data
355
359
  params = {}
356
360
  data = nil
357
- url = "/clear_data"
361
+ url = '/clear_data'
358
362
  result = POST(url, params, data)
359
363
  ApiResult.new(**result)
360
364
  end
361
365
 
362
-
363
366
  # hard-coded, not generated
364
367
  def get_facts(predicate, args)
365
368
  params = {}
366
- params["predicate"] = predicate
369
+ params['predicate'] = predicate
367
370
  args.each_with_index do |arg, i|
371
+ next if arg.nil?
372
+
368
373
  arg_query = OsoCloud::Helpers.extract_arg_query(arg)
369
374
  if arg_query
370
375
  params["args.#{i}.type"] = arg_query.type
@@ -372,24 +377,26 @@ module OsoCloud
372
377
  end
373
378
  end
374
379
  data = nil
375
- url = "/facts"
380
+ url = '/facts'
376
381
  result = GET(url, params, data)
377
382
  result.map { |v| Fact.new(**v) }
378
383
  end
379
384
 
380
- def headers()
385
+ def headers
381
386
  {
382
- "Authorization" => "Bearer %s" % @api_key,
383
- "User-Agent" => "Oso Cloud (ruby)",
384
- "Accept": "application/json",
385
- "Content-Type": "application/json",
386
- "X-OsoApiVersion": "0"
387
+ 'Authorization' => format('Bearer %s', @api_key),
388
+ 'User-Agent' => 'Oso Cloud (ruby)',
389
+ Accept: 'application/json',
390
+ 'Content-Type': 'application/json',
391
+ 'X-OsoApiVersion': '0'
387
392
  }
388
393
  end
389
394
 
390
- def GET(path, params, body)
391
- response = @connection.get("api#{path}", params, headers )
395
+ def GET(path, params, _body)
396
+ response = @connection.get("api#{path}", params, headers)
392
397
  handle_faraday_response response
398
+ rescue Faraday::Error => e
399
+ handle_faraday_error e
393
400
  end
394
401
 
395
402
  def POST(path, params, body)
@@ -397,6 +404,8 @@ module OsoCloud
397
404
  req.params = params
398
405
  end
399
406
  handle_faraday_response response
407
+ rescue Faraday::Error => e
408
+ handle_faraday_error e
400
409
  end
401
410
 
402
411
  def DELETE(path, params, body)
@@ -404,13 +413,21 @@ module OsoCloud
404
413
  req.body = body
405
414
  end
406
415
  handle_faraday_response response
416
+ rescue Faraday::Error => e
417
+ handle_faraday_error e
407
418
  end
408
419
 
409
420
  def handle_faraday_response(response)
410
- # TODO:(@patrickod) refactor duplicative JSON parsing
421
+ # TODO: (@patrickod) refactor duplicative JSON parsing
411
422
  JSON.parse(response.env[:raw_body], symbolize_names: true)
412
423
  end
413
- end
414
424
 
425
+ def handle_faraday_error(error)
426
+ err = JSON.parse(error.response[:body], symbolize_names: true)
427
+ raise ApiError.new(**err)
428
+ rescue JSON::ParserError => e
429
+ raise ApiError.new(message: e.message)
430
+ end
431
+ end
415
432
  end
416
433
  end
data/lib/oso/helpers.rb CHANGED
@@ -3,9 +3,9 @@ module OsoCloud
3
3
  module Helpers
4
4
  # @!visibility private
5
5
  def self.extract_value(x)
6
- return OsoCloud::Core::Value.new(type: "String", id: x) if x.is_a? String
6
+ return OsoCloud::Core::Value.new(type: 'String', id: x) if x.is_a? String
7
7
 
8
- return nil if x.nil?
8
+ return OsoCloud::Core::Value.new(type: nil, id: nil) if x.nil?
9
9
 
10
10
  type = (x.type.nil? ? nil : x.type.to_s)
11
11
  id = (x.id.nil? ? nil : x.id.to_s)
@@ -14,17 +14,33 @@ module OsoCloud
14
14
 
15
15
  # @!visibility private
16
16
  def self.extract_arg_query(x)
17
- self.extract_value(x)
17
+ extract_value(x)
18
18
  end
19
19
 
20
20
  # @!visibility private
21
21
  def self.param_to_fact(predicate, args)
22
- OsoCloud::Core::Fact.new(predicate: predicate, args: args.map { |a| self.extract_value(a) })
22
+ OsoCloud::Core::Fact.new(predicate: predicate, args: args.map { |a| extract_value(a) })
23
23
  end
24
24
 
25
25
  # @!visibility private
26
26
  def self.params_to_facts(facts)
27
- facts.map { |predicate, *args| self.param_to_fact(predicate, args) }
27
+ facts.map { |predicate, *args| param_to_fact(predicate, args) }
28
+ end
29
+
30
+ # @!visibility private
31
+ def self.facts_to_params(facts)
32
+ facts.map do |f|
33
+ name = f.predicate
34
+ args = f.args.map do |a|
35
+ v = from_value(a)
36
+ if v.is_a? Hash
37
+ OsoCloud::Value.new(type: v[:type], id: v[:id])
38
+ else
39
+ v
40
+ end
41
+ end
42
+ [name, *args]
43
+ end
28
44
  end
29
45
 
30
46
  def self.from_value(value)
@@ -34,25 +50,24 @@ module OsoCloud
34
50
  else
35
51
  { type: value.type }
36
52
  end
53
+ elsif value.type == 'String'
54
+ value.id
37
55
  else
38
- if value.type == "String"
39
- value.id
40
- else
41
- { id: value.id, type: value.type }
42
- end
56
+ { id: value.id, type: value.type }
43
57
  end
44
58
  end
45
59
 
46
60
  # @!visibility private
47
61
  def self.to_hash(o)
48
- return o.map { |v| self.to_hash(v) } if o.is_a? Array
62
+ return o.map { |v| to_hash(v) } if o.is_a? Array
49
63
  return o if o.instance_variables.empty?
64
+
50
65
  hash = {}
51
- o.instance_variables.each { |var|
52
- v = var.to_s.delete("@")
66
+ o.instance_variables.each do |var|
67
+ v = var.to_s.delete('@')
53
68
  value = o.send(v)
54
- hash[v] = self.to_hash(value)
55
- }
69
+ hash[v] = to_hash(value)
70
+ end
56
71
  hash
57
72
  end
58
73
  end
data/lib/oso/oso.rb CHANGED
@@ -10,11 +10,9 @@ require 'oso/helpers'
10
10
  # For more detailed documentation, see
11
11
  # https://www.osohq.com/docs/reference/client-apis/ruby
12
12
  module OsoCloud
13
-
14
13
  # Represents an object in your application, with a type and id.
15
14
  # Both "type" and "id" should be strings.
16
- Value = Struct::new(:type, :id, keyword_init: true) do
17
-
15
+ Value = Struct.new(:type, :id, keyword_init: true) do
18
16
  def to_api_value
19
17
  OsoCloud::Helpers.extract_value(self)
20
18
  end
@@ -43,7 +41,7 @@ module OsoCloud
43
41
  # @param policy [String]
44
42
  # @return [nil]
45
43
  def policy(policy)
46
- @api.post_policy(OsoCloud::Core::Policy.new(src: policy, filename: ""))
44
+ @api.post_policy(OsoCloud::Core::Policy.new(src: policy, filename: ''))
47
45
  nil
48
46
  end
49
47
 
@@ -58,18 +56,18 @@ module OsoCloud
58
56
  # @param resource [OsoCloud::Value]
59
57
  # @param context_facts [Array<fact>]
60
58
  # @return [Boolean]
61
- # @see Oso more information about facts
59
+ # @see Oso for more information about facts
62
60
  def authorize(actor, action, resource, context_facts = [])
63
61
  actor_typed_id = actor.to_api_value
64
62
  resource_typed_id = resource.to_api_value
65
63
  result = @api.post_authorize(OsoCloud::Core::AuthorizeQuery.new(
66
- actor_type: actor_typed_id.type,
67
- actor_id: actor_typed_id.id,
68
- action: action,
69
- resource_type: resource_typed_id.type,
70
- resource_id: resource_typed_id.id,
71
- context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
72
- ))
64
+ actor_type: actor_typed_id.type,
65
+ actor_id: actor_typed_id.id,
66
+ action: action,
67
+ resource_type: resource_typed_id.type,
68
+ resource_id: resource_typed_id.id,
69
+ context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
70
+ ))
73
71
  result.allowed
74
72
  end
75
73
 
@@ -84,7 +82,7 @@ module OsoCloud
84
82
  # @param resources [Array<OsoCloud::Value>]
85
83
  # @param context_facts [Array<fact>]
86
84
  # @return [Array<OsoCloud::Value>]
87
- # @see Oso more information about facts
85
+ # @see Oso for more information about facts
88
86
  def authorize_resources(actor, action, resources, context_facts = [])
89
87
  return [] if resources.nil?
90
88
  return [] if resources.empty?
@@ -99,26 +97,23 @@ module OsoCloud
99
97
  actor_type: actor_typed_id.type, actor_id: actor_typed_id.id,
100
98
  action: action,
101
99
  resources: resources_extracted,
102
- context_facts: OsoCloud::Helpers::params_to_facts(context_facts)
100
+ context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
103
101
  )
104
102
  result = @api.post_authorize_resources(data)
105
103
 
106
104
  return [] if result.results.empty?
107
105
 
108
- results_lookup = Hash.new
106
+ results_lookup = {}
109
107
  result.results.each do |r|
110
108
  k = key.call(r.type, r.id)
111
- if results_lookup[k] == nil
112
- results_lookup[k] = true
113
- end
109
+ results_lookup[k] = true if results_lookup[k].nil?
114
110
  end
115
111
 
116
- results = resources.select do |r|
112
+ resources.select do |r|
117
113
  e = r.to_api_value
118
114
  exists = results_lookup[key.call(e.type, e.id)]
119
115
  exists
120
116
  end
121
- results
122
117
  end
123
118
 
124
119
  ##
@@ -132,16 +127,16 @@ module OsoCloud
132
127
  # @param resource_type [String]
133
128
  # @param context_facts [Array<fact>]
134
129
  # @return [Array<String>]
135
- # @see Oso more information about facts
130
+ # @see Oso for more information about facts
136
131
  def list(actor, action, resource_type, context_facts = [])
137
132
  actor_typed_id = actor.to_api_value
138
133
  result = @api.post_list(OsoCloud::Core::ListQuery.new(
139
- actor_type: actor_typed_id.type,
140
- actor_id: actor_typed_id.id,
141
- action: action,
142
- resource_type: resource_type,
143
- context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
144
- ))
134
+ actor_type: actor_typed_id.type,
135
+ actor_id: actor_typed_id.id,
136
+ action: action,
137
+ resource_type: resource_type,
138
+ context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
139
+ ))
145
140
  result.results
146
141
  end
147
142
 
@@ -154,17 +149,17 @@ module OsoCloud
154
149
  # @param resource [OsoCloud::Value]
155
150
  # @param context_facts [Array<fact>]
156
151
  # @return [Array<String>]
157
- # @see Oso more information about facts
152
+ # @see Oso for more information about facts
158
153
  def actions(actor, resource, context_facts = [])
159
154
  actor_typed_id = actor.to_api_value
160
155
  resource_typed_id = resource.to_api_value
161
156
  result = @api.post_actions(OsoCloud::Core::ActionsQuery.new(
162
- actor_type: actor_typed_id.type,
163
- actor_id: actor_typed_id.id,
164
- resource_type: resource_typed_id.type,
165
- resource_id: resource_typed_id.id,
166
- context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
167
- ))
157
+ actor_type: actor_typed_id.type,
158
+ actor_id: actor_typed_id.id,
159
+ resource_type: resource_typed_id.type,
160
+ resource_id: resource_typed_id.id,
161
+ context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
162
+ ))
168
163
  result.results
169
164
  end
170
165
 
@@ -177,7 +172,7 @@ module OsoCloud
177
172
  # @param args [*[String, OsoCloud::Value]]
178
173
  # @return [nil]
179
174
  def tell(name, *args)
180
- typed_args = args.map { |a| OsoCloud::Helpers.extract_value(a)}
175
+ typed_args = args.map { |a| OsoCloud::Helpers.extract_value(a) }
181
176
  @api.post_facts(OsoCloud::Core::Fact.new(predicate: name, args: typed_args))
182
177
  nil
183
178
  end
@@ -189,7 +184,7 @@ module OsoCloud
189
184
  #
190
185
  # @param facts [Array<fact>]
191
186
  # @return [nil]
192
- # @see Oso more information about facts
187
+ # @see Oso for more information about facts
193
188
  def bulk_tell(facts)
194
189
  @api.post_bulk_load(OsoCloud::Helpers.params_to_facts(facts))
195
190
  nil
@@ -217,12 +212,32 @@ module OsoCloud
217
212
  #
218
213
  # @param facts [Array<fact>]
219
214
  # @return [nil]
220
- # @see Oso more information about facts
215
+ # @see Oso for more information about facts
221
216
  def bulk_delete(facts)
222
217
  @api.post_bulk_delete(OsoCloud::Helpers.params_to_facts(facts))
223
218
  nil
224
219
  end
225
220
 
221
+ ##
222
+ # Transactionally delete and insert fact(s)
223
+ #
224
+ # Delete(s) are processed before insertion(s). nil arguments in facts to be
225
+ # deleted act as wildcards. Does not throw an error if facts to be deleted
226
+ # are not found or facts to be inserted already exist.
227
+ #
228
+ #
229
+ # Throws an OsoCloud::Core::Api exception if error returned from server.
230
+ #
231
+ # @param delete [Array<fact>]
232
+ # @param insert [Array<fact>]
233
+ # @return [nil]
234
+ # @see Oso for more information about facts
235
+ def bulk(delete: [], insert: [])
236
+ @api.post_bulk(OsoCloud::Core::Bulk.new(delete: OsoCloud::Helpers.params_to_facts(delete),
237
+ tell: OsoCloud::Helpers.params_to_facts(insert)))
238
+ nil
239
+ end
240
+
226
241
  ##
227
242
  # List facts
228
243
  #
@@ -233,23 +248,27 @@ module OsoCloud
233
248
  # @param name [String]
234
249
  # @param args [*[String, OsoCloud::Value, nil]]
235
250
  # @return [Array<fact>]
236
- # @see Oso more information about facts
251
+ # @see Oso for more information about facts
237
252
  def get(name, *args)
238
- @api.get_facts(name, args).map do |f|
239
- name = f.predicate
240
- args = f.args.map do |a|
241
- v = OsoCloud::Helpers.from_value(a)
242
- if v.is_a? Hash
243
- OsoCloud::Value.new(type: v[:type], id: v[:id])
244
- else
245
- v
246
- end
247
- end
248
- [name, *args]
249
- end
253
+ OsoCloud::Helpers.facts_to_params(@api.get_facts(name, args))
250
254
  end
251
255
 
252
-
253
- # TODO query, bulk
256
+ ##
257
+ # List added and derived facts
258
+ #
259
+ # Lists facts that are stored in Oso Cloud in addition to derived facts
260
+ # from evaluating the policy. nil arguments operate as wildcards.
261
+ #
262
+ # @param name [String]
263
+ # @param args [Array<[String, OsoCloud::Value, nil]>]
264
+ # @param context_facts [Array<fact>]
265
+ # @return [Array<fact>]
266
+ # @see Oso for more information about facts
267
+ def query(name, *args, context_facts: [])
268
+ typed_args = args.map { |a| OsoCloud::Helpers.extract_value(a) }
269
+ result = @api.post_query(OsoCloud::Core::Query.new(fact: OsoCloud::Helpers.param_to_fact(name, typed_args),
270
+ context_facts: OsoCloud::Helpers.params_to_facts(context_facts)))
271
+ OsoCloud::Helpers.facts_to_params(result.results)
272
+ end
254
273
  end
255
274
  end
data/lib/oso/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module OsoCloud
2
- VERSION = '1.0.0'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oso-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oso Security, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-27 00:00:00.000000000 Z
11
+ date: 2023-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -60,6 +60,7 @@ extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
62
  - ".gitignore"
63
+ - ".rubocop.yml"
63
64
  - Gemfile
64
65
  - Gemfile.lock
65
66
  - README.md