Expand description
SqliteOperatorSessionStore — SQLite-backed OperatorSessionStore
using [rusqlite-isle].
The Connection is confined to a dedicated OS thread by AsyncIsle;
every call is a typed closure dispatched over a bounded channel.
capability_manifest and the 記名’s observed log are stored as JSON
blobs — neither is queried relationally; the boot-time list()
rehydration decodes them back into their Rust shapes.
§The file holds no bearer secret
token_digest is hex(SHA-256(bearer)), never the bearer itself (see
OperatorSessionRecord’s type doc). Two further measures back that up:
- the file is
chmod 0600on unix ([harden_file_permissions]) — best-effort, and skipped entirely on other platforms; - a pre-release database carrying the old plaintext
tokencolumn is dropped and recreated on open ([purge_legacy_plaintext_table]) rather than migrated, so no plaintext residue survives the upgrade. The cost is one forced re-login for sessions minted by a dev build.
§Schema
CREATE TABLE IF NOT EXISTS operator_sessions (
sid TEXT PRIMARY KEY,
token_digest TEXT NOT NULL, -- hex(SHA-256(bearer)), never the bearer
capability_manifest_json TEXT, -- JSON-encoded manifest, NULL when unset
joined_at_secs INTEGER NOT NULL,
join_desc TEXT, -- 記名 confirmed part (D1), NULL when unwritten
observed_json TEXT, -- 記名 observed part (D2), JSON array
observed_total INTEGER NOT NULL DEFAULT 0,
last_access_secs INTEGER NOT NULL DEFAULT 0 -- O1's expiry clock
);The 記名 columns (model §4.2) and last_access_secs (the 24h horizon) all
arrived after the table did, and are added to an older file the same
way the runs table grows a column — by
[migrate_add_column_if_missing], except for last_access_secs, whose
back-fill matters enough to have its own migration
([migrate_add_last_access_column]): a plain DEFAULT 0 would make
the first read after an upgrade expire every carried-over session.
A column also left: roles_json held the role aliases a session
claimed at join, back when a join claimed any. Role declaration moved
onto the Run, so an older file has the column dropped on open by
[migrate_drop_column_if_present] — see that function for why the
column cannot simply be ignored.
Structs§
- Sqlite
Operator Session Store - SQLite-backed persistent
OperatorSessionStore.