oso-oso 0.2.2

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.
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Oso
4
+ module Polar
5
+ # Polar predicate.
6
+ class Predicate
7
+ attr_reader :name, :args
8
+
9
+ # @param name [String]
10
+ # @param args [Array<Object>]
11
+ def initialize(name, args:)
12
+ @name = name
13
+ @args = args
14
+ end
15
+
16
+ # @param other [Predicate]
17
+ # @return [Boolean]
18
+ def ==(other)
19
+ name == other.name && args == other.args
20
+ end
21
+
22
+ # @see #==
23
+ alias eql? ==
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Oso
4
+ module Polar
5
+ # A single Polar query.
6
+ class Query
7
+ attr_reader :results
8
+
9
+ # @param ffi_instance [FFI::Query]
10
+ # @param polar [Polar]
11
+ def initialize(ffi_instance, polar:)
12
+ @ffi_instance = ffi_instance
13
+ @polar = polar
14
+ @results = start
15
+ end
16
+
17
+ private
18
+
19
+ # @return [FFI::Query]
20
+ attr_reader :ffi_instance
21
+ # @return [Polar]
22
+ attr_reader :polar
23
+
24
+ # Send next result of Ruby method call across FFI boundary.
25
+ #
26
+ # @param result [String]
27
+ # @param call_id [Integer]
28
+ # @raise [Error] if the FFI call raises one.
29
+ def call_result(result, call_id:)
30
+ ffi_instance.call_result(result, call_id: call_id)
31
+ end
32
+
33
+ # Send result of predicate check across FFI boundary.
34
+ #
35
+ # @param result [Boolean]
36
+ # @param call_id [Integer]
37
+ # @raise [Error] if the FFI call raises one.
38
+ def question_result(result, call_id:)
39
+ ffi_instance.question_result(result, call_id: call_id)
40
+ end
41
+
42
+ # Fetch the next result from calling a Ruby method and prepare it for
43
+ # transmission across the FFI boundary.
44
+ #
45
+ # @param method [#to_sym]
46
+ # @param args [Array<Hash>]
47
+ # @param call_id [Integer]
48
+ # @param instance_id [Integer]
49
+ # @raise [Error] if the FFI call raises one.
50
+ def handle_call(method, call_id:, instance:, args:)
51
+ polar.register_call(method, call_id: call_id, instance: instance, args: args)
52
+ result = JSON.dump(polar.next_call_result(call_id))
53
+ call_result(result, call_id: call_id)
54
+ rescue InvalidCallError, StopIteration
55
+ call_result(nil, call_id: call_id)
56
+ # @TODO: polar line numbers in errors once polar errors are better.
57
+ # raise PolarRuntimeError(f"Error calling {attribute}")
58
+ end
59
+
60
+ # Create a generator that can be polled to advance the query loop.
61
+ #
62
+ # @yieldparam [Hash<String, Object>]
63
+ # @return [Enumerator]
64
+ # @raise [Error] if any of the FFI calls raise one.
65
+ def start # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
66
+ Enumerator.new do |yielder| # rubocop:disable Metrics/BlockLength
67
+ loop do # rubocop:disable Metrics/BlockLength
68
+ event = ffi_instance.next_event
69
+ case event.kind
70
+ when 'Done'
71
+ break
72
+ when 'Result'
73
+ yielder << event.data['bindings'].transform_values { |v| polar.to_ruby(v) }
74
+ when 'MakeExternal'
75
+ id = event.data['instance_id']
76
+ raise DuplicateInstanceRegistrationError, id if polar.instance? id
77
+
78
+ cls_name = event.data['instance']['tag']
79
+ fields = event.data['instance']['fields']['fields']
80
+ polar.make_instance(cls_name, fields: fields, id: id)
81
+ when 'ExternalCall'
82
+ call_id = event.data['call_id']
83
+ instance = event.data['instance']
84
+ method = event.data['attribute']
85
+ args = event.data['args']
86
+ handle_call(method, call_id: call_id, instance: instance, args: args)
87
+ when 'ExternalIsSubSpecializer'
88
+ instance_id = event.data['instance_id']
89
+ left_tag = event.data['left_class_tag']
90
+ right_tag = event.data['right_class_tag']
91
+ answer = polar.subspecializer?(instance_id, left_tag: left_tag, right_tag: right_tag)
92
+ question_result(answer, call_id: event.data['call_id'])
93
+ when 'ExternalIsa'
94
+ instance_id = event.data['instance_id']
95
+ class_tag = event.data['class_tag']
96
+ answer = polar.isa?(instance_id, class_tag: class_tag)
97
+ question_result(answer, call_id: event.data['call_id'])
98
+ when 'ExternalUnify'
99
+ left_instance_id = event.data['left_instance_id']
100
+ right_instance_id = event.data['right_instance_id']
101
+ answer = polar.unify?(left_instance_id, right_instance_id)
102
+ question_result(answer, call_id: event.data['call_id'])
103
+ when 'Debug'
104
+ puts event.data['message'] if event.data['message']
105
+ print '> '
106
+ input = $stdin.gets.chomp!
107
+ command = JSON.dump(polar.to_polar_term(input))
108
+ ffi_instance.debug_command(command)
109
+ else
110
+ raise "Unhandled event: #{JSON.dump(event.inspect)}"
111
+ end
112
+ end
113
+ end.lazy
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Oso
4
+ module Polar
5
+ # A query event received across the FFI boundary.
6
+ class QueryEvent
7
+ # @return [String]
8
+ attr_reader :kind
9
+ # @return [Hash<String, Object>]
10
+ attr_reader :data
11
+
12
+ # @overload initialize(event_data)
13
+ # @param event_data [Hash<String, Object>]
14
+ # @overload initialize(event_data)
15
+ # @param event_data [String]
16
+ def initialize(event_data)
17
+ event_data = { event_data => nil } if event_data == 'Done'
18
+ @kind, @data = event_data.first
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Oso
4
+ module Polar
5
+ # Polar variable.
6
+ class Variable
7
+ attr_reader :name
8
+
9
+ # @param name [String]
10
+ def initialize(name)
11
+ @name = name
12
+ end
13
+
14
+ # @return [String]
15
+ def to_s
16
+ name
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Oso
4
+ VERSION = '0.2.2'
5
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/oso/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'oso-oso'
7
+ spec.version = Oso::VERSION
8
+ spec.authors = ['Oso Security']
9
+ spec.email = ['support@osohq.com']
10
+
11
+ spec.summary = 'Oso authorization API.'
12
+ spec.homepage = 'https://www.osohq.com/'
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
14
+
15
+ spec.metadata['homepage_uri'] = spec.homepage
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = 'exe'
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ['lib']
25
+
26
+ # Runtime dependencies
27
+ spec.add_runtime_dependency 'ffi', '~> 1.0'
28
+
29
+ # Development dependencies
30
+ spec.add_development_dependency 'pry-byebug', '~> 3.9.0'
31
+ spec.add_development_dependency 'rake', '~> 12.0'
32
+ spec.add_development_dependency 'rspec', '~> 3.0'
33
+ spec.add_development_dependency 'solargraph', '~> 0.39.8'
34
+ spec.add_development_dependency 'yard', '~> 0.9.25'
35
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oso-oso
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Oso Security
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-07-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry-byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 3.9.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 3.9.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: solargraph
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.39.8
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.39.8
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.9.25
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.9.25
97
+ description:
98
+ email:
99
+ - support@osohq.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".solargraph.yml"
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - Makefile
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - ext/oso-oso/lib/libpolar.dylib
115
+ - ext/oso-oso/lib/libpolar.so
116
+ - lib/oso.rb
117
+ - lib/oso/http.rb
118
+ - lib/oso/oso.rb
119
+ - lib/oso/path_mapper.rb
120
+ - lib/oso/polar.rb
121
+ - lib/oso/polar/errors.rb
122
+ - lib/oso/polar/ffi.rb
123
+ - lib/oso/polar/ffi/error.rb
124
+ - lib/oso/polar/ffi/polar.rb
125
+ - lib/oso/polar/ffi/query.rb
126
+ - lib/oso/polar/ffi/query_event.rb
127
+ - lib/oso/polar/polar.rb
128
+ - lib/oso/polar/predicate.rb
129
+ - lib/oso/polar/query.rb
130
+ - lib/oso/polar/query_event.rb
131
+ - lib/oso/polar/variable.rb
132
+ - lib/oso/version.rb
133
+ - oso-oso.gemspec
134
+ homepage: https://www.osohq.com/
135
+ licenses: []
136
+ metadata:
137
+ homepage_uri: https://www.osohq.com/
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: 2.4.0
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubygems_version: 3.1.4
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Oso authorization API.
157
+ test_files: []