oso-oso 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.solargraph.yml +17 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +95 -0
- data/Makefile +16 -0
- data/README.md +30 -0
- data/Rakefile +9 -0
- data/bin/console +33 -0
- data/bin/setup +6 -0
- data/ext/oso-oso/lib/libpolar.dylib +0 -0
- data/ext/oso-oso/lib/libpolar.so +0 -0
- data/lib/oso.rb +14 -0
- data/lib/oso/http.rb +16 -0
- data/lib/oso/oso.rb +47 -0
- data/lib/oso/path_mapper.rb +29 -0
- data/lib/oso/polar.rb +18 -0
- data/lib/oso/polar/errors.rb +84 -0
- data/lib/oso/polar/ffi.rb +47 -0
- data/lib/oso/polar/ffi/error.rb +123 -0
- data/lib/oso/polar/ffi/polar.rb +97 -0
- data/lib/oso/polar/ffi/query.rb +55 -0
- data/lib/oso/polar/ffi/query_event.rb +23 -0
- data/lib/oso/polar/polar.rb +381 -0
- data/lib/oso/polar/predicate.rb +26 -0
- data/lib/oso/polar/query.rb +117 -0
- data/lib/oso/polar/query_event.rb +22 -0
- data/lib/oso/polar/variable.rb +20 -0
- data/lib/oso/version.rb +5 -0
- data/oso-oso.gemspec +35 -0
- metadata +157 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ec2b2b33a484c1770041164811415985e0e6c135a3fb03688d40813d0b332772
|
4
|
+
data.tar.gz: 960bcf13f984e19b359da8da1ac6478702c48d68f1ed9f1150250d0d4d0d1df4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9b49f6a116fb1e542674a19047c16484f8f08a54dda51f83918644abfca808e164e628c164fcfd6ad0b2497549c3192a5a194264b138b018c01adbbea8b38cd7
|
7
|
+
data.tar.gz: 30d9fe7a3c625c1245140415c010066c21a388f79b5edce8b6376631712f33ca1bfc82f208e10244c6094b671588e6d1448e241bc11377e2b58c5a154b1afa66
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.solargraph.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
include:
|
3
|
+
- "lib/**/*.rb"
|
4
|
+
exclude:
|
5
|
+
- spec/**/*
|
6
|
+
- test/**/*
|
7
|
+
- vendor/**/*
|
8
|
+
- ".bundle/**/*"
|
9
|
+
require: []
|
10
|
+
domains: []
|
11
|
+
reporters:
|
12
|
+
- rubocop
|
13
|
+
- require_not_found
|
14
|
+
- typecheck
|
15
|
+
require_paths: []
|
16
|
+
plugins: []
|
17
|
+
max_files: 5000
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
oso-oso (0.2.2)
|
5
|
+
ffi (~> 1.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
ast (2.4.1)
|
11
|
+
backport (1.1.2)
|
12
|
+
benchmark (0.1.0)
|
13
|
+
byebug (11.1.3)
|
14
|
+
coderay (1.1.3)
|
15
|
+
diff-lcs (1.3)
|
16
|
+
e2mmap (0.1.0)
|
17
|
+
ffi (1.13.1)
|
18
|
+
jaro_winkler (1.5.4)
|
19
|
+
maruku (0.7.3)
|
20
|
+
method_source (1.0.0)
|
21
|
+
mini_portile2 (2.4.0)
|
22
|
+
nokogiri (1.10.9)
|
23
|
+
mini_portile2 (~> 2.4.0)
|
24
|
+
parallel (1.19.1)
|
25
|
+
parser (2.7.1.3)
|
26
|
+
ast (~> 2.4.0)
|
27
|
+
pry (0.13.1)
|
28
|
+
coderay (~> 1.1)
|
29
|
+
method_source (~> 1.0)
|
30
|
+
pry-byebug (3.9.0)
|
31
|
+
byebug (~> 11.0)
|
32
|
+
pry (~> 0.13.0)
|
33
|
+
rainbow (3.0.0)
|
34
|
+
rake (12.3.3)
|
35
|
+
regexp_parser (1.7.1)
|
36
|
+
reverse_markdown (2.0.0)
|
37
|
+
nokogiri
|
38
|
+
rexml (3.2.4)
|
39
|
+
rspec (3.9.0)
|
40
|
+
rspec-core (~> 3.9.0)
|
41
|
+
rspec-expectations (~> 3.9.0)
|
42
|
+
rspec-mocks (~> 3.9.0)
|
43
|
+
rspec-core (3.9.2)
|
44
|
+
rspec-support (~> 3.9.3)
|
45
|
+
rspec-expectations (3.9.2)
|
46
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
47
|
+
rspec-support (~> 3.9.0)
|
48
|
+
rspec-mocks (3.9.1)
|
49
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
50
|
+
rspec-support (~> 3.9.0)
|
51
|
+
rspec-support (3.9.3)
|
52
|
+
rubocop (0.85.1)
|
53
|
+
parallel (~> 1.10)
|
54
|
+
parser (>= 2.7.0.1)
|
55
|
+
rainbow (>= 2.2.2, < 4.0)
|
56
|
+
regexp_parser (>= 1.7)
|
57
|
+
rexml
|
58
|
+
rubocop-ast (>= 0.0.3)
|
59
|
+
ruby-progressbar (~> 1.7)
|
60
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
61
|
+
rubocop-ast (0.0.3)
|
62
|
+
parser (>= 2.7.0.1)
|
63
|
+
ruby-progressbar (1.10.1)
|
64
|
+
solargraph (0.39.8)
|
65
|
+
backport (~> 1.1)
|
66
|
+
benchmark
|
67
|
+
bundler (>= 1.17.2)
|
68
|
+
e2mmap
|
69
|
+
jaro_winkler (~> 1.5)
|
70
|
+
maruku (~> 0.7, >= 0.7.3)
|
71
|
+
nokogiri (~> 1.9, >= 1.9.1)
|
72
|
+
parser (~> 2.3)
|
73
|
+
reverse_markdown (>= 1.0.5, < 3)
|
74
|
+
rubocop (~> 0.52)
|
75
|
+
thor (~> 1.0)
|
76
|
+
tilt (~> 2.0)
|
77
|
+
yard (~> 0.9, >= 0.9.24)
|
78
|
+
thor (1.0.1)
|
79
|
+
tilt (2.0.10)
|
80
|
+
unicode-display_width (1.7.0)
|
81
|
+
yard (0.9.25)
|
82
|
+
|
83
|
+
PLATFORMS
|
84
|
+
ruby
|
85
|
+
|
86
|
+
DEPENDENCIES
|
87
|
+
oso-oso!
|
88
|
+
pry-byebug (~> 3.9.0)
|
89
|
+
rake (~> 12.0)
|
90
|
+
rspec (~> 3.0)
|
91
|
+
solargraph (~> 0.39.8)
|
92
|
+
yard (~> 0.9.25)
|
93
|
+
|
94
|
+
BUNDLED WITH
|
95
|
+
2.1.4
|
data/Makefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
CARGO_FLAGS := $(shell [ -z $${RELEASE} ] && echo "" || echo "--all-features --release")
|
2
|
+
export CARGO_FLAGS
|
3
|
+
TARGET_DIR := $(shell [ -z $${RELEASE} ] && echo "debug" || echo "release")
|
4
|
+
LIB_EXT := $(shell [ $$(uname) = "Linux" ] && echo "so" || echo "dylib")
|
5
|
+
|
6
|
+
.PHONY: install rust-build test
|
7
|
+
|
8
|
+
rust-build:
|
9
|
+
$(MAKE) -C ../.. rust-build
|
10
|
+
cp ../../target/$(TARGET_DIR)/libpolar.$(LIB_EXT) ext/oso-oso/lib/libpolar.$(LIB_EXT)
|
11
|
+
|
12
|
+
install: rust-build
|
13
|
+
bundle install
|
14
|
+
|
15
|
+
test: install
|
16
|
+
bundle exec rake spec
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Oso::Oso
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'oso-oso'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle install
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install oso-oso
|
18
|
+
|
19
|
+
## Development
|
20
|
+
|
21
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
22
|
+
`rake spec` to run the tests. You can also run `bin/console` for an interactive
|
23
|
+
prompt that will allow you to experiment.
|
24
|
+
|
25
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
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).
|
30
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'oso'
|
6
|
+
|
7
|
+
polar = Oso::Polar.new.tap do |p| # rubocop:disable Lint/UselessAssignment
|
8
|
+
p.load_str('f(1); f(2); g(1); g(2); h(2); k(x) := f(x), h(x), g(x);')
|
9
|
+
puts 'f(x)', p.send(:query_str, 'f(x)').to_a
|
10
|
+
puts 'k(x)', p.send(:query_str, 'k(x)').to_a
|
11
|
+
|
12
|
+
p.load_str('foo(1, 2); foo(3, 4); foo(5, 6);')
|
13
|
+
expected = [{ 'x' => 1, 'y' => 2 }, { 'x' => 3, 'y' => 4 }, { 'x' => 5, 'y' => 6 }]
|
14
|
+
raise 'AssertionError' if p.send(:query_str, 'foo(x, y)').to_a != expected
|
15
|
+
|
16
|
+
class TestClass # rubocop:disable Style/Documentation
|
17
|
+
def my_method
|
18
|
+
1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
p.register_class(TestClass)
|
23
|
+
|
24
|
+
p.load_str('external(x, 3) := x = new TestClass{}.my_method;')
|
25
|
+
results = p.send(:query_str, 'external(1, x)')
|
26
|
+
p results.next
|
27
|
+
|
28
|
+
# p.load_str('testDebug() := debug(), foo(x, y), k(y);')
|
29
|
+
# p.send(:query_str, 'testDebug()').next
|
30
|
+
end
|
31
|
+
|
32
|
+
require 'pry'
|
33
|
+
Pry.start
|
data/bin/setup
ADDED
Binary file
|
Binary file
|
data/lib/oso.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'oso/http'
|
4
|
+
require 'oso/oso'
|
5
|
+
require 'oso/path_mapper'
|
6
|
+
require 'oso/polar'
|
7
|
+
require 'oso/version'
|
8
|
+
|
9
|
+
# Top-level namespace for oso authorization library.
|
10
|
+
module Oso
|
11
|
+
def self.new
|
12
|
+
::Oso::Oso.new
|
13
|
+
end
|
14
|
+
end
|
data/lib/oso/http.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Oso
|
4
|
+
# An HTTP resource.
|
5
|
+
class Http
|
6
|
+
def initialize(hostname: nil, path: nil, query: nil)
|
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
|
data/lib/oso/oso.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Oso
|
4
|
+
# Oso authorization API.
|
5
|
+
class Oso
|
6
|
+
def initialize
|
7
|
+
@polar = ::Oso::Polar.new
|
8
|
+
register_class(Http, name: 'Http')
|
9
|
+
register_class(PathMapper, name: 'PathMapper')
|
10
|
+
end
|
11
|
+
|
12
|
+
def load_file(file)
|
13
|
+
polar.load_file(file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_str(str)
|
17
|
+
polar.load_str(str)
|
18
|
+
end
|
19
|
+
|
20
|
+
def register_class(cls, name: nil) # rubocop:disable Naming/MethodParameterName
|
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
|
30
|
+
true
|
31
|
+
rescue StopIteration
|
32
|
+
false
|
33
|
+
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
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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
|
data/lib/oso/polar.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'oso/polar/errors'
|
4
|
+
require 'oso/polar/ffi'
|
5
|
+
require 'oso/polar/polar'
|
6
|
+
require 'oso/polar/predicate'
|
7
|
+
require 'oso/polar/query'
|
8
|
+
require 'oso/polar/query_event'
|
9
|
+
require 'oso/polar/variable'
|
10
|
+
|
11
|
+
module Oso
|
12
|
+
# Top-level namespace for Polar language library.
|
13
|
+
module Polar
|
14
|
+
def self.new
|
15
|
+
::Oso::Polar::Polar.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Oso
|
4
|
+
module Polar
|
5
|
+
# Base error type for Oso::Polar.
|
6
|
+
class Error < ::RuntimeError
|
7
|
+
attr_reader :stack_trace
|
8
|
+
|
9
|
+
# @param message [String]
|
10
|
+
# @param details [Hash]
|
11
|
+
def initialize(message = nil, details: nil)
|
12
|
+
@details = details
|
13
|
+
if details and details.key?("stack_trace")
|
14
|
+
@stack_trace = details['stack_trace']
|
15
|
+
else
|
16
|
+
@stack_trace = nil
|
17
|
+
end
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Expected to find an FFI error to convert into a Ruby exception but found none.
|
23
|
+
class FFIErrorNotFound < Error; end
|
24
|
+
|
25
|
+
# Generic runtime exception.
|
26
|
+
class PolarRuntimeError < Error; end
|
27
|
+
|
28
|
+
# Errors from across the FFI boundary.
|
29
|
+
|
30
|
+
class SerializationError < PolarRuntimeError; end
|
31
|
+
class UnsupportedError < PolarRuntimeError; end
|
32
|
+
class PolarTypeError < PolarRuntimeError; end
|
33
|
+
class StackOverflowError < PolarRuntimeError; end
|
34
|
+
|
35
|
+
# Errors originating from this side of the FFI boundary.
|
36
|
+
|
37
|
+
class UnregisteredClassError < PolarRuntimeError; end
|
38
|
+
class MissingConstructorError < PolarRuntimeError; end
|
39
|
+
class UnregisteredInstanceError < PolarRuntimeError; end
|
40
|
+
class DuplicateInstanceRegistrationError < PolarRuntimeError; end
|
41
|
+
class InvalidCallError < PolarRuntimeError; end
|
42
|
+
class InvalidConstructorError < PolarRuntimeError; end
|
43
|
+
class InlineQueryFailedError < PolarRuntimeError; end
|
44
|
+
class NullByteInPolarFileError < PolarRuntimeError; end
|
45
|
+
class UnexpectedPolarTypeError < PolarRuntimeError; end
|
46
|
+
class PolarFileExtensionError < PolarRuntimeError # rubocop:disable Style/Documentation
|
47
|
+
def initialize
|
48
|
+
super('Polar files must have .pol or .polar extension.')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
class PolarFileNotFoundError < PolarRuntimeError # rubocop:disable Style/Documentation
|
52
|
+
# @param file [String]
|
53
|
+
def initialize(file)
|
54
|
+
super("Could not find file: #{file}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
class DuplicateClassAliasError < PolarRuntimeError # rubocop:disable Style/Documentation
|
58
|
+
# @param as [String]
|
59
|
+
# @param old [Class]
|
60
|
+
# @param new [Class]
|
61
|
+
def initialize(name:, old:, new:) # rubocop:disable Naming/MethodParameterName
|
62
|
+
super("Attempted to alias #{new} as '#{name}', but #{old} already has that alias.")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Generic operational exception.
|
67
|
+
class OperationalError < Error; end
|
68
|
+
class UnknownError < OperationalError; end
|
69
|
+
|
70
|
+
# Catch-all for a parsing error that doesn't match any of the more specific types.
|
71
|
+
class ParseError < Error
|
72
|
+
class ExtraToken < ParseError; end
|
73
|
+
class IntegerOverflow < ParseError; end
|
74
|
+
class InvalidTokenCharacter < ParseError; end
|
75
|
+
class InvalidToken < ParseError; end
|
76
|
+
class UnrecognizedEOF < ParseError; end
|
77
|
+
class UnrecognizedToken < ParseError; end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Generic Polar API exception.
|
81
|
+
class ApiError < Error; end
|
82
|
+
class ParameterError < ApiError; end
|
83
|
+
end
|
84
|
+
end
|