-
-
Notifications
You must be signed in to change notification settings - Fork 703
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
datasette.permission_allowed() should consider all checks, not just the last returned #2275
Comments
While investigating this issue I created a new debug mechanism, see this issue: |
I implemented the new pattern like so: diff --git a/datasette/app.py b/datasette/app.py
index d943b97b..5a54630c 100644
--- a/datasette/app.py
+++ b/datasette/app.py
@@ -903,6 +903,8 @@ class Datasette:
# Use default from registered permission, if available
if default is DEFAULT_NOT_SET and action in self.permissions:
default = self.permissions[action].default
+ results = []
+ # Every plugin gets a go
for check in pm.hook.permission_allowed(
datasette=self,
actor=actor,
@@ -911,7 +913,16 @@ class Datasette:
):
check = await await_me_maybe(check)
if check is not None:
- result = check
+ results.append(check)
+
+ result = None
+ # If anyone said False it's false
+ if any(r is False for r in results):
+ result = False
+ elif any(r is True for r in results):
+ # Otherwise, if anyone said True it's true
+ result = True
+
used_default = False
if result is None:
result = default All of the tests pass with the exception of this one:
Here's the relevant source code for that test: datasette/tests/test_permissions.py Lines 506 to 541 in 232a304
So this tests expects that if an actor has Here's the plugin that respects that datasette/tests/plugins/my_plugin.py Lines 211 to 218 in 232a304
I don't fully understand this failure, in part because I don't understand how the configuration works that default-blocks the database download. |
Using this new feature: DATASETTE_TRACE_PLUGINS=1 just test --lf -x --pdb Gives:
Which suggests to me that possibly But I'd expect that to work because of the cascade here: datasette/datasette/views/database.py Lines 296 to 305 in 232a304
|
Weirdly in the debugger:
I would expect |
It failed because the plugin returned |
Updated documentation to explain this more clearly: https://docs.datasette.io/en/latest/authentication.html#how-permissions-are-resolved |
Spotted this in the code for
datasette.permission_allowed()
:datasette/datasette/app.py
Lines 906 to 914 in 232a304
This is effectively saying that the permission hook which "wins" is the last one checked in the sequence.
This is actually new behaviour, introduced in dfdbdf3#diff-83d29b1fb42ebaa92e01122d8142807188ab7b6689697c9defdcdca60ce13bc5L435 - prior to that commit the logic looked like this instead:
datasette/datasette/app.py
Lines 426 to 436 in 57cf513
So the original logic was first-non-Null-wins, and then I changed it to last-non-Null-wins in dfdbdf3 - but the commit message and issue for that change don't mention it, which makes me think this was a mistake:
I don't think first wins OR last wins are the right solution here, especially given that Pluggy plugin order is a little bit non-deterministic (aside from when plugins use
tryfirst=
andtrylast=
).Instead, I think a better solution would be to run ALL of the hooks and then have these rules:
False
then the answer isFalse
(a veto rule)True
then the answer isTrue
None
(no opinion) then the answer is whatever the default is for that permissionThe text was updated successfully, but these errors were encountered: