bali 2.4.0 → 6.0.0rc1
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 +5 -13
- data/.rspec +1 -0
- data/lib/bali.rb +23 -14
- data/lib/bali/activerecord.rb +8 -0
- data/lib/bali/authorizer.rb +24 -0
- data/lib/bali/config.rb +12 -0
- data/lib/bali/dsl_error.rb +3 -0
- data/lib/bali/{foundations/exceptions/bali_error.rb → error.rb} +0 -0
- data/lib/bali/judge.rb +239 -0
- data/lib/bali/printer.rb +16 -26
- data/lib/bali/railtie.rb +13 -0
- data/lib/bali/role.rb +79 -0
- data/lib/bali/rule.rb +17 -0
- data/lib/bali/ruler.rb +36 -0
- data/lib/bali/rules.rb +68 -0
- data/lib/bali/tasks/bali/print_rules.rake +9 -0
- data/lib/bali/version.rb +1 -1
- data/lib/generators/rails/USAGE +8 -0
- data/lib/generators/rails/rules_generator.rb +17 -0
- data/lib/generators/rails/templates/rules.rb +4 -0
- data/lib/generators/rspec/rules_generator.rb +12 -0
- data/lib/generators/rspec/templates/rules_spec.rb +7 -0
- metadata +104 -47
- data/lib/bali/dsl/map_rules_dsl.rb +0 -75
- data/lib/bali/dsl/rules_for_dsl.rb +0 -130
- data/lib/bali/foundations/all_foundations.rb +0 -17
- data/lib/bali/foundations/exceptions/authorization_error.rb +0 -38
- data/lib/bali/foundations/exceptions/dsl_error.rb +0 -3
- data/lib/bali/foundations/exceptions/objection_error.rb +0 -3
- data/lib/bali/foundations/judger/judge.rb +0 -329
- data/lib/bali/foundations/judger/negative_judge.rb +0 -40
- data/lib/bali/foundations/judger/positive_judge.rb +0 -41
- data/lib/bali/foundations/role_extractor.rb +0 -61
- data/lib/bali/foundations/rule/rule.rb +0 -55
- data/lib/bali/foundations/rule/rule_class.rb +0 -54
- data/lib/bali/foundations/rule/rule_group.rb +0 -91
- data/lib/bali/integrators/all_integrators.rb +0 -8
- data/lib/bali/integrators/rule_class_integrator.rb +0 -27
- data/lib/bali/integrators/rule_group_integrator.rb +0 -29
- data/lib/bali/integrators/rule_integrator.rb +0 -56
- data/lib/bali/objector.rb +0 -173
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MzhkMjlhYzA4NDU3M2M4ODE1ODkxZTU0ZDA3NDJjZGUwODNmOTZhYg==
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6d59bbcd74624299c6680e6b33787924db86c22e95ea1eac9817835c90c8fd1b
|
4
|
+
data.tar.gz: 656f6455652098bd35ed58ea60434ace5643f2c5d6063a4ccf1e2b235156a79b
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YWViMDExYzMyZjI5Y2YyOTYxNDdhZWJmYWU5YTVlNDYwODgwZDA1NDhhZWRm
|
11
|
-
NTliMTI1ZGEyMjNjY2QyNGEwNTM5YjNjNDc5OGIxYjk2MTYyNTI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NTMzMzBjNTczZmM2MDE1YmI0NjA0ZjY1MDRhZGZmNWRiNTRjZGYzMDRmMWI4
|
14
|
-
Zjk4ZTEzNGZkZDg0NzFmZjg0YjYwNDQ2OGVlYjgwNzkwNTY4MGFlZDE1NjI3
|
15
|
-
ZDI1ZjlhNmFhODA4OGQzZDFhMjBkNjdjMjk1ZTI0YTkzZmQ4MTY=
|
6
|
+
metadata.gz: e66ac8fffcacebda88e299bef9e0ef512d0dbed4f9e4b309df3bec6b3afabe4af4fd2182f501df0847c396f918adcc128c68846fd163a049b56b2ec2c807884b
|
7
|
+
data.tar.gz: a629ff732df6cb1bc347de1bab16dafb87ad29d87029c3a87b30a4b0301da430cf15e47f5b6844f104a071d0f755dce18a0d29277a07c0f4bd5bdde12e7fd5e9
|
data/.rspec
CHANGED
data/lib/bali.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require_relative "bali/version"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
begin
|
4
|
+
require "rails"
|
5
|
+
require "rails/generators"
|
6
|
+
rescue LoadError => e
|
7
|
+
# ignores
|
8
|
+
end
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
require "zeitwerk"
|
11
|
+
loader = Zeitwerk::Loader.for_gem
|
12
|
+
loader.ignore("#{__dir__}/generators")
|
13
|
+
loader.ignore("#{__dir__}/bali/activerecord.rb")
|
14
|
+
loader.setup
|
12
15
|
|
13
16
|
module Bali
|
14
17
|
# mapping class to a RuleClass
|
@@ -21,13 +24,19 @@ module Bali
|
|
21
24
|
TRANSLATED_SUBTARGET_ROLES = {}
|
22
25
|
|
23
26
|
extend self
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
|
28
|
+
def config
|
29
|
+
@config ||= Bali::Config.new
|
27
30
|
end
|
28
31
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
+
def configure
|
33
|
+
yield config
|
34
|
+
end
|
35
|
+
|
36
|
+
if defined? Rails
|
37
|
+
require "bali/railtie"
|
38
|
+
require "bali/activerecord"
|
32
39
|
end
|
33
40
|
end
|
41
|
+
|
42
|
+
loader.eager_load
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bali::Authorizer
|
2
|
+
def self.included(base)
|
3
|
+
base.extend Bali::Authorizer::Statics
|
4
|
+
end
|
5
|
+
|
6
|
+
def can?(actor_or_roles, operation = nil)
|
7
|
+
self.class.can?(actor_or_roles, operation, self)
|
8
|
+
end
|
9
|
+
|
10
|
+
def cant?(actor_or_roles, operation = nil)
|
11
|
+
self.class.cant?(actor_or_roles, operation, self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# to allow class-level objection
|
16
|
+
module Bali::Authorizer::Statics
|
17
|
+
def can?(actor_or_roles, operation, record = self)
|
18
|
+
Bali::Judge.check(:can, actor_or_roles, operation, record)
|
19
|
+
end
|
20
|
+
|
21
|
+
def cant?(actor_or_roles, operation, record = self)
|
22
|
+
Bali::Judge.check(:cant, actor_or_roles, operation, record)
|
23
|
+
end
|
24
|
+
end
|
data/lib/bali/config.rb
ADDED
File without changes
|
data/lib/bali/judge.rb
ADDED
@@ -0,0 +1,239 @@
|
|
1
|
+
class Bali::Judge
|
2
|
+
# Fuzy value is possible when the evaluation is not yet clear cut, for example in this case:
|
3
|
+
#
|
4
|
+
# role :finance do
|
5
|
+
# cant :view
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# others do
|
9
|
+
# can :view
|
10
|
+
# can :index
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Checking cant view for finance role results in a definite false, but
|
14
|
+
# checking on index for the same role results in FUZY_TRUE. Eventually, all FUZY value will be
|
15
|
+
# normal TRUE or FALSE if no definite counterpart is found.
|
16
|
+
|
17
|
+
FUZY_FALSE = -2
|
18
|
+
FUZY_TRUE = 2
|
19
|
+
DEFINITE_FALSE = -1
|
20
|
+
DEFINITE_TRUE = 1
|
21
|
+
|
22
|
+
attr_accessor :term,
|
23
|
+
:actor,
|
24
|
+
:role,
|
25
|
+
:operation,
|
26
|
+
:record,
|
27
|
+
:should_cross_check
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def check(term, actor_or_roles, operation, record)
|
31
|
+
if operation.nil?
|
32
|
+
# eg: user.can? :sign_in
|
33
|
+
operation = actor_or_roles
|
34
|
+
actor_or_roles = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
judgement_value = default_value = term == :can ? false : true
|
38
|
+
roles = Bali::Role.formalize actor_or_roles
|
39
|
+
|
40
|
+
roles.each do |role|
|
41
|
+
judge = Bali::Judge.new(
|
42
|
+
term: term,
|
43
|
+
role: role,
|
44
|
+
actor: actor_or_roles,
|
45
|
+
operation: operation,
|
46
|
+
record: record
|
47
|
+
)
|
48
|
+
|
49
|
+
judgement_value = judge.judgement
|
50
|
+
break if judgement_value != default_value
|
51
|
+
end
|
52
|
+
|
53
|
+
judgement_value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize(term:,
|
58
|
+
actor:,
|
59
|
+
role:,
|
60
|
+
operation:,
|
61
|
+
record:,
|
62
|
+
should_cross_check: true)
|
63
|
+
|
64
|
+
@term = term
|
65
|
+
@role = role
|
66
|
+
@actor = actor
|
67
|
+
@operation = operation
|
68
|
+
@record = record
|
69
|
+
@should_cross_check = should_cross_check
|
70
|
+
end
|
71
|
+
|
72
|
+
def judgement
|
73
|
+
our_holy_judgement = natural_value if no_rule_group?
|
74
|
+
|
75
|
+
if our_holy_judgement.nil? && rule.nil? && may_have_reservation?
|
76
|
+
our_holy_judgement = cross_check_reverse_value(cross_check_judge.judgement)
|
77
|
+
end
|
78
|
+
|
79
|
+
if our_holy_judgement.nil? && rule.nil?
|
80
|
+
cross_check_value = nil
|
81
|
+
# default if can? for undefined rule is false, after related clause
|
82
|
+
# cant be found in cant?
|
83
|
+
if should_cross_check
|
84
|
+
cross_check_value = cross_check_judge.judgement
|
85
|
+
end
|
86
|
+
|
87
|
+
# if cross check value nil, then the reverse rule is not defined,
|
88
|
+
# let's determine whether they can do anything or not
|
89
|
+
if cross_check_value.nil?
|
90
|
+
# rule_group can be nil for when user checking under undefined rule-group
|
91
|
+
if rule_group
|
92
|
+
if rule_group.can_all?
|
93
|
+
our_holy_judgement = term == :cant ? DEFINITE_FALSE : DEFINITE_TRUE
|
94
|
+
elsif rule_group.cant_all?
|
95
|
+
our_holy_judgement = term == :cant ? DEFINITE_TRUE : DEFINITE_FALSE
|
96
|
+
end
|
97
|
+
|
98
|
+
end # if rule_group exist
|
99
|
+
else
|
100
|
+
# process value from cross checking
|
101
|
+
|
102
|
+
if otherly_rule && (cross_check_value == FUZY_FALSE || cross_check_value == FUZY_TRUE)
|
103
|
+
# give chance to check at others block
|
104
|
+
@rule = otherly_rule
|
105
|
+
else
|
106
|
+
our_holy_judgement = cross_check_reverse_value(cross_check_value)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end # if our judgement nil and rule is nil
|
110
|
+
|
111
|
+
# if our holy judgement is still nil, but rule is defined
|
112
|
+
if our_holy_judgement.nil? && rule
|
113
|
+
if rule.conditional?
|
114
|
+
our_holy_judgement = run_condition(rule, actor, record)
|
115
|
+
else
|
116
|
+
our_holy_judgement = DEFINITE_TRUE
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# return fuzy if otherly rule defines contrary to this term
|
121
|
+
if our_holy_judgement.nil? && rule.nil? && (other_rule_group && other_rule_group.find_rule(reversed_term, operation))
|
122
|
+
if rule_group && (rule_group.can_all? || rule_group.cant_all?)
|
123
|
+
# don't overwrite our holy judgement with fuzy value if rule group
|
124
|
+
# zeus/plant, because zeus/plant is more definite than any fuzy values
|
125
|
+
# eventhough the rule is abstractly defined
|
126
|
+
else
|
127
|
+
our_holy_judgement = term == :cant ? FUZY_TRUE : FUZY_FALSE
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# if at this point still nil, well,
|
132
|
+
# return the natural value for this judge
|
133
|
+
if our_holy_judgement.nil?
|
134
|
+
if otherly_rule
|
135
|
+
our_holy_judgement = FUZY_TRUE
|
136
|
+
else
|
137
|
+
our_holy_judgement = natural_value
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
return !should_cross_check ?
|
142
|
+
our_holy_judgement :
|
143
|
+
|
144
|
+
# translate response for value above to traditional true/false
|
145
|
+
# holy judgement refer to non-standard true/false being used inside Bali
|
146
|
+
# which need to be translated from other beings to know
|
147
|
+
our_holy_judgement > 0
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def record_class
|
153
|
+
record.is_a?(Class) ? record : record.class
|
154
|
+
end
|
155
|
+
|
156
|
+
def ruler
|
157
|
+
@ruler ||= Bali::Ruler.for record_class
|
158
|
+
end
|
159
|
+
|
160
|
+
def rule_group_for(role)
|
161
|
+
ruler.nil? ? nil : ruler[role]
|
162
|
+
end
|
163
|
+
|
164
|
+
def rule_group
|
165
|
+
@rule_group ||= rule_group_for role
|
166
|
+
end
|
167
|
+
|
168
|
+
def other_rule_group
|
169
|
+
@other_rule_group ||= rule_group_for nil
|
170
|
+
end
|
171
|
+
|
172
|
+
def no_rule_group?
|
173
|
+
rule_group.nil? && other_rule_group.nil?
|
174
|
+
end
|
175
|
+
|
176
|
+
def rule
|
177
|
+
# rule group may be nil, for when user checking for undefined rule group
|
178
|
+
@rule ||= rule_group ? rule_group.find_rule(term, operation) : nil
|
179
|
+
end
|
180
|
+
|
181
|
+
def otherly_rule
|
182
|
+
@otherly_rule ||= other_rule_group ? other_rule_group.find_rule(term, operation) : nil
|
183
|
+
end
|
184
|
+
|
185
|
+
def cross_check_judge
|
186
|
+
@cross_check_judge ||= begin
|
187
|
+
Bali::Judge.new(
|
188
|
+
term: reversed_term,
|
189
|
+
role: role,
|
190
|
+
operation: operation,
|
191
|
+
record: record,
|
192
|
+
should_cross_check: false,
|
193
|
+
actor: actor
|
194
|
+
)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def reversed_term
|
199
|
+
case term
|
200
|
+
when :can then :cant
|
201
|
+
when :cant then :can
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def natural_value
|
206
|
+
term == :cant ? DEFINITE_TRUE : DEFINITE_FALSE
|
207
|
+
end
|
208
|
+
|
209
|
+
# returns true if we need to check rule that can overwrite
|
210
|
+
# the most powerful rule defined
|
211
|
+
def may_have_reservation?
|
212
|
+
term == :cant ?
|
213
|
+
(rule_group && rule_group.cant_all?) :
|
214
|
+
(rule_group && rule_group.can_all?)
|
215
|
+
end
|
216
|
+
|
217
|
+
def run_condition(rule, actor, record)
|
218
|
+
# must test first
|
219
|
+
conditional = rule.conditional
|
220
|
+
case conditional.arity
|
221
|
+
when 0
|
222
|
+
return conditional.() ? DEFINITE_TRUE : DEFINITE_FALSE
|
223
|
+
when 1
|
224
|
+
return conditional.(record) ? DEFINITE_TRUE : DEFINITE_FALSE
|
225
|
+
when 2
|
226
|
+
return conditional.(record, actor) ? DEFINITE_TRUE : DEFINITE_FALSE
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def cross_check_reverse_value(cross_check_value)
|
231
|
+
case cross_check_value
|
232
|
+
when DEFINITE_TRUE then DEFINITE_FALSE
|
233
|
+
when DEFINITE_FALSE then DEFINITE_TRUE
|
234
|
+
when FUZY_FALSE then FUZY_TRUE
|
235
|
+
when FUZY_TRUE then FUZY_FALSE
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
data/lib/bali/printer.rb
CHANGED
@@ -4,7 +4,7 @@ require "date"
|
|
4
4
|
# module that would allow all defined rules to be printed for check
|
5
5
|
module Bali::Printer
|
6
6
|
module_function
|
7
|
-
|
7
|
+
|
8
8
|
SEPARATOR = " " * 6
|
9
9
|
SUBTARGET_TITLE_SEPARATOR = SEPARATOR + ("-" * 80) + "\n"
|
10
10
|
|
@@ -14,50 +14,40 @@ module Bali::Printer
|
|
14
14
|
# build up the string for pretty printing rules
|
15
15
|
Bali::RULE_CLASS_MAP.each do |klass, rule_class|
|
16
16
|
output << "===== #{klass.to_s} =====\n\n"
|
17
|
-
|
18
|
-
rule_class.rule_groups.each do |subtarget, rule_group|
|
19
|
-
print_rule_group(rule_group, output)
|
20
|
-
end
|
21
17
|
|
22
|
-
|
23
|
-
|
18
|
+
rule_class.roles.each do |subtarget, role|
|
19
|
+
print_role role, output
|
24
20
|
end
|
21
|
+
|
25
22
|
output << "\n\n"
|
26
23
|
end
|
27
24
|
|
28
|
-
output << "
|
29
|
-
output << DateTime.now.strftime("Printed at %d-%m-%Y %I:%M%p %Z")
|
25
|
+
output << DateTime.now.strftime("Printed at %Y-%m-%d %I:%M%p %Z")
|
30
26
|
|
31
27
|
output.string
|
32
28
|
end
|
33
29
|
|
34
|
-
def
|
35
|
-
|
36
|
-
subtarget =
|
37
|
-
|
38
|
-
is_zeus = rule_group.zeus?
|
39
|
-
is_plant = rule_group.plant?
|
30
|
+
def print_role role, target_io
|
31
|
+
subtarget = role.subtarget.to_s.capitalize
|
32
|
+
subtarget = "By default" if subtarget.blank?
|
33
|
+
can_all = role.can_all?
|
40
34
|
counter = 0
|
41
35
|
|
42
|
-
target_io << "#{SEPARATOR}#{subtarget}
|
36
|
+
target_io << "#{SEPARATOR}#{subtarget}\n"
|
43
37
|
target_io << SUBTARGET_TITLE_SEPARATOR
|
44
|
-
|
45
|
-
if
|
38
|
+
|
39
|
+
if can_all
|
46
40
|
target_io << "#{SEPARATOR} #{counter+=1}. #{subtarget} can do anything except if explicitly stated otherwise\n"
|
47
|
-
elsif is_plant
|
48
|
-
target_io << "#{SEPARATOR} #{counter+=1}. #{subtarget} cannot do anything except if explicitly stated otherwise\n"
|
49
41
|
end
|
50
|
-
|
51
|
-
|
42
|
+
|
43
|
+
role.rules.each do |rule|
|
52
44
|
written_rule = StringIO.new
|
53
|
-
written_rule << "#{SEPARATOR} #{counter+=1}. #{subtarget} #{rule.
|
54
|
-
if rule.
|
45
|
+
written_rule << "#{SEPARATOR} #{counter+=1}. #{subtarget} #{rule.term} #{rule.operation}"
|
46
|
+
if rule.conditional?
|
55
47
|
written_rule << ", with condition"
|
56
48
|
end
|
57
49
|
written_rule << "\n"
|
58
50
|
target_io << written_rule.string
|
59
51
|
end
|
60
|
-
|
61
|
-
target_io << "\n"
|
62
52
|
end
|
63
53
|
end
|
data/lib/bali/railtie.rb
ADDED