Skip to content

Commit

Permalink
Populate new acl_audit table, refs #7
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Aug 31, 2024
1 parent 3ff6f22 commit 1da7447
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 7 deletions.
52 changes: 47 additions & 5 deletions datasette_acl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@

CREATE_TABLES_SQL = """
create table if not exists acl_resources (
id integer primary key autoincrement,
id integer primary key,
database text not null,
resource text,
unique(database, resource)
);
create table if not exists acl_actions (
id integer primary key autoincrement,
id integer primary key,
name text not null unique
);
-- new table for groups
create table if not exists acl_groups (
id integer primary key autoincrement,
id integer primary key,
name text not null unique
);
Expand All @@ -31,7 +31,7 @@
);
create table if not exists acl (
acl_id integer primary key autoincrement,
acl_id integer primary key,
actor_id text,
group_id integer,
resource_id integer,
Expand All @@ -42,6 +42,21 @@
check ((actor_id is null) != (group_id is null)),
unique(actor_id, group_id, resource_id, action_id)
);
-- Audit log
create table if not exists acl_audit (
id integer primary key,
timestamp text default (datetime('now')),
operation_by text,
operation text check (operation in ('added', 'removed')),
action_id integer,
resource_id integer,
group_id integer,
actor_id text,
foreign key (group_id) references acl_groups(id),
foreign key (resource_id) references acl_resources(id),
foreign key (action_id) references acl_actions(id)
)
"""

ACL_RESOURCE_PAIR_SQL = """
Expand Down Expand Up @@ -323,6 +338,7 @@ async def table_acls(request, datasette):
"resource_id": resource_id,
},
)
operation = "added"
changes_made["added"].append((group_name, action_name))
else:
# They removed it
Expand All @@ -340,8 +356,34 @@ async def table_acls(request, datasette):
"resource_id": resource_id,
},
)
operation = "removed"
changes_made["removed"].append((group_name, action_name))

await internal_db.execute_write(
"""
insert into acl_audit (
operation,
actor_id,
group_id,
resource_id,
action_id,
operation_by
) values (
:operation,
null,
(SELECT id FROM acl_groups WHERE name = :group_name),
:resource_id,
(SELECT id FROM acl_actions WHERE name = :action_name),
:operation_by
)
""",
{
"operation": operation,
"group_name": group_name,
"resource_id": resource_id,
"action_name": action_name,
"operation_by": request.actor["id"],
},
)
datasette.add_message(request, f"Made changes: {repr(changes_made)}")
return Response.redirect(request.path)

Expand Down
72 changes: 70 additions & 2 deletions tests/test_acl.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ async def test_permission_allowed():
actor=admin_actor, action="insert-row", resource=["db", "t"]
)
assert not allowed
# acl_audit table should be empty
assert (await db.execute("select count(*) from acl_audit")).single_value() == 0
# Use the /db/table/-/acl page to insert a permission
csrf_token_response = await datasette.client.get(
"/db/t/-/acl",
Expand Down Expand Up @@ -150,9 +152,75 @@ async def test_permission_allowed():
"resource_name": "t",
}
]
allowed = await datasette.permission_allowed(
# Should have added to the audit table
AUDIT_SQL = """
select
acl_groups.name as group_name,
acl_actions.name as action_name,
acl_resources.database as database_name,
acl_resources.resource as resource_name,
acl_audit.operation_by,
acl_audit.operation
from acl_audit
join acl_groups on acl_audit.group_id = acl_groups.id
join acl_actions on acl_audit.action_id = acl_actions.id
join acl_resources on acl_audit.resource_id = acl_resources.id
order by acl_audit.id
"""
audit_rows = [dict(r) for r in (await db.execute(AUDIT_SQL))]
assert audit_rows == [
{
"group_name": "admin",
"action_name": "insert-row",
"database_name": "db",
"resource_name": "t",
"operation_by": "root",
"operation": "added",
}
]
# Now the admin actor should be able to insert a row
assert await datasette.permission_allowed(
actor=admin_actor,
action="insert-row",
resource=["db", "t"],
)
assert allowed
# remove insert-row and add alter-table and check the audit log
response2 = await datasette.client.post(
"/db/t/-/acl",
data={
"permissions_admin_alter-table": "on",
"csrftoken": csrftoken,
},
cookies={
"ds_actor": datasette.client.actor_cookie({"id": "root"}),
"ds_csrftoken": csrftoken,
},
)
assert response2.status_code == 302
audit_rows2 = [dict(r) for r in (await db.execute(AUDIT_SQL))]
assert audit_rows2 == [
{
"group_name": "admin",
"action_name": "insert-row",
"database_name": "db",
"resource_name": "t",
"operation_by": "root",
"operation": "added",
},
{
"group_name": "admin",
"action_name": "insert-row",
"database_name": "db",
"resource_name": "t",
"operation_by": "root",
"operation": "removed",
},
{
"group_name": "admin",
"action_name": "alter-table",
"database_name": "db",
"resource_name": "t",
"operation_by": "root",
"operation": "added",
},
]

0 comments on commit 1da7447

Please sign in to comment.