Add phase-aware pidfs process ownership records
This commit is contained in:
parent
f840a48376
commit
de57e77dc8
2 changed files with 3513 additions and 246 deletions
266
docs/schema.md
266
docs/schema.md
|
|
@ -98,7 +98,7 @@ classDiagram
|
|||
Domain "1" --> "0..*" Generation
|
||||
Generation "1" --> "0..*" Participant
|
||||
Participant --> ParticipantState
|
||||
Participant --> ParticipantOwnership
|
||||
Participant --> "0..1" ParticipantOwnership
|
||||
Generation "1" --> "0..*" Session
|
||||
Session "1" --> "0..1" SessionTerminal
|
||||
SessionTerminal --> SessionTerminalState
|
||||
|
|
@ -108,7 +108,121 @@ classDiagram
|
|||
|
||||
`durable_decision` and `session_phase` contain values defined by the application
|
||||
protocol model. This schema records them without redefining either state machine.
|
||||
Each store carries its own schema identity and version.
|
||||
Each store carries its own schema identity and version. The current Domain Store
|
||||
identity is `lazaret-domain-store-v2` with version `2`. Domain Store v1 metadata
|
||||
dispatches only to legacy migration handling; it is never decoded as v2. The
|
||||
Storage Catalog remains `lazaret-storage-catalog-v1` with version `1`.
|
||||
|
||||
### Host process identity and staged ownership
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class PidfsProcessAuthorityV1 {
|
||||
boot_id
|
||||
pidfs_st_dev
|
||||
pidfs_st_ino
|
||||
}
|
||||
|
||||
class PidfsProcessIdentityV1 {
|
||||
host_pid
|
||||
start_time_ticks
|
||||
}
|
||||
|
||||
class LegacyUnverifiedProcessIdentityV1 {
|
||||
host_pid
|
||||
start_time_ticks
|
||||
}
|
||||
|
||||
class HostProcessIdentity {
|
||||
<<union>>
|
||||
PidfsV1
|
||||
LegacyUnverifiedV1
|
||||
}
|
||||
|
||||
class PersistedHostProcessOwnership {
|
||||
<<union>>
|
||||
Unassigned
|
||||
Staged
|
||||
Committed
|
||||
}
|
||||
|
||||
class HostProcessOwnershipSlot {
|
||||
<<enumeration>>
|
||||
SandboxHostCoordinator
|
||||
SandboxRuntimeSupervisor
|
||||
SandboxAttachedRunsc
|
||||
StateAnchorDaemon
|
||||
GitRoutingDaemon
|
||||
NetworkRuntimeSupervisor
|
||||
HelperConnectivityHelper
|
||||
HelperRuntimeSupervisor
|
||||
SessionTerminalHostCoordinator
|
||||
SessionTerminalExecClient
|
||||
EscalationHostProcess
|
||||
}
|
||||
|
||||
class ProcessOwnershipMessageVersion {
|
||||
<<enumeration>>
|
||||
V1
|
||||
}
|
||||
|
||||
class StagedProcessOwnership {
|
||||
version
|
||||
domain_id
|
||||
generation_id
|
||||
coordinator_id
|
||||
slot
|
||||
identity
|
||||
}
|
||||
|
||||
class ProcessOwnershipCommitAck {
|
||||
version
|
||||
committed
|
||||
}
|
||||
|
||||
PidfsProcessIdentityV1 --> PidfsProcessAuthorityV1 : authority
|
||||
HostProcessIdentity --> PidfsProcessIdentityV1 : PidfsV1
|
||||
HostProcessIdentity --> LegacyUnverifiedProcessIdentityV1 : LegacyUnverifiedV1
|
||||
PersistedHostProcessOwnership --> PidfsProcessIdentityV1 : Staged
|
||||
PersistedHostProcessOwnership --> HostProcessIdentity : Committed
|
||||
StagedProcessOwnership --> ProcessOwnershipMessageVersion
|
||||
StagedProcessOwnership --> HostProcessOwnershipSlot
|
||||
StagedProcessOwnership --> PidfsProcessIdentityV1
|
||||
ProcessOwnershipCommitAck --> ProcessOwnershipMessageVersion
|
||||
ProcessOwnershipCommitAck --> StagedProcessOwnership : committed
|
||||
```
|
||||
|
||||
`boot_id` is the canonical 16-byte UUID value from the current Linux boot ID;
|
||||
`pidfs_st_dev` and `pidfs_st_ino` are distinct unsigned 64-bit pidfs types. Only
|
||||
their typed `PidfsProcessAuthorityV1` tuple is positive durable authority.
|
||||
`host_pid` is an unsigned 32-bit host-PID-namespace locator and
|
||||
`start_time_ticks` is unsigned 64-bit negative evidence. Equality of the latter
|
||||
two fields cannot produce or upgrade authority.
|
||||
|
||||
Every persisted host-process edge uses `PersistedHostProcessOwnership`.
|
||||
`Unassigned` records that no process ownership has been acquired. `Staged`
|
||||
contains only a current pidfs identity. It is positive authority for exact
|
||||
same-handle cleanup and `PidfsRecoveryMatch`, including bootstrap recovery, but
|
||||
cannot satisfy readiness, publication, dependent-resource creation, or
|
||||
adoption. `Committed` may contain a current pidfs identity or a
|
||||
legacy-unverified v1 PID/start-only value. Only committed current pidfs
|
||||
ownership is serviceable; the legacy variant always refuses positive process
|
||||
action. There is no observation-based conversion from legacy data to
|
||||
`PidfsProcessIdentityV1`.
|
||||
|
||||
Participant `Intent` and `ReleaseIntent` may retain any process-slot phase.
|
||||
Every active participant state and Session Terminal `Running` requires current
|
||||
committed ownership in every role-required process slot. `Clean` requires every
|
||||
process slot to be `Unassigned`.
|
||||
|
||||
`StagedProcessOwnership` binds one acquisition to its Domain, generation,
|
||||
generation-scoped Session Coordinator ID, exact ownership slot, and complete
|
||||
pidfs identity. `ProcessOwnershipCommitAck.committed` echoes that exact staged
|
||||
value. The receiver accepts one matching v1 acknowledgment only while that
|
||||
exact launch barrier is pending on the authenticated generation channel. A
|
||||
mismatched, duplicated after release, unknown-version, lost, or unauthenticated
|
||||
acknowledgment cannot release a barrier. These shapes define correlation and
|
||||
the durable boundary; they do not select the authentication or transport codec.
|
||||
|
||||
### Session terminal ownership
|
||||
|
||||
|
|
@ -127,31 +241,35 @@ classDiagram
|
|||
inode
|
||||
}
|
||||
|
||||
class ProcessIdentity {
|
||||
pid
|
||||
start_time
|
||||
}
|
||||
|
||||
class GuestProcessIdentity {
|
||||
leader_pid
|
||||
leader_start_time
|
||||
process_group_id
|
||||
}
|
||||
|
||||
SessionTerminal --> ProcessIdentity : host_coordinator
|
||||
SessionTerminal --> PersistedHostProcessOwnership : host_coordinator
|
||||
SessionTerminal --> PtyIdentity : pty_master
|
||||
SessionTerminal --> ProcessIdentity : exec_client
|
||||
SessionTerminal --> PersistedHostProcessOwnership : exec_client
|
||||
SessionTerminal --> GuestProcessIdentity : guest_process
|
||||
```
|
||||
|
||||
Host process identities use host pid and start time. Guest process identity uses
|
||||
the leader PID and start time observed inside the exact generation-bound runsc
|
||||
container; its process-group ID is relative to that container's root PID
|
||||
namespace.
|
||||
Host process ownership uses the phase-aware pidfs dispatch above. Guest
|
||||
process identity uses the leader PID and start time observed inside the exact
|
||||
generation-bound runsc container; its process-group ID is relative to that
|
||||
container's root PID namespace and never converts to host process authority.
|
||||
The PTY identity is exact only in combination with its Host Coordinator process
|
||||
identity. `SessionTerminalState` is a physical recovery state below the
|
||||
application protocol model; it does not redefine `session_phase`.
|
||||
|
||||
`SessionTerminal=Intent` permits partial acquisition: `container_id`,
|
||||
`pty_master`, and `guest_process` are optional, while both process slots use the
|
||||
three-phase ownership union. `Running` requires all three non-process identities
|
||||
and current committed HC and exec-client ownership. `ReleaseIntent` retains all
|
||||
recorded evidence, including staged current pidfs authority. `Clean` requires
|
||||
all three optional identities absent and both process slots unassigned. A bare
|
||||
Intent may become this explicit cleared snapshot only after runtime absence is
|
||||
proven.
|
||||
|
||||
## Session terminal protocol
|
||||
|
||||
```mermaid
|
||||
|
|
@ -452,11 +570,6 @@ classDiagram
|
|||
<<union>>
|
||||
}
|
||||
|
||||
class ProcessIdentity {
|
||||
pid
|
||||
start_time
|
||||
}
|
||||
|
||||
class NamespaceIdentity {
|
||||
device
|
||||
inode
|
||||
|
|
@ -469,57 +582,57 @@ classDiagram
|
|||
}
|
||||
|
||||
class PreparedLowerOwnership {
|
||||
prepared_artifact_id
|
||||
source_identity
|
||||
lease_state
|
||||
path
|
||||
device
|
||||
inode
|
||||
optional prepared_artifact_id
|
||||
optional source_identity
|
||||
optional lease_state
|
||||
optional path
|
||||
optional device
|
||||
optional inode
|
||||
}
|
||||
|
||||
class StateAnchorOwnership {
|
||||
lower_artifact_id
|
||||
upper_path
|
||||
work_path
|
||||
merged_path
|
||||
optional lower_artifact_id
|
||||
optional upper_path
|
||||
optional work_path
|
||||
optional merged_path
|
||||
daemon
|
||||
mount
|
||||
optional mount
|
||||
}
|
||||
|
||||
class GitRoutingOwnership {
|
||||
mountpoint
|
||||
host_root
|
||||
isolated_root
|
||||
optional mountpoint
|
||||
optional host_root
|
||||
optional isolated_root
|
||||
daemon
|
||||
mount
|
||||
optional mount
|
||||
}
|
||||
|
||||
class NetworkOwnership {
|
||||
derived_policy_digest
|
||||
readiness_fingerprint
|
||||
readiness_evidence
|
||||
namespace
|
||||
optional derived_policy_digest
|
||||
optional readiness_fingerprint
|
||||
optional readiness_evidence
|
||||
optional namespace
|
||||
runtime_supervisor
|
||||
}
|
||||
|
||||
class HelperOwnership {
|
||||
network_sidecar_id
|
||||
optional network_sidecar_id
|
||||
connectivity_helper
|
||||
runtime_supervisor
|
||||
}
|
||||
|
||||
class SandboxOwnership {
|
||||
container_id
|
||||
runtime_root
|
||||
bundle_digest
|
||||
optional container_id
|
||||
optional runtime_root
|
||||
optional bundle_digest
|
||||
host_coordinator
|
||||
runtime_supervisor
|
||||
attached_runsc
|
||||
}
|
||||
|
||||
class PublicationOwnership {
|
||||
socket_path
|
||||
identity_path
|
||||
optional socket_path
|
||||
optional identity_path
|
||||
}
|
||||
|
||||
ParticipantOwnership --> PreparedLowerOwnership
|
||||
|
|
@ -529,20 +642,62 @@ classDiagram
|
|||
ParticipantOwnership --> HelperOwnership
|
||||
ParticipantOwnership --> SandboxOwnership
|
||||
ParticipantOwnership --> PublicationOwnership
|
||||
StateAnchorOwnership --> ProcessIdentity : daemon
|
||||
StateAnchorOwnership --> PersistedHostProcessOwnership : daemon
|
||||
StateAnchorOwnership --> MountIdentity : mount
|
||||
GitRoutingOwnership --> ProcessIdentity : daemon
|
||||
GitRoutingOwnership --> PersistedHostProcessOwnership : daemon
|
||||
GitRoutingOwnership --> MountIdentity : mount
|
||||
NetworkOwnership --> NamespaceIdentity : namespace
|
||||
NetworkOwnership --> ProcessIdentity : runtime_supervisor
|
||||
NetworkOwnership --> PersistedHostProcessOwnership : runtime_supervisor
|
||||
NetworkOwnership --> NetworkReadinessEvidence : readiness_evidence
|
||||
HelperOwnership --> ProcessIdentity : connectivity_helper
|
||||
HelperOwnership --> ProcessIdentity : runtime_supervisor
|
||||
SandboxOwnership --> ProcessIdentity : host_coordinator
|
||||
SandboxOwnership --> ProcessIdentity : runtime_supervisor
|
||||
SandboxOwnership --> ProcessIdentity : attached_runsc
|
||||
HelperOwnership --> PersistedHostProcessOwnership : connectivity_helper
|
||||
HelperOwnership --> PersistedHostProcessOwnership : runtime_supervisor
|
||||
SandboxOwnership --> PersistedHostProcessOwnership : host_coordinator
|
||||
SandboxOwnership --> PersistedHostProcessOwnership : runtime_supervisor
|
||||
SandboxOwnership --> PersistedHostProcessOwnership : attached_runsc
|
||||
```
|
||||
|
||||
`Participant.ownership=None` is the single encoding of a bare role-bound
|
||||
Intent. Once a role snapshot exists it never returns to `None`. `Intent` admits
|
||||
a non-empty partial matching snapshot. `ReleaseIntent` admits a non-empty
|
||||
partial or complete matching snapshot and retains every exact acquired value.
|
||||
`Clean` requires a matching explicit empty snapshot: all optional physical
|
||||
fields are absent and all process slots are unassigned. This distinguishes
|
||||
"nothing acquired yet" from "absence was proved and cleanup committed."
|
||||
|
||||
The only serviceable role/state pairs are:
|
||||
|
||||
| Role | Active state | Required physical evidence |
|
||||
|---|---|---|
|
||||
| `PreparedLower` | `LeaseHeld` | artifact ID, source, `lease_state=LeaseHeld`, path, device, inode |
|
||||
| `StateAnchor` | `Prepared` | lower artifact, three paths, mount, current committed daemon |
|
||||
| `GitRouting` | `Prepared` | three paths, mount, current committed daemon |
|
||||
| `Network` | `Committed` | policy digest, fingerprint, readiness evidence, namespace, current committed RS |
|
||||
| `Helper` | `Committed` | sidecar ID, current committed helper and RS |
|
||||
| `Sandbox` | `Committed` | container, runtime root, bundle digest, current committed HC, RS, and runsc |
|
||||
| `Publication` | `Committed` | socket and identity paths |
|
||||
|
||||
Network readiness evidence must name the enclosing Participant generation and
|
||||
match its policy digest, fingerprint, namespace, and committed RS identity.
|
||||
|
||||
Intent acquisition is monotonic: optional fields move only absent-to-present,
|
||||
and newly acquired child slots move only `Unassigned` to `Staged` to exact
|
||||
matching current `Committed`. A current committed owner or supervisor may
|
||||
enter a newly created dependent-role snapshot directly and is then immutable;
|
||||
legacy ownership cannot use this rule. Recorded evidence cannot be replaced or
|
||||
cleared. A transition to ReleaseIntent preserves all evidence; PreparedLower
|
||||
changes only its lease phase to `ReleaseIntent`. ReleaseIntent becomes Clean
|
||||
only after independent absence proof and atomically clears every physical
|
||||
field. A bare Intent may become Clean only after the same sealed runtime-absence
|
||||
check.
|
||||
|
||||
The direct existing-process edges are Network RS, Helper RS, Sandbox HC, and
|
||||
Session Terminal HC. State Anchor daemon, Git-routing daemon, Helper process,
|
||||
Sandbox RS, attached runsc, and Session Terminal exec client are acquired child
|
||||
edges and require staging.
|
||||
No bare Intent moves directly to an active state. PreparedLower must also move
|
||||
from recorded `lease_state=Intent` to `LeaseHeld`; it cannot acquire the catalog
|
||||
lease from an absent lease phase.
|
||||
|
||||
## Storage Catalog
|
||||
|
||||
```mermaid
|
||||
|
|
@ -720,11 +875,6 @@ classDiagram
|
|||
inode
|
||||
}
|
||||
|
||||
class ProcessIdentity {
|
||||
pid
|
||||
start_time
|
||||
}
|
||||
|
||||
class NetworkReachabilityProbe {
|
||||
domain_id
|
||||
generation_id
|
||||
|
|
@ -751,8 +901,8 @@ classDiagram
|
|||
NetworkReadinessEvidence --> NetworkReadinessIdentity : fingerprints
|
||||
NetworkReadinessEvidence --> NetworkReachabilityProbe : includes
|
||||
NetworkReadinessAttestation --> NamespaceIdentity : enforcement_namespace
|
||||
NetworkReadinessAttestation --> ProcessIdentity : runtime_supervisor
|
||||
NetworkReadinessAttestation --> ProcessIdentity : connectivity_helper
|
||||
NetworkReadinessAttestation --> PidfsProcessIdentityV1 : runtime_supervisor
|
||||
NetworkReadinessAttestation --> PidfsProcessIdentityV1 : connectivity_helper
|
||||
NetworkReadinessAttestation --> NetworkObservation
|
||||
NetworkObservation --> PolicyDelivery
|
||||
NetworkReadinessIdentity --> NamespaceIdentity : enforcement_namespace
|
||||
|
|
|
|||
|
|
@ -194,6 +194,158 @@ mounts, `slirp4netns`, PTYs, runsc clients, durable store encoding, and exact
|
|||
ownership records). Physical recovery enumerates and inspects those resources
|
||||
independently of process liveness.
|
||||
|
||||
#### Host process identity and causal acquisition refinement
|
||||
|
||||
Lazaret supports host-process authority only on an exactly source/build-qualified
|
||||
Linux x86-64 kernel at or above 6.9. Each supported upstream or vendor build
|
||||
preserves the boot-monotonic 64-bit pidfs inode allocation used by the qualified
|
||||
build and passes its qualification suite. A release string, version floor,
|
||||
partial backport, or successful runtime smoke cannot substitute for exact build
|
||||
qualification. Linux 32-bit, other architectures, kernels below 6.9, and
|
||||
unqualified vendor builds refuse before a generation or external runtime
|
||||
resource is created.
|
||||
|
||||
On every boot Lazaret runs the finite `PidfsHostSupportProbe` before the first
|
||||
generation and caches success only under the current boot ID. The probe has the
|
||||
repository-registered operation sequence and bounds. It checks pidfd operations
|
||||
and pidfs magic, same-live-process concurrent and last-close/reopen identity,
|
||||
distinct simultaneous processes, stale-handle non-action, and
|
||||
exit/reap/drop-all/later-process non-reuse. Any missing operation, failed
|
||||
observation, cleanup uncertainty, timeout, or unexpected equality refuses
|
||||
support for that boot. This bounded smoke checks the running path; it does not
|
||||
prove global inode non-reuse or qualify the kernel source/build.
|
||||
|
||||
`PidfsProcessIdentityV1` separates three kinds of data:
|
||||
|
||||
- `PidfsProcessAuthorityV1 = (boot_id, pidfs_st_dev, pidfs_st_ino)` is the only
|
||||
positive durable host-process authority. The boot ID is stored as the 16 UUID
|
||||
bytes in canonical UUID field order; both pidfs values are unsigned 64-bit
|
||||
types distinct from general filesystem device and inode identities.
|
||||
- `host_pid` is an unsigned 32-bit lookup locator interpreted only in the host
|
||||
PID namespace where Host Coordinator and bootstrap recovery run.
|
||||
- `start_time_ticks` is unsigned 64-bit `/proc/<pid>/stat` negative evidence.
|
||||
Equality of PID and start time adds no authority; inequality or an unreadable
|
||||
required observation refuses.
|
||||
|
||||
A retained pidfd is the primary live authority. Polling, waiting, signaling,
|
||||
and termination act through that exact retained descriptor. Production process
|
||||
control has no numeric-PID signal or reopen-and-signal fallback.
|
||||
|
||||
`CausalChildAcquisitionV1` applies to every Lazaret-owned child that can become
|
||||
durable process ownership. Each Host Coordinator and Runtime Supervisor has one
|
||||
exclusive in-process broker for all spawn, `SIGCHLD`, and reap operations. The
|
||||
process has default non-auto-reaping `SIGCHLD`; no same-parent spawn or reap and
|
||||
no dependency process API bypasses the broker while acquisition is active. The
|
||||
broker performs this sequence:
|
||||
|
||||
1. Persist the owning participant or terminal intent without positive process
|
||||
ownership.
|
||||
2. Hold process-wide spawn/reap exclusion and create an inherited fail-closed
|
||||
launch barrier.
|
||||
3. Spawn a direct repository-owned wrapper that blocks before target work;
|
||||
barrier EOF or malformed release exits without executing the target.
|
||||
4. Capture the host-visible child PID, call `pidfd_open` exactly once, and call
|
||||
`waitid(P_PIDFD, WEXITED | WNOHANG | WNOWAIT)` on that descriptor. `ECHILD`
|
||||
or any other error refuses; `WNOWAIT` never reaps the child.
|
||||
5. `fstat` the same pidfd, read the current boot ID and diagnostic start time,
|
||||
and form `PidfsProcessIdentityV1`.
|
||||
6. Persist `Staged` ownership. An RS-launched child is sent as the exact
|
||||
`StagedProcessOwnership` tuple to HC, and RS waits for an authenticated
|
||||
`ProcessOwnershipCommitAck` that echoes the same Domain, generation,
|
||||
generation-scoped coordinator ID, ownership slot, and complete process
|
||||
identity. Lost, mismatched, unknown-version, unauthenticated, or duplicate
|
||||
after release acknowledgment is never success.
|
||||
7. Release the wrapper barrier only after the exact staged ownership commit is
|
||||
acknowledged. The receiver consumes the acknowledgment once while that
|
||||
exact barrier is pending.
|
||||
8. The wrapper arms its parent-death action, rechecks the expected parent pidfs
|
||||
authority to close the arming race, and execs the foreground,
|
||||
non-daemonizing target in place.
|
||||
9. Promote ownership to `Committed` only after target-specific readiness.
|
||||
Staged ownership cannot satisfy readiness, publication, dependent-resource
|
||||
creation, or adoption. It remains positive authority for exact same-handle
|
||||
cleanup and `PidfsRecoveryMatch`, including bootstrap recovery.
|
||||
|
||||
Every durable host-process slot is exactly `Unassigned`,
|
||||
`Staged(PidfsProcessIdentityV1)`, or `Committed(HostProcessIdentity)`. Only a
|
||||
current pidfs identity may be staged. A committed legacy-unverified identity is
|
||||
retained only for migration and refusal. Current staged and committed identity
|
||||
both authorize exact matched cleanup; only committed current ownership may
|
||||
satisfy an active role, readiness, publication, or adoption.
|
||||
|
||||
A role-bound Participant is first committed as bare `Intent` with no ownership
|
||||
snapshot. Once physical acquisition begins, its role snapshot is present and
|
||||
never returns to absent. Every non-process physical field is optional while
|
||||
acquisition is partial; every process field uses the three-phase slot above.
|
||||
Within Intent, optional fields move only absent-to-present. A newly acquired
|
||||
child slot moves only `Unassigned` to `Staged` to the exact same current
|
||||
identity in `Committed`. An already committed current owner or supervising
|
||||
process may enter a newly created dependent-role snapshot directly, but that
|
||||
recorded identity then remains immutable. Legacy data cannot use this
|
||||
existing-process rule. Recorded evidence cannot be replaced or cleared.
|
||||
The direct existing-process edges are Network RS, Helper RS, Sandbox HC, and
|
||||
Session Terminal HC. State Anchor daemon, Git-routing daemon, Helper process,
|
||||
Sandbox RS, attached runsc, and Session Terminal exec client are acquired child
|
||||
edges and require staging.
|
||||
No bare Intent moves directly to an active state: a non-empty acquisition
|
||||
snapshot is committed first. PreparedLower additionally records
|
||||
`lease_state=Intent` before the catalog insertion changes both participant and
|
||||
lease phase to `LeaseHeld`.
|
||||
|
||||
The active Participant pairs are `prepared_lower=LeaseHeld`,
|
||||
`state_anchor=Prepared`, `git_routing=Prepared`, and
|
||||
`network|helper|sandbox|publication=Committed`. An active snapshot contains all
|
||||
role-required physical evidence and current committed pidfs ownership in every
|
||||
required process slot. `SessionTerminal=Running` likewise requires its
|
||||
container, PTY, guest identity, and current committed HC and exec-client slots.
|
||||
Staged, unassigned, or legacy process ownership cannot satisfy either boundary.
|
||||
Network readiness evidence must also name the enclosing generation and match
|
||||
its policy, fingerprint, namespace, and committed RS identity internally.
|
||||
|
||||
Any partial or active snapshot moves to `ReleaseIntent` while preserving every
|
||||
recorded identity. A staged current identity remains exact cleanup and recovery
|
||||
authority in ReleaseIntent. `ReleaseIntent` becomes `Clean` only after exact or
|
||||
independent absence proof; that transaction clears every process slot to
|
||||
Unassigned and every optional physical field to absent. Clean retains the
|
||||
logical generation key, role, and state as an explicit empty role snapshot. A
|
||||
bare Intent may become that explicit Clean snapshot only after the sealed
|
||||
runtime-absence check. No ordinary lifecycle transition may clear evidence or
|
||||
produce Clean.
|
||||
|
||||
An exited, unreaped child remains pinned while acquisition completes. The
|
||||
descriptor-based child check rejects a foreign replacement, while the exclusive
|
||||
same-parent broker prevents a replacement child from passing the same-parent
|
||||
control case. Implementations preserve these as safety conditions rather than
|
||||
timing assumptions.
|
||||
|
||||
`PidfsRecoveryMatch` is the only positive recovery reacquisition path:
|
||||
|
||||
1. Read and validate the current boot ID.
|
||||
2. On boot mismatch, do not look up the stored PID. Reconcile only resources
|
||||
whose independent exact ownership survives reboot.
|
||||
3. Verify that the stored locator is a host-PID-namespace PID; nested or
|
||||
ambiguous mappings refuse before lookup.
|
||||
4. Call `pidfd_open` exactly once for that locator. `ESRCH` or any other error
|
||||
cannot authorize process action.
|
||||
5. `fstat` the resulting pidfd and compare its device and inode exactly with the
|
||||
durable authority. Either mismatch refuses and closes it without action.
|
||||
6. Apply start-time and expected namespace observations only as negative checks.
|
||||
7. Use that same matched pidfd for every action. An action-time `ESRCH` or
|
||||
observation failure refuses without numeric fallback.
|
||||
|
||||
Domain Store v1 PID/start-only values dispatch to
|
||||
`LegacyUnverifiedProcessIdentityV1`. They cannot be observed, converted, or
|
||||
infallibly migrated into positive authority. They refuse live process action
|
||||
until reboot, independently proven absence, or explicit operator resolution
|
||||
allows the ordinary recovery state machine to reconcile the surrounding record.
|
||||
Boot mismatch fences all old pidfs authority before PID lookup.
|
||||
|
||||
The contract accepts two residual assumptions: Linux boot-ID collision is
|
||||
operationally negligible but not mathematically impossible, and the qualified
|
||||
boot-monotonic 64-bit pidfs inode counter does not wrap during one boot. Codecs
|
||||
and comparisons support `u64::MAX` and refuse every unequal authority tuple;
|
||||
they do not claim to recognize a hypothetical equal tuple after wrap.
|
||||
|
||||
#### Protocol cryptography refinement
|
||||
|
||||
Before starting the Agent Sandbox, the Host Coordinator creates one ephemeral
|
||||
|
|
@ -291,15 +443,17 @@ connection is already lost, the outcome is not retained for reattachment.
|
|||
Physical Session Terminal acquisition is ordered as follows:
|
||||
|
||||
1. The Host Coordinator records `SessionTerminal=Intent` in the Domain Store.
|
||||
2. It allocates the PTY and forks a wrapper with the expected HC pid/start
|
||||
identity. The wrapper arms its HC parent-death edge, re-reads its parent pid
|
||||
and start identity, and aborts before invoking runsc if either differs. It may
|
||||
create the guest process only after that recheck succeeds.
|
||||
2. It allocates the PTY and starts the exec wrapper through
|
||||
`CausalChildAcquisitionV1` with the expected committed HC pidfs authority.
|
||||
The wrapper arms its HC parent-death edge, rechecks that authority, and aborts
|
||||
before invoking runsc if it differs. It may create the guest process only
|
||||
after staged exec-client ownership is durably committed and the barrier is
|
||||
released.
|
||||
3. It establishes the guest process group and obtains the guest leader PID,
|
||||
start time, and group ID.
|
||||
4. One Domain Store transaction records the exact Host Coordinator, PTY, exec
|
||||
client, container, guest leader, and guest process-group identities and sets
|
||||
`SessionTerminal=Running`.
|
||||
4. One Domain Store transaction promotes the exact Host Coordinator and exec
|
||||
client ownership to committed, records the PTY, container, guest leader, and
|
||||
guest process-group identities, and sets `SessionTerminal=Running`.
|
||||
5. Only then may the Host Coordinator accept terminal events for the session.
|
||||
|
||||
Failure before `Running` never admits the terminal. A live Host Coordinator uses
|
||||
|
|
@ -418,11 +572,12 @@ defined by the protocol model. The product store encodes that generation documen
|
|||
in typed tables under a schema/db version (unknown newer versions fail closed
|
||||
until an explicit Host Coordinator migration), including generation identity,
|
||||
minted runtime component IDs, and participant ownership material (for example
|
||||
prepared-artifact ID, pid/start, mount identity, network readiness fingerprint).
|
||||
prepared-artifact ID, staged or committed pidfs process ownership, mount
|
||||
identity, and network readiness fingerprint).
|
||||
Participant roles are `prepared_lower`, `state_anchor`, `git_routing`, `network`,
|
||||
`helper`, `sandbox`, and `publication`. The `helper` participant independently
|
||||
records durable intent and exact connectivity-helper pid/start identity before
|
||||
the `network` participant records readiness. Sessions and the generation mailbox
|
||||
records durable intent and exact committed connectivity-helper pidfs ownership
|
||||
before the `network` participant records readiness. Sessions and the generation mailbox
|
||||
are separate generation records. Deterministic paths are lookup hints for
|
||||
physical recovery, not ownership proofs.
|
||||
|
||||
|
|
@ -492,9 +647,11 @@ bootstrap recovery may advance it to release intent. These rules make every
|
|||
interrupted release conservative and prevent a mounted State Anchor from
|
||||
becoming unleased.
|
||||
|
||||
Store version acceptance occurs before physical resource inspection. The first
|
||||
product version has no product predecessor. Future migration steps create and
|
||||
validate destination rows in one redb transaction and update the version last.
|
||||
Store version acceptance occurs before physical resource inspection. The
|
||||
Domain Store v1-to-v2 migration preserves every PID/start-only value as
|
||||
legacy-unverified and never observes it into pidfs authority. Migration steps
|
||||
create and validate destination rows in one redb transaction and update the
|
||||
version last. Future versions follow the same fail-closed ordering.
|
||||
|
||||
Files not represented in the upper layer follow the selected base image. Files,
|
||||
directories, and whiteouts recorded in the upper layer remain authoritative when
|
||||
|
|
@ -530,9 +687,10 @@ inherited memfd. The Runtime Supervisor verifies the seals and digest, installs
|
|||
the policy, and returns observed route, helper, process, and namespace evidence
|
||||
over an inherited Host Coordinator-created private `SOCK_SEQPACKET` channel.
|
||||
Before helper launch, the Host Coordinator commits the independent `helper`
|
||||
participant as `Intent`. After launch it verifies and commits the exact helper
|
||||
and supervising Runtime Supervisor pid/start identities before accepting network
|
||||
readiness evidence and advancing the `network` participant.
|
||||
participant as `Intent`. It acquires the helper through
|
||||
`CausalChildAcquisitionV1`; after the exact helper and supervising Runtime
|
||||
Supervisor pidfs ownership is committed, it may accept network readiness
|
||||
evidence and advance the `network` participant.
|
||||
The Host Coordinator independently reads the Runtime Supervisor's namespace
|
||||
identity and persists the attestation, fingerprint, and generation-bound
|
||||
deny/permit/DNS probe result. Persisted readiness files are evidence after this
|
||||
|
|
@ -648,13 +806,13 @@ not duplicated here.
|
|||
| **FR-1** | Lazaret shall derive a stable Domain ID from the selected Agent Profile and canonical Agent Workspace. |
|
||||
| **FR-3** | Tracked and non-ignored workspace edits and supported Git operations shall propagate bidirectionally between host and sandbox. |
|
||||
| **FR-4** | Selected sandbox paths and Ignored Workspace State shall persist across Domain restarts without copying Lazaret host configuration into the sandbox. |
|
||||
| **FR-7** | Product recovery shall inspect external runtime resources independently of owner-process liveness and compare typed pid/start, namespace, mount, artifact, path, and inode evidence before physical cleanup. |
|
||||
| **FR-7** | Product recovery shall inspect external runtime resources independently of owner-process liveness. Host-process action shall require the retained pidfd or `PidfsRecoveryMatch` against staged or committed current `PidfsProcessIdentityV1`; legacy PID/start-only ownership, unequal pidfs authority, boot or namespace ambiguity, and unreadable negative evidence shall refuse without numeric-PID signaling. Staged ownership authorizes only exact cleanup/recovery, never service or adoption. Recovery shall also compare typed namespace, mount, artifact, path, and inode evidence before physical cleanup. |
|
||||
| **FR-8** | Lazaret shall support interactive terminal sessions without degrading supported host terminal capabilities. |
|
||||
| **FR-9** | Trusted host configuration shall allow the developer to disable Git-ignored path isolation for an Agent Profile. |
|
||||
| **FR-11** | The host CLI shall list, inspect, structurally verify, and reset all or selected State Anchors without requiring direct manipulation of Lazaret's storage layout. |
|
||||
| **FR-14** | The Host Coordinator shall own one host PTY master per interactive Client Session; the PTY slave shall attach through non-detached `runsc exec` standard streams. The root attached `runsc run` client shall remain terminal-neutral. Production Session PTYs shall not depend on `runsc exec -console-socket`. |
|
||||
| **FR-15** | For each interactive Client Session, Lazaret shall preserve the Session Terminal record and protocol in the normative design schema; serialize bounded terminal events and merged output by Session ID; map resize and the `Interrupt`, `Quit`, and `Suspend` events to the specified exact process-group operations; collect exit status from the non-detached `runsc exec` client; and follow the specified release and hard-loss recovery ordering without reattachment or mismatched cleanup. |
|
||||
| **FR-16** | Domain network connectivity shall use `slirp4netns` as the production connectivity helper. The Domain Store shall record independent `helper` intent before launch and exact helper and supervising Runtime Supervisor pid/start identities before network readiness. |
|
||||
| **FR-16** | Domain network connectivity shall use `slirp4netns` as the production connectivity helper. The Domain Store shall record independent `helper` intent before launch and exact committed helper and supervising Runtime Supervisor pidfs ownership before network readiness. |
|
||||
| **FR-17** | The Domain Store shall be opened only by the Host Coordinator process holding the Domain `flock`; mutations shall use whole redb transactions. Storage Catalog opens shall be bounded by `storage-catalog.lock` and one transaction. Cross-store lease release shall follow the durable release-intent, exact-unmount, catalog-delete, Domain-clean ordering defined by the durable generation refinement. |
|
||||
| **FR-18** | Product network-readiness evidence shall conform to the normative design schema and include the readiness fingerprint plus the generation-bound deny/permit/DNS probe result. |
|
||||
| **FR-19** | The Host Coordinator shall derive generation-bound network policy from trusted host configuration; the Runtime Supervisor shall install only that derived policy and attest readiness by observed namespace state. Durable network participant state shall record the network readiness fingerprint. |
|
||||
|
|
|
|||
Loading…
Reference in a new issue