oso-cloud 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 062aa3d76c978722bbc9242d4a7c594eb0feb62146559dcc9a07b3d24f81f5c2
4
- data.tar.gz: 8f5afb67fd4e4242c35c7808df00b0bf0bbcd9fcd83257d3a34f218a33625070
3
+ metadata.gz: f782a7cb7f39a37115f0a16e229d69b09f44d91a26228c3673dcd590b2395183
4
+ data.tar.gz: 3e396a943707635a5ce4659bdb39b283e20cd1f06fb7b2bb7dc008fd2cea01ae
5
5
  SHA512:
6
- metadata.gz: bd87423b50e294bbf5ea4761a9287fd9a885b94a803ba8a51f56b428197b1bb37612828e7e58c8124e140ff6a0173d7f5614b6eb86141e6a2aeb4affa705ac83
7
- data.tar.gz: b3b1bfd172c4adcd344b2531875d1337cf0a34b3ccd12d0536a1c419a51c1a333ff2363f9d7ca9ab686f468de25bc0696ae2cae60bee2bfcc7ae59e83a956abc
6
+ metadata.gz: 8af7ceabb0bb8c434e5dc8dc378d40b3dcb08a6a4f17f464538f21f026349d9dcef3a28f79176dd893543f1be1e6e5560c0892ba8d2b73953b990c0d078a418b
7
+ data.tar.gz: 2c87cb55cceedfde35f917e78882b02da50dade1bb1565fffa1648eb276754170a6ea79716828e21b6d345ec857f6f89d785df38a7513f8173acd4900a3215aa
data/Gemfile.lock CHANGED
@@ -1,17 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oso-cloud (0.3.0)
4
+ oso-cloud (0.3.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ minitest (5.15.0)
9
10
  rake (12.3.3)
10
11
 
11
12
  PLATFORMS
12
13
  ruby
13
14
 
14
15
  DEPENDENCIES
16
+ minitest (~> 5.15)
15
17
  oso-cloud!
16
18
  rake (~> 12.0)
17
19
 
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
data/lib/oso/client.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'json'
2
- require 'logger'
3
2
  require 'net/http'
4
3
  require 'uri'
5
4
 
@@ -7,73 +6,75 @@ require 'oso/version'
7
6
 
8
7
  module Oso
9
8
  class Client
10
- def initialize(url: 'https://cloud.osohq.com', api_key: nil, logger: nil)
9
+ def initialize(url: 'https://cloud.osohq.com', api_key: nil)
11
10
  @url = url
12
11
  @api_key = api_key
13
- @logger = logger || Logger.new(STDOUT)
14
- # TODO: why does this need to be configurable?
15
- # @to_type_and_id = method(default_to_type_and_id)
12
+ end
13
+
14
+ def policy(policy)
15
+ POST('policy', { src: policy })
16
16
  end
17
17
 
18
18
  def authorize(actor, action, resource)
19
- actor_type, actor_id = default_to_type_and_id actor
20
- resource_type, resource_id = default_to_type_and_id resource
21
- result = post('authorize', {
22
- actor_type: actor_type, actor_id: actor_id,
23
- action: action,
24
- resource_type: resource_type, resource_id: resource_id
25
- })
19
+ actor_typed_id = extract_typed_id actor
20
+ resource_typed_id = extract_typed_id resource
21
+ result = POST('authorize', {
22
+ actor_type: actor_typed_id.type, actor_id: actor_typed_id.id,
23
+ action: action,
24
+ resource_type: resource_typed_id.type, resource_id: resource_typed_id.id
25
+ })
26
26
  allowed = result['allowed']
27
- @logger.debug { "AUTHORIZING (#{actor}, #{action}, #{resource}) => ALLOWED? = #{allowed ? 'true' : 'false'} " }
28
-
29
27
  allowed
30
28
  end
31
29
 
32
30
  def list(actor, action, resource_type)
33
- actor_type, actor_id = default_to_type_and_id actor
34
- result = post('list',
35
- {
36
- actor_type: actor_type, actor_id: actor_id,
37
- action: action,
38
- resource_type: resource_type
39
- })
31
+ actor_typed_id = extract_typed_id actor
32
+ result = POST('list', {
33
+ actor_type: actor_typed_id.type, actor_id: actor_typed_id.id,
34
+ action: action,
35
+ resource_type: resource_type,
36
+ })
40
37
  results = result['results']
41
- @logger.debug { "AUTHORIZING (#{actor}, #{action}, #{resource_type}). RESULTS: #{results}" }
42
-
43
38
  results
44
39
  end
45
40
 
46
- def add_role(actor, role_name, resource)
47
- add_role_or_relation('role', resource, role_name, actor)
41
+ def tell(predicate, *args)
42
+ typed_args = args.map { |a| extract_typed_id a}
43
+ POST('facts', { predicate: predicate, args: typed_args })
48
44
  end
49
45
 
50
- def delete_role(actor, role_name, resource)
51
- delete_role_or_relation('role', resource, role_name, actor)
46
+ def bulk_tell(facts)
47
+ params = facts.map { |predicate, *args|
48
+ typed_args = args.map { |a| extract_typed_id a}
49
+ { predicate: predicate, args: typed_args }
50
+ }
51
+ POST('bulk_load', params)
52
52
  end
53
53
 
54
- def add_relation(subject, name, object)
55
- add_role_or_relation('relation', subject, name, object)
54
+ def delete(predicate, *args)
55
+ typed_args = args.map { |a| extract_typed_id a}
56
+ DELETE('facts', { predicate: predicate, args: typed_args })
56
57
  end
57
58
 
58
- def delete_relation(subject, name, object)
59
- delete_role_or_relation('relation', subject, name, object)
59
+ def bulk_delete(facts)
60
+ params = facts.map { |predicate, *args|
61
+ typed_args = args.map { |a| extract_typed_id a}
62
+ { predicate: predicate, args: typed_args }
63
+ }
64
+ POST('bulk_delete', params)
60
65
  end
61
66
 
62
- def get_roles(resource: nil, role: nil, actor: nil)
63
- params = {}
64
- unless actor.nil?
65
- actor_type, actor_id = default_to_type_and_id actor
66
- params[:actor_type] = actor_type
67
- params[:actor_id] = actor_id
68
- end
69
- unless resource.nil?
70
- resource_type, resource_id = default_to_type_and_id resource
71
- params[:resource_type] = resource_type
72
- params[:resource_id] = resource_id
67
+ def get(predicate, *args)
68
+ params = {predicate: predicate}
69
+ args.each_with_index do |arg, i|
70
+ typed_id = extract_arg_query(arg)
71
+ if typed_id
72
+ params["args.#{i}.type"] = typed_id.type
73
+ params["args.#{i}.id"] = typed_id.id
74
+ end
73
75
  end
74
- params[:role] = role unless role.nil?
75
76
 
76
- get('roles')
77
+ GET('facts', params)
77
78
  end
78
79
 
79
80
  private
@@ -82,65 +83,68 @@ module Oso
82
83
  {
83
84
  "Authorization" => "Basic %s" % @api_key,
84
85
  "User-Agent" => "Oso Cloud (ruby)",
85
- "Accept": "application/json"
86
+ "Accept": "application/json",
87
+ "Content-Type": "application/json"
86
88
  }
87
89
  end
88
90
 
89
- def get(path)
90
- result = Net::HTTP.get(URI("#{@url}/api/#{path}"), headers)
91
+
92
+ def GET(path, params)
93
+ uri = URI("#{@url}/api/#{path}")
94
+ uri.query = URI::encode_www_form(params)
95
+ use_ssl = (uri.scheme == 'https')
96
+
97
+ result = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl ) { |http|
98
+ http.request(Net::HTTP::Get.new(uri, headers)) {|r|
99
+ r.read_body
100
+ }
101
+ }
91
102
  handle_result result
103
+
92
104
  end
93
105
 
94
- def post(path, params)
106
+ def POST(path, params)
95
107
  result = Net::HTTP.post(URI("#{@url}/api/#{path}"), params.to_json, headers)
96
108
  handle_result result
97
109
  end
98
110
 
99
- def delete(path, params)
100
- result = Net::HTTP.delete(URI("#{@url}/api/#{path}"), params.to_json, headers)
111
+ def DELETE(path, params)
112
+ uri = URI("#{@url}/api/#{path}")
113
+ use_ssl = (uri.scheme == 'https')
114
+ result = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl ) { |http|
115
+ http.request(Net::HTTP::Delete.new(uri, headers), params.to_json) {|r|
116
+ r.read_body
117
+ }
118
+ }
101
119
  handle_result result
102
120
  end
103
121
 
104
- # TODO: why does this need to be configurable?
105
- def default_to_type_and_id(obj)
106
- if obj.nil?
107
- %w[null null]
108
- else
109
- [obj.class.to_s, obj.id.to_s]
110
- end
111
- end
112
-
113
122
  def handle_result(result)
114
123
  unless result.is_a?(Net::HTTPSuccess)
115
124
  raise "Got an unexpected error from Oso Service: #{result.code}\n#{result.body}"
116
125
  end
117
126
 
118
- # TODO: Always JSON?
119
127
  JSON.parse(result.body)
120
128
  end
121
129
 
122
- def to_params(role_or_relation, from, name, to)
123
- from_type, from_id = default_to_type_and_id from
124
- to_type, to_id = default_to_type_and_id to
130
+ def extract_typed_id(x)
131
+ return TypedId.new(type: "String", id: x) if x.is_a? String
125
132
 
126
- from_name = role_or_relation == 'role' ? 'resource' : 'from'
127
- to_name = role_or_relation == 'role' ? 'actor' : 'to'
133
+ raise "#{x} does not have an 'id' field" unless x.respond_to? :id
134
+ raise "Invalid 'id' field on #{x}: #{x.id}" if x.id.nil?
128
135
 
129
- {
130
- "#{from_name}_id" => from_id,
131
- "#{from_name}_type" => from_type,
132
- role_or_relation.to_s => name,
133
- "#{to_name}_id" => to_id,
134
- "#{to_name}_type" => to_type
135
- }
136
+ TypedId.new(type: x.class.name, id: x.id.to_s)
136
137
  end
137
138
 
138
- def add_role_or_relation(role_or_relation, from, name, to)
139
- post("#{role_or_relation}s", to_params(role_or_relation, from, name, to))
139
+ def extract_arg_query(x)
140
+ return nil if x.nil?
141
+ extract_typed_id(x)
140
142
  end
141
143
 
142
- def delete_role_or_relation(role_or_relation, from, name, to)
143
- delete("#{role_or_relation}s", to_params(role_or_relation, from, name, to))
144
+ TypedId = Struct.new(:type, :id, keyword_init: true) do
145
+ def to_json(*args)
146
+ to_h.to_json(*args)
147
+ end
144
148
  end
145
149
  end
146
150
  end
data/lib/oso/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Oso
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.3.1'.freeze
3
3
  end
data/oso-cloud.gemspec CHANGED
@@ -18,4 +18,6 @@ Gem::Specification.new do |spec|
18
18
  spec.bindir = 'exe'
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'minitest', '~> 5.15'
21
23
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oso-cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oso Security, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-13 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-05-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.15'
13
27
  description:
14
28
  email:
15
29
  - support@osohq.com