html_url,issue_url,id,node_id,user,created_at,updated_at,author_association,body,reactions,issue,performed_via_github_app
https://github.com/simonw/datasette/pull/1940#issuecomment-1347616055,https://api.github.com/repos/simonw/datasette/issues/1940,1347616055,IC_kwDOBm6k_c5QUv03,9599,2022-12-13T01:27:03Z,2022-12-13T01:27:03Z,OWNER,"I'm going to revert that last commit, see if I can get the tests running again and then apply the changes a line at a time to figure out which ones broke things.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1486011362,
https://github.com/simonw/datasette/pull/1940#issuecomment-1347620733,https://api.github.com/repos/simonw/datasette/issues/1940,1347620733,IC_kwDOBm6k_c5QUw99,9599,2022-12-13T01:33:06Z,2022-12-13T01:33:06Z,OWNER,"It's this change which triggers the failures:
```diff
diff --git a/datasette/app.py b/datasette/app.py
index 760063d5..defa9688 100644
--- a/datasette/app.py
+++ b/datasette/app.py
@@ -707,9 +707,12 @@ class Datasette:
)
return crumbs
- async def permission_allowed(self, actor, action, resource=None, default=False):
+ async def permission_allowed(self, actor, action, resource=None, default=None):
""""""Check permissions using the permissions_allowed plugin hook""""""
result = None
+ # Use default from registered permission, if available
+ if default is None and action in self.permissions:
+ default = self.permissions[action].default
for check in pm.hook.permission_allowed(
datasette=self,
actor=actor,
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1486011362,
https://github.com/simonw/datasette/pull/1940#issuecomment-1347632350,https://api.github.com/repos/simonw/datasette/issues/1940,1347632350,IC_kwDOBm6k_c5QUzze,22429695,2022-12-13T01:48:40Z,2022-12-13T02:00:52Z,NONE,"# [Codecov](https://codecov.io/gh/simonw/datasette/pull/1940?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) Report
Base: **92.00**% // Head: **92.03**% // Increases project coverage by **`+0.02%`** :tada:
> Coverage data is based on head [(`a1317ab`)](https://codecov.io/gh/simonw/datasette/pull/1940?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) compared to base [(`e539c1c`)](https://codecov.io/gh/simonw/datasette/commit/e539c1c024bc62d88df91d9107cbe37e7f0fe55f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).
> Patch coverage: 100.00% of modified lines in pull request are covered.
> :exclamation: Current head a1317ab differs from pull request most recent head 94e5c75. Consider uploading reports for the commit 94e5c75 to get more accurate results
Additional details and impacted files
```diff
@@ Coverage Diff @@
## main #1940 +/- ##
==========================================
+ Coverage 92.00% 92.03% +0.02%
==========================================
Files 38 38
Lines 5378 5396 +18
==========================================
+ Hits 4948 4966 +18
Misses 430 430
```
| [Impacted Files](https://codecov.io/gh/simonw/datasette/pull/1940?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison) | Coverage Δ | |
|---|---|---|
| [datasette/permissions.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL3Blcm1pc3Npb25zLnB5) | `100.00% <ø> (ø)` | |
| [datasette/views/database.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL3ZpZXdzL2RhdGFiYXNlLnB5) | `96.26% <ø> (ø)` | |
| [datasette/views/index.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL3ZpZXdzL2luZGV4LnB5) | `96.49% <ø> (ø)` | |
| [datasette/views/special.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL3ZpZXdzL3NwZWNpYWwucHk=) | `79.20% <ø> (-0.21%)` | :arrow_down: |
| [datasette/views/table.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL3ZpZXdzL3RhYmxlLnB5) | `92.57% <ø> (ø)` | |
| [datasette/\_\_init\_\_.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL19faW5pdF9fLnB5) | `100.00% <100.00%> (ø)` | |
| [datasette/app.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2FwcC5weQ==) | `94.47% <100.00%> (+0.04%)` | :arrow_up: |
| [datasette/default\_permissions.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2RlZmF1bHRfcGVybWlzc2lvbnMucHk=) | `95.20% <100.00%> (+0.39%)` | :arrow_up: |
| [datasette/hookspecs.py](https://codecov.io/gh/simonw/datasette/pull/1940/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison#diff-ZGF0YXNldHRlL2hvb2tzcGVjcy5weQ==) | `100.00% <100.00%> (ø)` | |
Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison)
[:umbrella: View full report at Codecov](https://codecov.io/gh/simonw/datasette/pull/1940?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Simon+Willison).
","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1486011362,
https://github.com/simonw/datasette/pull/1940#issuecomment-1347634128,https://api.github.com/repos/simonw/datasette/issues/1940,1347634128,IC_kwDOBm6k_c5QU0PQ,9599,2022-12-13T01:51:56Z,2022-12-13T01:51:56Z,OWNER,Actually one last thing: I said that the error would only occur if the permissions differed in some way.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1486011362,
https://github.com/simonw/datasette/pull/1940#issuecomment-1347640542,https://api.github.com/repos/simonw/datasette/issues/1940,1347640542,IC_kwDOBm6k_c5QU1ze,9599,2022-12-13T02:02:10Z,2022-12-13T02:02:10Z,OWNER,"This PR ended up bundling part of the implementation of:
- #1636
I'm going to be bad an NOT untangle that from this before I merge it.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1486011362,
https://github.com/simonw/datasette/issues/1943#issuecomment-1347645615,https://api.github.com/repos/simonw/datasette/issues/1943,1347645615,IC_kwDOBm6k_c5QU3Cv,9599,2022-12-13T02:06:47Z,2022-12-13T02:06:47Z,OWNER,This URL is already used for the https://latest.datasette.io/-/permissions tool - but it could include a block on that page that tells you what permissions are available.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1490576818,
https://github.com/simonw/datasette/issues/1939#issuecomment-1347646516,https://api.github.com/repos/simonw/datasette/issues/1939,1347646516,IC_kwDOBm6k_c5QU3Q0,9599,2022-12-13T02:07:50Z,2022-12-13T02:07:50Z,OWNER,Documentation for the new hook: https://docs.datasette.io/en/latest/plugin_hooks.html#register-permissions-datasette,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1485757511,
https://github.com/simonw/datasette/issues/1636#issuecomment-1347647298,https://api.github.com/repos/simonw/datasette/issues/1636,1347647298,IC_kwDOBm6k_c5QU3dC,9599,2022-12-13T02:08:46Z,2022-12-13T02:08:46Z,OWNER,"A bunch of the work for this just landed - in particular the new scheme is now documented (even though it doesn't work yet):
https://docs.datasette.io/en/latest/authentication.html#other-permissions-in-metadata","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1138008042,
https://github.com/simonw/datasette/issues/1636#issuecomment-1347648326,https://api.github.com/repos/simonw/datasette/issues/1636,1347648326,IC_kwDOBm6k_c5QU3tG,9599,2022-12-13T02:10:02Z,2022-12-13T02:10:02Z,OWNER,"The implementation for this will go here: https://github.com/simonw/datasette/blob/8bf06a76b51bc9ace7cf72cf0cca8f1da7704ea7/datasette/default_permissions.py#L81-L83
Here's the start of the tests (currently marked as `xfail`):
https://github.com/simonw/datasette/blob/8bf06a76b51bc9ace7cf72cf0cca8f1da7704ea7/tests/test_permissions.py#L652-L689","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1138008042,
https://github.com/simonw/datasette/issues/1636#issuecomment-1347655074,https://api.github.com/repos/simonw/datasette/issues/1636,1347655074,IC_kwDOBm6k_c5QU5Wi,9599,2022-12-13T02:21:04Z,2022-12-13T02:21:23Z,OWNER,"The thing I'm stuck on at the moment is how to implement it such that an `allow` block for `create-table` at the root of the metadata will be checked correctly.
Maybe the algorithm when `_resolve_metadata_permissions_blocks(datasette, actor, action, resource)` is called should do this:
1. If a root permission block matching that action exists, test with that
2. Next, if resource has been passed, check at the database level
3. If the resource included a table/query, check at that level too
So everything is keyed off the incoming `action` name.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1138008042,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347669087,https://api.github.com/repos/simonw/datasette/issues/1855,1347669087,IC_kwDOBm6k_c5QU8xf,9599,2022-12-13T02:45:15Z,2022-12-13T02:45:15Z,OWNER,The hardest piece here is the UI. I'm going to implement the CLI command first.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347675456,https://api.github.com/repos/simonw/datasette/issues/1855,1347675456,IC_kwDOBm6k_c5QU-VA,9599,2022-12-13T02:57:46Z,2022-12-13T02:57:46Z,OWNER,"I was going to have the CLI command throw an error if you attempt to use a permission that isn't registered with Datasette, but then I remembered that one of the uses for the CLI tool is to create signed tokens that will work against other Datasette instances (via the `--secret` option) that might have different plugins installed that register different permission names.
So I might have it output warnings instead.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347693620,https://api.github.com/repos/simonw/datasette/issues/1855,1347693620,IC_kwDOBm6k_c5QVCw0,9599,2022-12-13T03:25:41Z,2022-12-13T03:25:41Z,OWNER,"I'm going to rename ""t"" in the magic format to ""r"" for resource.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347694871,https://api.github.com/repos/simonw/datasette/issues/1855,1347694871,IC_kwDOBm6k_c5QVDEX,9599,2022-12-13T03:28:15Z,2022-12-13T03:28:15Z,OWNER,"Initial prototype of the `create-token` command changes:
```diff
diff --git a/datasette/default_permissions.py b/datasette/default_permissions.py
index 406dae40..bbe1247e 100644
--- a/datasette/default_permissions.py
+++ b/datasette/default_permissions.py
@@ -278,17 +278,55 @@ def register_commands(cli):
help=""Token should expire after this many seconds"",
type=int,
)
+ @click.option(
+ ""alls"",
+ ""-a"",
+ ""--all"",
+ type=str,
+ multiple=True,
+ help=""Restrict token to this permission"",
+ )
+ @click.option(
+ ""databases"",
+ ""-d"",
+ ""--database"",
+ type=(str, str),
+ multiple=True,
+ help=""Restrict token to this permission on this database"",
+ )
+ @click.option(
+ ""resources"",
+ ""-r"",
+ ""--resource"",
+ type=(str, str, str),
+ multiple=True,
+ help=""Restrict token to this permission on this database resource (a table, SQL view or named query)"",
+ )
@click.option(
""--debug"",
help=""Show decoded token"",
is_flag=True,
)
- def create_token(id, secret, expires_after, debug):
+ def create_token(id, secret, expires_after, alls, databases, resources, debug):
""Create a signed API token for the specified actor ID""
ds = Datasette(secret=secret)
bits = {""a"": id, ""token"": ""dstok"", ""t"": int(time.time())}
if expires_after:
bits[""d""] = expires_after
+ if alls or databases or resources:
+ bits[""_r""] = {}
+ if alls:
+ bits[""_r""][""a""] = list(alls)
+ if databases:
+ bits[""_r""][""d""] = {}
+ for database, action in databases:
+ bits[""_r""][""d""].setdefault(database, []).append(action)
+ if resources:
+ bits[""_r""][""r""] = {}
+ for database, table, action in resources:
+ bits[""_r""][""r""].setdefault(database, {}).setdefault(
+ table, []
+ ).append(action)
token = ds.sign(bits, namespace=""token"")
click.echo(""dstok_{}"".format(token))
if debug:
```
Still needs tests, plus I'd like it to use abbreviations if available to keep the token length shorter.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347695728,https://api.github.com/repos/simonw/datasette/issues/1855,1347695728,IC_kwDOBm6k_c5QVDRw,9599,2022-12-13T03:30:09Z,2022-12-13T03:30:09Z,OWNER,"I just noticed this in the existing code:
https://github.com/simonw/datasette/blob/c5d30b58a1cd1c66bbddcf3561db005543ecaf25/datasette/default_permissions.py#L195-L203
Hard-coding those action names should not be necessary any more, especially now we have `datasette.permissions` for looking up metadata about the permissions.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347707683,https://api.github.com/repos/simonw/datasette/issues/1855,1347707683,IC_kwDOBm6k_c5QVGMj,9599,2022-12-13T03:55:35Z,2022-12-13T04:15:27Z,OWNER,"Help looks like this:
```
Usage: datasette create-token [OPTIONS] ID
Create a signed API token for the specified actor ID
Example:
datasette create-token root --secret mysecret
To only allow create-table:
datasette create-token root --secret mysecret \
--all create-table
Or to only allow insert-row against a specific table:
datasette create-token root --secret myscret \
--resource mydb mytable insert-row
Restricted actions can be specified multiple times using multiple --all,
--database, and --resource options.
Add --debug to see a decoded version of the token.
Options:
--secret TEXT Secret used for signing the API tokens
[required]
-e, --expires-after INTEGER Token should expire after this many seconds
-a, --all ACTION Restrict token to this action
-d, --database DB ACTION Restrict token to this action on this
database
-r, --resource DB RESOURCE ACTION
Restrict token to this action on this
database resource (a table, SQL view or
named query)
--debug Show decoded token
--plugins-dir DIRECTORY Path to directory containing custom plugins
--help Show this message and exit.
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347726302,https://api.github.com/repos/simonw/datasette/issues/1855,1347726302,IC_kwDOBm6k_c5QVKve,9599,2022-12-13T04:16:26Z,2022-12-13T04:16:26Z,OWNER,I'm going to move this code into `datasette/cli.py` - it's a bit unexpected having it live in `default_permissions.py` like this (I couldn't find the code when I went looking for it earlier).,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347731288,https://api.github.com/repos/simonw/datasette/issues/1855,1347731288,IC_kwDOBm6k_c5QVL9Y,9599,2022-12-13T04:24:50Z,2022-12-13T04:24:50Z,OWNER,For the tests for `datasette create-token` it would be useful if `datasette --get` had a mechanism for sending an `Authorization: Bearer X` header.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1946#issuecomment-1347732039,https://api.github.com/repos/simonw/datasette/issues/1946,1347732039,IC_kwDOBm6k_c5QVMJH,9599,2022-12-13T04:26:20Z,2022-12-13T04:26:20Z,OWNER,"Two options:
- `--header ""Authorization: Bearer XXX""` which can be used to send any headers
- `--token XXX` to specify the token, which is then sent using that header
I like the second option more, simply because there are currently no other headers that affect how Datasette works. `--token` feels obvious and easy to use.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1493339206,
https://github.com/simonw/datasette/issues/1946#issuecomment-1347733217,https://api.github.com/repos/simonw/datasette/issues/1946,1347733217,IC_kwDOBm6k_c5QVMbh,9599,2022-12-13T04:28:45Z,2022-12-13T04:28:45Z,OWNER,"Demo of the new feature:
```
% datasette create-token --secret s root
dstok_eyJhIjoicm9vdCIsInRva2VuIjoiZHN0b2siLCJ0IjoxNjcwOTA1NjgwfQ.pqSWOwCSNp678hEWl9l5o7m1GaM
% datasette --get /-/actor.json
{""actor"": null}
% DATASETTE_SECRET=s datasette --get /-/actor.json --token dstok_eyJhIjoicm9vdCIsInRva2VuIjoiZHN0b2siLCJ0IjoxNjcwOTA1NjgwfQ.pqSWOwCSNp678hEWl9l5o7m1GaM
{""actor"": {""id"": ""root"", ""token"": ""dstok""}}
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1493339206,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347759522,https://api.github.com/repos/simonw/datasette/issues/1855,1347759522,IC_kwDOBm6k_c5QVS2i,9599,2022-12-13T05:11:43Z,2022-12-13T05:11:43Z,OWNER,"Decided to do the `/-/create-token` UI in a separate ticket:
- #1947","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1947#issuecomment-1347760109,https://api.github.com/repos/simonw/datasette/issues/1947,1347760109,IC_kwDOBm6k_c5QVS_t,9599,2022-12-13T05:12:00Z,2022-12-13T05:12:00Z,OWNER,"For the UI: I think I'm going to dump a whole bunch of form elements on the page (so you can set up to 3 of each category of limit without any JavaScript), then add JavaScript that hides all but one of the options and gives you a ""add another"" widget that adds multiple more.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1493390939,
https://github.com/simonw/datasette/issues/1855#issuecomment-1347761892,https://api.github.com/repos/simonw/datasette/issues/1855,1347761892,IC_kwDOBm6k_c5QVTbk,9599,2022-12-13T05:14:25Z,2022-12-13T05:14:25Z,OWNER,New documentation: https://docs.datasette.io/en/latest/authentication.html#restricting-the-actions-that-a-token-can-perform,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1423336089,
https://github.com/simonw/datasette/issues/1948#issuecomment-1347766530,https://api.github.com/repos/simonw/datasette/issues/1948,1347766530,IC_kwDOBm6k_c5QVUkC,9599,2022-12-13T05:22:19Z,2022-12-13T05:22:19Z,OWNER,"I tested:
```
{""id"": ""root"", ""_r"": {""a"": ""view-table""}}
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1493404423,
https://github.com/simonw/datasette/pull/1938#issuecomment-1347767048,https://api.github.com/repos/simonw/datasette/issues/1938,1347767048,IC_kwDOBm6k_c5QVUsI,9599,2022-12-13T05:23:18Z,2022-12-13T05:23:18Z,OWNER,"I landed this already:
- #1636 ","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1485488236,
https://github.com/simonw/datasette/issues/1947#issuecomment-1347768328,https://api.github.com/repos/simonw/datasette/issues/1947,1347768328,IC_kwDOBm6k_c5QVVAI,9599,2022-12-13T05:25:31Z,2022-12-13T22:25:46Z,OWNER,"https://latest.datasette.io/-/create-token currently looks like this:
![Image](https://user-images.githubusercontent.com/9599/207458002-7c46940b-22c0-45d3-a668-ec7f1082588c.png)
As a reminder, the CLI options that this needs to provide an alternative to are:
https://github.com/simonw/datasette/blob/d4b98d3924dec625a99236e65b1b169ff957381f/docs/cli-reference.rst#L619-L638","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1493390939,
https://github.com/simonw/datasette/issues/1947#issuecomment-1347768549,https://api.github.com/repos/simonw/datasette/issues/1947,1347768549,IC_kwDOBm6k_c5QVVDl,9599,2022-12-13T05:25:56Z,2022-12-13T22:29:12Z,OWNER,- [x] I should add a `--database` example to that help text.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1493390939,
https://github.com/simonw/datasette/issues/1937#issuecomment-1347770871,https://api.github.com/repos/simonw/datasette/issues/1937,1347770871,IC_kwDOBm6k_c5QVVn3,9599,2022-12-13T05:30:43Z,2022-12-13T05:30:43Z,OWNER,"Also you should need `update-row` permission to use the `""replace"": true` option - I should add that rule to `/-/insert` add well.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1483320357,
https://github.com/simonw/datasette/issues/1947#issuecomment-1347775760,https://api.github.com/repos/simonw/datasette/issues/1947,1347775760,IC_kwDOBm6k_c5QVW0Q,9599,2022-12-13T05:38:47Z,2022-12-13T05:38:47Z,OWNER,I'm going to hide the options for reducing the scope of the token inside a details/summary element.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1493390939,
https://github.com/simonw/datasette/issues/1914#issuecomment-1347801679,https://api.github.com/repos/simonw/datasette/issues/1914,1347801679,IC_kwDOBm6k_c5QVdJP,9599,2022-12-13T06:15:54Z,2022-12-13T06:15:54Z,OWNER,"Should make sure that every API that returns an object as the top level (that's almost all of them) includes `""ok"": true` to indicate no errors.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1468689139,
https://github.com/simonw/datasette/issues/1958#issuecomment-1352644262,https://api.github.com/repos/simonw/datasette/issues/1958,1352644262,IC_kwDOBm6k_c5Qn7am,11729897,2022-12-13T16:49:31Z,2022-12-13T16:49:52Z,NONE,"I may have found the reason. I don't think the `--root` option is taking effect.
Visited: http://127.0.0.1:8001/-/permissions
![image](https://user-images.githubusercontent.com/11729897/207394127-59f8320f-3410-4ff8-869d-b19ab955d67c.png)","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1497909798,
https://github.com/simonw/datasette/issues/1958#issuecomment-1352644267,https://api.github.com/repos/simonw/datasette/issues/1958,1352644267,IC_kwDOBm6k_c5Qn7ar,9599,2022-12-13T18:33:32Z,2022-12-13T18:33:32Z,OWNER,"When you run `--root` you need to follow the special link that gets output to the console:
```
% datasette --root
http://127.0.0.1:8001/-/auth-token?token=036d8055cc8000e9667f21c1dd08722a9358c066463873ad9566d23d88765c52
INFO: Started server process [53934]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
That `/-/auth-token?...` link is the one that sets the cookie and lets you in.","{""total_count"": 1, ""+1"": 1, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1497909798,
https://github.com/simonw/datasette/issues/1950#issuecomment-1349855620,https://api.github.com/repos/simonw/datasette/issues/1950,1349855620,IC_kwDOBm6k_c5QdSmE,9599,2022-12-13T22:08:50Z,2022-12-13T22:08:50Z,OWNER,https://github.com/simonw/datasette/blob/d4b98d3924dec625a99236e65b1b169ff957381f/datasette/views/table.py#L392-L400,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1495241162,
https://github.com/simonw/datasette/issues/1950#issuecomment-1349864950,https://api.github.com/repos/simonw/datasette/issues/1950,1349864950,IC_kwDOBm6k_c5QdU32,9599,2022-12-13T22:11:15Z,2022-12-13T22:11:15Z,OWNER,"Most places I use that exception at the moment set their own non-500 status error:
```
datasette % rg DatasetteError
datasette/handle_exception.py
7:from .views.base import DatasetteError
33: elif isinstance(exception, DatasetteError):
datasette/filters.py
2:from datasette.views.base import DatasetteError
22: raise DatasetteError(""_where= is not allowed"", status=403)
141: raise DatasetteError(
datasette/views/table.py
34:from .base import BaseView, DataView, DatasetteError, ureg, _error
178: raise DatasetteError(
192: raise DatasetteError(
390: raise DatasetteError(""Cannot use _sort and _sort_desc at the same time"")
394: raise DatasetteError(f""Cannot sort table by {sort}"")
400: raise DatasetteError(f""Cannot sort table by {sort_desc}"")
datasette/views/base.py
39:class DatasetteError(Exception):
219: raise DatasetteError(str(e), title=""Invalid SQL"", status=400)
222: raise DatasetteError(str(e))
224: except DatasetteError:
382: raise DatasetteError(
402: raise DatasetteError(str(e), title=""Invalid SQL"", status=400)
405: raise DatasetteError(str(e))
407: except DatasetteError:
datasette/views/table2.py
28:from .base import DataView, DatasetteError, ureg
296: raise DatasetteError(
310: raise DatasetteError(
472: raise DatasetteError(""Cannot use _sort and _sort_desc at the same time"")
476: raise DatasetteError(f""Cannot sort table by {sort}"")
482: raise DatasetteError(f""Cannot sort table by {sort_desc}"")
datasette/views/database.py
31:from .base import BaseView, DatasetteError, DataView, _error
188: raise DatasetteError(""Invalid database"", status=404)
190: raise DatasetteError(""Cannot download in-memory databases"", status=404)
194: raise DatasetteError(""Cannot download database"", status=404)
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1495241162,
https://github.com/simonw/datasette/issues/1947#issuecomment-1349972480,https://api.github.com/repos/simonw/datasette/issues/1947,1349972480,IC_kwDOBm6k_c5QdvIA,9599,2022-12-13T22:58:51Z,2022-12-13T22:58:51Z,OWNER,"I'm experimenting with a `