oso-oso 0.2.5 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +14 -13
- data/Makefile +10 -1
- data/README.md +6 -9
- data/Rakefile +0 -1
- data/bin/oso +7 -0
- 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/http.rb +1 -1
- data/lib/oso/oso.rb +14 -33
- data/lib/oso/path_mapper.rb +1 -1
- data/lib/oso/polar.rb +1 -0
- data/lib/oso/polar/errors.rb +25 -9
- data/lib/oso/polar/ffi.rb +14 -5
- data/lib/oso/polar/ffi/error.rb +2 -2
- data/lib/oso/polar/ffi/message.rb +37 -0
- data/lib/oso/polar/ffi/polar.rb +28 -18
- data/lib/oso/polar/ffi/query.rb +25 -0
- data/lib/oso/polar/host.rb +248 -0
- data/lib/oso/polar/polar.rb +171 -305
- data/lib/oso/polar/query.rb +99 -39
- data/lib/oso/version.rb +1 -1
- data/oso-oso.gemspec +10 -7
- metadata +30 -11
- data/bin/console +0 -33
- data/bin/setup +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '09ee09c3366406a34633c870ddfe4ff271971529'
|
4
|
+
data.tar.gz: 764b0f3b440d567e19e45b71eff823b9000f35ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fdae19c2528c46a85004241f0a8e59639123e416724239670cb9ff2ffc1172a87bb116b481d575e466c74f634213abdced263211f991721f1ff990e1e085d884
|
7
|
+
data.tar.gz: 309a196e2a0a3725e3bc1f45be8382ed85026dc7fc271662efaef8e207b0df2891f26da48ece702f1d9ce3e3731ea52c0a6cea30bf50af6acde54f08b44d79ec
|
data/.rubocop.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
oso-oso (0.
|
4
|
+
oso-oso (0.5.0)
|
5
5
|
ffi (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -12,18 +12,18 @@ GEM
|
|
12
12
|
benchmark (0.1.0)
|
13
13
|
byebug (11.1.3)
|
14
14
|
coderay (1.1.3)
|
15
|
-
diff-lcs (1.
|
15
|
+
diff-lcs (1.4.4)
|
16
16
|
e2mmap (0.1.0)
|
17
17
|
ffi (1.13.1)
|
18
18
|
jaro_winkler (1.5.4)
|
19
19
|
maruku (0.7.3)
|
20
20
|
method_source (1.0.0)
|
21
21
|
mini_portile2 (2.4.0)
|
22
|
-
nokogiri (1.10.
|
22
|
+
nokogiri (1.10.10)
|
23
23
|
mini_portile2 (~> 2.4.0)
|
24
|
-
parallel (1.19.
|
25
|
-
parser (2.7.1.
|
26
|
-
ast (~> 2.4.
|
24
|
+
parallel (1.19.2)
|
25
|
+
parser (2.7.1.4)
|
26
|
+
ast (~> 2.4.1)
|
27
27
|
pry (0.13.1)
|
28
28
|
coderay (~> 1.1)
|
29
29
|
method_source (~> 1.0)
|
@@ -49,19 +49,19 @@ GEM
|
|
49
49
|
diff-lcs (>= 1.2.0, < 2.0)
|
50
50
|
rspec-support (~> 3.9.0)
|
51
51
|
rspec-support (3.9.3)
|
52
|
-
rubocop (0.
|
52
|
+
rubocop (0.89.1)
|
53
53
|
parallel (~> 1.10)
|
54
|
-
parser (>= 2.7.
|
54
|
+
parser (>= 2.7.1.1)
|
55
55
|
rainbow (>= 2.2.2, < 4.0)
|
56
56
|
regexp_parser (>= 1.7)
|
57
57
|
rexml
|
58
|
-
rubocop-ast (>= 0.0.
|
58
|
+
rubocop-ast (>= 0.3.0, < 1.0)
|
59
59
|
ruby-progressbar (~> 1.7)
|
60
60
|
unicode-display_width (>= 1.4.0, < 2.0)
|
61
|
-
rubocop-ast (0.0
|
62
|
-
parser (>= 2.7.
|
61
|
+
rubocop-ast (0.3.0)
|
62
|
+
parser (>= 2.7.1.4)
|
63
63
|
ruby-progressbar (1.10.1)
|
64
|
-
solargraph (0.39.
|
64
|
+
solargraph (0.39.14)
|
65
65
|
backport (~> 1.1)
|
66
66
|
benchmark
|
67
67
|
bundler (>= 1.17.2)
|
@@ -88,7 +88,8 @@ DEPENDENCIES
|
|
88
88
|
pry-byebug (~> 3.9.0)
|
89
89
|
rake (~> 12.0)
|
90
90
|
rspec (~> 3.0)
|
91
|
-
|
91
|
+
rubocop (~> 0.89.1)
|
92
|
+
solargraph (~> 0.39.14)
|
92
93
|
yard (~> 0.9.25)
|
93
94
|
|
94
95
|
BUNDLED WITH
|
data/Makefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
.PHONY: install
|
1
|
+
.PHONY: rust install test lint typecheck repl
|
2
2
|
|
3
3
|
rust:
|
4
4
|
$(MAKE) -C ../.. rust-build
|
@@ -8,3 +8,12 @@ install: rust
|
|
8
8
|
|
9
9
|
test: install
|
10
10
|
bundle exec rake spec
|
11
|
+
|
12
|
+
lint:
|
13
|
+
bundle exec rubocop
|
14
|
+
|
15
|
+
typecheck:
|
16
|
+
bundle exec solargraph typecheck
|
17
|
+
|
18
|
+
repl: install
|
19
|
+
bundle exec oso
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# oso-oso
|
2
2
|
|
3
3
|
## Installation
|
4
4
|
|
@@ -18,13 +18,10 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Development
|
20
20
|
|
21
|
-
After checking out the repo, run `
|
22
|
-
`rake spec` to run the tests. You can also run `
|
23
|
-
|
21
|
+
After checking out the repo, run `bundle install` to install dependencies.
|
22
|
+
Then, run `bundle exec rake spec` to run the tests. You can also run `bundle
|
23
|
+
exec oso` for an interactive REPL that will allow you to experiment.
|
24
24
|
|
25
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
26
|
-
release a new version, update the version number in `version.rb`, and then run
|
27
|
-
`bundle exec rake release`, which will create a git tag for the version, push
|
28
|
-
git commits and tags, and push the `.gem` file to
|
29
|
-
[rubygems.org](https://rubygems.org).
|
25
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
30
26
|
|
27
|
+
New releases are minted and pushed to RubyGems via GitHub Actions workflows.
|
data/Rakefile
CHANGED
data/bin/oso
ADDED
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/http.rb
CHANGED
data/lib/oso/oso.rb
CHANGED
@@ -1,47 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'polar/polar'
|
4
|
+
|
3
5
|
module Oso
|
4
|
-
#
|
5
|
-
class Oso
|
6
|
+
# oso authorization API.
|
7
|
+
class Oso < Polar::Polar
|
6
8
|
def initialize
|
7
|
-
|
9
|
+
super
|
8
10
|
register_class(Http, name: 'Http')
|
9
11
|
register_class(PathMapper, name: 'PathMapper')
|
10
12
|
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
if block_given?
|
22
|
-
polar.register_class(cls, name: name, from_polar: Proc.new)
|
23
|
-
else
|
24
|
-
polar.register_class(cls, name: name)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def allow(actor:, action:, resource:)
|
29
|
-
polar.query_pred('allow', args: [actor, action, resource]).next
|
14
|
+
# Query the knowledge base to determine whether an actor is allowed to
|
15
|
+
# perform an action upon a resource.
|
16
|
+
#
|
17
|
+
# @param actor [Object] Subject.
|
18
|
+
# @param action [Object] Verb.
|
19
|
+
# @param resource [Object] Object.
|
20
|
+
# @return [Boolean] An access control decision.
|
21
|
+
def allowed?(actor:, action:, resource:)
|
22
|
+
query_rule('allow', actor, action, resource).next
|
30
23
|
true
|
31
24
|
rescue StopIteration
|
32
25
|
false
|
33
26
|
end
|
34
|
-
|
35
|
-
def query_predicate(name, *args)
|
36
|
-
polar.query_pred(name, args: args)
|
37
|
-
end
|
38
|
-
|
39
|
-
def load_queued_files
|
40
|
-
polar.load_queued_files
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
attr_reader :polar
|
46
27
|
end
|
47
28
|
end
|
data/lib/oso/path_mapper.rb
CHANGED
@@ -4,7 +4,7 @@ module Oso
|
|
4
4
|
# Map from a template string with capture groups of the form
|
5
5
|
# `{name}` to a dictionary of the form `{name: captured_value}`
|
6
6
|
class PathMapper
|
7
|
-
def initialize(template
|
7
|
+
def initialize(template)
|
8
8
|
capture_group = /({([^}]+)})/
|
9
9
|
|
10
10
|
template = template.dup
|
data/lib/oso/polar.rb
CHANGED
data/lib/oso/polar/errors.rb
CHANGED
@@ -5,16 +5,12 @@ module Oso
|
|
5
5
|
# Base error type for Oso::Polar.
|
6
6
|
class Error < ::RuntimeError
|
7
7
|
attr_reader :stack_trace
|
8
|
-
|
8
|
+
|
9
9
|
# @param message [String]
|
10
10
|
# @param details [Hash]
|
11
11
|
def initialize(message = nil, details: nil)
|
12
12
|
@details = details
|
13
|
-
|
14
|
-
@stack_trace = details['stack_trace']
|
15
|
-
else
|
16
|
-
@stack_trace = nil
|
17
|
-
end
|
13
|
+
@stack_trace = details&.fetch('stack_trace', nil)
|
18
14
|
super(message)
|
19
15
|
end
|
20
16
|
end
|
@@ -40,12 +36,32 @@ module Oso
|
|
40
36
|
class DuplicateInstanceRegistrationError < PolarRuntimeError; end
|
41
37
|
class InvalidCallError < PolarRuntimeError; end
|
42
38
|
class InvalidConstructorError < PolarRuntimeError; end
|
39
|
+
class InvalidQueryTypeError < PolarRuntimeError; end
|
43
40
|
class InlineQueryFailedError < PolarRuntimeError; end
|
44
41
|
class NullByteInPolarFileError < PolarRuntimeError; end
|
45
42
|
class UnexpectedPolarTypeError < PolarRuntimeError; end
|
43
|
+
class PolarFileAlreadyLoadedError < PolarRuntimeError # rubocop:disable Style/Documentation
|
44
|
+
# @param file [String]
|
45
|
+
def initialize(file)
|
46
|
+
super("File #{file} has already been loaded.")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
class PolarFileContentsChangedError < PolarRuntimeError # rubocop:disable Style/Documentation
|
50
|
+
# @param file [String]
|
51
|
+
def initialize(file)
|
52
|
+
super("A file with the name #{file}, but different contents, has already been loaded.")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
class PolarFileNameChangedError < PolarRuntimeError # rubocop:disable Style/Documentation
|
56
|
+
# @param file [String]
|
57
|
+
# @param existing [String]
|
58
|
+
def initialize(file, existing)
|
59
|
+
super("A file with the same contents as #{file} named #{existing} has already been loaded.")
|
60
|
+
end
|
61
|
+
end
|
46
62
|
class PolarFileExtensionError < PolarRuntimeError # rubocop:disable Style/Documentation
|
47
|
-
def initialize
|
48
|
-
super(
|
63
|
+
def initialize(file)
|
64
|
+
super("Polar files must have .polar extension. Offending file: #{file}")
|
49
65
|
end
|
50
66
|
end
|
51
67
|
class PolarFileNotFoundError < PolarRuntimeError # rubocop:disable Style/Documentation
|
@@ -58,7 +74,7 @@ module Oso
|
|
58
74
|
# @param as [String]
|
59
75
|
# @param old [Class]
|
60
76
|
# @param new [Class]
|
61
|
-
def initialize(name:, old:, new:)
|
77
|
+
def initialize(name:, old:, new:)
|
62
78
|
super("Attempted to alias #{new} as '#{name}', but #{old} already has that alias.")
|
63
79
|
end
|
64
80
|
end
|
data/lib/oso/polar/ffi.rb
CHANGED
@@ -5,10 +5,12 @@ require 'ffi'
|
|
5
5
|
module Oso
|
6
6
|
module Polar
|
7
7
|
module FFI
|
8
|
-
LIB = ::FFI::Platform::LIBPREFIX
|
9
|
-
|
10
|
-
|
11
|
-
#
|
8
|
+
LIB = "#{::FFI::Platform::LIBPREFIX}polar.#{::FFI::Platform::LIBSUFFIX}"
|
9
|
+
RELEASE_PATH = File.expand_path(File.join(__dir__, "../../../ext/oso-oso/lib/#{LIB}"))
|
10
|
+
DEV_PATH = File.expand_path(File.join(__dir__, "../../../../../target/debug/#{LIB}"))
|
11
|
+
# If the lib exists in the ext/ dir, use it. Otherwise, fall back to
|
12
|
+
# checking the local Rust target dir.
|
13
|
+
LIB_PATH = File.file?(RELEASE_PATH) ? RELEASE_PATH : DEV_PATH
|
12
14
|
|
13
15
|
# Wrapper classes defined upfront to fix Ruby loading issues. Actual
|
14
16
|
# implementations live in the sibling `ffi/` directory and are `require`d
|
@@ -35,7 +37,13 @@ module Oso
|
|
35
37
|
# Wrapper class for Error FFI pointer + operations.
|
36
38
|
class Error < ::FFI::AutoPointer
|
37
39
|
def self.release(ptr)
|
38
|
-
Rust.free(ptr)
|
40
|
+
Rust.free(ptr) unless ptr.null?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
# Wrapper class for Message FFI pointer + operations.
|
44
|
+
class Message < ::FFI::AutoPointer
|
45
|
+
def self.release(ptr)
|
46
|
+
Rust.free(ptr) unless ptr.null?
|
39
47
|
end
|
40
48
|
end
|
41
49
|
end
|
@@ -47,3 +55,4 @@ require 'oso/polar/ffi/polar'
|
|
47
55
|
require 'oso/polar/ffi/query'
|
48
56
|
require 'oso/polar/ffi/query_event'
|
49
57
|
require 'oso/polar/ffi/error'
|
58
|
+
require 'oso/polar/ffi/message'
|
data/lib/oso/polar/ffi/error.rb
CHANGED
@@ -22,7 +22,7 @@ module Oso
|
|
22
22
|
#
|
23
23
|
# @return [::Oso::Polar::Error] if there's an FFI error.
|
24
24
|
# @return [::Oso::Polar::FFIErrorNotFound] if there isn't one.
|
25
|
-
def self.get # rubocop:disable Metrics/
|
25
|
+
def self.get # rubocop:disable Metrics/MethodLength
|
26
26
|
error = Rust.get
|
27
27
|
return ::Oso::Polar::FFIErrorNotFound if error.null?
|
28
28
|
|
@@ -48,7 +48,7 @@ module Oso
|
|
48
48
|
# @param msg [String]
|
49
49
|
# @param details [Hash<String, Object>]
|
50
50
|
# @return [::Oso::Polar::ParseError] the object converted into the expected format.
|
51
|
-
private_class_method def self.parse_error(kind, msg:, details:) # rubocop:disable Metrics/
|
51
|
+
private_class_method def self.parse_error(kind, msg:, details:) # rubocop:disable Metrics/MethodLength
|
52
52
|
case kind
|
53
53
|
when 'ExtraToken'
|
54
54
|
::Oso::Polar::ParseError::ExtraToken.new(msg, details: details)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Oso
|
4
|
+
module Polar
|
5
|
+
module FFI
|
6
|
+
# Wrapper class for Message FFI pointer + operations.
|
7
|
+
class Message < ::FFI::AutoPointer
|
8
|
+
# @return [String]
|
9
|
+
def to_s
|
10
|
+
@to_s ||= read_string.force_encoding('UTF-8')
|
11
|
+
end
|
12
|
+
|
13
|
+
Rust = Module.new do
|
14
|
+
extend ::FFI::Library
|
15
|
+
ffi_lib FFI::LIB_PATH
|
16
|
+
|
17
|
+
attach_function :free, :string_free, [Message], :int32
|
18
|
+
end
|
19
|
+
|
20
|
+
def process
|
21
|
+
message = JSON.parse(to_s)
|
22
|
+
kind = message['kind']
|
23
|
+
msg = message['msg']
|
24
|
+
|
25
|
+
case kind
|
26
|
+
when 'Print'
|
27
|
+
puts(msg)
|
28
|
+
when 'Warning'
|
29
|
+
warn('[warning] %<msg>s')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private_constant :Rust
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/oso/polar/ffi/polar.rb
CHANGED
@@ -11,12 +11,12 @@ module Oso
|
|
11
11
|
|
12
12
|
attach_function :new, :polar_new, [], FFI::Polar
|
13
13
|
attach_function :load_str, :polar_load, [FFI::Polar, :string, :string], :int32
|
14
|
-
attach_function :next_inline_query, :polar_next_inline_query, [FFI::Polar], FFI::Query
|
14
|
+
attach_function :next_inline_query, :polar_next_inline_query, [FFI::Polar, :uint32], FFI::Query
|
15
15
|
attach_function :new_id, :polar_get_external_id, [FFI::Polar], :uint64
|
16
|
-
attach_function :new_query_from_str, :polar_new_query, [FFI::Polar, :string], FFI::Query
|
17
|
-
attach_function :new_query_from_term, :polar_new_query_from_term, [FFI::Polar, :string], FFI::Query
|
18
|
-
attach_function :new_query_from_repl, :polar_query_from_repl, [FFI::Polar], FFI::Query
|
16
|
+
attach_function :new_query_from_str, :polar_new_query, [FFI::Polar, :string, :uint32], FFI::Query
|
17
|
+
attach_function :new_query_from_term, :polar_new_query_from_term, [FFI::Polar, :string, :uint32], FFI::Query
|
19
18
|
attach_function :register_constant, :polar_register_constant, [FFI::Polar, :string, :string], :int32
|
19
|
+
attach_function :next_message, :polar_next_polar_message, [FFI::Polar], FFI::Message
|
20
20
|
attach_function :free, :polar_free, [FFI::Polar], :int32
|
21
21
|
end
|
22
22
|
private_constant :Rust
|
@@ -34,14 +34,17 @@ module Oso
|
|
34
34
|
# @param filename [String]
|
35
35
|
# @raise [FFI::Error] if the FFI call returns an error.
|
36
36
|
def load_str(src, filename: nil)
|
37
|
-
|
37
|
+
loaded = Rust.load_str(self, src, filename)
|
38
|
+
process_messages
|
39
|
+
raise FFI::Error.get if loaded.zero?
|
38
40
|
end
|
39
41
|
|
40
42
|
# @return [FFI::Query] if there are remaining inline queries.
|
41
43
|
# @return [nil] if there are no remaining inline queries.
|
42
44
|
# @raise [FFI::Error] if the FFI call returns an error.
|
43
45
|
def next_inline_query
|
44
|
-
query = Rust.next_inline_query(self)
|
46
|
+
query = Rust.next_inline_query(self, 0)
|
47
|
+
process_messages
|
45
48
|
query.null? ? nil : query
|
46
49
|
end
|
47
50
|
|
@@ -60,7 +63,8 @@ module Oso
|
|
60
63
|
# @return [FFI::Query]
|
61
64
|
# @raise [FFI::Error] if the FFI call returns an error.
|
62
65
|
def new_query_from_str(str)
|
63
|
-
query = Rust.new_query_from_str(self, str)
|
66
|
+
query = Rust.new_query_from_str(self, str, 0)
|
67
|
+
process_messages
|
64
68
|
raise FFI::Error.get if query.null?
|
65
69
|
|
66
70
|
query
|
@@ -70,16 +74,8 @@ module Oso
|
|
70
74
|
# @return [FFI::Query]
|
71
75
|
# @raise [FFI::Error] if the FFI call returns an error.
|
72
76
|
def new_query_from_term(term)
|
73
|
-
query = Rust.new_query_from_term(self, JSON.dump(term))
|
74
|
-
|
75
|
-
|
76
|
-
query
|
77
|
-
end
|
78
|
-
|
79
|
-
# @return [FFI::Query]
|
80
|
-
# @raise [FFI::Error] if the FFI call returns an error.
|
81
|
-
def new_query_from_repl
|
82
|
-
query = Rust.new_query_from_repl(self)
|
77
|
+
query = Rust.new_query_from_term(self, JSON.dump(term), 0)
|
78
|
+
process_messages
|
83
79
|
raise FFI::Error.get if query.null?
|
84
80
|
|
85
81
|
query
|
@@ -89,7 +85,21 @@ module Oso
|
|
89
85
|
# @param value [Hash<String, Object>]
|
90
86
|
# @raise [FFI::Error] if the FFI call returns an error.
|
91
87
|
def register_constant(name, value:)
|
92
|
-
|
88
|
+
registered = Rust.register_constant(self, name, JSON.dump(value))
|
89
|
+
raise FFI::Error.get if registered.zero?
|
90
|
+
end
|
91
|
+
|
92
|
+
def next_message
|
93
|
+
Rust.next_message(self)
|
94
|
+
end
|
95
|
+
|
96
|
+
def process_messages
|
97
|
+
loop do
|
98
|
+
message = next_message
|
99
|
+
break if message.null?
|
100
|
+
|
101
|
+
message.process
|
102
|
+
end
|
93
103
|
end
|
94
104
|
end
|
95
105
|
end
|