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 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 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 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 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 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 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 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 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 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 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 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, 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 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 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 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 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 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 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 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 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 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