oso-oso 0.7.0 → 0.9.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: 73b2001f3721fd450aaebcdf348ac8d05f1452f1
4
- data.tar.gz: bf829788c21e9eb8b91ce05504800df3b13fd4fe
3
+ metadata.gz: c567d76126dbe08f29eb4f7c3bec635a17224718
4
+ data.tar.gz: a9632184c981bcd2501d21da0dbe8850c6b53446
5
5
  SHA512:
6
- metadata.gz: 1590f8019ec1a5e13f8bb5b5f39a65a6e304d427312ea6996e41d6dfb56c0632a31d780dc55a9815734c7e3b6861d823a36878f46b26441d39c51296114b3086
7
- data.tar.gz: 5dbcc691578bdcf01864895ab305aa9a97f7924e0f77a7ce33193dc047c99253f48f1ddfdfba65e290580ca6558132c6473911e5a54a5a64542e6f701f67796d
6
+ metadata.gz: 12d72946b6e4af9d109757b6fcc0f983e2bf2f53df5dbd6f02d13ec4e0ff46c3a42adceaec2cc5c8433481dc48d5742290ce7ea469bcad55120f70feb21a7460
7
+ data.tar.gz: a0914390d8667609a6d908c50212899111cc2324f9283383d9e17e6863cafa31bf6752ca4b975760e8c3c20714d3bed6defc4df26e95b05765336e00d8c99688
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oso-oso (0.7.0)
4
+ oso-oso (0.9.0)
5
5
  ffi (~> 1.0)
6
6
 
7
7
  GEM
Binary file
Binary file
data/lib/oso.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'oso/http'
4
3
  require 'oso/oso'
5
- require 'oso/path_mapper'
6
4
  require 'oso/polar'
7
5
  require 'oso/version'
8
6
 
@@ -7,8 +7,6 @@ module Oso
7
7
  class Oso < Polar::Polar
8
8
  def initialize
9
9
  super
10
- register_class(Http, name: 'Http')
11
- register_class(PathMapper, name: 'PathMapper')
12
10
  end
13
11
 
14
12
  # Query the knowledge base to determine whether an actor is allowed to
@@ -38,6 +38,7 @@ module Oso
38
38
  # TODO: I think this should probably have some arguments to say what the call is
39
39
  class InvalidCallError < PolarRuntimeError; end
40
40
  class InvalidConstructorError < PolarRuntimeError; end
41
+ class InvalidIteratorError < PolarRuntimeError; end
41
42
  class InvalidQueryTypeError < PolarRuntimeError; end
42
43
  class NullByteInPolarFileError < PolarRuntimeError; end
43
44
  class UnexpectedPolarTypeError < PolarRuntimeError; end
@@ -38,6 +38,9 @@ module Oso
38
38
  @ffi_polar = FFI::Polar.create
39
39
  @host = Host.new(ffi_polar)
40
40
 
41
+ # Register global constants.
42
+ register_constant nil, name: 'nil'
43
+
41
44
  # Register built-in classes.
42
45
  register_class PolarBoolean, name: 'Boolean'
43
46
  register_class Integer
@@ -36,33 +36,6 @@ module Oso
36
36
  ffi_query.question_result(result, call_id: call_id)
37
37
  end
38
38
 
39
- # Register a Ruby method call, wrapping the call result in a generator if
40
- # it isn't already one.
41
- #
42
- # @param method [#to_sym]
43
- # @param call_id [Integer]
44
- # @param instance [Hash<String, Object>]
45
- # @param args [Array<Hash>]
46
- # @raise [InvalidCallError] if the method doesn't exist on the instance or
47
- # the args passed to the method are invalid.
48
- def register_call(attribute, call_id:, instance:, args:, kwargs:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
49
- return if calls.key?(call_id)
50
-
51
- instance = host.to_ruby(instance)
52
- args = args.map { |a| host.to_ruby(a) }
53
- kwargs = Hash[kwargs.map { |k, v| [k.to_sym, host.to_ruby(v)] }]
54
- # The kwargs.empty? check is for Ruby < 2.7.
55
- result = if kwargs.empty?
56
- instance.__send__(attribute, *args)
57
- else
58
- instance.__send__(attribute, *args, **kwargs)
59
- end
60
- result = [result].to_enum unless result.is_a? Enumerator # Call must be a generator.
61
- calls[call_id] = result.lazy
62
- rescue ArgumentError, NoMethodError
63
- raise InvalidCallError
64
- end
65
-
66
39
  # Send next result of Ruby method call across FFI boundary.
67
40
  #
68
41
  # @param result [String]
@@ -97,13 +70,33 @@ module Oso
97
70
  # @param call_id [Integer]
98
71
  # @param instance [Hash<String, Object>]
99
72
  # @raise [Error] if the FFI call raises one.
100
- def handle_call(attribute, call_id:, instance:, args:, kwargs:)
101
- register_call(attribute, call_id: call_id, instance: instance, args: args, kwargs: kwargs)
102
- result = JSON.dump(next_call_result(call_id))
73
+ def handle_call(attribute, call_id:, instance:, args:, kwargs:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
74
+ instance = host.to_ruby(instance)
75
+ args = args.map { |a| host.to_ruby(a) }
76
+ kwargs = Hash[kwargs.map { |k, v| [k.to_sym, host.to_ruby(v)] }]
77
+ # The kwargs.empty? check is for Ruby < 2.7.
78
+ result = if kwargs.empty?
79
+ instance.__send__(attribute, *args)
80
+ else
81
+ instance.__send__(attribute, *args, **kwargs)
82
+ end
83
+ result = JSON.dump(host.to_polar(result))
103
84
  call_result(result, call_id: call_id)
104
- rescue InvalidCallError => e
85
+ rescue ArgumentError, NoMethodError => e
105
86
  application_error(e.message)
106
87
  call_result(nil, call_id: call_id)
88
+ end
89
+
90
+ def handle_next_external(call_id, iterable)
91
+ unless calls.key? call_id
92
+ value = host.to_ruby iterable
93
+ raise InvalidIteratorError unless value.is_a? Enumerable
94
+
95
+ calls[call_id] = value.lazy
96
+ end
97
+
98
+ result = JSON.dump(next_call_result(call_id))
99
+ call_result(result, call_id: call_id)
107
100
  rescue StopIteration
108
101
  call_result(nil, call_id: call_id)
109
102
  end
@@ -173,6 +166,10 @@ module Oso
173
166
  ffi_query.debug_command(command)
174
167
  when 'ExternalOp'
175
168
  raise UnimplementedOperationError, 'comparison operators'
169
+ when 'NextExternal'
170
+ call_id = event.data['call_id']
171
+ iterable = event.data['iterable']
172
+ handle_next_external(call_id, iterable)
176
173
  else
177
174
  raise "Unhandled event: #{JSON.dump(event.inspect)}"
178
175
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Oso
4
- VERSION = '0.7.0'
4
+ VERSION = '0.9.0'
5
5
  end
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.7.0
4
+ version: 0.9.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: 2020-10-13 00:00:00.000000000 Z
11
+ date: 2020-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -130,9 +130,7 @@ files:
130
130
  - ext/oso-oso/lib/libpolar.so
131
131
  - ext/oso-oso/lib/polar.dll
132
132
  - lib/oso.rb
133
- - lib/oso/http.rb
134
133
  - lib/oso/oso.rb
135
- - lib/oso/path_mapper.rb
136
134
  - lib/oso/polar.rb
137
135
  - lib/oso/polar/errors.rb
138
136
  - lib/oso/polar/ffi.rb
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Oso
4
- # An HTTP resource.
5
- class Http
6
- def initialize(hostname, path, query)
7
- @hostname = hostname
8
- @path = path
9
- @query = query
10
- end
11
-
12
- private
13
-
14
- attr_reader :hostname, :path, :query
15
- end
16
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Oso
4
- # Map from a template string with capture groups of the form
5
- # `{name}` to a dictionary of the form `{name: captured_value}`
6
- class PathMapper
7
- def initialize(template)
8
- capture_group = /({([^}]+)})/
9
-
10
- template = template.dup
11
- template.scan(capture_group).each do |outer, inner|
12
- template = if inner == '*'
13
- template.gsub! outer, '.*'
14
- else
15
- template.gsub! outer, "(?<#{inner}>[^/]+)"
16
- end
17
- end
18
- @pattern = /\A#{template}\Z/
19
- end
20
-
21
- def map(string)
22
- string.match(pattern)&.named_captures || {}
23
- end
24
-
25
- private
26
-
27
- attr_reader :pattern
28
- end
29
- end