lazaret/docs/specification.md
ms2k f7ba1d539f docs: integrate domain-scoped multi-instance multiplexing and persistent overlay sharing
Overhaul the architectural specification (specification.md) and reorganize
the developer journals to incorporate the new Domain Anchor model. This scopes
sandbox container names, lockfiles, control sockets, and State Anchor persistent
overlay filesystem layers to unique (agent, workspace) hash pairings.

- Add Domain Anchor and Domain Root definitions to glossary and expansion tokens.
- Specify the Ephemeral Session Coordinator pattern with hold-to-bind locking.
- Document Git Sentry nested read-only mount layout replacing the legacy Git Shadow.
- Renamed and reorganized research sub-journals, embedding executable Python logic in-place.
- Include `redb` for embedded transactional state.
2026-06-28 23:20:06 +09:00

36 KiB

Lazaret: Unified Sandbox Quarantine & Host Escalation CLI

Architecture & Technical Specification

Lazaret is a secure developer-experience (DX) tool written in Rust. It orchestrates rootless, gVisor-sandboxed container environments for AI agents, isolating them from the host network and system namespace by default, while providing an interactive, human-in-the-loop (HITL) Host Escalation protocol for controlled actions.

Glossary

Term Definition
Agent Workspace The bind-mounted host project directory inside the Agent Sandbox (at /workspace).
Agent Sandbox The gVisor (runsc) container running an agent profile, scoped uniquely to a Domain Anchor (representing a specific agent and canonical workspace path pairing).
Client Session A dynamic pairing of an active host lazaret CLI process and its corresponding containerized shell session inside the Agent Sandbox, secured by a Session Anchor and a Trust Anchor.
Session Anchor The ephemeral asymmetric keypair (K_{pub\_proc}, K_{priv\_proc}) generated by a host CLI process upon startup, used to cryptographically sign process-level escalation requests.
Session Coordinator The background-detached, decentralized host coordinator process that manages the container, Network Sidecar, and State Anchor overlays for a specific Domain Anchor.
Network Sidecar The shell-less gateway container (from scratch) running the Netlink router under runc, scoped uniquely to a Domain Anchor to enforce network egress policies.
Git Sentry The hybrid nesting layout consisting of the read-write mounted host .git under /workspace/.git, paired with a transient tmpfs mask over hooks, and a read-only bind mount of .git/config.
State Anchor The host-side fuse-overlayfs structure (usr_changes, usr_work, usr_merged) that merges a read-only container base OS directory with a persistent, writable host layer (scoped under the Domain Root), bind-mounted over container system paths (e.g., /usr) to preserve state for that specific agent-workspace pairing across container restarts.
Trust Anchor The in-memory, local ephemeral Certificate Authority (CA) managed by the host orchestrator or Session Coordinator on startup to issue short-lived cryptographic client certificates to sandboxes for secure mutual TLS (mTLS) identity verification over the Escalation Socket.
Host Escalation The secure UDS channel (secured by mTLS via the Trust Anchor) from the Escalation Client to the host TUI for approved host actions.
Escalation Client The statically compiled lazaret-escalate binary, volume-mounted read-only inside the sandbox.
Escalation Socket The UNIX domain socket scoped to a Domain Anchor used for routing Host Escalation commands.
Domain Anchor The deterministic, cryptographically derived boundary (representing the pairing of a specific agent profile and a unique absolute host workspace path) used to scope and namespace the sandbox container name, the Session Coordinator's control socket, the advisory lockfile, and the persistent State Anchor storage.
Domain Root The directory on the host filesystem (<data_root>/domains/<domain_anchor_hash>/) under the Storage Root where the State Anchor and other domain-scoped files are stored.
Storage Root The host directory configured via the data_root property, serving as the base folder for all persistent agent profiles and domain storage.

Fixed In-Container Paths

Lazaret-managed files and sockets inside every Agent Sandbox live under /run/lazaret/:

Path Description
/run/lazaret/escalate The Escalation Client binary (volume-mounted, read-only).
/run/lazaret/escalate.sock The Escalation Socket.
/run/lazaret/certs Ephemeral Trust Anchor client certificates (memory-backed tmpfs, read-only).

The Agent Workspace is mounted at /workspace.


1. System Objectives & Goals

The primary objectives of Lazaret are to establish a secure, rootless, and isolated sandbox for untrusted AI agent execution while maintaining a functional developer experience through secure host escalation, persistent state, and real-time Git synchronization.

1.1 Core Objectives

  • Deep Virtualization-Based Isolation: Run AI agent workspaces in rootless Podman containers utilizing the gVisor (runsc) sandbox runtime to establish a host-container kernel boundary.
  • Network Sidecar: Route container traffic through a statically compiled, shell-less network gateway container (scratch) running a custom Netlink router that dynamically applies egress policies.
  • Persistent State: Provide configurable persistence folders via a State Anchor to persist designated system and workspace directories across container restarts.
  • Git Hook & Config Protection: Enforce the Git Sentry isolation pattern to block git hook writes and config pager modifications, while permitting standard local git commands and tracking upstream configuration changes.
  • Host Escalation: Provide a secure UNIX Domain Socket (UDS) Escalation Socket channel, verified via the Trust Anchor (using mTLS), to route structured command execution requests from the Escalation Client inside the Agent Sandbox to the host orchestrator for user approval or modification.

2. Architecture & Data Flow

graph TD
    subgraph Host Machine
        Orchestrator[Lazaret Host CLI Process]
        Config[~/.config/lazaret/config.toml]
        Storage[Sandbox Storage Root / NVMe]
        TUI[Interactive HITL TUI Prompt]
        UDS_Server[Unix Domain Socket Server]
    end

    subgraph Container Isolation Boundary
        subgraph Gateway Sidecar (scratch - runc)
            RouteProcess[Netlink Router Process]
        end

        subgraph Agent Sandbox (Debian Trixie - runsc/gVisor)
            AgentProcess[Agent Process / CLI]
            EscalateCLI[lazaret-escalate CLI]
        end
    end

    Orchestrator -->|Loads| Config
    Orchestrator -->|Initializes Storage| Storage
    Orchestrator -->|Spins up Sidecar| RouteProcess
    Orchestrator -->|Launches Sandbox| AgentProcess
    
    RouteProcess -->|Configures Netlink| GatewaySidecarNetwork
    AgentProcess -->|Binds Network Namespace| RouteProcess
    
    AgentProcess -->|Requests host command| EscalateCLI
    EscalateCLI -->|JSON Request via UDS| UDS_Server
    UDS_Server -->|Triggers Prompt| TUI
    TUI -->|User Approval / Modification| Orchestrator
    Orchestrator -->|Executes Command on Host| HostEnv[Host Environment]
    HostEnv -->|Sends Stdout / Stderr| UDS_Server
    UDS_Server -->|JSON Response| EscalateCLI

3. Configuration Contract

Configuration files are parsed hierarchically (lowest precedence to highest):

  1. User-wide global default: ~/.config/lazaret/config.toml
  2. Workspace local override: ./lazaret.toml (in the active working directory)
  3. Direct override command-line argument: --config <file>

A configuration template demonstrating representative agent profiles is located in the repository as example.toml.

3.1 Schema Contract Specification

Section [storage]

Property Type Required Description
data_root String Yes Absolute path on the host where persistent directories (home, usr, etc.) are initialized and mounted.

Section [network]

Property Type Required Description
default_allow Array of Strings Yes Global whitelist of destination CIDR networks permitted for all containers.
default_deny Array of Strings Yes Global blacklist of destination CIDR networks (e.g., RFC 1918) blackholed for all containers.

Section [escalation]

Property Type Required Description
enabled Boolean Yes Activates or suspends the host-side Escalation Socket listener during the lifecycle of the CLI command.
socket_dir String Yes Path on the host filesystem (e.g. /run/user/1000/lazaret/ or /tmp/lazaret) where profile-specific Unix Escalation Sockets are created.
auto_approve Array of Strings No List of user-defined CLI commands allowed to execute on the host automatically without interactive confirmation.

Section [profiles.<profile_name>]

Property Type Required Description
image String Yes The fully-qualified OCI container image to pull and launch. To prevent background updates and local host state drift, specific image tags or SHA-256 digests should be pinned.
persistent_dirs Array of Strings No Paths inside the container copied out and persisted under the host's storage directory (e.g. /usr, /var).
allow_egress Array of Strings No CIDRs allowed specifically for this agent, merged with the default global network whitelist.
env Map of Key-Value No Environment variables forwarded to the container. Setting a value prefix of env:VAR_NAME pulls dynamically from the host.
volumes Array of Objects No Custom volumes mapped from host to container. Hosts support the {profile_dir} expansion.

Custom Volume Object

  • host: String. Host directory or file path. May use {profile_dir} which resolves to <data_root>/<profile_name>/.
  • container: String. Target path inside the container's directory tree.
  • mode: String. Mount properties (e.g., z for SELinux sharing, ro for read-only bind mounts).

3.2 Variable Expansion, Templating & Sanitation Specification

Lazaret implements a custom, zero-dependency, safe variable substitution engine for configuration parsing.

3.2.1 Linux-Only Tilde (~) Expansion

Lazaret supports only Linux-based host environments. Path resolution and tilde (~) expansion must conform to Linux directory standards:

  • Lazaret retrieves the host user's home directory by reading the $HOME environment variable, falling back to query the host's /etc/passwd entry if $HOME is unpopulated.
  • Strict Validation: Tilde is only expanded if it is the absolute first character of the path string (e.g. ~/config resolves to /home/user/config, but some/path/~ is treated as a literal directory named ~).

3.2.2 Expansion Tokens

Lazaret parses and expands a small, strictly defined whitelist of local variables inside configuration fields:

  • {profile_name}: Evaluates to the lowercase alphanumeric name of the active agent profile.
  • {profile_dir}: Expands dynamically on the host to: {data_root}/{profile_name}.
  • {domain_hash}: Evaluates to the 12-character SHA-256 hexadecimal hash representing the Domain Anchor of the active (agent_name, canonical_workspace_path) pair.
  • {domain_dir}: Expands dynamically on the host to the Domain Root directory: {data_root}/domains/{domain_hash}.
  • {workspace_dir}: Evaluates to the current host working directory.

3.2.3 Sanitation & Directory Traversal Protection

Lazaret enforces three structural validation boundaries for configuration paths:

  1. Profile Name Sanitation: Profile names must strictly match the regex pattern: ^[a-z0-9_-]{2,32}$. Any profile name containing dots (.), slashes (/, \), or shell metacharacters is immediately rejected, preventing injection attacks when creating paths like {data_root}/{profile_name}.

  2. Path Traversal Interception: Before resolving any expanded path, Lazaret passes the resulting string to a sanitation function that checks for the presence of relative path segments. If a resolved path contains a dot-dot segment (..), the execution is aborted immediately with a security panic, preventing the agent from escaping the storage boundaries.

  3. Absolute Path Verification: All host paths used for mounts, storage, and volumes are canonicalized (resolving all symlinks and relative segments to absolute paths) before being passed to Podman execution commands. This prevents relative symlink tricks or path obfuscation from bypassing rootless boundaries.


4. Key Security & Functional Mechanisms

4.1 Git Hook & Config Isolation (Git Sentry)

Lazaret isolates the container's Git environment and prevents modifications to host configuration and hook files using a nested ("Inside Mount") layout called Git Sentry.

When a git configuration is updated on the host, Git atomically unlinks and replaces .git/config. A direct single-file read-only bind mount of .git/config remains bound to the stale, unlinked file inode inside the container namespace (the Unix stale inode problem). To ensure that the container namespace dynamically reflects host-side updates, the read-only file mount must be nested inside a parent read-write bind-mounted directory, allowing the kernel to resolve the updated inode path dynamically.

4.1.1 The Decoupling Protocol

The host orchestrator constructs a nested virtual layout inside the container's mount namespace to isolate the Git configuration and hook directories:

  1. Agent Workspace Mount: The active Agent Workspace is bind-mounted read-write at /workspace (utilizing the :z flag for rootless SELinux compatibility). This exposes the host's .git/index to enable standard git status and staging operations from within the container.
  2. Hooks Sandbox Mount: A memory-backed tmpfs volume is mounted over /workspace/.git/hooks inside the container to isolate hook creation and execution to transient container memory.
  3. Config Read-Only Mount: The host's .git/config file is bind-mounted read-only over /workspace/.git/config. Because this mount is nested inside the parent bind-mounted /workspace directory, parent directory resolution propagates host-side atomic replacements of .git/config to the container namespace, bypassing the stale inode problem.

Filesystem Mount Mapping Table

Path in Agent Workspace Mount Type Properties / Permissions Purpose
/workspace Bind Mount Read / Write (z shared) Shares the active project folder with the Agent Sandbox.
/workspace/.git/hooks tmpfs Memory-only, transient Masks the git hooks folder inside the Agent Workspace, blocking direct host hook writes.
/workspace/.git/config Bind Mount Read-Only (ro, z shared) Prevents modification of git configurations, while allowing dynamic updates from host.
/workspace/.vscode tmpfs Memory-only Masks user's host VSCode preferences inside the Agent Workspace.
/workspace/.idea tmpfs Memory-only Masks user's host IntelliJ configurations inside the Agent Workspace.

4.1.2 Security & Operational Guarantees

  • Immutable Target Integrity: Write or append attempts targeting /workspace/.git/config inside the container must fail at the kernel level with EROFS.
  • Deletion Blocked: Deletion or unlinking of /workspace/.git/config inside the container must be blocked by the kernel VFS layer with EBUSY (Device or resource busy).
  • Instant Configuration Visibility: Updates to .git/config on the host must propagate instantly to the container's /workspace/.git/config mount via parent directory resolution.
  • State Propagation: Branch modifications and reference writes made by the container to /workspace/.git/HEAD and /workspace/.git/refs must propagate to the host in real-time.

4.2 Sandbox Git Worktree/Branch Isolation

Lazaret isolates sandbox git actions to a dedicated branch namespace:

  • Dedicated Branch: Lazaret must automatically derive an agent-specific branch name (lazaret/agent-<name>) from the active host commit.
  • Stash Protection: The host workspace active working tree must remain unmodified during sandbox execution. Changes made by the agent within the sandbox must be committed or written only to the dedicated branch, allowing the user to inspect differences on the host with git diff or merge changes explicitly.

4.3 State Scoping & Multi-Instance Lifecycle via Domain Anchor

Lazaret scopes persistent state, socket routing, and container lifecycles to a cryptographically derived Domain Anchor.

4.3.1 Domain Anchor Derivation Protocol

For every CLI invocation, the host orchestrator must compute a unique, deterministic 12-character hexadecimal identifier (the domain_hash) representing the active boundary. The hash is derived as follows:

  1. Retrieve the lowercase alphanumeric agent profile name.
  2. Canonicalize the absolute filesystem path of the active Agent Workspace on the host.
  3. Compute the SHA-256 digest of the UTF-8 encoded string: "<agent_name>:<canonical_workspace_path>".
  4. Truncate the resulting hexadecimal string to its first 12 characters.

This identifier must be used to isolate host-side resources. The resource mapping rules are defined below:

Resource Type Host Pathing Rule Format / Name Scheme
Domain Root {data_root}/domains/{domain_hash}/ Path to persistent domain storage.
Control Socket /tmp/lazaret_coord_{domain_hash}.sock Unix socket for Coordinator control.
Lock File /tmp/lazaret_coord_{domain_hash}.lock Path used for advisory locking.
Container Name lazaret-coord-{domain_hash} Scoped Podman container instance name.

4.3.2 Host-Side Directory Layout

The State Anchor directory structure is established on the host under the Domain Root ({data_root}/domains/{domain_hash}/):

  • usr_changes/: The persistent, writable layer (upperdir) storing user-installed packages and modifications. Initially empty.
  • usr_work/: The private metadata workspace directory (workdir) required by overlayfs.
  • usr_merged/: The virtual, merged mount point directory (mergeddir) exposed to the sandbox.

4.3.3 State Anchor Mounting Protocol

The host orchestrator establishes a user-space overlay filesystem (such as fuse-overlayfs) on the host within the rootless user namespace before launching the container:

  1. Locate Base Image Mount: The orchestrator must query the OCI runtime to resolve the base-image read-only root mount path on the host.
  2. Mount User-Space Overlay: The orchestrator must mount a user-space overlay filesystem (e.g. fuse-overlayfs) within the rootless user namespace, using the base-image mount /usr directory as the read-only lower directory (lowerdir), and the domain-scoped directories usr_changes/ and usr_work/ as the upperdir and workdir, respectively.
  3. Sandbox Mount Injection: The orchestrator must launch the container with the merged user-space overlay directory (usr_merged/) bind-mounted read-write over the container's /usr path.

4.3.4 Image Drift Mitigation & Podman Compatibility

The State Anchor overlay structure dynamically tracks updates to the underlying OCI container base image.

  • Base Image Update Inheritance: Upon pulling an updated base image, the orchestrator uses the new image's /usr directory as the read-only lowerdir for subsequent user-space overlay mounts, preserving modifications in usr_changes/.
  • Podman Integration Compatibility Exclusion: When applying State Anchor overlays over system directories (such as /etc), the orchestrator must exclude runtime-injected configuration files (specifically /etc/resolv.conf, /etc/hosts, and /etc/hostname) from the overlay merge to preserve container DNS and hostname resolution.

4.3.5 Ephemeral Session Coordinator & Multi-Instance Multiplexing

Lazaret coordinates concurrent CLI processes interacting with the same Domain Anchor using a decentralized, background-detached Session Coordinator pattern.

graph TD
    %% Nodes
    subgraph Host OS Namespace
        CLI_A["CLI Session A<br>(Leader)"]
        CLI_B["CLI Session B<br>(Follower)"]
        
        Lock["Advisory Lockfile<br>(LOCK_EX)"]
        
        Coord["Session Coordinator<br>(Background Process)"]
        Socket["Control Socket<br>(AF_UNIX)"]
        
        Overlay["State Anchor<br>(fuse-overlayfs)"]
    end
    
    subgraph gVisor Sandbox Namespace
        Container["gVisor Container<br>(lazaret-coord-{hash})"]
    end

    %% Interactions (Leader Sequence)
    CLI_A -->|1. Acquires LOCK_EX| Lock
    CLI_A -->|2. Spawns| Coord
    Coord -->|3. Mounts usr_merged| Overlay
    Coord -->|4. Boots| Container
    Coord -->|5. Binds socket| Socket
    Coord -.->|6. Releases LOCK_EX| Lock

    %% Interactions (Follower Sequence)
    CLI_B -->|1. Blocks on LOCK_EX| Lock
    Lock -.->|2. Unblocks after socket bind| CLI_B
    CLI_B -->|3. Connects| Socket
    CLI_B -->|4. podman exec| Container
Step 1: The "Hold-to-Bind" Advisory Locking Protocol

During CLI startup, the process must handle concurrency via Linux advisory file locking (flock):

  1. Acquire Lock: The process attempts to acquire an exclusive, non-blocking lock (LOCK_EX | LOCK_NB) on /tmp/lazaret_coord_{domain_hash}.lock.
  2. If Successful (Leader):
    • The process must check if the Control Socket exists. If not, it must spawn the Session Coordinator in the background, fully detached from the parent's process group (e.g., creating a new session via standard POSIX setsid or equivalent OS APIs, detaching it from the controlling terminal).
    • The leader process must poll the host filesystem for the Control Socket to bind (up to 10 seconds).
    • The leader must not release its exclusive lock on the lockfile until the control socket has successfully bound and is ready to accept connections.
  3. If Unsuccessful (Follower):
    • The process blocks on the lock (LOCK_EX) until the leader completes coordinator setup and releases the lock.
    • Once unblocked, the follower immediately releases the lock (LOCK_UN) and safely connects to the active Control Socket.
Step 2: Reference Counted Teardown

The Session Coordinator keeps an active map of connected CLI processes.

  • Whenever a CLI process terminates, it disconnects from the control socket.
  • When the active connection count on the Coordinator reaches zero, the Coordinator must initiate an automatic clean teardown: stopping the sandboxed container, unmounting the fuse-overlayfs State Anchor, and unlinking the control socket.
Step 3: Session Identity & Escalation Routing via Session Anchor

To maintain exact terminal isolation and prevent spoofing or PID-reuse hijacking during interactive prompts:

  1. The host CLI process generates a Session Anchor (an ephemeral asymmetric keypair (K_{pub\_proc}, K_{priv\_proc})) and registers K_{pub\_proc} alongside a unique LAZARET_SESSION_ID (represented by a cryptographically secure unique identifier) with the Session Coordinator.
  2. When launching a shell or command session inside the container (via podman exec), the host CLI process injects a cryptographically signed capability token or delegates a short-lived keypair derived from K_{priv\_proc} into that specific process's environment.
  3. When the in-container Escalation Client (lazaret-escalate) triggers an escalation request, it must sign the JSON payload (including the request ID and LAZARET_SESSION_ID) with the injected session credential.
  4. The Session Coordinator receives the request over mTLS, verifies the container certificate, retrieves the registered K_{pub\_proc} matching the LAZARET_SESSION_ID, and validates the signature.
  5. Once verified, the Session Coordinator routes the interactive terminal user interface (TUI) prompt exclusively to the corresponding host terminal socket matching that verified ID.

4.4 Embedded State Store & Audit Trail Persistence

Lazaret implements a local persistence layer using an embedded transactional key-value store to manage session state transitions, lock statuses, and host escalation audit trails.

4.4.1 Single-Process Exclusive Database Ownership

The state database file (stored inside the Domain Root) is strictly owned and opened exclusively by the background-detached Session Coordinator process.

  • Process-Level Exclusive Locking: The embedded transactional key-value store enforces absolute process-level exclusive locking on the physical file. Any attempt by other processes (such as secondary CLI follower processes or standalone status query commands) to open the state file directly will fail immediately.
  • IPC-Facade Query Pattern: Consequently, all secondary CLI follower sessions, dashboard widgets, or status utilities must never access the state store directly on the filesystem. Instead, they must communicate with the active Session Coordinator over the Control Socket using Unix Domain Sockets, and the Coordinator must perform all queries, registrations, and updates on their behalf.

4.4.2 Asynchronous Event Loop Thread Integration

To prevent async event loop starvation from blocking database operations, all database transactions must be executed on a designated synchronous threadpool managed by the asynchronous runtime.

4.4.3 Manual Schema Migration Protocol

To maintain zero external C-dependencies for frictionless static compilation, the persistence layer utilizes a lightweight, typed key-value table layout.

  • Manual Evolution: The store does not support automated relational schema migration engines.
  • Table-to-Table Copying: Any schema evolution or configuration structural changes across feature updates must be coordinated by manual, programmatically written migration routines. These routines must query old tables, convert the underlying serializations, and write them to newer table versions inside a single atomic transaction.

4.4.4 Division of Labor between State Store, Session Coordinator, and OS

To prevent race conditions, memory leaks, and stale process tracking, the active runtime state is decoupled from passive storage:

  1. Passive ACID State Store: Responsible solely for persisting completed session metadata, verified escalation approvals, and tamper-safe host command audit logs. It does not track real-time process heartbeats or actively coordinate system actions.
  2. Active Session Coordinator: Acts as the exclusive in-memory broker, managing async UNIX sockets, mTLS handshake parsing, active client connection reference counting, and executing actual container launches or workspace mounts.
  3. OS Kernel Primitives: Responsible for process death detection. The Session Coordinator and CLI processes utilize advisory file locking (flock) on the Lock File to manage active-leader lifecycles and clean up sockets upon process termination (including hard crashes such as SIGKILL).

5. Agent-to-Host Escalation Protocol

5.1 Cryptographic Identity Verification & Message Transport

The Escalation Client is placed inside the Agent Sandbox. It communicates with the host orchestrator over the Escalation Socket (UDS) utilizing a secure Mutual TLS (mTLS) handshake verified by the Trust Anchor to cryptographically prove sandbox identity.

The host orchestrator creates the Escalation Socket file inside a secure, host-private directory owned by the host developer (defined by socket_dir in the configuration) and bind-mounts only that socket into the Agent Sandbox, keeping it decoupled from the writable Agent Workspace.

5.1.1 Cryptographic Identity Verification via Trust Anchor and Session Anchor

Lazaret establishes process-level and container-level identities using the Trust Anchor and Session Anchor protocols:

  1. Host CA Generation: On startup, the host orchestrator instantiates the Trust Anchor as an in-memory, local ephemeral Certificate Authority (CA), generating a self-signed root CA certificate and private key in-memory.
  2. Sandbox Client Certificate: For each active sandbox container, the Trust Anchor generates a unique, short-lived client certificate and private key. This certificate encodes the active container's profile name and unique sandbox ID inside its Subject Alternative Name (SAN).
  3. Mount Injection: The host orchestrator mounts these Trust Anchor certificates into the container namespace using a memory-backed, read-only tmpfs volume (see Fixed In-Container Paths).
  4. mTLS Handshake Check: When the Escalation Client initiates a request, it performs a complete mutual TLS handshake over the Escalation Socket. The host verifies that the client certificate presented by the connection is signed by the active Trust Anchor root CA, and checks the profile SAN to confirm exact container identity before any payloads are parsed.
  5. Session Signature Verification: Once the mTLS connection is verified, the Session Coordinator reads the payload's session_id, retrieves the public key of the corresponding Session Anchor registered on startup, and verifies the payload's cryptographic signature. Only requests carrying a valid signature produced by that session's injected private key are approved for TUI routing or auto-approval.

5.1.2 Command Request (Sandbox -> Host JSON payload over mTLS)

  • request_id: A cryptographically secure unique identifier.
  • session_id: The LAZARET_SESSION_ID corresponding to the requesting Client Session.
  • profile: The current agent profile requesting escalation.
  • command: Raw CLI command to run on the host.
  • justification: Detailed justification explaining why host resources are needed.
  • signature: Cryptographic signature of the request payload produced by the process's injected private credential, verifiable using the Session Anchor's registered public key.

5.1.3 Command Response (Host -> Sandbox JSON payload over mTLS)

  • request_id: Matches the original command request ID.
  • approved: Boolean indicating if the user permitted execution.
  • exit_code: Process exit code (only set if approved is true).
  • stdout: Combined standard output text.
  • stderr: Combined standard error text.

5.2 HITL Interactive Console Interface & Whitelisting

When a request is received on the host, the lazaret orchestrator must temporarily suspend standard TTY forwarding and render a dedicated interactive terminal user interface prompt. The interface must isolate the request ID, profile, justification, and the requested command, offering the user four distinct actions:

  • [A] Approve & Run: Executes the command on the host.
  • [D] Deny Request: Rejects the escalation, returning an access-denied response to the sandbox.
  • [E] Edit Command: Prompts the developer to edit the command in-place before execution.
  • [Q] Abort: Terminates the CLI orchestrator process, initiating a graceful shutdown of the container and Network Sidecar operations.
graph TD
    Request[Escalation Request from Sandbox] --> Metachar{Contains Shell<br>Metacharacters?}
    
    %% Non-Shell Path
    Metachar -->|No| Whitelist{Matches Auto-Approve<br>Prefix Vector?}
    Whitelist -->|Yes| Auto[Auto-Approve Path]
    Whitelist -->|No| Prompt[Force Human HITL Prompt]
    
    %% Shell Path
    Metachar -->|Yes| Prompt
    
    %% Execution Paths
    Auto -->|Executes Directly| Execve[Direct execve Execution<br>No shell spawned]
    
    Prompt -->|User Approves| ExecType{Has Shell<br>Metacharacters?}
    Prompt -->|User Denies| Deny[Return Access Denied]
    
    ExecType -->|No| Execve
    ExecType -->|Yes| ShellExec[Execute in Host Shell]

5.2.1 Whitelisting & Injection Prevention (Argument Vector Prefix Matching)

The orchestrator implements a command validation pipeline:

  1. Shell Metacharacter Auto-Approve Bypass: Any requested command containing shell-interpreted metacharacters, control characters, or redirections (including ;, |, &, $(), ` `, >, <, \n, \r, and backslashes) must bypass the automatic whitelisting engine. Such commands must require interactive human-in-the-loop (HITL) approval to prevent arbitrary command chaining, background execution, or output redirection on the host.

  2. Argument Vector Prefix Whitelisting: The requested command string must be parsed into an argument vector using a POSIX-compliant shell words parser to resolve quotes and escape spaces. This requested vector must be validated against the parsed vectors defined in the auto_approve configuration. To prevent argument injection vulnerabilities (where arbitrary parameters are appended to authorized binaries), the auto-approve verification must assert that the whitelisted vector is a strict prefix of the requested vector.

    • Banned Commands: Executables that permit arbitrary command redirection (including raw git or any git subcommands) must not be permitted on the auto-approve whitelist.
  3. Direct Execution: Following verification, the orchestrator must pass the literal argument vector directly to the host's native process execution engine (such as the standard execve system call or equivalent system process APIs), launching the binary directly without invoking an intermediate host shell.


6. Functional & Non-Functional Requirements

6.1 Functional Requirements

ID Requirement Description
FR-1 TOML Profile Loading Dynamically parses and loads config from ~/.config/lazaret/config.toml or override paths.
FR-2 Podman & gVisor Integration Configures container executions using --runtime=runsc for sandboxes and --runtime=runc for sidecars.
FR-3 Network Sidecar Lifecycle Ensures the shell-less Network Sidecar running in runc is active before spawning any Agent Sandbox.
FR-4 Git Hooks Isolation Automatically isolates the container git environment using the Git Sentry.
FR-5 Host Escalation Establishes private host Escalation Socket listener with ephemeral mTLS certificate verification, parses JSON requests, and displays interactive HITL terminal prompt.
FR-6 Domain Scoped Multiplexing Orchestrates concurrent multi-session execution within a Domain Anchor utilizing a decentralized Session Coordinator, hold-to-bind locking, and identity-aware Host Escalation prompt routing.

6.2 Non-Functional Requirements

ID Requirement Description
NFR-1 Minimal Sidecar Footprint The Network Sidecar binary must compile statically (via musl) with minimal external dependencies to maintain a small footprint suitable for scratch.
NFR-2 Robust Async Cancellation Utilizes native asynchronous task cancellation and signal-handling mechanisms to cleanly close containers, clean up Network Sidecar instances, and close sockets on SIGINT or other termination events.
NFR-3 Dynamic Terminfo Mapping Locates host terminal terminfo configurations (Ghostty, Alacritty, Kitty) and bind-mounts them read-only into the Agent Sandbox.
NFR-4 Zero Shell Footprint The Network Sidecar container has no shell (sh, bash), preventing any remote execution/hijacking.

7. Library Roles Map

The following table maps the abstract architectural roles used in this specification to their concrete library dependencies.

Architectural Role Abstract Prose Reference Concrete Library Justification
Embedded Transactional Key-Value Store "embedded transactional key-value store" redb (v4.1.0) Pure-Rust, transactional store enabling static cross-compilation with robust ACID/MVCC features.
Terminal User Interface Library "interactive terminal user interface library" or "terminal user interface" ratatui Terminal rendering and layout primitives for the interactive prompt.
Asynchronous Runtime Event Loop "asynchronous runtime event loop" tokio (v1.52.3) Asynchronous execution runtime for socket and multiplexer coordination.
Cryptographically Secure Unique Identifiers "cryptographically secure unique identifier" or "unique session identifier" uuid (v1.23.4) Generation and validation of unique identifiers.