Skip to content

Commit

Permalink
Label expand permission check respects cascade, closes #2178
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Sep 7, 2023
1 parent ab04047 commit c263704
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 17 deletions.
22 changes: 14 additions & 8 deletions datasette/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,13 +950,19 @@ async def expand_foreign_keys(self, actor, database, table, column, values):
except IndexError:
return {}
# Ensure user has permission to view the referenced table
if not await self.permission_allowed(
actor=actor,
action="view-table",
resource=(database, fk["other_table"]),
):
other_table = fk["other_table"]
other_column = fk["other_column"]
visible, _ = await self.check_visibility(
actor,
permissions=[
("view-table", (database, other_table)),
("view-database", database),
"view-instance",
],
)
if not visible:
return {}
label_column = await db.label_column_for_table(fk["other_table"])
label_column = await db.label_column_for_table(other_table)
if not label_column:
return {(fk["column"], value): str(value) for value in values}
labeled_fks = {}
Expand All @@ -965,9 +971,9 @@ async def expand_foreign_keys(self, actor, database, table, column, values):
from {other_table}
where {other_column} in ({placeholders})
""".format(
other_column=escape_sqlite(fk["other_column"]),
other_column=escape_sqlite(other_column),
label_column=escape_sqlite(label_column),
other_table=escape_sqlite(fk["other_table"]),
other_table=escape_sqlite(other_table),
placeholders=", ".join(["?"] * len(set(values))),
)
try:
Expand Down
52 changes: 43 additions & 9 deletions tests/test_table_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -1207,9 +1207,11 @@ async def test_format_of_binary_links(size, title, length_bytes):


@pytest.mark.asyncio
async def test_foreign_key_labels_obey_permissions():
ds = Datasette(
metadata={
@pytest.mark.parametrize(
"metadata",
(
# Blocked at table level
{
"databases": {
"foreign_key_labels": {
"tables": {
Expand All @@ -1218,15 +1220,47 @@ async def test_foreign_key_labels_obey_permissions():
}
}
}
}
)
},
# Blocked at database level
{
"databases": {
"foreign_key_labels": {
# Only root can view this database
"allow": {"id": "root"},
"tables": {
# But table b is visible to everyone
"b": {"allow": True},
},
}
}
},
# Blocked at the instance level
{
"allow": {"id": "root"},
"databases": {
"foreign_key_labels": {
"tables": {
# Table b is visible to everyone
"b": {"allow": True},
}
}
},
},
),
)
async def test_foreign_key_labels_obey_permissions(metadata):
ds = Datasette(metadata=metadata)
db = ds.add_memory_database("foreign_key_labels")
await db.execute_write("create table a(id integer primary key, name text)")
await db.execute_write("insert into a (id, name) values (1, 'hello')")
await db.execute_write(
"create table b(id integer primary key, name text, a_id integer references a(id))"
"create table if not exists a(id integer primary key, name text)"
)
await db.execute_write("insert or replace into a (id, name) values (1, 'hello')")
await db.execute_write(
"create table if not exists b(id integer primary key, name text, a_id integer references a(id))"
)
await db.execute_write(
"insert or replace into b (id, name, a_id) values (1, 'world', 1)"
)
await db.execute_write("insert into b (id, name, a_id) values (1, 'world', 1)")
# Anonymous user can see table b but not table a
blah = await ds.client.get("/foreign_key_labels.json")
anon_a = await ds.client.get("/foreign_key_labels/a.json?_labels=on")
Expand Down

0 comments on commit c263704

Please sign in to comment.