home / github

Menu
  • Search all tables
  • GraphQL API

issue_comments

Table actions
  • GraphQL API for issue_comments

8 rows where issue = 1805076818 and "updated_at" is on date 2023-08-24 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 8

issue 1

  • API tokens with view-table but not view-database/view-instance cannot access the table · 8 ✖

author_association 1

  • OWNER 8
id html_url issue_url node_id user created_at updated_at ▲ author_association body reactions issue performed_via_github_app
1691842259 https://github.com/simonw/datasette/issues/2102#issuecomment-1691842259 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5k13bT simonw 9599 2023-08-24T14:55:54Z 2023-08-24T14:55:54Z OWNER

So what's needed to finish this is: - Tests that demonstrate that nothing is revealed that shouldn't be by tokens restricted in this way - Similar tests for other permissions like create-table that check that they work (and don't also need view-instance etc). - Documentation

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  
1691824713 https://github.com/simonw/datasette/issues/2102#issuecomment-1691824713 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5k1zJJ simonw 9599 2023-08-24T14:45:49Z 2023-08-24T14:45:49Z OWNER

I tested this out against a Datasette Cloud instance. I created a restricted token and tested it like this: bash curl -H "Authorization: Bearer $TOKEN" \ 'https://$INSTANCE/-/actor.json' | jq json { "actor": { "id": "245", "token": "dsatok", "token_id": 2, "_r": { "r": { "data": { "all_stocks": [ "vt" ] } } } } } It can access the all_stocks demo table: bash curl -H "Authorization: Bearer $TOKEN" \ 'https://$INSTANCE/data/all_stocks.json?_size=1' | jq json { "ok": true, "next": "1", "rows": [ { "rowid": 1, "Date": "2013-01-02", "Open": 79.12, "High": 79.29, "Low": 77.38, "Close": 78.43, "Volume": 140124866, "Name": "AAPL" } ], "truncated": false } Accessing the database returns just information about that table, even though other tables exist: bash curl -H "Authorization: Bearer $TOKEN" \ 'https://$INSTANCE/data.json?_size=1' json { "database": "data", "private": true, "path": "/data", "size": 3796992, "tables": [ { "name": "all_stocks", "columns": [ "Date", "Open", "High", "Low", "Close", "Volume", "Name" ], "primary_keys": [], "count": 8813, "hidden": false, "fts_table": null, "foreign_keys": { "incoming": [], "outgoing": [] }, "private": true } ], "hidden_count": 0, "views": [], "queries": [], "allow_execute_sql": false, "table_columns": {} } And hitting the top-level /.json thing does the same - it reveals that table but not any of the other tables or databases: bash curl -H "Authorization: Bearer $TOKEN" \ 'https://$INSTANCE/.json?_size=1' json { "data": { "name": "data", "hash": null, "color": "8d777f", "path": "/data", "tables_and_views_truncated": [ { "name": "all_stocks", "columns": [ "Date", "Open", "High", "Low", "Close", "Volume", "Name" ], "primary_keys": [], "count": null, "hidden": false, "fts_table": null, "num_relationships_for_sorting": 0, "private": false } ], "tables_and_views_more": false, "tables_count": 1, "table_rows_sum": 0, "show_table_row_counts": false, "hidden_table_rows_sum": 0, "hidden_tables_count": 0, "views_count": 0, "private": false } }

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  
1691758168 https://github.com/simonw/datasette/issues/2102#issuecomment-1691758168 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5k1i5Y simonw 9599 2023-08-24T14:09:45Z 2023-08-24T14:09:45Z OWNER

I'm going to implement this in a branch to make it easier to test out.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  
1691045051 https://github.com/simonw/datasette/issues/2102#issuecomment-1691045051 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5ky0y7 simonw 9599 2023-08-24T05:51:59Z 2023-08-24T05:51:59Z OWNER

With that fix in place, this works: bash datasette fixtures.db --get '/fixtures/facetable.json' --actor '{ "_r": { "r": { "fixtures": { "facetable": [ "vt" ] } } }, "a": "user" }' But this fails, because it's for a table not explicitly listed: bash datasette fixtures.db --get '/fixtures/searchable.json' --actor '{ "_r": { "r": { "fixtures": { "facetable": [ "vt" ] } } }, "a": "user" }'

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  
1691044283 https://github.com/simonw/datasette/issues/2102#issuecomment-1691044283 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5ky0m7 simonw 9599 2023-08-24T05:51:02Z 2023-08-24T05:51:02Z OWNER

Also need to confirm that permissions like insert-row, delete-row, create-table etc don't also need special cases to ensure they get through the view-instance etc checks, if those exist for those actions.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  
1691043475 https://github.com/simonw/datasette/issues/2102#issuecomment-1691043475 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5ky0aT simonw 9599 2023-08-24T05:50:04Z 2023-08-24T05:50:04Z OWNER

On first test this seems to work!

```diff diff --git a/datasette/default_permissions.py b/datasette/default_permissions.py index 63a66c3c..9303dac8 100644 --- a/datasette/default_permissions.py +++ b/datasette/default_permissions.py @@ -187,6 +187,30 @@ def permission_allowed_actor_restrictions(datasette, actor, action, resource): return None _r = actor.get("_r")

  • Special case for view-instance: it's allowed if there are any view-database

  • or view-table permissions defined

  • if action == "view-instance":
  • database_rules = _r.get("d") or {}
  • for rules in database_rules.values():
  • if "vd" in rules or "view-database" in rules:
  • return None
  • Now check resources

  • resource_rules = _r.get("r") or {}
  • for _database, resources in resource_rules.items():
  • for rules in resources.values():
  • if "vt" in rules or "view-table" in rules:
  • return None +
  • Special case for view-database: it's allowed if there are any view-table permissions

  • defined within that database

  • if action == "view-database":
  • database_name = resource
  • resource_rules = _r.get("r") or {}
  • resources_in_database = resource_rules.get(database_name) or {}
  • for rules in resources_in_database.values():
  • if "vt" in rules or "view-table" in rules:
  • return None + # Does this action have an abbreviation? to_check = {action} permission = datasette.permissions.get(action) ``` Needs a LOT of testing to make sure what it's doing is sensible though.
{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  
1691037971 https://github.com/simonw/datasette/issues/2102#issuecomment-1691037971 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5kyzET simonw 9599 2023-08-24T05:42:47Z 2023-08-24T05:42:47Z OWNER

I applied a fun trick to help test this out: diff diff --git a/datasette/cli.py b/datasette/cli.py index 58f89c1c..830f47ef 100644 --- a/datasette/cli.py +++ b/datasette/cli.py @@ -445,6 +445,10 @@ def uninstall(packages, yes): "--token", help="API token to send with --get requests", ) +@click.option( + "--actor", + help="Actor to use for --get requests", +) @click.option("--version-note", help="Additional note to show on /-/versions") @click.option("--help-settings", is_flag=True, help="Show available settings") @click.option("--pdb", is_flag=True, help="Launch debugger on any errors") @@ -499,6 +503,7 @@ def serve( root, get, token, + actor, version_note, help_settings, pdb, @@ -611,7 +616,10 @@ def serve( headers = {} if token: headers["Authorization"] = "Bearer {}".format(token) - response = client.get(get, headers=headers) + cookies = {} + if actor: + cookies["ds_actor"] = client.actor_cookie(json.loads(actor)) + response = client.get(get, headers=headers, cookies=cookies) click.echo(response.text) exit_code = 0 if response.status == 200 else 1 sys.exit(exit_code) This adds a --actor option to datasette ... --get /path which makes it easy to test an API endpoint using a fake actor with a set of _r restrictions.

With that in place I can try this, with a token that has view-instance and view-database and view-table: bash datasette fixtures.db --get '/fixtures/facetable.json' --actor '{ "_r": { "a": [ "vi" ], "d": { "fixtures": [ "vd" ] }, "r": { "fixtures": { "facetable": [ "vt" ] } } }, "a": "user" }' Or this, with a token that just has view-table but is missing the view-database and view-instance: bash datasette fixtures.db --get '/fixtures/facetable.json' --actor '{ "_r": { "r": { "fixtures": { "facetable": [ "vt" ] } } }, "a": "user" }'

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  
1691036559 https://github.com/simonw/datasette/issues/2102#issuecomment-1691036559 https://api.github.com/repos/simonw/datasette/issues/2102 IC_kwDOBm6k_c5kyyuP simonw 9599 2023-08-24T05:40:53Z 2023-08-24T05:40:53Z OWNER

There might be an easier way to solve this. Here's some permission checks that run when hitting /fixtures/facetable.json:

``` permission_allowed: action=view-table, resource=('fixtures', 'facetable'), actor={'_r': {'a': ['vi'], 'd': {'fixtures': ['vd']}, 'r': {'fixtures': {'facetable': ['vt']}}}, 'a': 'user'}

File "/datasette/views/table.py", line 727, in table_view_traced view_data = await table_view_data(

File "/datasette/views/table.py", line 875, in table_view_data visible, private = await datasette.check_visibility(

File "/datasette/app.py", line 890, in check_visibility await self.ensure_permissions(actor, permissions)

permission_allowed: action=view-database, resource=fixtures, actor={'_r': {'a': ['vi'], 'd': {'fixtures': ['vd']}, 'r': {'fixtures': {'facetable': ['vt']}}}, 'a': 'user'}

File "/datasette/views/table.py", line 727, in table_view_traced view_data = await table_view_data(

File "/datasette/views/table.py", line 875, in table_view_data visible, private = await datasette.check_visibility(

File "/datasette/app.py", line 890, in check_visibility await self.ensure_permissions(actor, permissions)

permission_allowed: action=view-instance, resource=<None>, actor={'_r': {'a': ['vi'], 'd': {'fixtures': ['vd']}, 'r': {'fixtures': {'facetable': ['vt']}}}, 'a': 'user'}

File "/datasette/views/table.py", line 727, in table_view_traced view_data = await table_view_data(

File "/datasette/views/table.py", line 875, in table_view_data visible, private = await datasette.check_visibility(

File "/datasette/app.py", line 890, in check_visibility await self.ensure_permissions(actor, permissions) ``` That's with a token that has the view instance, view database and view table permissions required.

But... what if the restrictions logic said that if you have view-table you automatically also get view-database and view-instance?

Would that actually let people do anything they shouldn't be able to do? I don't think it would even let them see a list of tables that they weren't allowed to visit, so it might be OK.

I'll try that and see how it works.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
API tokens with view-table but not view-database/view-instance cannot access the table 1805076818  

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 27.199ms · About: github-to-sqlite