oso-oso 0.25.1 → 0.26.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
  SHA1:
3
- metadata.gz: 82a8f9d2d54d8179e5a6067c929ec37ab0363250
4
- data.tar.gz: 28a9724e32230d89c3e6140ab3d914aa6e0bd798
3
+ metadata.gz: 9c6a70f052d3142dbaf1f8d9c699a7f3c6697060
4
+ data.tar.gz: 9820ca345e2b1bb85c31183a3f43a1748d412d77
5
5
  SHA512:
6
- metadata.gz: cd73f0a8bb0dd364229686d212c8b8cd56512ba9affee5dfd1a1f3b32b466cd793774121e2dd4425a708f7a35dd03bd35568d7097296fd568979cbfce77cffc8
7
- data.tar.gz: 60a6991495c8666c8cab642e82d0f11988b726d5911ecccd7aec079e5f3041dfb978e21181bd910dbde1b7e551aef29a0d05e901432f2a1a1789e0c9fd16c137
6
+ metadata.gz: '08cabc94530a44164fef27de25cac7477fc8906b6a4766197b003c4f629332ce4a24b88fc96e7fa78e305c23f0e16f0f5df5481bc7ffb82e5c51a9ffb7cd260c'
7
+ data.tar.gz: f534eec40e00a8c10dc9379843e8b08dc4bc95bd6526e4c00e0a88aaca11877b31bf643d82e934fe0b01ccdb1d957ae25c3fa069875e46ea7765634313bd43ec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oso-oso (0.25.1)
4
+ oso-oso (0.26.0)
5
5
  ffi (~> 1.0)
6
6
 
7
7
  GEM
Binary file
Binary file
Binary file
data/lib/oso/oso.rb CHANGED
@@ -182,16 +182,7 @@ module Oso
182
182
  #
183
183
  # @return A query for resources accessible to the actor.
184
184
  def authorized_query(actor, action, resource_cls)
185
- if host.use_new_data_filtering?
186
-
187
- unless host.types[resource_cls].build_query == ::Oso::Polar::Host::DEFAULT_BUILD_QUERY
188
- warn 'Warning: redundant data filtering configuration detected'
189
- end
190
-
191
- new_authorized_query(actor, action, resource_cls)
192
- else
193
- old_authorized_query(actor, action, resource_cls)
194
- end
185
+ new_authorized_query(actor, action, resource_cls)
195
186
  end
196
187
 
197
188
  # Determine the resources of type +resource_cls+ that +actor+
@@ -203,25 +194,7 @@ module Oso
203
194
  #
204
195
  # @return A list of resources accessible to the actor.
205
196
  def authorized_resources(actor, action, resource_cls)
206
- q = authorized_query(actor, action, resource_cls)
207
-
208
- if host.use_new_data_filtering?
209
- host.adapter.execute_query q
210
- elsif q.nil?
211
- []
212
- else
213
- host.types[resource_cls].exec_query[q]
214
- end
215
- end
216
-
217
- # Register default values for data filtering query functions.
218
- # These can be overridden by passing specific implementations to
219
- # `register_class` or by defining `build_query`, `exec_query` and
220
- # `combine_query` methods on the class object.
221
- def set_data_filtering_query_defaults(build_query: nil, exec_query: nil, combine_query: nil)
222
- host.build_query = build_query if build_query
223
- host.exec_query = exec_query if exec_query
224
- host.combine_query = combine_query if combine_query
197
+ host.adapter.execute_query authorized_query(actor, action, resource_cls)
225
198
  end
226
199
 
227
200
  def data_filtering_adapter=(adapter)
@@ -4,110 +4,6 @@ module Oso
4
4
  module Polar
5
5
  # Data filtering interface for Ruby
6
6
  module DataFiltering
7
- GETATTR = ->(x, attr) { attr.nil? ? x : x.send(attr) }
8
- # Represents a set of filter sequences that should allow the host
9
- # to obtain the records satisfying a query.
10
- class FilterPlan
11
- attr_reader :result_sets
12
-
13
- def self.parse(polar, partials, class_name)
14
- types = polar.host.serialize_types
15
- parsed_json = polar.ffi.build_filter_plan(types, partials, 'resource', class_name)
16
- result_sets = parsed_json['result_sets'].map do |rset|
17
- ResultSet.parse polar, rset
18
- end
19
-
20
- new polar: polar, result_sets: result_sets
21
- end
22
-
23
- def initialize(polar:, result_sets:)
24
- @polar = polar
25
- @result_sets = result_sets
26
- end
27
-
28
- def build_query # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
29
- combine = nil
30
- result_sets.each_with_object([]) do |rs, qb|
31
- rs.resolve_order.each_with_object({}) do |i, set_results|
32
- req = rs.requests[i]
33
- cs = req.ground(set_results)
34
- typ = @polar.host.types[req.class_tag]
35
- q = typ.build_query[cs]
36
- if i != rs.result_id
37
- set_results[i] = typ.exec_query[q]
38
- else
39
- combine = typ.combine_query
40
- qb.push q
41
- end
42
- end
43
- end.reduce(&combine)
44
- end
45
-
46
- # Represents a sequence of filters for one set of results
47
- class ResultSet
48
- attr_reader :requests, :resolve_order, :result_id
49
-
50
- def self.parse(polar, parsed_json)
51
- resolve_order = parsed_json['resolve_order']
52
- result_id = parsed_json['result_id']
53
- requests = parsed_json['requests'].each_with_object({}) do |req, reqs|
54
- reqs[req[0].to_i] = Request.parse(polar, req[1])
55
- end
56
-
57
- new resolve_order: resolve_order, result_id: result_id, requests: requests
58
- end
59
-
60
- def initialize(requests:, resolve_order:, result_id:)
61
- @resolve_order = resolve_order
62
- @requests = requests
63
- @result_id = result_id
64
- end
65
- end
66
-
67
- # Represents a filter for a result set
68
- class Request
69
- attr_reader :constraints, :class_tag
70
-
71
- def self.parse(polar, parsed_json)
72
- @polar = polar
73
- constraints = parsed_json['constraints'].map do |con|
74
- Filter.parse polar, con
75
- end
76
- class_tag = parsed_json['class_tag']
77
-
78
- new(constraints: constraints, class_tag: class_tag)
79
- end
80
-
81
- def ground(results) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
82
- xrefs, rest = constraints.partition do |c|
83
- c.value.is_a?(Ref) and !c.value.result_id.nil?
84
- end
85
-
86
- yrefs, nrefs = xrefs.partition { |r| %w[In Eq].include? r.kind }
87
- [[yrefs, 'In'], [nrefs, 'Nin']].each do |refs, kind|
88
- refs.group_by { |f| f.value.result_id }.each do |rid, fils|
89
- if fils.length > 1
90
- value = results[rid].map { |r| fils.map { |f| GETATTR[r, f.value.field] } }
91
- field = fils.map(&:field)
92
- rest.push(Filter.new(kind: kind, value: value, field: field))
93
- else
94
- fil = fils[0]
95
- field = fil.value.field
96
- value = results[rid].map { |r| field.nil? ? r : r.send(field) }
97
- rest.push(Filter.new(kind: kind, field: fil.field, value: value))
98
- end
99
- end
100
- end
101
- rest
102
- end
103
-
104
- def initialize(constraints:, class_tag:)
105
- @constraints = constraints
106
- @class_tag = class_tag
107
- end
108
- end
109
- end
110
-
111
7
  # Represents relationships between resources, eg. one-one or one-many
112
8
  class Relation
113
9
  attr_reader :kind, :other_type, :my_field, :other_field
@@ -124,92 +20,6 @@ module Oso
124
20
  @other_field = other_field
125
21
  end
126
22
  end
127
-
128
- # Represents field-field relationships on one resource.
129
- class Field
130
- attr_reader :field
131
-
132
- def initialize(field:)
133
- @field = field
134
- end
135
- end
136
-
137
- # Represents field-field relationships on different resources.
138
- class Ref
139
- attr_reader :field, :result_id
140
-
141
- def initialize(field:, result_id:)
142
- @field = field
143
- @result_id = result_id
144
- end
145
- end
146
-
147
- # Represents a condition that must hold on a resource.
148
- class Filter
149
- attr_reader :kind, :field, :value
150
-
151
- CHECKS = {
152
- 'Eq' => ->(a, b) { a == b },
153
- 'In' => ->(a, b) { b.include? a },
154
- 'Neq' => ->(a, b) { a != b },
155
- 'Nin' => ->(a, b) { !b.include?(a) },
156
- 'Contains' => ->(a, b) { a.include? b }
157
- }.freeze
158
-
159
- # Create a new predicate for data filtering.
160
- # @param kind [String] Represents a condition. One of "Eq", "Neq", "In", "Contains".
161
- # @param field The field the condition applies to.
162
- # @param value The value with which to compare the field according to the condition.
163
- def initialize(kind:, field:, value:)
164
- @kind = kind
165
- @field = field
166
- @value = value
167
- end
168
-
169
- def ground(results)
170
- return unless value.is_a? Ref
171
-
172
- ref = value
173
- @value = results[ref.result_id]
174
- @value = value.map { |v| v.send ref.field } unless ref.field.nil?
175
- end
176
-
177
- def check(item) # rubocop:disable Metrics/AbcSize
178
- val = value.is_a?(Field) ? item.send(value.field) : value
179
- item = if field.nil?
180
- item
181
- elsif field.is_a? Array
182
- field.map { |f| GETATTR[item, f] }
183
- else
184
- item.send field
185
- end
186
- CHECKS[@kind][item, val]
187
- end
188
-
189
- def self.parse(polar, constraint) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
190
- kind = constraint['kind']
191
- field = constraint['field']
192
- value = constraint['value']
193
-
194
- value_kind = value.keys.first
195
- value = value[value_kind]
196
-
197
- case value_kind
198
- when 'Term'
199
- value = polar.host.to_ruby value
200
- when 'Ref'
201
- child_field = value['field']
202
- result_id = value['result_id']
203
- value = Ref.new field: child_field, result_id: result_id
204
- when 'Field'
205
- value = Field.new field: value
206
- else
207
- raise "Unknown value kind `#{value_kind}`"
208
- end
209
-
210
- new kind: kind, field: field, value: value
211
- end
212
- end
213
23
  end
214
24
  end
215
25
  end
@@ -319,17 +319,24 @@ module Oso
319
319
  end
320
320
  else
321
321
  instance_id = nil
322
- instance_id = types[value].id if value.is_a?(Class) && types.key?(value)
323
-
324
- # only pass class_repr for registered types
322
+ class_id = nil
325
323
  class_repr = nil
326
- class_repr = value.class.to_s if types.key?(value.class)
324
+ # id=class_id,
325
+
326
+ # pass `class_id` & `class_repr` for registered types
327
+ if value.is_a?(Class) && types.key?(value)
328
+ instance_id = class_id = types[value].id
329
+ elsif types.key?(value.class)
330
+ class_id = types[value.class].id
331
+ class_repr = types[value.class].name
332
+ end
327
333
 
328
334
  {
329
335
  'ExternalInstance' => {
330
336
  'instance_id' => cache_instance(value, id: instance_id),
331
337
  'repr' => nil,
332
- 'class_repr' => class_repr
338
+ 'class_repr' => class_repr,
339
+ 'class_id' => class_id
333
340
  }
334
341
  }
335
342
  end
@@ -407,10 +414,6 @@ module Oso
407
414
  get_instance(Regexp.last_match[1].to_i).to_s
408
415
  end
409
416
  end
410
-
411
- def use_new_data_filtering?
412
- !adapter.nil?
413
- end
414
417
  end
415
418
  end
416
419
  end
@@ -217,6 +217,7 @@ module Oso
217
217
  exec_query: exec_query || maybe_mtd(cls, :exec_query)
218
218
  )
219
219
  register_constant(cls, name: name)
220
+ host.register_mros
220
221
  end
221
222
 
222
223
  # Register a Ruby object with Polar.
@@ -277,13 +278,6 @@ module Oso
277
278
  host.adapter.build_query filter
278
279
  end
279
280
 
280
- def old_authorized_query(actor, action, resource_cls)
281
- results = partial_query(actor, action, resource_cls)
282
- ::Oso::Polar::DataFiltering::FilterPlan
283
- .parse(self, results, class_to_name(resource_cls))
284
- .build_query
285
- end
286
-
287
281
  # handle Isa constraints in a partial query
288
282
  def prefilter_isas(key, val) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
289
283
  # this will usually be the case! sometimes not, if it's an instance.
@@ -343,7 +337,6 @@ module Oso
343
337
  # Register MROs, load Polar code, and check inline queries.
344
338
  # @param sources [Array<Source>] Polar sources to load.
345
339
  def load_sources(sources)
346
- host.register_mros
347
340
  ffi_polar.load(sources)
348
341
  check_inline_queries
349
342
  end
@@ -245,31 +245,22 @@ module Oso
245
245
  def handle_relationship(call_id, instance, rel) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
246
246
  typ = host.types[rel.other_type]
247
247
 
248
- if host.use_new_data_filtering?
249
- cls = typ.klass.get
250
-
251
- condition = ::Oso::Polar::Data::Filter::Condition.new(
252
- ::Oso::Polar::Data::Filter::Projection.new(cls, rel.other_field),
253
- 'Eq',
254
- instance.send(rel.my_field)
255
- )
256
-
257
- filter = ::Oso::Polar::Data::Filter.new(
258
- model: cls,
259
- relations: [],
260
- conditions: [[condition]],
261
- types: host.types
262
- )
263
-
264
- res = host.adapter.execute_query host.adapter.build_query(filter)
265
- else
266
- constraint = ::Oso::Polar::DataFiltering::Filter.new(
267
- kind: 'Eq',
268
- field: rel.other_field,
269
- value: instance.send(rel.my_field)
270
- )
271
- res = typ.exec_query[typ.build_query[[constraint]]]
272
- end
248
+ cls = typ.klass.get
249
+
250
+ condition = ::Oso::Polar::Data::Filter::Condition.new(
251
+ ::Oso::Polar::Data::Filter::Projection.new(cls, rel.other_field),
252
+ 'Eq',
253
+ instance.send(rel.my_field)
254
+ )
255
+
256
+ filter = ::Oso::Polar::Data::Filter.new(
257
+ model: cls,
258
+ relations: [],
259
+ conditions: [[condition]],
260
+ types: host.types
261
+ )
262
+
263
+ res = host.adapter.execute_query host.adapter.build_query(filter)
273
264
 
274
265
  if rel.kind == 'one'
275
266
  raise "multiple parents: #{res}" unless res.length == 1
data/lib/oso/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Oso
4
- VERSION = '0.25.1'
4
+ VERSION = '0.26.0'
5
5
  end
data/lib/oso.rb CHANGED
@@ -8,7 +8,6 @@ require 'oso/version'
8
8
  # Top-level namespace for Oso authorization library.
9
9
  module Oso
10
10
  Relation = ::Oso::Polar::DataFiltering::Relation
11
- Filter = ::Oso::Polar::DataFiltering::Filter
12
11
 
13
12
  def self.new(not_found_error: NotFoundError, forbidden_error: ForbiddenError, read_action: 'read')
14
13
  ::Oso::Oso.new(not_found_error: not_found_error, forbidden_error: forbidden_error, read_action: read_action)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oso-oso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.1
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oso Security, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-07 00:00:00.000000000 Z
11
+ date: 2022-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi