id,node_id,number,title,user,user_label,state,locked,assignee,assignee_label,milestone,milestone_label,comments,created_at,updated_at,closed_at,author_association,pull_request,body,repo,repo_label,type,active_lock_reason,performed_via_github_app,reactions,draft,state_reason 314506669,MDU6SXNzdWUzMTQ1MDY2Njk=,215,Allow plugins to define additional URL routes and views,9599,simonw,closed,0,,,5512395,Datasette 0.44,14,2018-04-16T05:31:09Z,2020-06-09T03:14:32Z,2020-06-09T03:12:08Z,OWNER,,"Might be as simple as having plugins get passed the `app` after the other routes have been defined: https://github.com/simonw/datasette/blob/b2955d9065ea019500c7d072bcd9d49d1967f051/datasette/app.py#L1270-L1274 Refs #14",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/215/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 582517965,MDU6SXNzdWU1ODI1MTc5NjU=,698,Ability for a canned query to write to the database,9599,simonw,closed,0,,,5512395,Datasette 0.44,26,2020-03-16T18:31:59Z,2020-06-06T19:43:49Z,2020-06-06T19:43:48Z,OWNER,,"Canned queries are currently read-only: https://datasette.readthedocs.io/en/0.38/sql_queries.html#canned-queries Add a `""write"": true` option to their definition in `metadata.json` which turns them into queries that are submitted via POST and send their queries to the write queue. Then they can be used as a really quick way to define a writable interface and JSON API!",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/698/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 582526961,MDU6SXNzdWU1ODI1MjY5NjE=,699,Authentication (and permissions) as a core concept,9599,simonw,closed,0,,,5512395,Datasette 0.44,40,2020-03-16T18:48:00Z,2020-06-06T19:42:11Z,2020-06-06T19:42:11Z,OWNER,,"Right now Datasette authentication is provided exclusively by plugins: * https://github.com/simonw/datasette-auth-github * https://github.com/simonw/datasette-auth-existing-cookies This is an all-or-nothing approach: either your Datasette instance requires authentication at the top level or it does not. But... as I build new plugins like https://github.com/simonw/datasette-configure-fts and https://github.com/simonw/datasette-edit-tables I increasingly have individual features which should be reserved for logged-in users while still wanting other parts of Datasette to be open to all. This is too much for plugins to own independently of Datasette core. Datasette needs to ship a single ""user is authenticated"" concept (independent of how users actually sign in) so that different plugins can integrate with it.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/699/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 626171242,MDU6SXNzdWU2MjYxNzEyNDI=,777,Error pages not correctly loading CSS,9599,simonw,closed,0,,,5512395,Datasette 0.44,4,2020-05-28T02:47:52Z,2020-06-09T00:35:29Z,2020-06-09T00:35:29Z,OWNER,,"e.g. https://latest.datasette.io/fixtures/compound_three_primary_keys.tsv?_size=max The HTML starts like this: ```html Error 404 ```",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/777/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 628003707,MDU6SXNzdWU2MjgwMDM3MDc=,784,Ability to sign in to Datasette as a root account,9599,simonw,closed,0,,,5512395,Datasette 0.44,5,2020-05-31T17:10:15Z,2020-07-06T19:31:53Z,2020-06-01T01:18:20Z,OWNER,,"> I'm going to draw the line here: default Datasette supports authentication but only for a single user account (""admin""). Plugins can then add support for multiple user accounts, social auth, SSO etc. _Originally posted by @simonw in https://github.com/simonw/datasette/issues/699#issuecomment-636498770_",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/784/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 628025100,MDU6SXNzdWU2MjgwMjUxMDA=,785,Datasette secret mechanism - initially for signed cookies,9599,simonw,closed,0,,,5512395,Datasette 0.44,11,2020-05-31T19:14:52Z,2020-06-06T00:43:40Z,2020-06-01T00:18:40Z,OWNER,,"See comment in https://github.com/simonw/datasette/issues/784#issuecomment-636514974 Datasette needs to be able to set signed cookies - which means it needs a mechanism for safely handling a signing secret. Since Datasette is a long-running process the default behaviour here can be to create a random secret on startup. This means that if the server restarts any signed cookies will be invalidated. If the user wants a persistent secret they'll have to generate it themselves - maybe by setting an environment variable?",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/785/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 628087971,MDU6SXNzdWU2MjgwODc5NzE=,786,Documentation page describing Datasette's authentication system,9599,simonw,closed,0,,,5512395,Datasette 0.44,2,2020-06-01T01:10:06Z,2020-06-06T19:40:20Z,2020-06-06T19:40:20Z,OWNER,,_Originally posted by @simonw in https://github.com/simonw/datasette/issues/699#issuecomment-636562999_,107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/786/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 628089318,MDU6SXNzdWU2MjgwODkzMTg=,787,"""datasette publish"" should bake in a random --secret",9599,simonw,closed,0,,,5512395,Datasette 0.44,1,2020-06-01T01:15:26Z,2020-06-11T16:02:05Z,2020-06-11T16:02:05Z,OWNER,,"To allow signed cookies etc to work reliably (see #785) all of the `datasette publish` commands should generate a random secret on publish and bake it into the configuration - probably by setting the `DATASETTE_SECRET` environment variable. - [ ] Cloud Run - [ ] Heroku - [ ] https://github.com/simonw/datasette-publish-now - [ ] https://github.com/simonw/datasette-publish-fly",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/787/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 628121234,MDU6SXNzdWU2MjgxMjEyMzQ=,788, /-/permissions debugging tool,9599,simonw,closed,0,,,5512395,Datasette 0.44,2,2020-06-01T03:13:47Z,2020-06-06T00:43:40Z,2020-06-01T05:01:01Z,OWNER,,"> Debugging tool idea: `/-/permissions` page which shows you the actor and lets you type in the strings for `action`, `resource_type` and `resource_identifier` - then shows you EVERY plugin hook that would have executed and what it would have said, plus when the chain would have terminated. > > Bonus: if you're logged in as the `root` user (or a user that matches some kind of permission check, maybe a check for `permissions_debug`) you get to see a rolling log of the last 30 permission checks and what the results were across the whole of Datasette. This should make figuring out permissions policies a whole lot easier. _Originally posted by @simonw in https://github.com/simonw/datasette/issues/699#issuecomment-636576603_",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/788/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 628499086,MDU6SXNzdWU2Mjg0OTkwODY=,790,"""flash messages"" mechanism",9599,simonw,closed,0,,,5512395,Datasette 0.44,20,2020-06-01T14:55:44Z,2020-06-08T19:33:59Z,2020-06-02T21:14:03Z,OWNER,,"> Passing `?_success` like this isn't necessarily the best approach. Potential improvements include: > > - Signing this message so it can't be tampered with (I could generate a signing secret on startup) > - Using a cookie with a temporary flash message in it instead > - Using HTML5 history API to remove the `?_success=` from the URL bar when the user lands on the page > > If I add an option to redirect the user to another page after success I may need a mechanism to show a flash message on that page as well, in which case I'll need a general flash message solution that works for any page. _Originally posted by @simonw in https://github.com/simonw/datasette/pull/703_",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/790/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 629524205,MDU6SXNzdWU2Mjk1MjQyMDU=,793,CSRF protection for /-/messages tool and writable canned queries,9599,simonw,closed,0,,,5512395,Datasette 0.44,3,2020-06-02T21:22:21Z,2020-06-06T00:43:41Z,2020-06-05T19:05:59Z,OWNER,,"> The `/-/messages` debug tool will need CSRF protection or people will be able to add messages using a hidden form on another website. _Originally posted by @simonw in https://github.com/simonw/datasette/issues/790#issuecomment-637790860_",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/793/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 629541395,MDU6SXNzdWU2Mjk1NDEzOTU=,795,response.set_cookie() method,9599,simonw,closed,0,,,5512395,Datasette 0.44,2,2020-06-02T21:57:05Z,2020-06-09T22:33:33Z,2020-06-09T22:19:48Z,OWNER,,"Mainly to clean up this code: https://github.com/simonw/datasette/blob/4fa7cf68536628344356d3ef8c92c25c249067a0/datasette/app.py#L439-L454",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/795/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 630120235,MDU6SXNzdWU2MzAxMjAyMzU=,797,"Documentation for new ""params"" setting for canned queries",9599,simonw,closed,0,,,5512395,Datasette 0.44,3,2020-06-03T15:55:11Z,2020-06-09T04:00:40Z,2020-06-03T21:04:51Z,OWNER,,Added here: https://github.com/simonw/datasette/commit/aa82d0370463580f2cb10d9617f1bcbe45cc994a#diff-5e0ffd62fced7d46339b9b2cd167c2f9R236,107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/797/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 631300342,MDExOlB1bGxSZXF1ZXN0NDI4MjEyNDIx,798,CSRF protection,9599,simonw,closed,0,,,5512395,Datasette 0.44,5,2020-06-05T04:22:35Z,2020-06-06T00:43:41Z,2020-06-05T19:05:58Z,OWNER,simonw/datasette/pulls/798,Refs #793,107914493,datasette,pull,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/798/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",0, 631931408,MDU6SXNzdWU2MzE5MzE0MDg=,800,Canned query permissions mechanism,9599,simonw,closed,0,,,5512395,Datasette 0.44,14,2020-06-05T20:28:21Z,2020-06-07T16:22:53Z,2020-06-07T16:22:53Z,OWNER,,"> Idea: default is anyone can execute a query. > > Or you can specify the following: > > ```json > > { > ""databases"": { > ""my-database"": { > ""queries"": { > ""add_twitter_handle"": { > ""sql"": ""insert into twitter_handles (username) values (:username)"", > ""write"": true, > ""allow"": { > ""id"": [""simon""], > ""role"": [""staff""] > } > } > } > } > } > } > ``` > These get matched against the actor JSON. If any of the fields in any of the keys of `""allow""` match a key on the actor, the query is allowed. > > `""id"": ""*""` matches any actor with an `id` key. _Originally posted by @simonw in https://github.com/simonw/datasette/issues/698#issuecomment-639784651_",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/800/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 632673972,MDU6SXNzdWU2MzI2NzM5NzI=,804,python tests/fixtures.py command has a bug,9599,simonw,closed,0,,,5512395,Datasette 0.44,6,2020-06-06T19:17:36Z,2020-06-09T20:01:30Z,2020-06-09T19:58:34Z,OWNER,,"This command is meant to write out `fixtures.db`, `metadata.json` and a plugins directory: ``` $ python tests/fixtures.py /tmp/fixtures.db /tmp/metadata.json /tmp/plugins/ Test tables written to /tmp/fixtures.db - metadata written to /tmp/metadata.json Traceback (most recent call last): File ""tests/fixtures.py"", line 833, in (""my_plugin.py"", PLUGIN1), NameError: name 'PLUGIN1' is not defined ```",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/804/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 632753851,MDU6SXNzdWU2MzI3NTM4NTE=,806,Release Datasette 0.44,9599,simonw,closed,0,,,5512395,Datasette 0.44,10,2020-06-06T21:49:52Z,2020-06-12T01:20:03Z,2020-06-12T01:20:03Z,OWNER,,"See also [milestone](https://github.com/simonw/datasette/milestone/14). This is a pretty big release: flash messaging, writable canned queries, authentication and permissions! I'll want to ship some plugin releases in conjunction with this - `datasette-auth-github` for example.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/806/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 632918799,MDU6SXNzdWU2MzI5MTg3OTk=,808,Permission check for every view in Datasette (plus docs),9599,simonw,closed,0,,,5512395,Datasette 0.44,2,2020-06-07T01:59:23Z,2020-06-07T05:30:49Z,2020-06-07T05:30:49Z,OWNER,,"Every view in Datasette should perform a permission check to see if the current user/actor is allowed to view that page. This permission check will default to allowed, but having this check will allow plugins to lock down access selectively or even to everything in a Datasette instance.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/808/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 632919570,MDExOlB1bGxSZXF1ZXN0NDI5NjEzODkz,809,Publish secrets,9599,simonw,closed,0,,,5512395,Datasette 0.44,4,2020-06-07T02:00:31Z,2020-06-11T16:02:13Z,2020-06-11T16:02:03Z,OWNER,simonw/datasette/pulls/809,Refs #787. Will need quite a bit of manual testing since this involves code which runs against Heroku and Cloud Run.,107914493,datasette,pull,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/809/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",0, 633066114,MDU6SXNzdWU2MzMwNjYxMTQ=,810,Refactor permission check for canned query,9599,simonw,closed,0,,,5512395,Datasette 0.44,1,2020-06-07T05:33:05Z,2020-06-07T17:03:15Z,2020-06-07T17:03:15Z,OWNER,,"This code here (TODO is follow-on from #808). https://github.com/simonw/datasette/blob/86dec9e8fffd6c4efec928ae9b5713748dec7e74/datasette/views/database.py#L133-L142 I can improve this with extra code in https://github.com/simonw/datasette/blob/86dec9e8fffd6c4efec928ae9b5713748dec7e74/datasette/default_permissions.py",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/810/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 633578769,MDU6SXNzdWU2MzM1Nzg3Njk=,811,"Support ""allow"" block on root, databases and tables, not just queries",9599,simonw,closed,0,,,5512395,Datasette 0.44,16,2020-06-07T17:01:09Z,2020-06-08T19:34:00Z,2020-06-08T19:32:36Z,OWNER,,"No reason not to expand the ""allow"" mechanism [described here](https://github.com/simonw/datasette/blob/86dec9e8fffd6c4efec928ae9b5713748dec7e74/docs/authentication.rst#permissions-for-canned-queries) to the root of `metadata.json` plus to databases and tables. Refs #810 and #800. ```json { ""databases"": { ""mydatabase"": { ""allow"": { ""id"": [""root""] } } } } ``` TODO: - [x] Instance level - [x] Database level - [x] Table level - [x] Query level - [x] Affects list of queries - [x] Affects list of tables on database page - [x] Affects truncated list of tables on index page - [x] Affects list of SQL views on database page - [x] Affects list of databases on index page - [x] Show ๐Ÿ”’ in header on index page for private instances - [x] Show ๐Ÿ”’ in header on private database page - [x] Show ๐Ÿ”’ in header on private table page - [x] Show ๐Ÿ”’ in header on private query page - [x] Move `assert_permissions_checked()` calls from `test_html.py` to `test_permissions.py` - [x] Update documentation",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/811/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 634139848,MDU6SXNzdWU2MzQxMzk4NDg=,813,Mechanism for specifying allow_sql permission in metadata.json,9599,simonw,closed,0,,,5512395,Datasette 0.44,6,2020-06-08T04:57:19Z,2020-06-09T00:09:57Z,2020-06-09T00:07:19Z,OWNER,,"Split from #811. It would be useful if finely-grained permissions configured in `metadata.json` could be used to specify if a user is allowed to execute arbitrary SQL queries. We have a permission check call for this already: https://github.com/simonw/datasette/blob/9397d718345c4b35d2a5c55bfcbd1468876b5ab9/datasette/views/database.py#L159 But there's currently no way to implement this check without writing a plugin. I think a `""allow_sql"": {...}` block at the database level in `metadata.json` (sibling to the current `""allow""` block for that database implemented in #811) would be a good option for this.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/813/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 634783573,MDU6SXNzdWU2MzQ3ODM1NzM=,816,Come up with a new example for extra_template_vars plugin,9599,simonw,closed,0,,,5512395,Datasette 0.44,2,2020-06-08T16:57:59Z,2020-06-08T19:06:44Z,2020-06-08T19:06:11Z,OWNER,,"This example is obsolete, it's from a time before `request.actor` and authentication as a built-in concept (#699): https://github.com/simonw/datasette/blob/0c064c5fe220b7b3d8dcf85b02b4e60452c47232/docs/plugins.rst#L696-L700 https://github.com/simonw/datasette/blob/0c064c5fe220b7b3d8dcf85b02b4e60452c47232/docs/plugins.rst#extra_template_varstemplate-database-table-view_name-request-datasette",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/816/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 634917088,MDU6SXNzdWU2MzQ5MTcwODg=,818,Example permissions plugin,9599,simonw,closed,0,,,5512395,Datasette 0.44,9,2020-06-08T20:35:56Z,2020-06-11T05:40:07Z,2020-06-11T05:40:07Z,OWNER,,To show how they work. Also useful to confirm how they interact with the default permissions.,107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/818/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635037204,MDExOlB1bGxSZXF1ZXN0NDMxNDc4NzI0,819,register_routes() plugin hook,9599,simonw,closed,0,,,5512395,Datasette 0.44,0,2020-06-09T01:20:44Z,2020-06-09T03:12:08Z,2020-06-09T03:12:07Z,OWNER,simonw/datasette/pulls/819,Refs #215,107914493,datasette,pull,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/819/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",0, 635076066,MDU6SXNzdWU2MzUwNzYwNjY=,821,Add Response class to internals documentation,9599,simonw,closed,0,,,5512395,Datasette 0.44,0,2020-06-09T03:11:06Z,2020-06-09T03:32:16Z,2020-06-09T03:32:16Z,OWNER,,"> I'll need to add documentation of the `Response` object (and `Response.html()` and `Response.text()` class methods - I should add `Response.json()` too) to the internals page https://datasette.readthedocs.io/en/stable/internals.html _Originally posted by @simonw in https://github.com/simonw/datasette/issues/215#issuecomment-640971470_",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/821/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635077656,MDU6SXNzdWU2MzUwNzc2NTY=,822,request.url_vars helper property,9599,simonw,closed,0,,,5512395,Datasette 0.44,2,2020-06-09T03:15:53Z,2020-06-09T03:40:07Z,2020-06-09T03:40:06Z,OWNER,,"This example: https://github.com/simonw/datasette/blob/f5e79adf26d0daa3831e3fba022f1b749a9efdee/docs/plugins.rst#register_routes ```python from datasette.utils.asgi import Response import html async def hello_from(scope): name = scope[""url_route""][""kwargs""][""name""] return Response.html(""Hello from {}"".format( html.escape(name) )) @hookimpl def register_routes(): return [ (r""^/hello-from/(?P.*)$""), hello_from) ] ``` Would be nicer if you could easily get `scope[""url_route""][""kwargs""][""name""]` directly from the request object, without looking at the `scope`.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/822/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635107393,MDU6SXNzdWU2MzUxMDczOTM=,823,"Documentation is inconsistent about ""id"" as required field on actor",9599,simonw,closed,0,,,5512395,Datasette 0.44,3,2020-06-09T04:47:58Z,2020-06-09T14:58:36Z,2020-06-09T14:58:19Z,OWNER,,"Docs at https://github.com/simonw/datasette/blob/5a6a73e3190cac103906b479d56129413e5ef190/docs/authentication.rst#actors say: > The only required field in an actor is `""id""`, which must be a string. But the example here returns `{""token"": token}`: ```python @hookimpl def actor_from_request(datasette, request): async def inner(): token = request.args.get(""_token"") if not token: return None # Look up ?_token=xxx in sessions table result = await datasette.get_database().execute( ""select count(*) from sessions where token = ?"", [token] ) if result.first()[0]: return {""token"": token} else: return None return inner ```",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/823/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635108074,MDU6SXNzdWU2MzUxMDgwNzQ=,824,Example authentication plugin,9599,simonw,closed,0,,,5512395,Datasette 0.44,4,2020-06-09T04:49:53Z,2020-06-12T00:11:51Z,2020-06-12T00:11:50Z,OWNER,,https://github.com/simonw/datasette-auth-github/issues/62 will work for this.,107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/824/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635147716,MDU6SXNzdWU2MzUxNDc3MTY=,825,Way to enable a default=False permission for anonymous users,9599,simonw,closed,0,,,5512395,Datasette 0.44,6,2020-06-09T06:26:27Z,2020-06-09T17:19:19Z,2020-06-09T17:01:10Z,OWNER,,"I'd like plugins to be able to ship with a default that says ""anonymous users cannot do this"", but allow site administrators to over-ride that such that anonymous users can use the feature after all. This is tricky because right now the anonymous user doesn't have an actor dictionary at all, so there's no key to match to an allow block.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/825/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635519358,MDU6SXNzdWU2MzU1MTkzNTg=,826,Document the ds_actor signed cookie,9599,simonw,closed,0,,,5512395,Datasette 0.44,3,2020-06-09T15:06:52Z,2020-06-09T22:33:12Z,2020-06-09T22:32:31Z,OWNER,,"Most authentication plugins (https://github.com/simonw/datasette-auth-github for example) are likely to work by setting the `ds_actor` signed cookie, which is already magically decoded and supported by default Datasette here: https://github.com/simonw/datasette/blob/4fa7cf68536628344356d3ef8c92c25c249067a0/datasette/actor_auth_cookie.py#L1-L13 I should document this.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/826/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635696400,MDU6SXNzdWU2MzU2OTY0MDA=,827,Document CSRF protection (for plugins),9599,simonw,closed,0,,,5512395,Datasette 0.44,1,2020-06-09T19:19:10Z,2020-06-09T19:38:30Z,2020-06-09T19:35:13Z,OWNER,,"Plugin authors need to know that if they want to POST a form they should include this: ```html+jinja ```",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/827/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 635914822,MDU6SXNzdWU2MzU5MTQ4MjI=,828,Horizontal scrollbar on changelog page on mobile,9599,simonw,closed,0,,,5512395,Datasette 0.44,3,2020-06-10T04:18:54Z,2020-06-10T04:28:17Z,2020-06-10T04:28:17Z,OWNER,,"You can scroll sideways on that page and it looks bad: The cause is these long links: ",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/828/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 636426530,MDU6SXNzdWU2MzY0MjY1MzA=,829,Ability to set ds_actor cookie such that it expires,9599,simonw,closed,0,,,5512395,Datasette 0.44,6,2020-06-10T17:31:40Z,2020-06-10T19:41:35Z,2020-06-10T19:40:05Z,OWNER,,I need this for `datasette-auth-github`: https://github.com/simonw/datasette-auth-github/issues/62#issuecomment-642152076,107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/829/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 636614868,MDU6SXNzdWU2MzY2MTQ4Njg=,831,"It would be more intuitive if ""allow"": none meant ""no-one can do this""",9599,simonw,closed,0,,,5512395,Datasette 0.44,1,2020-06-10T23:43:56Z,2020-06-10T23:57:25Z,2020-06-10T23:50:55Z,OWNER,,"Now that I'm starting to write alternative plugins to control permissions - see #818 - I think I need an easy way to tell Datasette ""no-one has permission to do X unless a plugin says otherwise"". One relatively intuitive way to do that could be like this: ```json { ""databases"": { ""fixtures"": { ""allow"": null } } } ``` Right now I think that opens up permissions to everyone, which isn't as obvious.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/831/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 637253789,MDU6SXNzdWU2MzcyNTM3ODk=,833,/-/metadata and so on should respect view-instance permission,9599,simonw,closed,0,,,5512395,Datasette 0.44,4,2020-06-11T19:07:21Z,2020-06-11T22:15:32Z,2020-06-11T22:14:59Z,OWNER,,"The only URLs that should be available without authentication at all times are the `/-/static/` prefix, to allow for HTTP caching.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/833/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 637365801,MDU6SXNzdWU2MzczNjU4MDE=,836,actor_matches_allow fails to consider all keys,9599,simonw,closed,0,,,5512395,Datasette 0.44,0,2020-06-11T22:46:34Z,2020-06-11T22:47:25Z,2020-06-11T22:47:25Z,OWNER,,"actor: `{""id"": ""root""}` allow block: `{""bot_id"": ""my-bot"", ""id"": [""root""]}` This should pass, because the `id` matches - but it fails.",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/836/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 637370652,MDU6SXNzdWU2MzczNzA2NTI=,837,Plugin $env secrets mechanism doesn't work inside lists,9599,simonw,closed,0,,,5512395,Datasette 0.44,0,2020-06-11T22:59:54Z,2020-06-12T00:25:20Z,2020-06-12T00:25:19Z,OWNER,,"This didn't work: ```json { ""plugins"": { ""datasette-auth-tokens"": [ { ""token"": { ""$env"": ""BOT_TOKEN"" }, ""actor"": { ""bot_id"": ""my-bot"" } } ] } } ```",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/837/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed 637409144,MDU6SXNzdWU2Mzc0MDkxNDQ=,839,"{""$file"": ...} mechanism is broken",9599,simonw,closed,0,,,5512395,Datasette 0.44,0,2020-06-12T00:46:24Z,2020-06-12T00:48:26Z,2020-06-12T00:48:26Z,OWNER,,"https://travis-ci.org/github/simonw/datasette/jobs/697445318 ``` def test_plugin_config_file(app_client): open(TEMP_PLUGIN_SECRET_FILE, ""w"").write(""FROM_FILE"") > assert {""foo"": ""FROM_FILE""} == app_client.ds.plugin_config(""file-plugin"") E AssertionError: assert {'foo': 'FROM_FILE'} == {'foo': {'$fi...ugin-secret'}} E Differing items: E {'foo': 'FROM_FILE'} != {'foo': {'$file': '/tmp/plugin-secret'}} E Use -v to get the full diff ``` Broken in https://github.com/simonw/datasette/commit/fba8ff6e76253af2b03749ed8dd6e28985a7fb8f as part of #837",107914493,datasette,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/839/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed