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 +4 -4
- data/Gemfile.lock +1 -1
- data/ext/oso-oso/lib/libpolar.dylib +0 -0
- data/ext/oso-oso/lib/libpolar.so +0 -0
- data/ext/oso-oso/lib/polar.dll +0 -0
- data/lib/oso/oso.rb +2 -29
- data/lib/oso/polar/data_filtering.rb +0 -190
- data/lib/oso/polar/host.rb +12 -9
- data/lib/oso/polar/polar.rb +1 -8
- data/lib/oso/polar/query.rb +16 -25
- data/lib/oso/version.rb +1 -1
- data/lib/oso.rb +0 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c6a70f052d3142dbaf1f8d9c699a7f3c6697060
|
4
|
+
data.tar.gz: 9820ca345e2b1bb85c31183a3f43a1748d412d77
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08cabc94530a44164fef27de25cac7477fc8906b6a4766197b003c4f629332ce4a24b88fc96e7fa78e305c23f0e16f0f5df5481bc7ffb82e5c51a9ffb7cd260c'
|
7
|
+
data.tar.gz: f534eec40e00a8c10dc9379843e8b08dc4bc95bd6526e4c00e0a88aaca11877b31bf643d82e934fe0b01ccdb1d957ae25c3fa069875e46ea7765634313bd43ec
|
data/Gemfile.lock
CHANGED
Binary file
|
data/ext/oso-oso/lib/libpolar.so
CHANGED
Binary file
|
data/ext/oso-oso/lib/polar.dll
CHANGED
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
|
-
|
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
|
-
|
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
|
data/lib/oso/polar/host.rb
CHANGED
@@ -319,17 +319,24 @@ module Oso
|
|
319
319
|
end
|
320
320
|
else
|
321
321
|
instance_id = nil
|
322
|
-
|
323
|
-
|
324
|
-
# only pass class_repr for registered types
|
322
|
+
class_id = nil
|
325
323
|
class_repr = nil
|
326
|
-
|
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
|
data/lib/oso/polar/polar.rb
CHANGED
@@ -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
|
data/lib/oso/polar/query.rb
CHANGED
@@ -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
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
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.
|
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-
|
11
|
+
date: 2022-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|