bali 2.0.0 → 2.1.1

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 CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0e4656b297055440ffa3f95c4b402ef9205944e3
4
- data.tar.gz: 00793b60bed79d06ac0ae2d9edaf07a8b6331bc4
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OGE5M2M0ZmE1MGJmMDc4M2ZmM2Q3NzlkNGY3OTAxMDUzNGEwYTBiNg==
5
+ data.tar.gz: !binary |-
6
+ NmQ0MGNkOGRiMjJlZjc1YTFmZmMzN2FjNDNiNTU1N2I3OTZkZjMyYg==
5
7
  SHA512:
6
- metadata.gz: f29d7f76ca30d09aeb996f7bf1a7ad8ccb340552ff68744fd75a1ba7b5a823dabb033022176f545fa5c439495dfa3bfe5b7a8620dad6a62766f3196398c17f5e
7
- data.tar.gz: a275d79a14aab95e03efb0401f152884c16cfe02f256eb6c16d16bb5936989421c51a6a4318c8885174d09006fcbec92a828d89ac46549bee9404eb44ec0bcfb
8
+ metadata.gz: !binary |-
9
+ NWUxZDA3YmFkMDI1YzIwMDUzMjdmNTIxNjBhZmZjNTZmNzc3NWUxMjNmNDU4
10
+ MmYzNDgxNzczZjc1ODcxMDU0N2FkN2U0ZDM0NDhmYzI1NzY5N2ZjZTAyZGY1
11
+ MTBiYTQ1ZjU2ZjhhNmUxNjZhZjJkYWM1NTk1Yzk4ZDAyNjM2OWM=
12
+ data.tar.gz: !binary |-
13
+ NWUwZTM5NTA5NGFiZDI3NDgxMGM5YTlkYzM2Mzc0Y2NjM2IyMmZiYTNiODFh
14
+ NWMzMzMzZjgyY2QyZWM4MTc1YzdlNGI0NmE0YzM3YmZjNTg4M2I0OWFmZTAw
15
+ MWE0Mzk4OWY3YzI2NTVhZjIxOGNkYWRjOGE0NzhiMzYzZWQ2NjE=
@@ -0,0 +1,69 @@
1
+ ## Changelog
2
+
3
+ == Version 1.0.0beta1
4
+
5
+ 1. Initial version
6
+
7
+ == Version 1.0.0rc1
8
+
9
+ 1. Fix bug where user can't check on class
10
+ 2. Adding new clause: cant_all
11
+
12
+ == Version 1.0.0rc2
13
+
14
+ 1. [Fix bug when class's name, as a constant, is reloaded](http://stackoverflow.com/questions/2509350/rails-class-object-id-changes-after-i-make-a-request) (re-allocated to different address in the memory)
15
+ 2. Allow describing rule for `nil`, useful if user is not authenticated thus role is probably `nil`
16
+ 3. Remove pry from development dependency
17
+
18
+ == Version 1.0.0rc3
19
+
20
+ 1. Each target class should includes `Bali::Objector`, for the following reasons:
21
+ - Makes it clear that class do want to include the Bali::Objector
22
+ - Transparant, and thus less confusing as to where "can?" and "cant" come from
23
+ - When ruby re-parse the class's codes for any reasons, parser will be for sure include Bali::Objector
24
+ 2. Return `true` to any `can?` for undefined target/subtarget alike
25
+ 3. Return `false` to any `cant?` for undefined target/subtarget alike
26
+
27
+ == Version 1.0.0
28
+
29
+ 1. Released the stable version of this gem
30
+
31
+ == Version 1.1.0rc1
32
+
33
+ 1. Ability for rule class to be parsed later by passing `later: true` to rule class definition
34
+ 2. Add `Bali.parse` and `Bali.parse!` (`Bali.parse!` executes "later"-tagged rule class, Bali.parse executes automatically after all rules are defined)
35
+ 3. Added more thorough testing specs
36
+ 4. Proc can be served under `unless` for defining the rule's decider
37
+
38
+ == Version 1.1.0rc2
39
+
40
+ 1. Ability to check `can?` and `cant?` for subtarget with multiple roles
41
+ 2. Describe multiple rules at once for multiple subtarget
42
+
43
+ == Version 1.2.0
44
+
45
+ 1. Passing real object as subtarget's role, instead of symbol or array of symbol
46
+ 2. Clause can also yielding user, along with the object in question
47
+
48
+ == Version 2.0.0rc1
49
+
50
+ 1. `Bali::AuthorizationError` subclass of `StandardError` tailored for raising error regarding with authorisation
51
+ 2. Deprecating `cant`, `cant?`, and `cant_all` in favor of `cannot`, `cannot?` and `cannot_all`
52
+ 3. new objectors `can!` and `cannot!` to raise error on inappropriate access
53
+
54
+ == Version 2.0.0
55
+
56
+ 1. Release!
57
+
58
+ == Version 2.1.0
59
+
60
+ 1. `others` block would allow for rule definitions within it to be applied for all undefined subtargets of a target
61
+ 2. Fixing bug when roles_for of a user object retrieves `nil` as the user's role, it won't acknowledge that the user is indeed having `nil`-role and raising an error instead.
62
+ 3. Inherits rules by passing `:inherits` option when defining `rules_for`
63
+ 4. `clear_rules` within `describe` or `others` block to remove all inherited rules (or any rules previously defined) for that subtarget
64
+ 5. Adding `Bali::Printer` that would enable for rules to be printed by calling `.pretty_print` on it
65
+
66
+ == Version 2.1.1
67
+
68
+ 1. Bug fixes on `clear_rules` which it clear rules defined in `others` even when not asked to
69
+ 2. Bug fixes on `Bali::Printer` where inherited rules print the wrong target class due to another bug in an internal file (but doesn't hamper rules-checking logic)
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [ ![Codeship Status for saveav/bali](https://codeship.com/projects/d2f3ded0-20cf-0133-e425-0eade5a669ff/status?branch=release)](https://codeship.com/projects/95727)
4
4
 
5
+ [![Code Climate](https://codeclimate.com/github/saveav/bali/badges/gpa.svg)](https://codeclimate.com/github/saveav/bali)
6
+
5
7
  Bali is a powerful, framework-agnostic, thread-safe Ruby language authorization library. It is a universal authorization library, in the sense that it does not assume you to use specific Ruby library/gem/framework in order for successful use of this gem.
6
8
 
7
9
  Bali is short for Bulwark Authorization Library.
@@ -29,49 +31,7 @@ And then execute:
29
31
 
30
32
  ## Usage
31
33
 
32
- ### Defining access rules
33
-
34
- Rule in Bali is the law determining whether a user (called `subtarget`) can do or perform a specific operation on a target (which is your resource/model).
35
-
36
- ```ruby
37
- Bali.map_rules do
38
- rules_for My::Transaction, as: :transaction do
39
- describe(:supreme_user) { can_all }
40
- describe :admin_user do
41
- can_all
42
- # a more specific rule would be executed even if can_all is present
43
- can :cancel,
44
- if: proc { |record| record.payment_channel == "CREDIT_CARD" &&
45
- !record.is_settled? }
46
- end
47
- describe "general user", can: [:update, :edit], cant: [:delete]
48
- describe "finance user" do
49
- can :update, :delete, :edit
50
- can :delete, if: proc { |record| record.is_settled? }
51
- can :cancel, unless: proc { |record| record.is_settled? }
52
- end # finance_user description
53
- describe :guest { cant_all }
54
- describe nil { cant_all }
55
- end # rules_for
56
- end
57
- ```
58
-
59
- You may or may not assign an alias name (`as`). Make sure to keep it unique had you decided to give alias name to your rules group.
60
-
61
- It is also possible for a rule to be defined for multiple subtarget at once:
62
-
63
- ```ruby
64
- Bali.map_rules do
65
- rules_for My::Transaction do
66
- # rules described bellow will affect both :general_user and :finance_user
67
- describe :general_user, :finance_user do
68
- can :update, :edit
69
- end
70
- end
71
- end
72
- ```
73
-
74
- ### Can and Cant? testing
34
+ Please access [wiki pages](https://github.com/saveav/bali/wiki) for a more detailed, guided explanation, and see what Bali can do. This usage is a simple demonstration what average, standard use of Bali would looks like.
75
35
 
76
36
  Say:
77
37
 
@@ -96,143 +56,94 @@ class My::Employee
96
56
  end
97
57
  ```
98
58
 
99
- Assuming that there exist a variable `transaction` which is an instance of `My::Transaction`, we can query about whether the subtarget is granted to perform certain operation:
100
-
101
- ```ruby
102
- transaction.cant?(:general_user, :delete) # => true
103
- transaction.can("general user", :update) # => true
104
- transaction.can?(:finance_user, :delete) # depend on context
105
- transaction.can?(:monitoring_user, :view) # => true
106
- transaction.can?(:admin_user, :cancel) # depend on context
107
- transaction.can?(:supreme_user, :cancel) # => true
108
- transaction.can?(:guest, :view) # => false
109
- transaction.can?(:undefined_subtarget, :see) # => false
110
- transaction.cant?(:undefined_subtarget, :new) # => true
111
- ```
112
-
113
- If a rule is depending on a certain context, then the context will be evaluated to determine whether the subtarget is authorized or not.
114
-
115
- In the above example, deletion of `transaction` is only allowed if the subtarget is a "finance user" and, the `transaction` itself is already settled.
116
-
117
- Also, asking `can?` on which the subtarget is not yet defined will always return `false`. In the example above, as `undefined_subtarget` is by itself has never been defined in `describe` under `My::Transaction` rule class, `can?` for `undefined_subtarget` will always return `false`. But, `cant` on simillar ocassion will return `true`.
118
-
119
- Rule can also be tested on a class:
120
-
121
- ```ruby
122
- My::Transaction.can?(:supreme_user, :new) # => true
123
- My::Transaction.can?(:guest, :view) # => false
124
- My::Employee.can?(:undefined_subtarget, :new) # => false, rule class for this is by its own undefined
125
- ```
126
-
127
- As we have never define the `rules_for` My::Employee before, any attempt to `can?` for `My::Employee` will return `false`, so does any attempt to object `cant?` on which will only return `true` for any given subtarget and operation.
128
-
129
- ### Can and Cant testing with multiple-roles subtarget
130
-
131
- A subtarget may have multiple roles. For eg., a user may have a role of `finance_user` and `general_user`. A general user normally by itself cannot `delete`, or `cancel`; but a `finance_user` does can, so long the condition is met. But, if a subtarget has role of both `finance_user` and `general_user`, he/she can perform `delete` or `cancel` (so far that the condition is met.)
132
-
133
- Thus, if we have:
134
-
135
- ```ruby
136
- txn = My::Transaction.new
137
- txn.process_transaction(from_user_input)
138
-
139
- # delete or cancel can only happen when a transaction is settled
140
- # as per rule definition
141
- txn.is_settled = true
142
- txn.save
143
-
144
- subtarget = User.new
145
- subtarget.roles = [:finance_user, :general_user]
146
-
147
- txn.can?(subtarget.roles, :delete) # => true
148
- txn.cant?(subtarget.roles, :delete) # => false
149
- txn.can?(:general_user, :delete) # => false
150
- ```
151
-
152
- That is, we can check `can?` and `cant?` with multiple roles by passing array of roles to it.
153
-
154
- ### Using subtarget's instance for Can and Cant testing
155
-
156
- You may pass in real subtarget instance rather than (1) a symbol, (2) string or (3) array of string/symbol for can/cant testing.
157
-
158
- In order to do so, you need to specify the field/method in the subtarget that will be used to evaluating the subtarget's role(s). To do that, we define `roles_for` as follow inside `Bali.map_rules` block:
159
-
160
- ```ruby
161
- Bali.map_rules do
162
- roles_for My::Employee, :roles
163
- roles_for My::AdminUser, :admin_roles
164
- roles_for My::BankUser, :roles
165
-
166
- # rules definition
167
- # may follow
168
- end
169
- ```
170
-
171
- `roles_for` accept two parameters, namely the class of the subtarget, and the field/method that will be invoked on it to gain data about its role(s).
172
-
173
- By doing so, we can now perform authorisation testing as follow:
59
+ Your task is to define rule, with context to `My::Transaction` object, in which:
60
+
61
+ 1. Supreme user can do everything
62
+ 2. Admin user can do everything, but:
63
+ - Can only cancel transaction if the transaction is done using credit card, and the transaction itself is not settled yet
64
+ 3. General user can:
65
+ - Download transaction
66
+ 4. Finance user can:
67
+ - Index transaction
68
+ - Download transaction
69
+ - Delete transaction if the transaction is settled
70
+ - Cancel transaction if the transaction is settled
71
+ 5. Monitoring user can:
72
+ - Index transaction
73
+ - Download transaction
74
+ 6. Sales team can:
75
+ - Index transaction
76
+ - Download transaction
77
+ 6. Unlogged in user can:
78
+ - Index transaction
79
+ - Download transaction
80
+ - Report fraud
81
+ 7. Guest user can:
82
+ - Index transaction
83
+ - Download transaction
84
+ - Report fraud
85
+
86
+ The specification above seems very terrifying, but with Bali, those can be defined in a succinct way, as follow:
174
87
 
175
88
  ```ruby
176
- txn = My::Transaction.new
177
- current_employee = My::Employee.find_by_id(1)
178
- txn.can?(current_employee, :print)
179
- ```
180
-
181
- ### Raises error on unauthorized access
182
-
183
- `can?` and `cant?` just return boolean values on whether access is granted or not. If you want to raise an exception when an operation is inappropriate, use its variant: `can!` and `cant!`
184
-
185
- When `can!` result in denied operation, it will raise `Bali::AuthorizationError`. In the other hand, `cant!` will raise `Bali::AuthorizationError` if it allows an operation.
186
-
187
- `can!` and `cant` are invoked with a similar fashion as you would invoke `can?` and `cant?`
188
-
189
- `Bali::AuthorizationError` is more than an exception, it also store information regarding:
190
-
191
- 1. `auth_level`: whether it is can, or cant testing.
192
- 2. `role`: the role under which authorisation is performed
193
- 3. `subtarget`: the object (if passing an object), or string/symbol representing the role
194
- 4. `operation`: the action
195
- 5. `target`: targeted object/class of the authorization
196
-
197
- ### Rule clause if/unless
198
-
199
- Rule clause may contain `if` and `unless` (decider) proc as already seen before. This `if` and `unless` `proc` have three variants that can be used to express your rule in sufficient detail:
200
-
201
- 1. Zero arity
202
- 2. One arity
203
- 3. Two arity
204
-
205
- When rule is very brief, use zero-arity rule clause as below:
206
-
207
- ```ruby
208
- Bali.map_rules do
209
- rules_for My::Transaction do
210
- describe(:staff) { can :cancel }
211
- describe(:finance) { can :cancel }
89
+ Bali.map_rules do
90
+ rules_for My::Transaction do
91
+ describe(:supreme_user) { can_all }
92
+ describe :admin_user do
93
+ can_all
94
+ # a more specific rule would be executed even if can_all is present
95
+ can :cancel,
96
+ if: proc { |record| record.payment_channel == "CREDIT_CARD" &&
97
+ !record.is_settled? }
98
+ end
99
+ describe "general user", can: [:download]
100
+ describe "finance" do
101
+ can :delete, if: proc { |record| record.is_settled? }
102
+ can :cancel, unless: proc { |record| record.is_settled? }
103
+ end # finance_user description
104
+ describe :guest, nil { can :report_fraud }
105
+ describe :client do
106
+ can :create
107
+ end
108
+ others do
109
+ cannot_all
110
+ can :download, :index
111
+ cannot :create
112
+ end
113
+ end # rules_for
212
114
  end
213
- end
214
115
  ```
215
116
 
216
- Say that (for staff) to cancel a transaction, the transaction must have not been settled yet, you need to define the rule by using one-arity rule clause decider:
117
+ ## Can and Cant? testing
118
+
119
+ Assuming that there exist a variable `transaction` which is an instance of `My::Transaction`:
217
120
 
218
121
  ```ruby
219
- describe :staff do
220
- can :cancel, if: { |txn| txn.is_settled? }
221
- end
122
+ transaction.cant?(:general_user, :delete) # => false
123
+ transaction.can("general user", :download) # => true
124
+ transaction.can?(:finance, :delete) # depends on context
125
+ transaction.can?(:monitoring, :index) # => true
126
+ transaction.can?(:sales, :download) # => true
127
+ transaction.can?(:admin_user, :cancel) # depends on context
128
+ transaction.can?(:supreme_user, :cancel) # => true
129
+ transaction.can?(:guest, :download) # => false
130
+ transaction.can?(nil, :download) # => true
131
+ transaction.can?(nil, :report_fraud) # => true
132
+ transaction.can?(:undefined_subtarget, :see) # => false
133
+ transaction.cant?(:undefined_subtarget, :index) # => true
134
+ transaction.can?(:client, :create) # => true
135
+ transaction.can?(:finance, :create) # => false
136
+ transaction.can?(:admin, :create) # => true
222
137
  ```
223
138
 
224
- Good, but, in addition to that, how to allow transaction cancellation only to staff who has 3 years or so experience in working with the company?
225
-
226
- In order to do that, we need to resort to 2-arity decider, as follow:
139
+ Rule can also be tested on a class:
227
140
 
228
141
  ```ruby
229
- describe :staff do
230
- can :cancel, if: { |txn, usr| txn.is_settled? && usr.exp_years >= 3 }
231
- end
142
+ My::Transaction.can?(:client, :create) # => true
143
+ My::Transaction.can?(:guest, :create) # => false
144
+ My::Employee.can?(:undefined_subtarget, :create) # => false
232
145
  ```
233
146
 
234
- This way, we can keep our controller/logic/model clean from unnecessary and un-DRY role-testing logic.
235
-
236
147
  ## Contributing
237
148
 
238
149
  Bug reports and pull requests are welcome on GitHub at https://github.com/saveav/bali. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
@@ -243,57 +154,4 @@ Bali is proudly available as open source under the terms of the [MIT License](ht
243
154
 
244
155
  ## Changelog
245
156
 
246
- == Version 1.0.0beta1
247
-
248
- 1. Initial version
249
-
250
- == Version 1.0.0rc1
251
-
252
- 1. Fix bug where user can't check on class
253
- 2. Adding new clause: cant_all
254
-
255
- == Version 1.0.0rc2
256
-
257
- 1. [Fix bug when class's name, as a constant, is reloaded](http://stackoverflow.com/questions/2509350/rails-class-object-id-changes-after-i-make-a-request) (re-allocated to different address in the memory)
258
- 2. Allow describing rule for `nil`, useful if user is not authenticated thus role is probably `nil`
259
- 3. Remove pry from development dependency
260
-
261
- == Version 1.0.0rc3
262
-
263
- 1. Each target class should includes `Bali::Objector`, for the following reasons:
264
- - Makes it clear that class do want to include the Bali::Objector
265
- - Transparant, and thus less confusing as to where "can?" and "cant" come from
266
- - When ruby re-parse the class's codes for any reasons, parser will be for sure include Bali::Objector
267
- 2. Return `true` to any `can?` for undefined target/subtarget alike
268
- 3. Return `false` to any `cant?` for undefined target/subtarget alike
269
-
270
- == Version 1.0.0
271
-
272
- 1. Released the stable version of this gem
273
-
274
- == Version 1.1.0rc1
275
-
276
- 1. Ability for rule class to be parsed later by passing `later: true` to rule class definition
277
- 2. Add `Bali.parse` and `Bali.parse!` (`Bali.parse!` executes "later"-tagged rule class, Bali.parse executes automatically after all rules are defined)
278
- 3. Added more thorough testing specs
279
- 4. Proc can be served under `unless` for defining the rule's decider
280
-
281
- == Version 1.1.0rc2
282
-
283
- 1. Ability to check `can?` and `cant?` for subtarget with multiple roles
284
- 2. Describe multiple rules at once for multiple subtarget
285
-
286
- == Version 1.2.0
287
-
288
- 1. Passing real object as subtarget's role, instead of symbol or array of symbol
289
- 2. Clause can also yielding user, along with the object in question
290
-
291
- == Version 2.0.0rc1
292
-
293
- 1. `Bali::AuthorizationError` subclass of `StandardError` tailored for raising error regarding with authorisation
294
- 2. Deprecating `cant`, `cant?`, and `cant_all` in favor of `cannot`, `cannot?` and `cannot_all`
295
- 3. new objectors `can!` and `cannot!` to raise error on inappropriate access
296
-
297
- == Version 2.0.0
298
-
299
- 1. Release!
157
+ Please refer to CHANGELOG.md to see it
@@ -3,12 +3,5 @@
3
3
  require "bundler/setup"
4
4
  require "bali"
5
5
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
6
  require "irb"
14
7
  IRB.start
@@ -5,6 +5,7 @@ require_relative "bali/dsl/map_rules_dsl"
5
5
  require_relative "bali/dsl/rules_for_dsl"
6
6
 
7
7
  require_relative "bali/objector"
8
+ require_relative "bali/printer"
8
9
 
9
10
  require_relative "bali/foundations/all_foundations"
10
11
  require_relative "bali/integrators/all_integrators"
@@ -13,12 +14,6 @@ module Bali
13
14
  # mapping class to a RuleClass
14
15
  RULE_CLASS_MAP = {}
15
16
 
16
- # from symbol to full class name
17
- ALIASED_RULE_CLASS_MAP = {}
18
-
19
- # from full class name to symbol
20
- REVERSE_ALIASED_RULE_CLASS_MAP = {}
21
-
22
17
  # {
23
18
  # User: :roles,
24
19
  # AdminUser: :admin_roles
@@ -38,8 +33,6 @@ module Bali
38
33
 
39
34
  def clear_rules
40
35
  Bali::RULE_CLASS_MAP.clear
41
- Bali::REVERSE_ALIASED_RULE_CLASS_MAP.clear
42
- Bali::ALIASED_RULE_CLASS_MAP.clear
43
36
  true
44
37
  end
45
38
  end