39 rows where milestone = 5512395 sorted by updated_at descending

View and edit SQL

Suggested facets: comments, created_at (date), updated_at (date), closed_at (date)




id node_id number title user state locked assignee milestone comments created_at updated_at ▲ closed_at author_association pull_request body repo type active_lock_reason performed_via_github_app
628003707 MDU6SXNzdWU2MjgwMDM3MDc= 784 Ability to sign in to Datasette as a root account simonw 9599 closed 0   Datasette 0.44 5512395 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

datasette 107914493 issue    
632753851 MDU6SXNzdWU2MzI3NTM4NTE= 806 Release Datasette 0.44 simonw 9599 closed 0   Datasette 0.44 5512395 10 2020-06-06T21:49:52Z 2020-06-12T01:20:03Z 2020-06-12T01:20:03Z OWNER  

See also milestone. 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.

datasette 107914493 issue    
637409144 MDU6SXNzdWU2Mzc0MDkxNDQ= 839 {"$file": ...} mechanism is broken simonw 9599 closed 0   Datasette 0.44 5512395 0 2020-06-12T00:46:24Z 2020-06-12T00:48:26Z 2020-06-12T00:48:26Z OWNER

    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 as part of #837

datasette 107914493 issue    
637370652 MDU6SXNzdWU2MzczNzA2NTI= 837 Plugin $env secrets mechanism doesn't work inside lists simonw 9599 closed 0   Datasette 0.44 5512395 0 2020-06-11T22:59:54Z 2020-06-12T00:25:20Z 2020-06-12T00:25:19Z OWNER  

This didn't work:

    "plugins": {
        "datasette-auth-tokens": [
                "token": {
                    "$env": "BOT_TOKEN"
                "actor": {
                    "bot_id": "my-bot"
datasette 107914493 issue    
635108074 MDU6SXNzdWU2MzUxMDgwNzQ= 824 Example authentication plugin simonw 9599 closed 0   Datasette 0.44 5512395 4 2020-06-09T04:49:53Z 2020-06-12T00:11:51Z 2020-06-12T00:11:50Z OWNER will work for this.

datasette 107914493 issue    
637365801 MDU6SXNzdWU2MzczNjU4MDE= 836 actor_matches_allow fails to consider all keys simonw 9599 closed 0   Datasette 0.44 5512395 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.

datasette 107914493 issue    
637253789 MDU6SXNzdWU2MzcyNTM3ODk= 833 /-/metadata and so on should respect view-instance permission simonw 9599 closed 0   Datasette 0.44 5512395 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.

datasette 107914493 issue    
632919570 MDExOlB1bGxSZXF1ZXN0NDI5NjEzODkz 809 Publish secrets simonw 9599 closed 0   Datasette 0.44 5512395 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.

datasette 107914493 pull    
628089318 MDU6SXNzdWU2MjgwODkzMTg= 787 "datasette publish" should bake in a random --secret simonw 9599 closed 0   Datasette 0.44 5512395 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.

datasette 107914493 issue    
634917088 MDU6SXNzdWU2MzQ5MTcwODg= 818 Example permissions plugin simonw 9599 closed 0   Datasette 0.44 5512395 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.

datasette 107914493 issue    
636614868 MDU6SXNzdWU2MzY2MTQ4Njg= 831 It would be more intuitive if "allow": none meant "no-one can do this" simonw 9599 closed 0   Datasette 0.44 5512395 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:

  "databases": {
    "fixtures": {
      "allow": null

Right now I think that opens up permissions to everyone, which isn't as obvious.

datasette 107914493 issue    
636426530 MDU6SXNzdWU2MzY0MjY1MzA= 829 Ability to set ds_actor cookie such that it expires simonw 9599 closed 0   Datasette 0.44 5512395 6 2020-06-10T17:31:40Z 2020-06-10T19:41:35Z 2020-06-10T19:40:05Z OWNER  

I need this for datasette-auth-github:

datasette 107914493 issue    
635914822 MDU6SXNzdWU2MzU5MTQ4MjI= 828 Horizontal scrollbar on changelog page on mobile simonw 9599 closed 0   Datasette 0.44 5512395 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:">

datasette 107914493 issue    
629541395 MDU6SXNzdWU2Mjk1NDEzOTU= 795 response.set_cookie() method simonw 9599 closed 0   Datasette 0.44 5512395 2 2020-06-02T21:57:05Z 2020-06-09T22:33:33Z 2020-06-09T22:19:48Z OWNER  

Mainly to clean up this code:

datasette 107914493 issue    
635519358 MDU6SXNzdWU2MzU1MTkzNTg= 826 Document the ds_actor signed cookie simonw 9599 closed 0   Datasette 0.44 5512395 3 2020-06-09T15:06:52Z 2020-06-09T22:33:12Z 2020-06-09T22:32:31Z OWNER  

Most authentication plugins ( for example) are likely to work by setting the ds_actor signed cookie, which is already magically decoded and supported by default Datasette here:

I should document this.

datasette 107914493 issue    
632673972 MDU6SXNzdWU2MzI2NzM5NzI= 804 python tests/ command has a bug simonw 9599 closed 0   Datasette 0.44 5512395 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/ /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/", line 833, in <module>
    ("", PLUGIN1),
NameError: name 'PLUGIN1' is not defined
datasette 107914493 issue    
635696400 MDU6SXNzdWU2MzU2OTY0MDA= 827 Document CSRF protection (for plugins) simonw 9599 closed 0   Datasette 0.44 5512395 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:

<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
datasette 107914493 issue    
635147716 MDU6SXNzdWU2MzUxNDc3MTY= 825 Way to enable a default=False permission for anonymous users simonw 9599 closed 0   Datasette 0.44 5512395 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.

datasette 107914493 issue    
635107393 MDU6SXNzdWU2MzUxMDczOTM= 823 Documentation is inconsistent about "id" as required field on actor simonw 9599 closed 0   Datasette 0.44 5512395 3 2020-06-09T04:47:58Z 2020-06-09T14:58:36Z 2020-06-09T14:58:19Z OWNER  

Docs at say:

The only required field in an actor is "id", which must be a string.

But the example here returns {"token": token}:

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}
            return None

    return inner
datasette 107914493 issue    
630120235 MDU6SXNzdWU2MzAxMjAyMzU= 797 Documentation for new "params" setting for canned queries simonw 9599 closed 0   Datasette 0.44 5512395 3 2020-06-03T15:55:11Z 2020-06-09T04:00:40Z 2020-06-03T21:04:51Z OWNER  

Added here:

datasette 107914493 issue    
635077656 MDU6SXNzdWU2MzUwNzc2NTY= 822 request.url_vars helper property simonw 9599 closed 0   Datasette 0.44 5512395 2 2020-06-09T03:15:53Z 2020-06-09T03:40:07Z 2020-06-09T03:40:06Z OWNER  

This example:

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(

def register_routes():
    return [
        (r"^/hello-from/(?P<name>.*)$"), 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.

datasette 107914493 issue    
635076066 MDU6SXNzdWU2MzUwNzYwNjY= 821 Add Response class to internals documentation simonw 9599 closed 0   Datasette 0.44 5512395 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

_Originally posted by @simonw in

datasette 107914493 issue    
314506669 MDU6SXNzdWUzMTQ1MDY2Njk= 215 Allow plugins to define additional URL routes and views simonw 9599 closed 0   Datasette 0.44 5512395 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:

Refs #14

datasette 107914493 issue    
635037204 MDExOlB1bGxSZXF1ZXN0NDMxNDc4NzI0 819 register_routes() plugin hook simonw 9599 closed 0   Datasette 0.44 5512395 0 2020-06-09T01:20:44Z 2020-06-09T03:12:08Z 2020-06-09T03:12:07Z OWNER simonw/datasette/pulls/819

Refs #215

datasette 107914493 pull    
626171242 MDU6SXNzdWU2MjYxNzEyNDI= 777 Error pages not correctly loading CSS simonw 9599 closed 0   Datasette 0.44 5512395 4 2020-05-28T02:47:52Z 2020-06-09T00:35:29Z 2020-06-09T00:35:29Z OWNER  


The HTML starts like this:

<!DOCTYPE html>
    <title>Error 404</title>
    <link rel="stylesheet" href="-/static/app.css?">
datasette 107914493 issue    
634139848 MDU6SXNzdWU2MzQxMzk4NDg= 813 Mechanism for specifying allow_sql permission in metadata.json simonw 9599 closed 0   Datasette 0.44 5512395 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:

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.

datasette 107914493 issue    
633578769 MDU6SXNzdWU2MzM1Nzg3Njk= 811 Support "allow" block on root, databases and tables, not just queries simonw 9599 closed 0   Datasette 0.44 5512395 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 to the root of metadata.json plus to databases and tables.

Refs #810 and #800.

    "databases": {
        "mydatabase": {
            "allow": {
                "id": ["root"]


  • Instance level
  • Database level
  • Table level
  • Query level
  • Affects list of queries
  • Affects list of tables on database page
  • Affects truncated list of tables on index page
  • Affects list of SQL views on database page
  • Affects list of databases on index page
  • Show 🔒 in header on index page for private instances
  • Show 🔒 in header on private database page
  • Show 🔒 in header on private table page
  • Show 🔒 in header on private query page
  • Move assert_permissions_checked() calls from to
  • Update documentation
datasette 107914493 issue    
628499086 MDU6SXNzdWU2Mjg0OTkwODY= 790 "flash messages" mechanism simonw 9599 closed 0   Datasette 0.44 5512395 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

datasette 107914493 issue    
634783573 MDU6SXNzdWU2MzQ3ODM1NzM= 816 Come up with a new example for extra_template_vars plugin simonw 9599 closed 0   Datasette 0.44 5512395 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 and authentication as a built-in concept (#699):

datasette 107914493 issue    
633066114 MDU6SXNzdWU2MzMwNjYxMTQ= 810 Refactor permission check for canned query simonw 9599 closed 0   Datasette 0.44 5512395 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).

I can improve this with extra code in

datasette 107914493 issue    
631931408 MDU6SXNzdWU2MzE5MzE0MDg= 800 Canned query permissions mechanism simonw 9599 closed 0   Datasette 0.44 5512395 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:


"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

datasette 107914493 issue    
632918799 MDU6SXNzdWU2MzI5MTg3OTk= 808 Permission check for every view in Datasette (plus docs) simonw 9599 closed 0   Datasette 0.44 5512395 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.

datasette 107914493 issue    
582517965 MDU6SXNzdWU1ODI1MTc5NjU= 698 Ability for a canned query to write to the database simonw 9599 closed 0   Datasette 0.44 5512395 26 2020-03-16T18:31:59Z 2020-06-06T19:43:49Z 2020-06-06T19:43:48Z OWNER  

Canned queries are currently read-only:

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!

datasette 107914493 issue    
582526961 MDU6SXNzdWU1ODI1MjY5NjE= 699 Authentication (and permissions) as a core concept simonw 9599 closed 0   Datasette 0.44 5512395 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:

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 and 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.

datasette 107914493 issue    
628087971 MDU6SXNzdWU2MjgwODc5NzE= 786 Documentation page describing Datasette's authentication system simonw 9599 closed 0   Datasette 0.44 5512395 2 2020-06-01T01:10:06Z 2020-06-06T19:40:20Z 2020-06-06T19:40:20Z OWNER  

_Originally posted by @simonw in

datasette 107914493 issue    
629524205 MDU6SXNzdWU2Mjk1MjQyMDU= 793 CSRF protection for /-/messages tool and writable canned queries simonw 9599 closed 0   Datasette 0.44 5512395 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

datasette 107914493 issue    
631300342 MDExOlB1bGxSZXF1ZXN0NDI4MjEyNDIx 798 CSRF protection simonw 9599 closed 0   Datasette 0.44 5512395 5 2020-06-05T04:22:35Z 2020-06-06T00:43:41Z 2020-06-05T19:05:58Z OWNER simonw/datasette/pulls/798

Refs #793

datasette 107914493 pull    
628025100 MDU6SXNzdWU2MjgwMjUxMDA= 785 Datasette secret mechanism - initially for signed cookies simonw 9599 closed 0   Datasette 0.44 5512395 11 2020-05-31T19:14:52Z 2020-06-06T00:43:40Z 2020-06-01T00:18:40Z OWNER  

See comment in

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?

datasette 107914493 issue    
628121234 MDU6SXNzdWU2MjgxMjEyMzQ= 788 /-/permissions debugging tool simonw 9599 closed 0   Datasette 0.44 5512395 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

datasette 107914493 issue    

Advanced export

JSON shape: default, array, newline-delimited, object

CSV options:

CREATE TABLE [issues] (
   [node_id] TEXT,
   [number] INTEGER,
   [title] TEXT,
   [user] INTEGER REFERENCES [users]([id]),
   [state] TEXT,
   [locked] INTEGER,
   [assignee] INTEGER REFERENCES [users]([id]),
   [milestone] INTEGER REFERENCES [milestones]([id]),
   [comments] INTEGER,
   [created_at] TEXT,
   [updated_at] TEXT,
   [closed_at] TEXT,
   [author_association] TEXT,
   [pull_request] TEXT,
   [body] TEXT,
   [repo] INTEGER REFERENCES [repos]([id]),
   [type] TEXT
, [active_lock_reason] TEXT, [performed_via_github_app] TEXT);
CREATE INDEX [idx_issues_repo]
                ON [issues] ([repo]);
CREATE INDEX [idx_issues_milestone]
                ON [issues] ([milestone]);
CREATE INDEX [idx_issues_assignee]
                ON [issues] ([assignee]);
CREATE INDEX [idx_issues_user]
                ON [issues] ([user]);
Powered by Datasette · Query took 46.357ms · About: github-to-sqlite