home / github

Menu
  • Search all tables
  • GraphQL API

issue_comments

Table actions
  • GraphQL API for issue_comments

19 rows where issue = 1423336089 sorted by updated_at descending

✖
✖

✎ View and edit SQL

This data as json, CSV (advanced)

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

user 1

  • simonw 19

issue 1

  • `datasette create-token` ability to create tokens with a reduced set of permissions · 19 ✖

author_association 1

  • OWNER 19
id html_url issue_url node_id user created_at updated_at ▲ author_association body reactions issue performed_via_github_app
1347761892 https://github.com/simonw/datasette/issues/1855#issuecomment-1347761892 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVTbk simonw 9599 2022-12-13T05:14:25Z 2022-12-13T05:14:25Z OWNER

New documentation: https://docs.datasette.io/en/latest/authentication.html#restricting-the-actions-that-a-token-can-perform

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347759522 https://github.com/simonw/datasette/issues/1855#issuecomment-1347759522 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVS2i simonw 9599 2022-12-13T05:11:43Z 2022-12-13T05:11:43Z OWNER

Decided to do the /-/create-token UI in a separate ticket: - #1947

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347731288 https://github.com/simonw/datasette/issues/1855#issuecomment-1347731288 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVL9Y simonw 9599 2022-12-13T04:24:50Z 2022-12-13T04:24:50Z OWNER

For the tests for datasette create-token it would be useful if datasette --get had a mechanism for sending an Authorization: Bearer X header.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347726302 https://github.com/simonw/datasette/issues/1855#issuecomment-1347726302 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVKve simonw 9599 2022-12-13T04:16:26Z 2022-12-13T04:16:26Z OWNER

I'm going to move this code into datasette/cli.py - it's a bit unexpected having it live in default_permissions.py like this (I couldn't find the code when I went looking for it earlier).

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347707683 https://github.com/simonw/datasette/issues/1855#issuecomment-1347707683 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVGMj simonw 9599 2022-12-13T03:55:35Z 2022-12-13T04:15:27Z OWNER

Help looks like this:

``` Usage: datasette create-token [OPTIONS] ID

Create a signed API token for the specified actor ID

Example:

  datasette create-token root --secret mysecret

To only allow create-table:

  datasette create-token root --secret mysecret \
      --all create-table

Or to only allow insert-row against a specific table:

  datasette create-token root --secret myscret \
      --resource mydb mytable insert-row

Restricted actions can be specified multiple times using multiple --all, --database, and --resource options.

Add --debug to see a decoded version of the token.

Options: --secret TEXT Secret used for signing the API tokens [required] -e, --expires-after INTEGER Token should expire after this many seconds -a, --all ACTION Restrict token to this action -d, --database DB ACTION Restrict token to this action on this database -r, --resource DB RESOURCE ACTION Restrict token to this action on this database resource (a table, SQL view or named query) --debug Show decoded token --plugins-dir DIRECTORY Path to directory containing custom plugins --help Show this message and exit. ```

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347695728 https://github.com/simonw/datasette/issues/1855#issuecomment-1347695728 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVDRw simonw 9599 2022-12-13T03:30:09Z 2022-12-13T03:30:09Z OWNER

I just noticed this in the existing code:

https://github.com/simonw/datasette/blob/c5d30b58a1cd1c66bbddcf3561db005543ecaf25/datasette/default_permissions.py#L195-L203

Hard-coding those action names should not be necessary any more, especially now we have datasette.permissions for looking up metadata about the permissions.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347694871 https://github.com/simonw/datasette/issues/1855#issuecomment-1347694871 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVDEX simonw 9599 2022-12-13T03:28:15Z 2022-12-13T03:28:15Z OWNER

Initial prototype of the create-token command changes:

diff diff --git a/datasette/default_permissions.py b/datasette/default_permissions.py index 406dae40..bbe1247e 100644 --- a/datasette/default_permissions.py +++ b/datasette/default_permissions.py @@ -278,17 +278,55 @@ def register_commands(cli): help="Token should expire after this many seconds", type=int, ) + @click.option( + "alls", + "-a", + "--all", + type=str, + multiple=True, + help="Restrict token to this permission", + ) + @click.option( + "databases", + "-d", + "--database", + type=(str, str), + multiple=True, + help="Restrict token to this permission on this database", + ) + @click.option( + "resources", + "-r", + "--resource", + type=(str, str, str), + multiple=True, + help="Restrict token to this permission on this database resource (a table, SQL view or named query)", + ) @click.option( "--debug", help="Show decoded token", is_flag=True, ) - def create_token(id, secret, expires_after, debug): + def create_token(id, secret, expires_after, alls, databases, resources, debug): "Create a signed API token for the specified actor ID" ds = Datasette(secret=secret) bits = {"a": id, "token": "dstok", "t": int(time.time())} if expires_after: bits["d"] = expires_after + if alls or databases or resources: + bits["_r"] = {} + if alls: + bits["_r"]["a"] = list(alls) + if databases: + bits["_r"]["d"] = {} + for database, action in databases: + bits["_r"]["d"].setdefault(database, []).append(action) + if resources: + bits["_r"]["r"] = {} + for database, table, action in resources: + bits["_r"]["r"].setdefault(database, {}).setdefault( + table, [] + ).append(action) token = ds.sign(bits, namespace="token") click.echo("dstok_{}".format(token)) if debug: Still needs tests, plus I'd like it to use abbreviations if available to keep the token length shorter.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347693620 https://github.com/simonw/datasette/issues/1855#issuecomment-1347693620 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QVCw0 simonw 9599 2022-12-13T03:25:41Z 2022-12-13T03:25:41Z OWNER

I'm going to rename "t" in the magic format to "r" for resource.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347675456 https://github.com/simonw/datasette/issues/1855#issuecomment-1347675456 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QU-VA simonw 9599 2022-12-13T02:57:46Z 2022-12-13T02:57:46Z OWNER

I was going to have the CLI command throw an error if you attempt to use a permission that isn't registered with Datasette, but then I remembered that one of the uses for the CLI tool is to create signed tokens that will work against other Datasette instances (via the --secret option) that might have different plugins installed that register different permission names.

So I might have it output warnings instead.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1313148519 https://github.com/simonw/datasette/issues/1855#issuecomment-1313148519 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5ORQ5n simonw 9599 2022-11-14T06:13:43Z 2022-12-13T02:46:51Z OWNER

The datasette create-token command will need to be able to do this too.

Right now that command looks like this: ``` % datasette create-token --help Usage: datasette create-token [OPTIONS] ID

Create a signed API token for the specified actor ID

Options: --secret TEXT Secret used for signing the API tokens [required] -e, --expires-after INTEGER Token should expire after this many seconds --debug Show decoded token --help Show this message and exit. % datasette create-token root --secret sec --debug -e 445 dstok_eyJhIjoicm9vdCIsInRva2VuIjoiZHN0b2siLCJ0IjoxNjY4NDA2MjEzLCJkIjo0NDV9.Hd6qRli6xRKkOIRQgZkPO5iN1wM

Decoded:

{ "a": "root", "token": "dstok", "t": 1668406213, "d": 445 } `` (The--debug` bit adds the decoded token.)

Syntax for adding "insert row" for everything, "update row" for all in the "data" database and "delete row" just for the docs / titles table: datasette create-token root --secret sec \ --all insert-row \ --database data update-row \ --table docs titles delete-row The ir / ur / dr options would work too. To add multiple permissions use these options multiple times: datasette create-token root --secret sec \ --all insert-row \ --all delete-row Short versions: -a and -d and -t.

UPDATE: I have decided to use the term resource in the user-facing elements of this feature instead of table, since that can refer to a SQL view and a canned query as well.

So --resource and -r, not -t.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1347669087 https://github.com/simonw/datasette/issues/1855#issuecomment-1347669087 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5QU8xf simonw 9599 2022-12-13T02:45:15Z 2022-12-13T02:45:15Z OWNER

The hardest piece here is the UI. I'm going to implement the CLI command first.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1339952692 https://github.com/simonw/datasette/issues/1855#issuecomment-1339952692 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5P3g40 simonw 9599 2022-12-06T20:15:50Z 2022-12-06T20:16:00Z OWNER

That commit there https://github.com/simonw/datasette/commit/6da17d5529773dfe41b53ed4ce5a6ecb46ed2457 (which will be squash-merged in a PR later on) made it so that _r was correctly copied across from the token to the created actor, and fixed a bug in the code that checks permissions against it for resources.

I needed that mechanism to write a test that exercised different API permissions.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1302815929 https://github.com/simonw/datasette/issues/1855#issuecomment-1302815929 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5Np2S5 simonw 9599 2022-11-04T00:19:10Z 2022-12-03T07:05:51Z OWNER

Added the tests.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1301646670 https://github.com/simonw/datasette/issues/1855#issuecomment-1301646670 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5NlY1O simonw 9599 2022-11-03T05:11:26Z 2022-11-03T05:11:26Z OWNER

That still needs comprehensive tests before I land it.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1301646493 https://github.com/simonw/datasette/issues/1855#issuecomment-1301646493 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5NlYyd simonw 9599 2022-11-03T05:11:06Z 2022-11-03T05:11:06Z OWNER

Built a prototype of the above:

```diff diff --git a/datasette/default_permissions.py b/datasette/default_permissions.py index 32b0c758..f68aa38f 100644 --- a/datasette/default_permissions.py +++ b/datasette/default_permissions.py @@ -6,8 +6,8 @@ import json import time

-@hookimpl(tryfirst=True) -def permission_allowed(datasette, actor, action, resource): +@hookimpl(tryfirst=True, specname="permission_allowed") +def permission_allowed_default(datasette, actor, action, resource): async def inner(): if action in ( "permissions-debug", @@ -57,6 +57,44 @@ def permission_allowed(datasette, actor, action, resource): return inner

+@hookimpl(specname="permission_allowed") +def permission_allowed_actor_restrictions(actor, action, resource): + if actor is None: + return None + r = actor.get("_r") + if not _r: + # No restrictions, so we have no opinion + return None + action_initials = "".join([word[0] for word in action.split("-")]) + # If _r is defined then we use those to further restrict the actor + # Crucially, we only use this to say NO (return False) - we never + # use it to return YES (True) because that might over-ride other + # restrictions placed on this actor + all_allowed = _r.get("a") + if all_allowed is not None: + assert isinstance(all_allowed, list) + if action_initials in all_allowed: + return None + # How about for the current database? + if action in ("view-database", "view-database-download", "execute-sql"): + database_allowed = _r.get("d", {}).get(resource) + if database_allowed is not None: + assert isinstance(database_allowed, list) + if action_initials in database_allowed: + return None + # Or the current table? That's any time the resource is (database, table) + if not isinstance(resource, str) and len(resource) == 2: + database, table = resource + table_allowed = _r.get("t", {}).get(database, {}).get(table) + # TODO: What should this do for canned queries? + if table_allowed is not None: + assert isinstance(table_allowed, list) + if action_initials in table_allowed: + return None + # This action is not specifically allowed, so reject it + return False + + @hookimpl def actor_from_request(datasette, request): prefix = "dstok"

```

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1301594495 https://github.com/simonw/datasette/issues/1855#issuecomment-1301594495 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5NlMF_ simonw 9599 2022-11-03T03:11:17Z 2022-11-03T03:11:17Z OWNER

Maybe the way to do this is through a new standard mechanism on the actor: a set of additional restrictions, e.g.:

{ "id": "root", "_r": { "a": ["ir", "ur", "dr"], "d": { "fixtures": ["ir", "ur", "dr"] }, "t": { "fixtures": { "searchable": ["ir"] } } } "a" is "all permissions" - these apply to everything. "d" permissions only apply to the specified database "t" permissions only apply to the specified table

The way this works is there's a default permission_allowed(datasette, actor, action, resource) hook which only consults these, and crucially just says NO if those rules do not match.

In this way it would apply as an extra layer of permission rules over the defaults (which for this root instance would all return yes).

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1292962813 https://github.com/simonw/datasette/issues/1855#issuecomment-1292962813 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5NEQv9 simonw 9599 2022-10-27T04:31:40Z 2022-10-27T04:31:40Z OWNER

My hunch on this is that anyone with that level of complex permissions requirements needs to be using a custom authentication plugin which includes much more concrete token rules, rather than the default signed stateless token implementation that ships with Datasette core.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1292959886 https://github.com/simonw/datasette/issues/1855#issuecomment-1292959886 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5NEQCO simonw 9599 2022-10-27T04:30:07Z 2022-10-27T04:30:07Z OWNER

Here's an interesting edge-case to consider: what if a user creates themselves a token for a specific table, then deletes that table, and waits for another user to create a table of the same name... and then uses their previously created token to write to the table that someone else created?

Not sure if this is a threat I need to actively consider, but it's worth thinking a little bit about the implications of such a thing - since there will be APIs that allow users to create tables, and there may be cases where people want to have a concept of users "owning" specific tables.

This is probably something that could be left for plugins to solve, but it still needs to be understood and potentially documented.

There may even be a world in which tracking the timestamp at which a table was created becomes useful - because that could then be baked into API tokens, such that a token created BEFORE the table was created does not grant access to that table.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  
1291485444 https://github.com/simonw/datasette/issues/1855#issuecomment-1291485444 https://api.github.com/repos/simonw/datasette/issues/1855 IC_kwDOBm6k_c5M-oEE simonw 9599 2022-10-26T04:30:34Z 2022-10-26T04:30:34Z OWNER

I'm going to delay working on this until after I have some of the write APIs built to try it against: - #1851

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
`datasette create-token` ability to create tokens with a reduced set of permissions 1423336089  

Advanced export

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

CSV options:

CREATE TABLE [issue_comments] (
   [html_url] TEXT,
   [issue_url] TEXT,
   [id] INTEGER PRIMARY KEY,
   [node_id] TEXT,
   [user] INTEGER REFERENCES [users]([id]),
   [created_at] TEXT,
   [updated_at] TEXT,
   [author_association] TEXT,
   [body] TEXT,
   [reactions] TEXT,
   [issue] INTEGER REFERENCES [issues]([id])
, [performed_via_github_app] TEXT);
CREATE INDEX [idx_issue_comments_issue]
                ON [issue_comments] ([issue]);
CREATE INDEX [idx_issue_comments_user]
                ON [issue_comments] ([user]);
Powered by Datasette · Queries took 26.265ms · About: github-to-sqlite
  • Sort ascending
  • Sort descending
  • Facet by this
  • Hide this column
  • Show all columns
  • Show not-blank rows