oso-cloud 1.10.1 → 1.11.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: 7747b42bd66825a62104ba2873c1b86fba9886b79e9b23b2de498e78bdf4240b
4
- data.tar.gz: 78841fd6edb4eb87bd80b3372e75a9db1e9f56ad71955a95e2f3796a99ff74a6
3
+ metadata.gz: c6dfcfe3d534a83d8c96e9fe04ae500921a483507c386baa4133143677fbac17
4
+ data.tar.gz: e61cb97030c944f5038e5214bc7573145c22f1d8674884a3c46fd57bc334d490
5
5
  SHA512:
6
- metadata.gz: e93b2627d5245dad5b20fa2bbddaada1783e4d2a71192d225c2dd89f1682e181fb4334ef34cba7a74fc670cb419dfaa07c44c727e8720ddde6777a2fc6dc6918
7
- data.tar.gz: 0272c0446e6ebc4b1d6be4d9773710c4e236e7608e5af4fe93b83a5dc33ec21a8e1e68a56e30ef15225b4d765cc4c7a4be42fb07cca0265c6709cb761d9b4b5d
6
+ metadata.gz: e3492c5a64c6a57aa72800736b096993fef0420c0719cfd86b0a98ed08c4ef30ca4a50a3802c01e4d8be5879078123820672119c6c9178d751124e20a8013ee8
7
+ data.tar.gz: 16e736b6a0e8fed24aa24f449be5065b83f88b8eb9de4908299d2069b6fc02d165479d04354d0011e7ad451e8a80498ef24f46191e9370a20f3674942328464f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oso-cloud (1.10.1)
4
+ oso-cloud (1.11.0)
5
5
  faraday (~> 2.5.2)
6
6
  faraday-net_http_persistent (~> 2.0)
7
7
  faraday-retry (~> 2.0.0)
data/lib/oso/api.rb CHANGED
@@ -22,7 +22,10 @@ module OsoCloud
22
22
 
23
23
  # @!visibility private
24
24
  class ApiError < StandardError
25
- def initialize(message:)
25
+ attr_reader :status_code, :retry_after
26
+ def initialize(message:, status_code: nil, retry_after: nil)
27
+ @status_code = status_code
28
+ @retry_after = retry_after
26
29
  super(message)
27
30
  end
28
31
  end
@@ -164,23 +167,26 @@ module OsoCloud
164
167
 
165
168
  # @!visibility private
166
169
  class ListResult
167
- attr_reader :results
170
+ attr_reader :results, :next_page_token
168
171
 
169
- def initialize(results:)
172
+ def initialize(results:, next_page_token: nil)
170
173
  @results = results
174
+ @next_page_token = next_page_token
171
175
  end
172
176
  end
173
177
 
174
178
  # @!visibility private
175
179
  class ListQuery
176
- attr_reader :actor_type, :actor_id, :action, :resource_type, :context_facts
180
+ attr_reader :actor_type, :actor_id, :action, :resource_type, :context_facts, :page_size, :page_token
177
181
 
178
- def initialize(actor_type:, actor_id:, action:, resource_type:, context_facts:)
182
+ def initialize(actor_type:, actor_id:, action:, resource_type:, context_facts:, page_size: nil, page_token: nil)
179
183
  @actor_type = actor_type
180
184
  @actor_id = actor_id
181
185
  @action = action
182
186
  @resource_type = resource_type
183
187
  @context_facts = context_facts.map { |v| (v.is_a? Fact) ? v : Fact.new(**v) }
188
+ @page_size = page_size
189
+ @page_token = page_token
184
190
  end
185
191
  end
186
192
 
@@ -287,6 +293,9 @@ module OsoCloud
287
293
  interval_randomness: 0.005,
288
294
  max_interval: 1,
289
295
  backoff_factor: 2,
296
+ # 409 (Conflict) is intentionally not retried here. The server uses 409
297
+ # with Retry-After for paginated results not yet ready, which needs
298
+ # longer delays than HTTP-level backoff. Handled by per-page retry in list().
290
299
  retry_statuses: [429, 500, 502, 503, 504],
291
300
  # This is the default set of methods plus POST.
292
301
  # ref: https://github.com/lostisland/faraday-retry#specify-which-methods-will-be-retried
@@ -581,10 +590,13 @@ module OsoCloud
581
590
 
582
591
  def handle_faraday_error(error)
583
592
  resp = error.response
584
- create_api_error(resp, error.message)
593
+ status_code = resp && resp[:status]
594
+ retry_after = resp && resp[:headers] && resp[:headers]['Retry-After']
595
+ retry_after = retry_after.to_f if retry_after
596
+ create_api_error(resp, error.message, status_code: status_code, retry_after: retry_after)
585
597
  end
586
598
 
587
- def create_api_error(resp, message)
599
+ def create_api_error(resp, message, status_code: nil, retry_after: nil)
588
600
  formatted_request_id = if resp.nil? || resp[:headers].nil? || resp[:headers]['X-Request-ID'].nil?
589
601
  ''
590
602
  else
@@ -596,7 +608,11 @@ module OsoCloud
596
608
  else
597
609
  resp[:body][:message]
598
610
  end
599
- raise ApiError.new(message: err + formatted_request_id)
611
+
612
+ sc = status_code || (resp && resp[:status])
613
+ ra = retry_after || (resp && resp[:headers] && resp[:headers]['Retry-After'] ? resp[:headers]['Retry-After'].to_f : nil)
614
+
615
+ raise ApiError.new(message: err + formatted_request_id, status_code: sc, retry_after: ra)
600
616
  end
601
617
 
602
618
  def post_expected_result(expected_result)
data/lib/oso/oso.rb CHANGED
@@ -228,15 +228,50 @@ module OsoCloud
228
228
  # @return [Array<String>]
229
229
  # @see Oso for more information about facts
230
230
  def list(actor, action, resource_type, context_facts = [])
231
+ all_results = []
232
+ page_token = nil
233
+ loop do
234
+ page = list_paginated(actor, action, resource_type, 10000, page_token: page_token, context_facts: context_facts)
235
+ all_results.concat(page.results)
236
+ break if page.next_page_token.nil?
237
+ page_token = page.next_page_token
238
+ end
239
+ all_results
240
+ end
241
+
242
+ ##
243
+ # List authorized resources with pagination
244
+ #
245
+ # Fetches a page of resource ids on which an actor can perform a
246
+ # particular action. Returns a ListResult with `results` and `next_page_token`.
247
+ # Pass `next_page_token` to fetch subsequent pages.
248
+ #
249
+ # @param actor [OsoCloud::Value]
250
+ # @param action [String]
251
+ # @param resource_type [String]
252
+ # @param page_size [Integer]
253
+ # @param page_token [String, nil]
254
+ # @param context_facts [Array<fact>]
255
+ # @return [OsoCloud::Core::ListResult]
256
+ def list_paginated(actor, action, resource_type, page_size, page_token: nil, context_facts: [])
231
257
  actor_typed_id = actor.to_api_value
232
- result = @api.post_list(OsoCloud::Core::ListQuery.new(
233
- actor_type: actor_typed_id.type,
234
- actor_id: actor_typed_id.id,
235
- action: action,
236
- resource_type: resource_type,
237
- context_facts: OsoCloud::Helpers.params_to_facts(context_facts)
238
- ))
239
- result.results
258
+ 10.times do |attempt|
259
+ begin
260
+ return @api.post_list(OsoCloud::Core::ListQuery.new(
261
+ actor_type: actor_typed_id.type,
262
+ actor_id: actor_typed_id.id,
263
+ action: action,
264
+ resource_type: resource_type,
265
+ context_facts: OsoCloud::Helpers.params_to_facts(context_facts),
266
+ page_size: page_size,
267
+ page_token: page_token
268
+ ))
269
+ rescue OsoCloud::Core::ApiError => e
270
+ raise unless e.status_code == 409 && e.retry_after && attempt < 9
271
+ sleep(e.retry_after)
272
+ end
273
+ end
274
+ raise OsoCloud::Core::ApiError.new(message: 'Page not available after retries', status_code: 409)
240
275
  end
241
276
 
242
277
  ##
data/lib/oso/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  # !! IMPORTANT: Update the ruby docs to reflect the latest version !!
4
4
  module OsoCloud
5
- VERSION = '1.10.1'
5
+ VERSION = '1.11.0'
6
6
  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.10.1
4
+ version: 1.11.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: 2026-02-03 00:00:00.000000000 Z
11
+ date: 2026-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday