Classify serialized and runtime schema records

This commit is contained in:
ms2k 2026-07-14 23:34:56 +09:00
commit f106a9f636

View file

@ -63,9 +63,10 @@ workspace paths remain writable, while Git-ignored paths are isolated into
Domain-scoped sandbox state by default. The developer may explicitly disable that
isolation in trusted host configuration.
The physical refinement of model configuration confinement canonicalizes the
configuration file and every bind-mount source, compares their resolved ancestry,
and omits configuration bytes from the sandbox mount specification.
The trusted-host configuration refinement below owns strict parsing,
canonicalization, path authority, and configuration fingerprinting. Successful
loading is the physical meaning of the model's `ConfigSafe`; configuration bytes
never enter a sandbox mount specification.
## 2. Glossary
@ -178,7 +179,154 @@ Runtime paths and durable rows carry Domain ID, generation, configuration
fingerprint, role identity, and physical ownership fields. Bootstrap recovery is
initiated by a host Lazaret CLI invocation, not by a resident scheduler.
### 3.2 Domain and Session Lifecycle Refinement
### 3.2 Trusted Host Configuration Refinement
The trusted-host configuration has the closed v1 shape in the
[design schemas](schema.md). Lazaret chooses its configuration file from an
explicit host CLI option or, when absent, from
`$XDG_CONFIG_HOME/lazaret/config.toml`, with
`$HOME/.config/lazaret/config.toml` as the XDG fallback. It derives the Storage
Root from `storage.data_root` when present, otherwise from
`$XDG_DATA_HOME/lazaret`, with `$HOME/.local/share/lazaret` as the fallback. The
Runtime Root is `$XDG_RUNTIME_DIR/lazaret`; v1 has no configuration field that
can redirect runtime control state elsewhere. Required XDG and home inputs must
be NUL-free host paths. An unset, empty, or relative XDG config or data value is
treated as unset and uses its home fallback; the home path and XDG runtime path
must be present and absolute. An invalid fallback or runtime value refuses
loading.
The caller supplies one profile name explicitly. Lazaret never selects the
first profile, infers a profile from an image or executable, or falls back to a
different profile. The canonical Agent Workspace is the existing directory
selected by the caller, normally the current working directory. Lazaret opens
it as a directory, obtains its canonical raw pathname and filesystem identity,
and retains the descriptor. The selected profile name and canonical workspace
bytes produce `DomainIdV1` exactly as defined by the schema.
The explicit configuration path follows the schema's strict host-path grammar.
The loader resolves any declared symlink once to a canonical target and builds
a no-symlink confined plan to that target. The source is limited to 1,048,576
bytes, must be a regular file owned by root or the invoking user with exactly
one hard link, and must not grant group or other write permission. Lazaret first
opens it
with an O_PATH-style descriptor so validating the file type cannot activate a
special file, reopens that exact descriptor for nonblocking read, and compares
their identities. It records size and nanosecond change time, reads exactly the
recorded size into owned bytes, refuses trailing growth or a short read, reads
the same range a second time, and requires equal bytes and unchanged identity,
size, and change time before and after both reads. The loader never retries a
changed source. It then performs recursive strict TOML decoding and v1 dispatch.
No parser default or permissive flattening may make an unknown, duplicate,
aliased, or unknown-version field meaningful. Every profile is structurally
decoded, but filesystem and environment resolution applies only to the
explicitly selected profile.
Path resolution produces a `ConfinedPathPlan`, not an ambient absolute path.
Each plan retains a validated ancestor directory descriptor and a normalized
relative suffix, records the ancestor's device, inode, and mount identity, and
keeps canonical raw pathname bytes only as a diagnostic label or digest input.
Every consumer uses descriptor-relative opens with beneath, no-magic-link,
no-symlink, and no-mount-crossing resolution and revalidates the expected type.
The consumer refuses a replaced ancestor, mount transition, symlink, special
file, type mismatch, or any source that cannot be revalidated; it does not
recover by opening the canonical label as an absolute pathname.
Lazaret creates a missing Storage, Runtime, profile, or Domain root one path
component at a time beneath its retained existing ancestor. Every created
component has mode `0700`. Creation refuses symlinks, magic links, and child
mounts, and reopens each new component before proceeding. The selected root, if
it already exists, and every component Lazaret creates beneath the closest
existing ambient ancestor are Lazaret-owned: each must be a directory owned by
the invoking user with mode exactly `0700`. Ambient ancestors above that
ownership boundary use the same descriptor-relative confinement but need not
use Lazaret's ownership or mode; an ordinary `0755` home-directory ancestor
therefore does not by itself refuse loading. A creation or validation failure is
final for that load and never authorizes a partially resolved root.
The profile directory is the `profiles/<profile-name>` child of the Storage
Root. Persistent and runtime Domain roots use the lowercase hexadecimal Domain
ID beneath separate `domains` children of the Storage and Runtime Roots. Those
fixed layouts are constructed only from validated root handles; a path string
or matching digest alone is not authority over a root.
Configuration confinement compares canonical component ancestry and retained
filesystem identities after every source has been opened. The configuration
file, Agent Workspace, Storage Root, Runtime Root, and their Domain/control
trees may not overlap in either ancestor direction. Volume sources may be
strict descendants of the profile directory, but they may not overlap the
configuration source, Agent Workspace, runtime or Domain control trees, or one
another. Other volume sources must be disjoint from all Lazaret data and control
trees as well. All paths are reopened through their plans after the comparisons;
any identity or mount change refuses the complete load. Volume creation is
limited to a declared directory strictly beneath the profile directory and uses
the same component-wise `0700` creation rules.
Configuration resolution also requires an internal `SandboxLayoutV1`. Its
closed protected-destination set contains `/workspace` and every product-owned
sandbox mount destination selected by production layout construction. Each
persistent or volume destination is compared with every member in both ancestry
directions. The configuration loader does not guess paths for control,
credential, mailbox, proc, sys, dev, runtime, or later product mounts, and a
layout cannot be constructed without `/workspace`. Production layout
construction, rather than trusted-host configuration syntax, owns the remaining
exact destination choices.
The loader resolves environment references only after structural, path, and
network validation. A missing, non-UTF-8, or NUL-containing host value refuses
the selected profile. Resolved values live only in the move-owned
`ResolvedDomainConfiguration`; its representation is not serializable and its
diagnostics redact values. Only reference names enter the configuration
fingerprint. Configuration bytes, nonselected profiles, and unreferenced host
environment values are not retained as runtime authority or copied into the
Agent Sandbox.
The Host Coordinator derives the selected profile's effective IPv4 policy and
`ConfigurationFingerprintV1` using the schema's exact normalization and
canonical framing. IPv6 is disabled for a v1 sandbox. Joining a running Domain
requires the same Domain ID and configuration fingerprint; the modeled
configuration-mismatch path refuses every other value.
For auto-approval, the configured executable resolves to one canonical path
outside every sandbox-writable or Lazaret control tree. That path, rather than a
`PATH` lookup or basename, is fingerprinted and matched. On every approved
execution the Host Coordinator reopens the current object through its confined
plan, requires a regular file with exactly one hard link, root or invoking-user
ownership, no group or other write permission, and an executable mode for the
invoking user, and passes that open descriptor into the causal launch wrapper.
The same checks apply when configuration is loaded. The wrapper
executes `/proc/self/fd/<inherited-descriptor>` while retaining that descriptor,
so pathname replacement after validation cannot select another object. There is
no shell, numeric descriptor supplied by the requester, ambient-path reopen, or
fallback execution path. Scripts are subject to the kernel's ordinary shebang
handling; the rule authorizes the exact opened script object, not an arbitrary
requester-selected interpreter.
`MailboxRequest.command_argv` is nonempty. Every element is UTF-8 and NUL-free;
element zero is an absolute path byte-equal to the rule's canonical executable,
and elements one onward are matched against the rule arguments. Lazaret performs
no `PATH` lookup. The v1 structured request language accepts no command-string
or shell-expansion form; an unsupported form has the physical
`CommandRequiresShell` classification and cannot auto-approve. The launcher
never inserts or interprets a shell. An explicitly configured `/bin/sh -c ...`
vector can match only its exact configured rule. A directly configured script
continues to use ordinary kernel shebang handling for the same opened script
object.
Any shell-requiring request form, invalid executable, post-load path conflict,
or argument mismatch follows the modeled developer approval path or is refused;
it is never widened into automatic approval. Requiring one hard link rejects
hardlinked package layouts, including affected Nix-style binaries, in v1. This
is a deliberate conservative compatibility boundary. Relaxing it requires a
new executable-alias authority policy in a later version; v1 has no exception or
fallback.
`ResolvedDomainConfiguration` is created before a generation, durable intent,
or external runtime resource. Every production configuration consumer receives
that same owned resolved value or a capability-bounded borrow from it; consumers
do not reparse the TOML document or independently repeat default, path, network,
environment, fingerprint, or approval decisions.
### 3.3 Domain and Session Lifecycle Refinement
The Host Coordinator implements Domain ownership with a non-blocking host
`flock`, Domain-scoped runtime paths, an exclusive Domain Store handle, and
@ -375,7 +523,7 @@ withdraws publication before dropping keys and credential artifacts. HC loss
destroys the in-memory package; bootstrap never restores it into another
generation.
### 3.3 Session Terminals
### 3.4 Session Terminals
The Host Coordinator owns one host PTY master per interactive Client Session. The
PTY slave is attached to non-detached `runsc exec` standard streams with a guest
@ -491,7 +639,7 @@ after that runtime-absence check. A process, container, PTY, or generation
mismatch fails closed and retains the record; it is never adopted or signaled as
the recorded session.
### 3.4 Filesystem and Git Model
### 3.5 Filesystem and Git Model
The Agent Workspace is mounted read-write. Tracked paths and untracked paths that
are not ignored propagate in both directions. The Git index, `HEAD`, references,
@ -523,7 +671,7 @@ These protections do not make the workspace immutable. Their purpose is to stop
the sandbox from writing the protected host Git configuration and default hook
directory while preserving normal Git operations and bidirectional source edits.
### 3.5 Persistent Sandbox State
### 3.6 Persistent Sandbox State
The State Anchor preserves developer tooling and selected sandbox system paths for
one Domain. It combines a Lazaret-owned prepared lower from the selected base
@ -654,7 +802,7 @@ allowing unmodified base-image content to follow the selected image.
Persistent state is sandbox state, not host configuration. It must not contain or
override Lazaret's host control plane.
### 3.6 Network Isolation
### 3.7 Network Isolation
The Network Sidecar role is realized on the Runtime Supervisor-owned install
path. The Runtime Supervisor holds network-administration capability while it
@ -712,7 +860,7 @@ The OCI configuration joins only the Domain enforcement network namespace, and
`slirp4netns` attached to that namespace is the sole external egress mechanism.
Dynamic policy changes are outside the current physical refinement.
### 3.7 Host Escalation
### 3.8 Host Escalation
The Escalation Client exchanges request and result records through the
Escalation Mailbox: regular files written by atomic rename beneath host-private,
@ -748,7 +896,7 @@ Escalation authentication, correlation, approval, execution, cancellation, resul
delivery, and terminal routing are defined by the
[TLA+ application protocol model](protocol/Lazaret.tla).
### 3.8 State Inspection and Reset
### 3.9 State Inspection and Reset
The host CLI provides read-only discovery, inspection, structural verification,
and explicit reset operations for Domain State Anchors. These operations resolve