Skip to content

Commit

Permalink
Record last_used_by and last_used_at, closes #4
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Apr 23, 2024
1 parent b0d4bef commit 458d59b
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 6 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,14 @@ To obtain the current value of the secret, use the `await get_secret()` method:
```python
from datasette_secrets import get_secret
secret = await get_secret(datasette, "OPENAI_API_KEY")
# Third argument is the actor_id, optional
secret = await get_secret(datasette, "OPENAI_API_KEY", "root")
```
If the Datasette administrator set a `DATASETTE_SECRETS_OPENAI_API_KEY` environment variable, that will be returned.

Otherwise the encrypted value in the database table will be decrypted and returned - or `None` if there is no configured secret.

The `last_used_at` column is updated every time a secret is accessed. The `last_used_by` column will be set to the actor ID passed to `get_secret()`, or `null` if no actor ID was passed.

## Development

Expand Down
25 changes: 20 additions & 5 deletions datasette_secrets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
pm.add_hookspecs(hookspecs)


async def get_secret(datasette, secret_name):
async def get_secret(datasette, secret_name, actor_id=None):
secrets_by_name = {secret.name: secret for secret in await get_secrets(datasette)}
if secret_name not in secrets_by_name:
return None
Expand All @@ -24,16 +24,31 @@ async def get_secret(datasette, secret_name):
# Now look it up in the database
config = get_config(datasette)
db = get_database(datasette)
encrypted = (
db_secret = (
await db.execute(
"select encrypted from datasette_secrets where name = ? order by version desc limit 1",
"select id, encrypted from datasette_secrets where name = ? order by version desc limit 1",
(secret_name,),
)
).first()
if not encrypted:
if not db_secret:
return None
key = Fernet(config["encryption_key"].encode("utf-8"))
decrypted = key.decrypt(encrypted["encrypted"])
decrypted = key.decrypt(db_secret["encrypted"])
# Update the last used timestamp and actor_id
params = (actor_id, db_secret["id"])
if not actor_id:
params = (db_secret["id"],)
await db.execute_write(
"""
update datasette_secrets
set last_used_at = datetime('now'),
last_used_by = {}
where id = ?
""".format(
"?" if actor_id else "null"
),
params,
)
return decrypted.decode("utf-8")


Expand Down
25 changes: 25 additions & 0 deletions tests/test_secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ async def test_get_secret(ds, monkeypatch):
get_response = await ds.client.get("/-/secrets/EXAMPLE_SECRET", cookies=cookies)
csrftoken = get_response.cookies["ds_csrftoken"]
cookies["ds_csrftoken"] = csrftoken
db = ds.get_internal_database()
# Reset state
await db.execute_write(
"update datasette_secrets set last_used_at = null, last_used_by = null"
)
post_response = await ds.client.post(
"/-/secrets/EXAMPLE_SECRET",
cookies=cookies,
Expand All @@ -156,7 +161,27 @@ async def test_get_secret(ds, monkeypatch):
)
assert post_response.status_code == 302

assert await get_secret(ds, "EXAMPLE_SECRET", "actor") == "manually-set-secret"

# Should have updated last_used_at and last_used_by
secret = (
await db.execute(
"select * from datasette_secrets where name = ? order by version desc limit 1",
["EXAMPLE_SECRET"],
)
).first()
assert secret["last_used_by"] == "actor"
assert secret["last_used_at"] is not None

# Calling again without actor ID should set that to null
assert await get_secret(ds, "EXAMPLE_SECRET") == "manually-set-secret"
secret2 = (
await db.execute(
"select * from datasette_secrets where name = ? order by version desc limit 1",
["EXAMPLE_SECRET"],
)
).first()
assert secret2["last_used_by"] is None

# Now over-ride with an environment variable
monkeypatch.setenv("DATASETTE_SECRETS_EXAMPLE_SECRET", "from env")
Expand Down

0 comments on commit 458d59b

Please sign in to comment.