cellos-host-cellos
The default proprietary CellOS L2 host backend — a simulated host runtime today, with FD-hygiene primitives ready for the day the real kernel/userspace ABI lands.
What it is
cellos-host-cellos is the supervisor's default [CellBackend]
implementation. It is selected whenever CELLOS_CELL_BACKEND is unset
or matches no known enum value
(crates/cellos-supervisor/src/composition.rs:1113-1138), so every
out-of-the-box run of cellos-supervisor uses it. It also provides the
default [MemorySecretBroker] used by the same composition root when
CELLOS_BROKER is unset (crates/cellos-supervisor/src/composition.rs:1158).
The crate has two surfaces. The first is the simulated host backend:
[ProprietaryCellBackend] (src/lib.rs:251) tracks live cells in an
Arc<Mutex<HashMap<String, CellRecord>>> (src/lib.rs:251-253),
optionally creates a cgroup-v2 leaf at create() when
CELLOS_CGROUP_PARENT is set (src/lib.rs:281-301), and removes all
host-side state at destroy() so residue tests can falsify leaks
(src/lib.rs:344-372). When the real kernel/userspace ABI exists, the
inner implementation can be replaced with FFI / IPC while the same
CellBackend contract holds on the outside.
The second is the FD-hygiene primitive:
[spawn_isolated_workload] (src/lib.rs:134) is the only sanctioned
way for this backend to materialise a child process. It enforces three
invariants on Unix (src/lib.rs:7-23):
- No ambient env.
env_clear()plus exactly the declared injection set — nothing inherited from the supervisor. - Stdio replaced with pipes. stdin / stdout / stderr are wired to fresh pipes whose parent ends drop before the caller can write or read, so a child cannot reach back into the supervisor's terminal or log streams.
- All FDs > 2 closed on exec. A
pre_execclosure walks/proc/self/fdand setsFD_CLOEXECon every fd > 2. The kernel atomically closes those atexecve(2)so a workload never inherits NATS sockets, broker handles, or audit-log writers. There is aRLIMIT_NOFILE-bounded fallback for kernels without/proc(src/lib.rs:188-210).
What it deliberately does not do:
- It does not spawn microVMs. The Firecracker path lives in
cellos-host-firecracker. - It does not own nftables enforcement.
CellHandle.nft_rules_appliedis alwaysNonefrom this backend (src/lib.rs:334-336); the supervisor's host-subprocess path surfaces the egress signal. - It does not implement boot-artifact manifest digests
(
kernel_digest_sha256,rootfs_digest_sha256,firecracker_digest_sha256are allNone,src/lib.rs:338-340).
Public API surface
| Item | Where |
|---|---|
pub struct ProprietaryCellBackend |
src/lib.rs:251 |
impl ProprietaryCellBackend { pub fn new() } |
src/lib.rs:262 |
async fn tracked_cell_count(&self) -> usize |
src/lib.rs:269 |
async fn has_tracked_state(&self, cell_id: &str) -> bool |
src/lib.rs:274 |
impl CellBackend for ProprietaryCellBackend |
src/lib.rs:304 |
pub struct WorkloadEnv |
src/lib.rs:48 |
WorkloadEnv::{new, push, iter, len, is_empty} |
src/lib.rs:52-93 |
pub struct SpawnedWorkload (Unix) |
src/lib.rs:97 |
SpawnedWorkload::{pid, wait, kill} (Unix) |
src/lib.rs:101-117 |
pub fn spawn_isolated_workload(argv: &[String], env: &WorkloadEnv) -> Result<SpawnedWorkload, CellosError> (Unix) |
src/lib.rs:134 |
pub fn spawn_isolated_workload(_argv, _env) -> Result<(), CellosError> (non-Unix stub) |
src/lib.rs:234 |
pub use memory_broker::MemorySecretBroker |
src/lib.rs:27, src/memory_broker.rs:20 |
WorkloadEnv::push rejects keys that are empty, contain =, or contain
NUL; values are rejected when they contain NUL
(src/lib.rs:58-79). spawn_isolated_workload rejects an empty argv
(src/lib.rs:141-145). Non-Unix targets return
CellosError::Host("spawn_isolated_workload: host subprocess spawn is Unix-only") (src/lib.rs:234-238).
ProprietaryCellBackend::create() rejects an empty spec.id
(src/lib.rs:307-308) and rejects a duplicate live cell_id
(src/lib.rs:312-315) — no two live cells ever share an id. On Linux,
when CELLOS_CGROUP_PARENT is set and writable, a per-cell leaf is
created at <parent>/cellos_<sanitized-id>_<uuid> and stored on the
returned CellHandle.cgroup_path (src/lib.rs:289-300).
destroy() rejects an unknown / already-torn-down id with
CellosError::Host (src/lib.rs:347-351) and reports
peers_tracked_after as the remaining live-cell count.
MemorySecretBroker (src/memory_broker.rs:20) implements
cellos_core::ports::SecretBroker with TTL-bound resolve() storing
the simulated value in zeroize::Zeroizing<String>, plus
revoke_for_cell() which drops every row keyed under cell_id
(src/memory_broker.rs:44-73). Tests / operators observe state via
materialized_keys_for_cell() and total_materialized_rows()
(src/memory_broker.rs:29-42).
Architecture / how it works
The backend is a thin in-memory map plus the FD-hygiene spawn helper.
There is no thread pool, no tokio::process::Child tracking, no
background reaper — every method is async fn only because the
CellBackend trait requires it. The map is the source of truth for
"which cells does this host think are live"; the supervisor calls
destroy() at end-of-cell and the entry vanishes, including its cgroup
leaf if one exists (src/lib.rs:355-364).
spawn_isolated_workload is structurally separate from
CellBackend::create. The backend's create() does not spawn a child
itself; the supervisor's host-subprocess path
(cellos-supervisor::supervisor::run_cell_command) calls
spawn_isolated_workload with the argv and the declared env injection
set, and the backend only tracks the existence of the cell. This
matches the L2/L3 split in the layer model: L2 owns
the isolation primitive (FD hygiene + cgroup leaf), L3 owns the
lifecycle (spawn + reap + emit events).
When the proprietary kernel ABI lands, replace the spawn helper's
Command-based pre_exec wiring with the equivalent FFI/IPC call without
changing the WorkloadEnv / SpawnedWorkload shape the supervisor
depends on. The crate-level doc-comment calls this out explicitly
(src/lib.rs:1-6).
Configuration
| Env var | Default | Effect |
|---|---|---|
CELLOS_CELL_BACKEND |
proprietary (this backend) | Set to anything else (firecracker, gvisor, stub) to bypass this backend; unset or unknown values land here. Resolved at crates/cellos-supervisor/src/composition.rs:1029. |
CELLOS_BROKER |
MemorySecretBroker (this crate's broker) |
Same pattern: unset selects the broker exported from this crate; set to env / file / github-oidc / vault-approle to override (crates/cellos-supervisor/src/composition.rs:1146-1158). |
CELLOS_CGROUP_PARENT |
unset → no cgroup leaf | Linux only. When set and writable, every create() makes <parent>/cellos_<sanitized-id>_<uuid> and stores it on the returned handle; destroy() best-effort remove_dir of the leaf, logging warnings on failure (src/lib.rs:282, src/lib.rs:355-364). |
No from_env() / FirecrackerConfig-style struct. The backend is
constructed with ProprietaryCellBackend::new() and reads env vars
lazily.
Examples
use Arc;
use ;
use ;
let backend: = new;
let broker: = new;
// The supervisor composition root wires both into the cell lifecycle.
FD-hygiene-bounded spawn (Unix only):
use ;
let mut env = new;
env.push?;
env.push?;
let argv = vec!;
let mut child = spawn_isolated_workload?;
let status = child.wait?;
assert!;
# Ok::
Testing
cargo test -p cellos-host-cellos
Integration tests under tests/:
| File | Scope |
|---|---|
smoke.rs |
Construction + happy-path create/destroy through the trait. |
cellos_host_cellos_happy_path.rs |
End-to-end happy path. |
contract.rs |
HCELLOS-COV — pins the observable contract against the CellBackend trait so the proprietary backend does not drift from cellos-host-stub / cellos-host-firecracker. |
fd_isolation.rs |
Reads /proc/<child>/environ of a real child and asserts byte-for-byte equality with the declared injection set, validating invariants 1–3 of spawn_isolated_workload (Linux-only). |
In-source unit tests under src/lib.rs:375-433 cover destroy-removes-state,
double-destroy-errors, and peers_tracked_after accounting. The memory
broker's residue contract is in src/memory_broker.rs:80-90.
Related crates
cellos-core— definesCellBackend,SecretBroker,CellHandle,TeardownReport,SecretView, andCellosError.cellos-host-stub— the no-op alternative used in unit tests where this backend's tracking-map behaviour matters but the spawn helper is overkill.cellos-host-firecracker— the microVM backend selected withCELLOS_CELL_BACKEND=firecracker.cellos-host-gvisor— therunscbackend selected withCELLOS_CELL_BACKEND=gvisor.cellos-supervisor— callscreate()/destroy()on this backend by default and invokesspawn_isolated_workloadfromrun_cell_command.
ADRs
- ADR-0001 — Rust + NATS/JetStream + proprietary host — names "the proprietary CellOS host" as the long-horizon path this crate is the simulated stand-in for.
- ADR-0005 — TLS termination design — TLS termination is an egress concern, not a backend concern; this crate does not interpose on the cell's TCP stack.
- ADR-0007 — RBAC + secret-ref admission
— the broker contract this crate's
MemorySecretBrokerimplements (TTL-boundedresolve, fullrevoke_for_cellon teardown).