oso-cloud 1.0.0 → 1.1.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 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