cubesys: add cube systemd daemon (cube-server) + socket client (cubec)

Implements the requested cube service: a long-lived daemon that holds ONE
CubeStore for its whole lifetime and serves the cube command language over a
Unix-domain socket, plus cubec to talk to it.

- cubesys::commands: factored the single command interpreter (Session::exec)
  so cube REPL, cubec client, and the daemon run identical logic
- cubesys::net: dependency-free length-framed AF_UNIX transport
- cubesys::persist: dependency-free JSON snapshot (atomic tmp+rename) so the
  store -- including sealed/encrypted records -- survives daemon restarts
- cube-server: listens on $XDG_RUNTIME_DIR/cube/cube.sock, snapshots to
  $XDG_STATE_HOME/cube/cube-store.json, replays on startup
- cubec: one-shot + REPL client over the socket
- cube.rs trimmed to a thin REPL/script/demo driver (help text updated)
- /etc/systemd/system/cube.service: runs as luulu, ProtectSystem=strict,
  RestrictAddressFamilies=AF_UNIX, Restart=on-failure; enabled + active
- integration.md documents the daemon + caveat (open rewrites plaintext)

Verified: ./check (fmt+tests+clippy -D warnings) green; ./check mount (27
FUSE e2e) green; socket CLI round-trips; sealed record survived a full
service restart and reopened+r with original value.
This commit is contained in:
CUBELinux-2
2026-08-11 00:10:45 -04:00
parent 35e5183193
commit 06ea3252eb
9 changed files with 807 additions and 227 deletions
+49 -1
View File
@@ -79,6 +79,51 @@ the spec never defined.
record, reopen + run). Prints evidence at each step.
* `cube` — CLI: `write`, `run`, `ls`, `stat`, `seal`, `open` over one store,
interactively (`repl`), from a file (`script`), or as the demo (`demo`).
* `cube-server` — long-lived daemon: holds ONE `CubeStore` for its whole
lifetime and serves the same command language over a Unix-domain socket.
Snapshots the store to a JSON file on every request so the cube survives
restarts (see below).
* `cubec` — client for `cube-server`: one-shot (`cubec prog ...`) or REPL
(`cubec` with stdin), talking the framed Unix socket.
## The daemon: `cube-server` + `cubec`
The directive asked for "a cube systemd service that holds the store and
exposes the CLI over a socket." That is `cube-server` + `cubec`:
* **One store, one process.** The daemon owns a single [`Session`] (one
`CubeStore`) and serves requests sequentially. Every front-end — `cube`,
`cubec`, the daemon — executes the *identical* command interpreter
(`cubesys::commands::Session::exec`), so behavior cannot drift.
* **Socket transport** (`cubesys::net`): each request is one frame
(`[u32 len][utf8 command line]`), one reply frame. No delimiters, no partial
reads. Default socket is `$XDG_RUNTIME_DIR/cube/cube.sock`.
* **Persistence** (`cubesys::persist`): every record is serialized to a JSON
snapshot (`$XDG_STATE_HOME/cube/cube-store.json`) after each mutating
command (atomic temp-write + rename). On startup the daemon replays the
snapshot so sealed/encrypted state survives a restart. Verified: a record
sealed, then the service restarted, then `open`+run still halts with the
original value.
* **systemd unit** (`/etc/systemd/system/cube.service`): runs as `luulu`,
`Restart=on-failure`, `ProtectSystem=strict`, `RestrictAddressFamilies=AF_UNIX`
(socket only), writes confined to `/home/luulu/.cubelinux` and the runtime dir.
Enabled + running.
```sh
# daemon already running via systemd; talk to it:
cubec prog /c005/z001/y001/x007 const 7 halt
cubec run /c005/z001/y001/x007
cubec seal /c005/z001/y001/x007 0.1.0.1 gcm
cubec open /c005/z001/y001/x007 0.1.0.1 gcm
cubec ls /
```
**Caveat (inherited from the CLI):** `open` decrypts a sealed record and writes
the plaintext back to the same coordinate before running, so the encrypted
state is replaced by plaintext after one `open`. That is the original
`cube`/`cubesys` behavior and is acceptable for a demo/control socket; a
read-only "open" (decrypt into a scratch coordinate, run, leave the sealed
record intact) would be the fix if sealed-at-rest must be preserved across reads.
## Building / testing
@@ -87,4 +132,7 @@ cd /home/CUBELinux/CUBELinux-2
./check quick # fmt + clippy -D warnings + tests (the gate)
./check mount # also builds cubefs --features mount (FUSE adapter)
cargo run -p cubesys --bin cube-demo
```
cargo run -p cubesys --bin cube -- repl # local in-process REPL
# daemon mode:
systemctl status cube.service
cubec --socket /run/user/1000/cube/cube.sock ls /