pub struct State {
pub store: Mutex<Store>,
pub root: PathBuf,
pub sessions: Mutex<HashMap<MergeSessionId, ApiMergeSession>>,
pub policy_ceiling: Option<Policy>,
}Fields§
§store: Mutex<Store>§root: PathBufFilesystem root of the store. Held alongside the Store
itself so handlers that need to read store-level files
(e.g. users.json for actor auth) don’t have to round-
trip through the lock.
sessions: Mutex<HashMap<MergeSessionId, ApiMergeSession>>In-memory merge sessions, keyed by MergeSessionId. Sessions
are ephemeral by design (#134 foundation): they live for the
lifetime of the server process and are GC’d on commit. A
future slice can persist them to disk so a session survives
process restarts. For now an agent that gets unlucky with a
restart re-runs merge/start and gets a fresh session.
policy_ceiling: Option<Policy>Optional server-imposed ceiling on the effect policy honored
by /v1/run and /v1/replay. None (the default, used by
single-tenant lex serve) runs the caller’s request policy
as-is — the operator is the caller there, so that’s
intended. When Some, the request policy is clamped via
[clamp_policy] so it can only narrow the ceiling, never
widen it.
Any embedder that exposes this API to untrusted callers — a
hosted, multi-tenant gateway like lex-hub — MUST set this.
Without it the request body can grant itself [proc]
(arbitrary subprocess spawn), [fs_*] over /, and
unrestricted [net]: arbitrary code execution as the server
process. See lex-hub#6.
NOTE: an empty scope list means “any path/host” in the
runtime, so a ceiling that puts fs_read/fs_write/net in
allow_effects MUST also populate the matching scope list
(allow_fs_read, …) or it re-opens the wildcard. Granting
none of those kinds is the safe default.
Implementations§
Source§impl State
impl State
pub fn open(root: PathBuf) -> Result<Self>
Sourcepub fn open_with_ceiling(
root: PathBuf,
policy_ceiling: Option<Policy>,
) -> Result<Self>
pub fn open_with_ceiling( root: PathBuf, policy_ceiling: Option<Policy>, ) -> Result<Self>
Like State::open but installs a policy_ceiling
that /v1/run and /v1/replay clamp the caller’s request
policy against. Embedders exposing this API to untrusted
callers must use this constructor (or set the field directly).
Sourcepub fn new_with_tenant(tenant_id: &str, store_root: PathBuf) -> Result<Self>
pub fn new_with_tenant(tenant_id: &str, store_root: PathBuf) -> Result<Self>
Construct a per-tenant State by prefixing store_root with the
tenant id. Single-tenant lex serve is unaffected — it calls
State::open directly.
tenant_id is restricted to [A-Za-z0-9_-]{1,64}: anything else
(path separators, .., NUL, absolute paths, dotfiles, empty
string) is rejected before touching the filesystem. Without this
PathBuf::join("/etc") would silently replace store_root, and
PathBuf::join("../foo") would escape the tenant root.
Sourcepub fn new_with_tenant_and_ceiling(
tenant_id: &str,
store_root: PathBuf,
policy_ceiling: Option<Policy>,
) -> Result<Self>
pub fn new_with_tenant_and_ceiling( tenant_id: &str, store_root: PathBuf, policy_ceiling: Option<Policy>, ) -> Result<Self>
Multi-tenant constructor that also installs a policy ceiling
for /v1/run / /v1/replay. The path-traversal guard from
new_with_tenant and the effect
ceiling are the two halves a hosted gateway needs.