-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ehouriga/ch9191/implement grant #3
Conversation
@@ -2,6 +2,10 @@ | |||
require "accesscontrol/query" | |||
|
|||
module AccessControl | |||
|
|||
unless defined?(CouldNotGrantError) == "constant" && CouldNotGrantError.class == Class |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
borrowed this structure from acts_as_archival
test/schema.rb
Outdated
t.column :action, :integer | ||
t.column :actor_id, :integer | ||
t.column :actor_type, :string | ||
t.column :object_type, :string | ||
t.column :object_id, :integer | ||
end | ||
|
||
add_index(:access_control_permitted_actions, [:segment_id, :action, :actor_id, :actor_type, :object_type], unique: true, name: "acpm_acpa_uniq_table_idx") | ||
add_index(:access_control_permitted_action_on_objects, [:segment_id, :action, :actor_id, :actor_type, :object_type, :object_id], unique: true, name: "acpm_acpaoo_uniq_table_idx") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
adding unique index on all columns to force it at the database level (prevents identical GRANTs)
test/schema.rb
Outdated
@@ -6,20 +6,23 @@ | |||
end | |||
|
|||
create_table :access_control_permitted_actions, force: true, id: :uuid do |t| | |||
t.column :segment_id, :integer | |||
t.column :segment_id, :integer, default: -1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The table indexes need a sensible default on segment_id for the unique constraint functionality
I just added the Clubhouse wekbhook, so: [ch9191] |
test/grant_records_test.rb
Outdated
assert_nil(AccessControl::Query.new(actor).grant(1, Post, post.id)) | ||
end | ||
|
||
it 'retuns raises an error the actor has access' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fix all these poorly worded 'it' blocks in #4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good! I have a few questions here asking whether we should tweak a couple things. But overall, I like this.
One caveat: I haven't tested it fully yet, but I wanted to get my comments to you early in case there's any discussion. I will be testing shortly.
lib/accesscontrol.rb
Outdated
|
||
unless defined?(CouldNotGrantError) == "constant" && CouldNotGrantError.class == Class | ||
CouldNotGrantError = Class.new(StandardError) | ||
end | ||
# AccessControl's tables are prefixed with access_control to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tiny nitpick, but normally I would expect to see an empty line between the end
of one thing and the comment for the next thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
# A grant is universally unique and is enforced at the database level. | ||
# | ||
# @param action_id [Integer] The action to grant for the object | ||
# @param object_type [ActiveRecord::Base] The ActiveRecord model that receives a permission grant. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, we pass in a Class
for object_type
, right? I know I did in can?
exactly what you're doing here by specifying ActiveRecord::Base
, but I'm wondering if this should actually be Class
. I'm still getting used to yardoc, so I could be wrong. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya I think you're right - I was talking with @rreinhardt9 about it yesterday and were talking about this scenario:
Consider we have a LessonPolicy
and a RestrictedLessonPolicy
- Both of these policies define actions with different meaning BUT refer to the Lesson
ActiveRecord model/object. This means that the object_type
we compare against should be different between the two policies? (in this case modifying what you have suggested to Class
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on previous conversations, I expect LessonPolicy
and RestrictedLessonPolicy
to use the same Lesson
permissions via Accessly, but to filter them with business logic. Especially since we use object_type
to chain AR calls on in list
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup! business logic
The only argument I can think of to keep [ActiveRecord::Base]
as the object_type
is in support of the list
operation
# @param action_id [Integer] The action to grant for the object | ||
# @param object_type [ActiveRecord::Base] The ActiveRecord model that receives a permission grant. | ||
# @param object_id [Integer] The id of the ActiveRecord object which receives a permission grant | ||
# @return [nil] Returns nil if successful, otherwise will raise an Error (AccessControl::CouldNotGrantError). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use yardoc's @raise syntax to describe raised exceptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
# # Allow the user access to Post 7 | ||
# AccessControl::Query.new(user).grant(3, Post, 7) | ||
def grant(action_id, object_type, object_id) | ||
a = PermittedActionOnObject.create( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a need for the local variable a
? If so, can we name it something more clear? If not, remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
damn - that shouldn't be there
# | ||
# @param action_id [Integer] The action to grant for the object | ||
# @param object_type [String] The namespace of the given action_id. | ||
# @return [nil] Returns nil if successful, otherwise will raise an Error (AccessControl::CouldNotGrantError). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, you can use yardoc's @raise syntax to describe raised exceptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
) | ||
nil | ||
rescue | ||
raise AccessControl::CouldNotGrantError.new("Could not grant action #{action_id} on object #{object_type} with id #{object_id} for actor #{@actor}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we should silently rescue
from PG::UniqueViolation
(or the equivalent on other DBMSs if we end up supporting them)? Technically, if that error is raised, then the permission has already been granted and nothing really wrong has happened, right?
Of course, if other errors happened, then the caller definitely needs to know about it. In those cases, should we bubble up or include the error message so it's clear what the problem is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we just return nil
on the PG::UniqueViolation?
Also, if we start using Postgres
specific errors we will need to update our test suite to run against a Postgres
database, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we just return nil on the PG::UniqueViolation?
Makes sense to me!
Also, if we start using Postgres specific errors we will need to update our test suite to run against a Postgres database, right?
Bah, you're right! Is there a more generic way we can do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know there's an easier way - but since we're leveraging where_tuples
we may just want to support Postgres to start with?
rescue ActiveRecord::RecordNotUnique
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sweet!
) | ||
nil | ||
rescue => e | ||
raise AccessControl::CouldNotGrantError.new("Could not grant action #{action_id} on object #{object_type} for actor #{@actor}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I asked above, should we silently rescue
from PG::UniqueViolation
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see question above
# # Allow the user access to Post 7 | ||
# AccessControl::Query.new(user).grant(3, Post, 7) | ||
def grant(action_id, object_type, object_id) | ||
a = PermittedActionOnObject.create( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be create!
with the !
so that errors get raised (which we rescue below) instead of it just returning false
and failing relatively silently. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍- I had it there initially and then changed it
it 'returns nil after a successful grant' do | ||
actor = User.create! | ||
|
||
assert_nil(AccessControl::Query.new(actor).grant(1, Post)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed this before, but we're using must_equal
in other tests and assert_stuff
here. It feels like we should standardize one way or the other.
Preferences? I think it's fine either way. I'm just looking for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had must_equal nil
-- but there were a bunch of deprecation warnings about that and the suggested remedy was to use assert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fantastic! I like that we're swallowing duplicate records and bubbling up anything else. And the tests look like they cover the cases I thought of.
Onward!
test/schema.rb
Outdated
t.column :action, :integer, null: false | ||
t.column :actor_id, :integer, null: false | ||
t.column :actor_type, :string, null: false | ||
t.column :object_type, :string, null: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call!
Resolves [ch9191]
add the ability to GRANT permissions on a namespace or specific object
Please SQUASH my commits