{"html_url": "https://github.com/simonw/datasette/issues/852#issuecomment-645781482", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/852", "id": 645781482, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NTc4MTQ4Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T05:24:55Z", "updated_at": "2020-06-18T05:25:00Z", "author_association": "OWNER", "body": "Question about this on Twitter: https://twitter.com/amjithr/status/1273440766862352384", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 640917326, "label": "canned_queries() plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/852#issuecomment-645785830", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/852", "id": 645785830, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NTc4NTgzMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T05:37:00Z", "updated_at": "2020-06-18T05:37:00Z", "author_association": "OWNER", "body": "The easiest way to do this would be with a new plugin hook:\r\n\r\n def canned_queries(datasette, database):\r\n \"\"\"Return a list of canned query definitions\r\n or an awaitable function that returns them\"\r\n\r\nAnother approach would be to make the whole of `metadata.json` customizable by plugins.\r\n\r\nI think I like the dedicated `canned_queries` option better. I'm not happy with the way metadata keeps growing - see #493 - so adding a dedicated hook would be more future proof against other changes I might make to the metadata mechanism.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 640917326, "label": "canned_queries() plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/853#issuecomment-646140022", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/853", "id": 646140022, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjE0MDAyMg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T16:21:53Z", "updated_at": "2020-06-18T16:21:53Z", "author_association": "OWNER", "body": "I have a test that demonstrates this working, but also demonstrates that the CSRF protection from #798 makes this really tricky to work with. I'd like to improve that.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 640943441, "label": "Ensure register_routes() works for POST"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646151706", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646151706, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjE1MTcwNg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T16:36:23Z", "updated_at": "2020-06-18T16:36:23Z", "author_association": "OWNER", "body": "Tweeted about this here: https://twitter.com/simonw/status/1273655053170077701", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646172200", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646172200, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjE3MjIwMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T16:57:45Z", "updated_at": "2020-06-18T16:57:45Z", "author_association": "OWNER", "body": "I think there are a couple of steps to this one.\r\n\r\nThe nature of CSRF is that it's about hijacking existing authentication credentials. If your Datasette site runs without any authentication plugins at all CSRF protection isn't actually useful.\r\n\r\nSome POST endpoints should be able to opt-out of CSRF protection entirely. A writable canned query that accepts anonymous poll submissions for example might determine that CSRF is not needed.\r\n\r\nIf a plugin adds `Authorization: Bearer xxx` token support that plugin should also be able to specify that CSRF protection can be skipped. https://github.com/simonw/datasette-auth-tokens could do this.\r\n\r\nThis means I need two new mechanisms:\r\n\r\n- A way for wrapped views to indicate \"actually don't CSRF protect me\". I'm not sure how feasible this is without a major redesign, since the decision to return a 403 forbidden status is made before the wrapped function has even been called.\r\n- A way for authentication plugins like `datasette-auth-tokens` to say \"CSRF protection is not needed for this request\". This is a bit tricky too, since right now the `actor_from_request` hook doesn't have a channel for information other than returning the actor dictionary.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646175055", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646175055, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjE3NTA1NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T17:00:45Z", "updated_at": "2020-06-18T17:00:45Z", "author_association": "OWNER", "body": "Here's the Rails pattern for this: https://gist.github.com/maxivak/a25957942b6c21a41acd", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646204308", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646204308, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjIwNDMwOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T17:32:41Z", "updated_at": "2020-06-18T17:32:41Z", "author_association": "OWNER", "body": "The only way I can think of for a view to opt-out of CSRF protection is for them to be able to reconfigure the `asgi-csrf` middleware to skip specific URL patterns.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646209520", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646209520, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjIwOTUyMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T17:39:30Z", "updated_at": "2020-06-18T17:40:53Z", "author_association": "OWNER", "body": "`datasette-auth-tokens` could switch to using `asgi_wrapper` instead of `actor_from_request` - then it could add a `scope[\"skip_csrf\"] = True` scope property to indicate that CSRF should not be protected.\r\n\r\nSince `asgi_wrapper` wraps the CSRF protection middleware changes made to the `scope` by an `asgi_wrapper` will be visible to the CSRF middleware:\r\n\r\nhttps://github.com/simonw/datasette/blob/d2aef9f7ef30fa20b1450cd181cf803f44fb4e21/datasette/app.py#L877-L888", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646214158", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646214158, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjIxNDE1OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T17:48:45Z", "updated_at": "2020-06-18T17:48:45Z", "author_association": "OWNER", "body": "I wonder if it's safe to generically say \"Don't do CSRF protection on any request that includes a `Authorization: Bearer...` header - because it's not possible for a regular browser to send that header since the format is different from the header used in browser-based HTTP basic auth?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646216934", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646216934, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjIxNjkzNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T17:54:14Z", "updated_at": "2020-06-18T17:54:14Z", "author_association": "OWNER", "body": "> if you did Origin based CSRF checks, then could the absence of an Origin header be used?\r\nhttps://twitter.com/cnorthwood/status/1273674392757829632", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646217766", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646217766, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjIxNzc2Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T17:55:54Z", "updated_at": "2020-06-18T17:56:04Z", "author_association": "OWNER", "body": "Idea: a mechanism where the `asgi_csrf()` can take an optional `should_protect()` callback function which gets called with the `scope` and decides if the current request should be protected or not. It can then look at headers and paths and suchlike and make its own decisions. Datasette could then provide a `should_protect()` callback which can interact with plugins.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/820#issuecomment-646218809", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/820", "id": 646218809, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjIxODgwOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T17:58:02Z", "updated_at": "2020-06-18T17:58:02Z", "author_association": "OWNER", "body": "I had the same idea again ten days later: #852.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 635049296, "label": "Idea: Plugin hook for registering canned queries"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/842#issuecomment-646238702", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/842", "id": 646238702, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjIzODcwMg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T18:39:07Z", "updated_at": "2020-06-18T18:39:07Z", "author_association": "OWNER", "body": "It would be nice if Datasette didn't have to do any additional work to find e.g. `_request_ip` if that parameter turned out not to be used by the query.\r\n\r\nCould I do this with a custom class that implements `__getitem__()` and then gets passed as SQLite arguments?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 638212085, "label": "Magic parameters for canned queries"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/842#issuecomment-646242172", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/842", "id": 646242172, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI0MjE3Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T18:46:06Z", "updated_at": "2020-06-18T18:53:31Z", "author_association": "OWNER", "body": "Yes that can work - and using `__missing__` (new in Python 3) is nicer because then the regular dictionary gets checked first:\r\n```python\r\nimport sqlite3\r\n\r\nconn = sqlite3.connect(\":memory:\")\r\n\r\n\r\nclass Magic(dict):\r\n def __missing__(self, key):\r\n return key.upper()\r\n\r\n\r\nconn.execute(\"select :name\", Magic()).fetchall()\r\n```\r\nOutputs:\r\n```\r\n[('NAME',)]\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 638212085, "label": "Magic parameters for canned queries"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/842#issuecomment-646246062", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/842", "id": 646246062, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI0NjA2Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T18:54:41Z", "updated_at": "2020-06-18T18:54:41Z", "author_association": "OWNER", "body": "The `_actor_id` param makes this a bit trickier, because we can't just say \"if you see an unknown parameter called X call this function\" - our magic parameter logic isn't adding single parameters, it might add a whole family of them.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 638212085, "label": "Magic parameters for canned queries"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/842#issuecomment-646264051", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/842", "id": 646264051, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI2NDA1MQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T19:32:13Z", "updated_at": "2020-06-18T19:32:37Z", "author_association": "OWNER", "body": "If every magic parameter has a prefix and suffix, like `_request_ip` and `_actor_id`, then plugins could register a function for a prefix. Register a function to `_actor` and `actor(\"id\")`will be called for `_actor_id`.\r\n\r\nBut does it make sense for every magic parameter to be of form `_a_b`? I think so.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 638212085, "label": "Magic parameters for canned queries"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/842#issuecomment-646272627", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/842", "id": 646272627, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3MjYyNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T19:51:32Z", "updated_at": "2020-06-18T19:51:32Z", "author_association": "OWNER", "body": "I'd be OK with the first version of this not including a plugin hook.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 638212085, "label": "Magic parameters for canned queries"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646273035", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646273035, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3MzAzNQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T19:52:28Z", "updated_at": "2020-06-18T19:52:28Z", "author_association": "OWNER", "body": "I'd like this soon, because I want to start experimenting with things like #852 and #842 without shipping those plugin hooks in a full stable release.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646276150", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646276150, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3NjE1MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T19:59:17Z", "updated_at": "2020-06-18T19:59:17Z", "author_association": "OWNER", "body": "Relevant PEP: https://www.python.org/dev/peps/pep-0440/\r\n\r\nDjango's implementation dates back 8 years: https://github.com/django/django/commit/40f0ecc56a23d35c2849f8e79276f6d8931412d1\r\n\r\nFrom the PEP:\r\n\r\n> Implicit pre-release number\r\n>\r\n> Pre releases allow omitting the numeral in which case it is implicitly assumed to be 0. The normal form for this is to include the 0 explicitly. This allows versions such as 1.2a which is normalized to 1.2a0.\r\n\r\nI'm going to habitually include the 0.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646277155", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646277155, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3NzE1NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:01:31Z", "updated_at": "2020-06-18T20:01:31Z", "author_association": "OWNER", "body": "I thought I might have to update a regex (my CircleCI configs won't match on `a0`, [example](https://github.com/simonw/datasette-publish-now/blob/420f349b278857f62183d8e9835d64f116758be7/.circleci/config.yml#L22)) but it turns out Travis is currently configured to treat ALL tags as potential releases:\r\n\r\nhttps://github.com/simonw/datasette/blob/6151c25a5a8d566c109af296244b9267c536bd9a/.travis.yml#L21-L35", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646277680", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646277680, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3NzY4MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:02:42Z", "updated_at": "2020-06-18T20:02:42Z", "author_association": "OWNER", "body": "So I think if I push a tag of `0.45a0` everything might just work - Travis will build it, push the build to PyPI, PyPI won't treat it as a stable release.\r\n\r\nExcept... I don't want to push alphas as Docker images - so I need to fix this code:\r\n\r\nhttps://github.com/simonw/datasette/blob/6151c25a5a8d566c109af296244b9267c536bd9a/.travis.yml#L34-L43", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646278801", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646278801, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3ODgwMQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:05:18Z", "updated_at": "2020-06-18T20:05:18Z", "author_association": "OWNER", "body": "Travis conditions documentation: https://docs.travis-ci.com/user/conditions-v1\r\n\r\nThese look useful:\r\n```\r\nbranch =~ /^(one|two)-three$/\r\n(tag =~ ^v) AND (branch = master)\r\n```\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646279280", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646279280, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3OTI4MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:06:24Z", "updated_at": "2020-06-18T20:06:24Z", "author_association": "OWNER", "body": "So maybe this condition is right?\r\n\r\n if: (tag IS present) AND NOT (tag =~ [ab])", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646279428", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646279428, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI3OTQyOA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:06:43Z", "updated_at": "2020-06-18T20:06:43Z", "author_association": "OWNER", "body": "I'm going to try this on a separate repository so I don't accidentally publish a Datasette release I didn't mean to publish!", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646280134", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646280134, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI4MDEzNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:08:15Z", "updated_at": "2020-06-18T20:08:15Z", "author_association": "OWNER", "body": "https://github.com/simonw/datasette-render-images uses Travis and is low-risk for trying this out.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646288146", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646288146, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI4ODE0Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:26:22Z", "updated_at": "2020-06-18T20:26:31Z", "author_association": "OWNER", "body": "Useful tip from Carlton Gibson: https://twitter.com/carltongibson/status/1273680590672453632\r\n\r\n> DRF makes ALL views CSRF exempt and then enforces CSRF if you're using Session auth only. \r\n>\r\n> View: https://github.com/encode/django-rest-framework/blob/e18e40d6ae42457f60ca9c68054ad40d15ba8433/rest_framework/views.py#L144\r\n> Auth: https://github.com/encode/django-rest-framework/blob/e18e40d6ae42457f60ca9c68054ad40d15ba8433/rest_framework/authentication.py#L130", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646290171", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646290171, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI5MDE3MQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:30:48Z", "updated_at": "2020-06-18T20:30:48Z", "author_association": "OWNER", "body": "OK, I just shipped 0.2a0 of `datasette-render-images` - https://pypi.org/project/datasette-render-images/ has no indication of that:\r\n\r\n\"Banners_and_Alerts_and_datasette-render-images_\u00b7_PyPI\"\r\n\r\nBut this page does: https://pypi.org/project/datasette-render-images/#history\r\n\r\n\"Banners_and_Alerts_and_datasette-render-images_\u00b7_PyPI\"\r\n\r\nAnd https://pypi.org/project/datasette-render-images/0.2a0/ exists.\r\n\r\nIn a fresh virtual environment `pip install datasette-render-images` gets 0.1.\r\n\r\n`pip install datasette-render-images==0.2a0` gets 0.2a0.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646291309", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646291309, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI5MTMwOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:33:31Z", "updated_at": "2020-06-18T20:33:31Z", "author_association": "OWNER", "body": "One more experiment: I'm going to ship `datasette-render-images` 0.2 and see if that works correctly - including printing out the new debug section I put in the Travis config here: https://github.com/simonw/datasette-render-images/blob/6b5f22dab75ca364f671f5597556d2665a251bd8/.travis.yml#L35-L39 - which should demonstrate if my conditional for pushing to Docker Hub will work or not.\r\n\r\nIn the alpha releasing run on Travis that echo statement did NOT execute: https://travis-ci.com/github/simonw/datasette-render-images/builds/172116625", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646292578", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646292578, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI5MjU3OA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:36:22Z", "updated_at": "2020-06-18T20:36:22Z", "author_association": "OWNER", "body": "https://travis-ci.com/github/simonw/datasette-render-images/builds/172118541 demonstrates that the alpha/beta conditional is working as intended:\r\n\r\n\"Banners_and_Alerts_and_Build__13_-_simonw_datasette-render-images_-_Travis_CI\"", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646293029", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646293029, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI5MzAyOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:37:28Z", "updated_at": "2020-06-18T20:37:46Z", "author_association": "OWNER", "body": "Here's the Read The Docs documentation on versioned releases: https://docs.readthedocs.io/en/stable/versions.html\r\n\r\nIt looks like they do the right thing:\r\n\r\n> We in fact are parsing your tag names against the rules given by PEP 440. This spec allows \u201cnormal\u201d version numbers like 1.4.2 as well as pre-releases. An alpha version or a release candidate are examples of pre-releases and they look like this: 2.0a1.\r\n> \r\n> We only consider non pre-releases for the stable version of your documentation.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646293670", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646293670, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjI5MzY3MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T20:38:50Z", "updated_at": "2020-06-18T20:38:50Z", "author_association": "OWNER", "body": "https://pypi.org/project/datasette-render-images/#history worked:\r\n\r\n\"Banners_and_Alerts_and_datasette-render-images_\u00b7_PyPI\"\r\n\r\nI'm now confident enough that I'll make these changes and ship an alpha of Datasette itself.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646302909", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646302909, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjMwMjkwOQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T21:00:02Z", "updated_at": "2020-06-18T21:00:02Z", "author_association": "OWNER", "body": "Alpha release is running through Travis now: https://travis-ci.org/github/simonw/datasette/builds/699864168", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646303240", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646303240, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjMwMzI0MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T21:00:41Z", "updated_at": "2020-06-18T21:00:41Z", "author_association": "OWNER", "body": "New documentation about the alpha/beta releases: https://datasette.readthedocs.io/en/latest/contributing.html#contributing-alpha-beta", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646307083", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646307083, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjMwNzA4Mw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T21:09:35Z", "updated_at": "2020-06-18T21:09:35Z", "author_association": "OWNER", "body": "So maybe one really easy fix here is to disable CSRF checks entirely for any request that doesn't have any cookies? Also suggested here: https://twitter.com/mrkurt/status/1273682965168603137", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/835#issuecomment-646308467", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/835", "id": 646308467, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjMwODQ2Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T21:12:50Z", "updated_at": "2020-06-18T21:12:50Z", "author_association": "OWNER", "body": "Problem there is Login CSRF attacks: https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#login-csrf - I still want to perform CSRF checks on login forms, even though the user may not yet have any cookies.\r\n\r\nMaybe I can turn off CSRF checks for cookie-free requests but allow login forms to specifically opt back in to CSRF protection?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 637363686, "label": "Mechanism for skipping CSRF checks on API posts"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646319315", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646319315, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjMxOTMxNQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T21:38:56Z", "updated_at": "2020-06-18T21:38:56Z", "author_association": "OWNER", "body": "This worked!\r\n\r\nhttps://pypi.org/project/datasette/#history\r\n\r\n\"Banners_and_Alerts_and_datasette_\u00b7_PyPI\"\r\n\r\nhttps://github.com/simonw/datasette/releases/tag/0.45a0 is my manually created GitHub prerelease.\r\n\r\nhttps://datasette.readthedocs.io/en/latest/changelog.html#a0-2020-06-18 has the release notes.\r\n\r\nA shame Read The Docs doesn't seem to build the docs for these releases -it's not showing the tag in the releases pane here:\r\n\r\n\"Changelog_\u2014_Datasette_documentation\"\r\n\r\nAlso the new tag isn't an option in the Build menu on https://readthedocs.org/projects/datasette/builds/\r\n\r\nNot a big problem though since the \"latest\" tag on Read The Docs will still carry the in-development documentation.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/807#issuecomment-646320237", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/807", "id": 646320237, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjMyMDIzNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T21:41:16Z", "updated_at": "2020-06-18T21:41:16Z", "author_association": "OWNER", "body": "https://pypi.org/project/datasette/0.45a0/ is the release on PyPI.\r\n\r\nAnd in a fresh virtual environment:\r\n\r\n```\r\n$ pip install datasette==0.45a0\r\n...\r\n$ datasette --version\r\ndatasette, version 0.45a0\r\n```\r\nBut running `pip install datasette` still gets 0.44.\r\n\r\n\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 632843030, "label": "Ability to ship alpha and beta releases"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/852#issuecomment-646329456", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/852", "id": 646329456, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjMyOTQ1Ng==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T22:07:09Z", "updated_at": "2020-06-18T22:07:37Z", "author_association": "OWNER", "body": "It would be neat if the queries returned by this hook could be restricted to specific users. I think I can do that by returning an \"allow\" block as part of the query.\r\n\r\nBut... what if we allow users to save private queries and we might have thousands of users each with hundreds of saved queries?\r\n\r\nFor that case it would be good if the plugin hook could take an optional `actor` parameter.\r\n\r\nThis would also allow us to dynamically generate a canned query for \"return the bookmarks belonging to this actor\" or similar!", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 640917326, "label": "canned_queries() plugin hook"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/852#issuecomment-646350530", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/852", "id": 646350530, "node_id": "MDEyOklzc3VlQ29tbWVudDY0NjM1MDUzMA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-06-18T23:13:57Z", "updated_at": "2020-06-18T23:14:11Z", "author_association": "OWNER", "body": "```python\r\n@hookspec\r\ndef canned_queries(datasette, database, actor):\r\n \"Return a dictionary of canned query definitions or an awaitable function that returns them\"\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 640917326, "label": "canned_queries() plugin hook"}, "performed_via_github_app": null}