also looking at this
A read-scoped project key, so a Stacks dashboard can read logs without a person's credentials
#15
9 files
+537
-17
| @@ -0,0 +1,25 @@ | ||
| 1 | -- SQLITE DIALECT, WRITTEN BY HAND. See stacksjs/stacks#2346. | |
| 2 | -- | |
| 3 | -- A read-scoped project key, so a machine can read this project's logs without | |
| 4 | -- holding a person's credentials (loghqorg/loghq#14). | |
| 5 | -- | |
| 6 | -- `ingest_key` beside it is public and write-only: it ships in client bundles | |
| 7 | -- and only permits writing to one project. This one returns data, so it is a | |
| 8 | -- secret, it is compared in constant time (app/Support/read-key.ts), and the | |
| 9 | -- ingest route never accepts it. | |
| 10 | -- | |
| 11 | -- Both columns are nullable because a key is issued on demand rather than at | |
| 12 | -- creation. A project that never needs one never has one, and revoking is | |
| 13 | -- setting the column back to NULL — which is also why the uniqueness below is | |
| 14 | -- a partial index: every revoked project would otherwise collide on NULL. | |
| 15 | -- | |
| 16 | -- `read_key_last_used_at` exists so somebody can tell whether a key is still | |
| 17 | -- in use before revoking it. It is written at most once a minute per key | |
| 18 | -- (LAST_USED_RESOLUTION_MS), not on every request: the dashboard polls the log | |
| 19 | -- stream, and an UPDATE in front of every poll would cost more than the stamp | |
| 20 | -- is worth. | |
| 21 | -- | |
| 22 | -- Numbered 24, continuing past 0000000023. | |
| 23 | ALTER TABLE "projects" ADD COLUMN "read_key" TEXT; | |
| 24 | ALTER TABLE "projects" ADD COLUMN "read_key_last_used_at" TEXT; | |
| 25 | CREATE UNIQUE INDEX IF NOT EXISTS "projects_read_key_unique" ON "projects" ("read_key") WHERE "read_key" IS NOT NULL; | |