feat(users): unlock and start unencrypted users at boot
Nightly Build / build (push) Successful in 8m10s
Nightly Build / build (push) Successful in 8m10s
A login is what makes an *encrypted* database readable; for an
unencrypted one it gated nothing but the runtime — the file has no key
and is already readable by this process. The cost was user-visible and
read as a bug: after every restart the Telegram bot answered "your
account is locked, log in via the web app", cron fired nothing and no
background agent ran, until a human opened the SPA.
`Skald::new` now calls `UserManager::unlock_all_unencrypted`, which
registers the pools exactly as a login would and refuses an encrypted or
inactive user. Unlocking alone only makes the data readable, so
`wiring::spawn_unlocked_user_runtimes` then builds a `UserContext` for
each — cron, the notify queue, the hub and the per-user MCP runtime all
hang off it. That build is a background supervisor task rather than part
of `new()`: it starts every member's MCP servers inside their container,
and the HTTP listener must not wait behind it. The same two steps run
per user off the lifecycle bus (`UserCreated`,
`UserActiveChanged{active:true}`, after the container `ensure`), so a
member created at runtime does not wait for the next restart.
Two boundaries stay where they were. Authentication is untouched:
`SessionStore` sits above `UserManager`, so no HTTP request
authenticates as anyone because of this. And the auto-unlock is
deliberately not on a lazy path such as `Skald::user_context` —
`revoke_user_runtime` locks a pool synchronously and expects nothing to
re-open it, so the writers of that map stay boot, login and the bus.
`open_db` and the two unencrypted openers now share `register_unlocked`
and `open_unencrypted_file`; `open_unencrypted` (the supervision path)
still does not register its pool.
This commit is contained in:
@@ -65,11 +65,13 @@ The report is kept where the supervisors can read it rather than in the reviewed
|
||||
|
||||
## Why a run can be missing
|
||||
|
||||
Users are handled one at a time, and a user is **skipped** if they have not logged in since the server last restarted.
|
||||
Users are handled one at a time, and a user with an **encrypted** space is **skipped** if they have not logged in since the server last restarted.
|
||||
|
||||
This is not a fault, it is how the encryption works: a person's data is unreadable until they log in and their password unlocks it. Until that happens there is nothing to read and nowhere to write. Nothing is lost — events keep accumulating, and the first run after they log in picks up everything waiting.
|
||||
This is not a fault, it is how the encryption works: their data is unreadable until they log in and their password unlocks it. Until that happens there is nothing to read and nowhere to write. Nothing is lost — events keep accumulating, and the first run after they log in picks up everything waiting.
|
||||
|
||||
So if someone asks "why didn't it tell me about that email from this morning?", the first thing to check is whether they had logged in at the time. The same applies to the shared memory lint: it needs an admin who has logged in since the restart.
|
||||
Someone whose space is **not** encrypted is picked up as soon as the server starts, with no login at all: there is no key to wait for, so their agents (and their scheduled tasks, and their Telegram chat) work straight after a restart.
|
||||
|
||||
So if someone asks "why didn't it tell me about that email from this morning?", the first thing to check is whether they have an encrypted space, and if so whether they had logged in at the time. The same applies to the shared memory lint: it needs an admin who is available — which for an encrypted admin means logged in since the restart.
|
||||
|
||||
Schedules are counted **per person from their own last run**, and they survive a restart — so a weekly pass stays weekly even on a machine that gets rebooted every few days.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user