- Replaces stream/socket escalation with a sandboxed regular-file Escalation Mailbox to satisfy runsc isolation boundaries without exposing `host-uds=open`. - Expands the TLA+ protocol model with role-bound certificates, tuple authorization, and structured domain-failure recovery paths. - Adds physical integration journals for host terminfo injection, persistent /etc DNS shims, rootless Podman network topology, and static client delivery. - Establishes specification requirements for safe host-only State Anchor inspection and crash-consistent reset operations.
1161 lines
43 KiB
Text
1161 lines
43 KiB
Text
------------------------------ MODULE Lazaret ------------------------------
|
|
EXTENDS Naturals, FiniteSets, Sequences, TLC
|
|
|
|
(***************************************************************************
|
|
Application-wide protocol model for Lazaret.
|
|
|
|
The model covers Domain startup, ordered resource preparation, role-separated
|
|
runtime identity tuples, sandbox launch isolation, Client Session registration,
|
|
host escalation, correlated result delivery, terminal ownership, failure, and
|
|
teardown.
|
|
Cryptographic algorithms, serialization, container commands, filesystems, and
|
|
network packet handling are refinement boundaries validated by implementation
|
|
tests rather than modeled internally.
|
|
***************************************************************************)
|
|
|
|
CONSTANTS
|
|
Domains,
|
|
Sessions,
|
|
Requests,
|
|
Commands,
|
|
Identities,
|
|
SessionAnchors,
|
|
NoSession,
|
|
NoRequest,
|
|
NoCommand,
|
|
NoApproval,
|
|
SessionDomain,
|
|
SessionFingerprint,
|
|
DomainFingerprint,
|
|
DomainCoordinatorIdentity,
|
|
DomainSidecarIdentity,
|
|
DomainSandboxIdentity,
|
|
SessionCliIdentity,
|
|
SessionAnchorIdentity,
|
|
CoordinatorCertificateValid,
|
|
SidecarCertificateValid,
|
|
SandboxCertificateValid,
|
|
CliCertificateValid,
|
|
ConfigSafe,
|
|
SandboxIsolationSafe,
|
|
RequestSession,
|
|
RequestCommand,
|
|
RequestSandboxIdentity,
|
|
RequestCliIdentity,
|
|
RequestSessionAnchor,
|
|
RequestCredentialValid,
|
|
RequestSignatureValid,
|
|
ApprovalCliIdentity,
|
|
ApprovalSessionAnchor,
|
|
ApprovalSignatureValid,
|
|
ApprovalCommand,
|
|
AutoRuleMatches,
|
|
CommandRequiresShell,
|
|
CommandContentSafe,
|
|
D1,
|
|
S1,
|
|
S2,
|
|
R1,
|
|
R2,
|
|
R3,
|
|
ExactCmd,
|
|
PromptCmd,
|
|
ShellCmd,
|
|
EditedCmd
|
|
|
|
ASSUME
|
|
/\ IsFiniteSet(Domains)
|
|
/\ IsFiniteSet(Sessions)
|
|
/\ IsFiniteSet(Requests)
|
|
/\ IsFiniteSet(Commands)
|
|
/\ IsFiniteSet(Identities)
|
|
/\ IsFiniteSet(SessionAnchors)
|
|
/\ Domains # {}
|
|
/\ Sessions # {}
|
|
/\ Requests # {}
|
|
/\ NoSession \notin Sessions
|
|
/\ NoRequest \notin Requests
|
|
/\ NoCommand \notin Commands
|
|
/\ SessionDomain \in [Sessions -> Domains]
|
|
/\ SessionFingerprint \in [Sessions -> STRING]
|
|
/\ DomainFingerprint \in [Domains -> STRING]
|
|
/\ DomainCoordinatorIdentity \in [Domains -> Identities]
|
|
/\ DomainSidecarIdentity \in [Domains -> Identities]
|
|
/\ DomainSandboxIdentity \in [Domains -> Identities]
|
|
/\ SessionCliIdentity \in [Sessions -> Identities]
|
|
/\ SessionAnchorIdentity \in [Sessions -> SessionAnchors]
|
|
/\ CoordinatorCertificateValid \in [Domains -> BOOLEAN]
|
|
/\ SidecarCertificateValid \in [Domains -> BOOLEAN]
|
|
/\ SandboxCertificateValid \in [Domains -> BOOLEAN]
|
|
/\ CliCertificateValid \in [Sessions -> BOOLEAN]
|
|
/\ ConfigSafe \in [Domains -> BOOLEAN]
|
|
/\ SandboxIsolationSafe \in [Domains -> BOOLEAN]
|
|
/\ RequestSession \in [Requests -> Sessions]
|
|
/\ RequestCommand \in [Requests -> Commands]
|
|
/\ RequestSandboxIdentity \in [Requests -> Identities]
|
|
/\ RequestCliIdentity \in [Requests -> Identities]
|
|
/\ RequestSessionAnchor \in [Requests -> SessionAnchors]
|
|
/\ RequestCredentialValid \in [Requests -> BOOLEAN]
|
|
/\ RequestSignatureValid \in [Requests -> BOOLEAN]
|
|
/\ ApprovalCliIdentity \in [Requests -> Identities]
|
|
/\ ApprovalSessionAnchor \in [Requests -> SessionAnchors]
|
|
/\ ApprovalSignatureValid \in [Requests -> BOOLEAN]
|
|
/\ ApprovalCommand \in [Requests -> Commands]
|
|
/\ AutoRuleMatches \in [Requests -> BOOLEAN]
|
|
/\ CommandRequiresShell \in [Commands -> BOOLEAN]
|
|
/\ CommandContentSafe \in [Commands -> BOOLEAN]
|
|
|
|
DomainPhases == {
|
|
"Absent", "Starting", "Ready", "Stopping", "Failed", "Recovering"
|
|
}
|
|
CoordinatorStates == {"Absent", "Starting", "Ready", "Stopping", "Failed"}
|
|
MountStates == {"Unmounted", "Mounted"}
|
|
ResourceStates == {"Stopped", "Ready", "Failed"}
|
|
SessionPhases == {
|
|
"New", "Waiting", "Registering", "Attached", "Prompting",
|
|
"HostExecuting", "Closed", "Failed"
|
|
}
|
|
TerminalRoutes == {"Detached", "Sandbox", "Prompt", "HostProcess"}
|
|
ConnectionStates == {"Disconnected", "Connected"}
|
|
RequestPhases == {
|
|
"Unused", "Verified", "AwaitingApproval", "Approved", "Executing",
|
|
"CompletionPending", "DenialPending", "TimeoutPending",
|
|
"CancellationPending", "FailurePending",
|
|
"Completed", "Denied", "TimedOut", "Cancelled", "Failed"
|
|
}
|
|
ApprovalSources == {NoApproval, "AutoRule", "Developer"}
|
|
PendingResultPhases == {
|
|
"CompletionPending", "DenialPending", "TimeoutPending",
|
|
"CancellationPending", "FailurePending"
|
|
}
|
|
TerminalRequestPhases == {"Completed", "Denied", "TimedOut", "Cancelled", "Failed"}
|
|
|
|
DeliveredResultPhase(p) ==
|
|
CASE p = "CompletionPending" -> "Completed"
|
|
[] p = "DenialPending" -> "Denied"
|
|
[] p = "TimeoutPending" -> "TimedOut"
|
|
[] p = "CancellationPending" -> "Cancelled"
|
|
[] p = "FailurePending" -> "Failed"
|
|
|
|
(***************************************************************************
|
|
Finite fixture operators used by Lazaret.cfg. The protocol itself depends only
|
|
on the abstract constants above; other TLC configurations may override them with
|
|
different finite operators.
|
|
***************************************************************************)
|
|
|
|
DomainsFixture == {D1}
|
|
SessionsFixture == {S1, S2}
|
|
RequestsFixture == {R1, R2, R3}
|
|
CommandsFixture == {ExactCmd, PromptCmd, ShellCmd, EditedCmd}
|
|
IdentitiesFixture == {
|
|
"coordinator-1", "sidecar-1", "sandbox-1", "sandbox-other",
|
|
"cli-1", "cli-2"
|
|
}
|
|
SessionAnchorsFixture == {"anchor-1", "anchor-2"}
|
|
|
|
SessionDomainFixture == (S1 :> D1) @@ (S2 :> D1)
|
|
SessionFingerprintFixture ==
|
|
(S1 :> "config-a") @@ (S2 :> "config-a")
|
|
DomainFingerprintFixture == D1 :> "config-a"
|
|
DomainCoordinatorIdentityFixture == D1 :> "coordinator-1"
|
|
DomainSidecarIdentityFixture == D1 :> "sidecar-1"
|
|
DomainSandboxIdentityFixture == D1 :> "sandbox-1"
|
|
SessionCliIdentityFixture == (S1 :> "cli-1") @@ (S2 :> "cli-2")
|
|
SessionAnchorIdentityFixture ==
|
|
(S1 :> "anchor-1") @@ (S2 :> "anchor-2")
|
|
CoordinatorCertificateValidFixture == D1 :> TRUE
|
|
SidecarCertificateValidFixture == D1 :> TRUE
|
|
SandboxCertificateValidFixture == D1 :> TRUE
|
|
CliCertificateValidFixture == (S1 :> TRUE) @@ (S2 :> TRUE)
|
|
ConfigSafeFixture == D1 :> TRUE
|
|
SandboxIsolationSafeFixture == D1 :> TRUE
|
|
RequestSessionFixture ==
|
|
(R1 :> S1) @@ (R2 :> S2) @@ (R3 :> S1)
|
|
RequestCommandFixture ==
|
|
(R1 :> ExactCmd) @@ (R2 :> PromptCmd) @@ (R3 :> ShellCmd)
|
|
RequestSandboxIdentityFixture ==
|
|
(R1 :> "sandbox-1") @@
|
|
(R2 :> "sandbox-1") @@
|
|
(R3 :> "sandbox-other")
|
|
RequestCliIdentityFixture ==
|
|
(R1 :> "cli-1") @@ (R2 :> "cli-2") @@ (R3 :> "cli-1")
|
|
RequestSessionAnchorFixture ==
|
|
(R1 :> "anchor-1") @@
|
|
(R2 :> "anchor-2") @@
|
|
(R3 :> "anchor-1")
|
|
RequestCredentialValidFixture ==
|
|
(R1 :> TRUE) @@ (R2 :> TRUE) @@ (R3 :> TRUE)
|
|
RequestSignatureValidFixture ==
|
|
(R1 :> TRUE) @@ (R2 :> TRUE) @@ (R3 :> TRUE)
|
|
ApprovalCliIdentityFixture ==
|
|
(R1 :> "cli-1") @@ (R2 :> "cli-2") @@ (R3 :> "cli-1")
|
|
ApprovalSessionAnchorFixture ==
|
|
(R1 :> "anchor-1") @@
|
|
(R2 :> "anchor-2") @@
|
|
(R3 :> "anchor-1")
|
|
ApprovalSignatureValidFixture ==
|
|
(R1 :> TRUE) @@ (R2 :> TRUE) @@ (R3 :> TRUE)
|
|
ApprovalCommandFixture ==
|
|
(R1 :> ExactCmd) @@ (R2 :> EditedCmd) @@ (R3 :> ShellCmd)
|
|
AutoRuleMatchesFixture ==
|
|
(R1 :> TRUE) @@ (R2 :> FALSE) @@ (R3 :> TRUE)
|
|
CommandRequiresShellFixture ==
|
|
(ExactCmd :> FALSE) @@
|
|
(PromptCmd :> FALSE) @@
|
|
(ShellCmd :> TRUE) @@
|
|
(EditedCmd :> FALSE)
|
|
CommandContentSafeFixture ==
|
|
(ExactCmd :> TRUE) @@
|
|
(PromptCmd :> TRUE) @@
|
|
(ShellCmd :> TRUE) @@
|
|
(EditedCmd :> TRUE)
|
|
|
|
VARIABLES
|
|
domainPhase,
|
|
coordinatorState,
|
|
stateAnchorState,
|
|
sidecarState,
|
|
sandboxState,
|
|
trustReady,
|
|
lockOwner,
|
|
published,
|
|
registered,
|
|
connected,
|
|
sessionPhase,
|
|
terminalRoute,
|
|
connectionState,
|
|
activeRequest,
|
|
requestPhase,
|
|
approvalSource,
|
|
approvedCommand,
|
|
hostRunning
|
|
|
|
vars == <<
|
|
domainPhase,
|
|
coordinatorState,
|
|
stateAnchorState,
|
|
sidecarState,
|
|
sandboxState,
|
|
trustReady,
|
|
lockOwner,
|
|
published,
|
|
registered,
|
|
connected,
|
|
sessionPhase,
|
|
terminalRoute,
|
|
connectionState,
|
|
activeRequest,
|
|
requestPhase,
|
|
approvalSource,
|
|
approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
Dom(s) == SessionDomain[s]
|
|
ReqSession(r) == RequestSession[r]
|
|
ReqDomain(r) == Dom(ReqSession(r))
|
|
IsTerminalRequest(r) == requestPhase[r] \in TerminalRequestPhases
|
|
|
|
RuntimeIdentityTupleReady(d) ==
|
|
/\ trustReady[d]
|
|
/\ sidecarState[d] = "Ready"
|
|
/\ sandboxState[d] = "Ready"
|
|
/\ CoordinatorCertificateValid[d]
|
|
/\ SidecarCertificateValid[d]
|
|
/\ SandboxCertificateValid[d]
|
|
/\ Cardinality({
|
|
DomainCoordinatorIdentity[d],
|
|
DomainSidecarIdentity[d],
|
|
DomainSandboxIdentity[d]
|
|
}) = 3
|
|
|
|
SessionIdentityTupleRegistered(s) ==
|
|
/\ s \in registered[Dom(s)]
|
|
/\ s \in connected[Dom(s)]
|
|
/\ CliCertificateValid[s]
|
|
|
|
RequestIdentityTupleMatches(r) ==
|
|
LET s == ReqSession(r)
|
|
d == ReqDomain(r)
|
|
IN
|
|
/\ RequestSandboxIdentity[r] = DomainSandboxIdentity[d]
|
|
/\ RequestCliIdentity[r] = SessionCliIdentity[s]
|
|
/\ RequestSessionAnchor[r] = SessionAnchorIdentity[s]
|
|
|
|
ApprovalIdentityTupleMatches(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ ApprovalCliIdentity[r] = SessionCliIdentity[s]
|
|
/\ ApprovalSessionAnchor[r] = SessionAnchorIdentity[s]
|
|
\* This predicate abstracts verification over the request ID, decision, and
|
|
\* exact approved command bytes, not merely verification of any signature by
|
|
\* the registered key.
|
|
/\ ApprovalSignatureValid[r]
|
|
|
|
Interested(d) == {
|
|
s \in Sessions :
|
|
Dom(s) = d /\
|
|
sessionPhase[s] \in {
|
|
"Waiting", "Registering", "Attached", "Prompting", "HostExecuting"
|
|
}
|
|
}
|
|
|
|
RequestsForDomain(d) == {r \in Requests : ReqDomain(r) = d}
|
|
|
|
Init ==
|
|
/\ domainPhase = [d \in Domains |-> "Absent"]
|
|
/\ coordinatorState = [d \in Domains |-> "Absent"]
|
|
/\ stateAnchorState = [d \in Domains |-> "Unmounted"]
|
|
/\ sidecarState = [d \in Domains |-> "Stopped"]
|
|
/\ sandboxState = [d \in Domains |-> "Stopped"]
|
|
/\ trustReady = [d \in Domains |-> FALSE]
|
|
/\ lockOwner = [d \in Domains |-> NoSession]
|
|
/\ published = {}
|
|
/\ registered = [d \in Domains |-> {}]
|
|
/\ connected = [d \in Domains |-> {}]
|
|
/\ sessionPhase = [s \in Sessions |-> "New"]
|
|
/\ terminalRoute = [s \in Sessions |-> "Detached"]
|
|
/\ connectionState = [s \in Sessions |-> "Disconnected"]
|
|
/\ activeRequest = [s \in Sessions |-> NoRequest]
|
|
/\ requestPhase = [r \in Requests |-> "Unused"]
|
|
/\ approvalSource = [r \in Requests |-> NoApproval]
|
|
/\ approvedCommand = [r \in Requests |-> NoCommand]
|
|
/\ hostRunning = {}
|
|
|
|
(***************************************************************************
|
|
Domain and Session lifecycle
|
|
***************************************************************************)
|
|
|
|
StartNewDomain(s) ==
|
|
LET d == Dom(s) IN
|
|
/\ sessionPhase[s] = "New"
|
|
/\ ConfigSafe[d]
|
|
/\ domainPhase[d] = "Absent"
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Starting"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Starting"]
|
|
/\ lockOwner' = [lockOwner EXCEPT ![d] = s]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Waiting"]
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, trustReady, published,
|
|
registered, connected, terminalRoute, connectionState, activeRequest,
|
|
requestPhase, approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
StartReadySession(s) ==
|
|
LET d == Dom(s) IN
|
|
/\ sessionPhase[s] = "New"
|
|
/\ domainPhase[d] = "Ready"
|
|
/\ SessionFingerprint[s] = DomainFingerprint[d]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Registering"]
|
|
/\ connectionState' = [connectionState EXCEPT ![s] = "Connected"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
terminalRoute, activeRequest, requestPhase, approvalSource,
|
|
approvedCommand, hostRunning
|
|
>>
|
|
|
|
WaitForDomain(s) ==
|
|
LET d == Dom(s) IN
|
|
/\ sessionPhase[s] = "New"
|
|
/\ domainPhase[d] \in {"Starting", "Stopping"}
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Waiting"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
RestartWaitingDomain(s) ==
|
|
LET d == Dom(s) IN
|
|
/\ sessionPhase[s] = "Waiting"
|
|
/\ ConfigSafe[d]
|
|
/\ domainPhase[d] = "Absent"
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Starting"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Starting"]
|
|
/\ lockOwner' = [lockOwner EXCEPT ![d] = s]
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, trustReady, published,
|
|
registered, connected, sessionPhase, terminalRoute, connectionState,
|
|
activeRequest, requestPhase, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
MountStateAnchor(d) ==
|
|
/\ domainPhase[d] = "Starting"
|
|
/\ coordinatorState[d] = "Starting"
|
|
/\ stateAnchorState[d] = "Unmounted"
|
|
/\ stateAnchorState' = [stateAnchorState EXCEPT ![d] = "Mounted"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, sidecarState, sandboxState, trustReady,
|
|
lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
CreateTrustAnchor(d) ==
|
|
/\ domainPhase[d] = "Starting"
|
|
/\ coordinatorState[d] = "Starting"
|
|
/\ ~trustReady[d]
|
|
/\ CoordinatorCertificateValid[d]
|
|
/\ trustReady' = [trustReady EXCEPT ![d] = TRUE]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, lockOwner, published, registered, connected,
|
|
sessionPhase, terminalRoute, connectionState, activeRequest,
|
|
requestPhase, approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
StartSidecar(d) ==
|
|
/\ domainPhase[d] = "Starting"
|
|
/\ stateAnchorState[d] = "Mounted"
|
|
/\ trustReady[d]
|
|
/\ SidecarCertificateValid[d]
|
|
/\ sidecarState[d] = "Stopped"
|
|
/\ sidecarState' = [sidecarState EXCEPT ![d] = "Ready"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sandboxState,
|
|
trustReady, lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
StartSandbox(d) ==
|
|
/\ domainPhase[d] = "Starting"
|
|
/\ sidecarState[d] = "Ready"
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ SandboxIsolationSafe[d]
|
|
/\ SandboxCertificateValid[d]
|
|
/\ sandboxState' = [sandboxState EXCEPT ![d] = "Ready"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
trustReady, lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
PublishDomain(d) ==
|
|
/\ domainPhase[d] = "Starting"
|
|
/\ coordinatorState[d] = "Starting"
|
|
/\ stateAnchorState[d] = "Mounted"
|
|
/\ sidecarState[d] = "Ready"
|
|
/\ sandboxState[d] = "Ready"
|
|
/\ trustReady[d]
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Ready"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Ready"]
|
|
/\ lockOwner' = [lockOwner EXCEPT ![d] = NoSession]
|
|
/\ published' = published \cup {d}
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, trustReady, registered,
|
|
connected, sessionPhase, terminalRoute, connectionState,
|
|
activeRequest, requestPhase, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
AdvanceWaitingSession(s) ==
|
|
LET d == Dom(s) IN
|
|
/\ sessionPhase[s] = "Waiting"
|
|
/\ domainPhase[d] = "Ready"
|
|
/\ SessionFingerprint[s] = DomainFingerprint[d]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Registering"]
|
|
/\ connectionState' = [connectionState EXCEPT ![s] = "Connected"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
terminalRoute, activeRequest, requestPhase, approvalSource,
|
|
approvedCommand, hostRunning
|
|
>>
|
|
|
|
RejectConfigurationMismatch(s) ==
|
|
LET d == Dom(s) IN
|
|
/\ sessionPhase[s] \in {"New", "Waiting"}
|
|
/\ domainPhase[d] = "Ready"
|
|
/\ SessionFingerprint[s] # DomainFingerprint[d]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Failed"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Detached"]
|
|
/\ connectionState' = [connectionState EXCEPT ![s] = "Disconnected"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
activeRequest, requestPhase, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
RegisterSession(s) ==
|
|
LET d == Dom(s) IN
|
|
/\ sessionPhase[s] = "Registering"
|
|
/\ connectionState[s] = "Connected"
|
|
/\ domainPhase[d] = "Ready"
|
|
/\ SessionFingerprint[s] = DomainFingerprint[d]
|
|
/\ CliCertificateValid[s]
|
|
/\ registered' = [registered EXCEPT ![d] = @ \cup {s}]
|
|
/\ connected' = [connected EXCEPT ![d] = @ \cup {s}]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Attached"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Sandbox"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, connectionState,
|
|
activeRequest, requestPhase, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
DisconnectSession(s) ==
|
|
LET d == Dom(s)
|
|
r == activeRequest[s]
|
|
leaderLost ==
|
|
lockOwner[d] = s /\ domainPhase[d] = "Starting"
|
|
IN
|
|
/\ sessionPhase[s] \in {
|
|
"Waiting", "Registering", "Attached", "Prompting", "HostExecuting"
|
|
}
|
|
/\ registered' = [registered EXCEPT ![d] = @ \ {s}]
|
|
/\ connected' = [connected EXCEPT ![d] = @ \ {s}]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Closed"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Detached"]
|
|
/\ connectionState' = [connectionState EXCEPT ![s] = "Disconnected"]
|
|
/\ activeRequest' = [activeRequest EXCEPT ![s] = NoRequest]
|
|
/\ requestPhase' = [q \in Requests |->
|
|
IF r # NoRequest /\ q = r /\ ~IsTerminalRequest(q)
|
|
THEN "Cancelled"
|
|
ELSE requestPhase[q]]
|
|
/\ hostRunning' = IF r = NoRequest THEN hostRunning ELSE hostRunning \ {r}
|
|
/\ domainPhase' = [domainPhase EXCEPT
|
|
![d] = IF leaderLost THEN "Failed" ELSE @]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT
|
|
![d] = IF leaderLost THEN "Failed" ELSE @]
|
|
/\ trustReady' = [trustReady EXCEPT
|
|
![d] = IF leaderLost THEN FALSE ELSE @]
|
|
/\ lockOwner' = [lockOwner EXCEPT
|
|
![d] = IF leaderLost THEN NoSession ELSE @]
|
|
/\ published' = IF leaderLost THEN published \ {d} ELSE published
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, approvalSource,
|
|
approvedCommand
|
|
>>
|
|
|
|
BeginTeardown(d) ==
|
|
/\ domainPhase[d] = "Ready"
|
|
/\ Interested(d) = {}
|
|
/\ registered[d] = {}
|
|
/\ connected[d] = {}
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Stopping"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Stopping"]
|
|
/\ published' = published \ {d}
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, trustReady, lockOwner,
|
|
registered, connected, sessionPhase, terminalRoute, connectionState,
|
|
activeRequest, requestPhase, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
StopSandbox(d) ==
|
|
/\ domainPhase[d] = "Stopping"
|
|
/\ sandboxState[d] = "Ready"
|
|
/\ sandboxState' = [sandboxState EXCEPT ![d] = "Stopped"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
trustReady, lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
StopSidecar(d) ==
|
|
/\ domainPhase[d] = "Stopping"
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ sidecarState[d] = "Ready"
|
|
/\ sidecarState' = [sidecarState EXCEPT ![d] = "Stopped"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sandboxState,
|
|
trustReady, lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
UnmountStateAnchor(d) ==
|
|
/\ domainPhase[d] = "Stopping"
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ sidecarState[d] = "Stopped"
|
|
/\ stateAnchorState[d] = "Mounted"
|
|
/\ stateAnchorState' = [stateAnchorState EXCEPT ![d] = "Unmounted"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, sidecarState, sandboxState, trustReady,
|
|
lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
FinishTeardown(d) ==
|
|
/\ domainPhase[d] = "Stopping"
|
|
/\ stateAnchorState[d] = "Unmounted"
|
|
/\ sidecarState[d] = "Stopped"
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Absent"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Absent"]
|
|
/\ trustReady' = [trustReady EXCEPT ![d] = FALSE]
|
|
/\ lockOwner' = [lockOwner EXCEPT ![d] = NoSession]
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, published, registered,
|
|
connected, sessionPhase, terminalRoute, connectionState,
|
|
activeRequest, requestPhase, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
(***************************************************************************
|
|
Host escalation protocol
|
|
***************************************************************************)
|
|
|
|
ReceiveEscalation(r) ==
|
|
LET s == ReqSession(r)
|
|
d == ReqDomain(r)
|
|
IN
|
|
/\ requestPhase[r] = "Unused"
|
|
/\ sessionPhase[s] = "Attached"
|
|
/\ activeRequest[s] = NoRequest
|
|
/\ s \in registered[d]
|
|
/\ s \in connected[d]
|
|
/\ RuntimeIdentityTupleReady(d)
|
|
/\ SessionIdentityTupleRegistered(s)
|
|
/\ RequestIdentityTupleMatches(r)
|
|
/\ RequestCredentialValid[r]
|
|
/\ RequestSignatureValid[r]
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "Verified"]
|
|
/\ activeRequest' = [activeRequest EXCEPT ![s] = r]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
sessionPhase, terminalRoute, connectionState, approvalSource,
|
|
approvedCommand, hostRunning
|
|
>>
|
|
|
|
AutoApprove(r) ==
|
|
/\ requestPhase[r] = "Verified"
|
|
/\ AutoRuleMatches[r]
|
|
/\ ~CommandRequiresShell[RequestCommand[r]]
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "Approved"]
|
|
/\ approvalSource' = [approvalSource EXCEPT ![r] = "AutoRule"]
|
|
/\ approvedCommand' = [approvedCommand EXCEPT ![r] = RequestCommand[r]]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
sessionPhase, terminalRoute, connectionState, activeRequest, hostRunning
|
|
>>
|
|
|
|
QueuePrompt(r) ==
|
|
/\ requestPhase[r] = "Verified"
|
|
/\ ~(AutoRuleMatches[r] /\ ~CommandRequiresShell[RequestCommand[r]])
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "AwaitingApproval"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
sessionPhase, terminalRoute, connectionState, activeRequest,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
BeginPrompt(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] = "AwaitingApproval"
|
|
/\ sessionPhase[s] = "Attached"
|
|
/\ activeRequest[s] = r
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Prompting"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Prompt"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
connectionState, activeRequest, requestPhase, approvalSource,
|
|
approvedCommand, hostRunning
|
|
>>
|
|
|
|
DeveloperApprove(r, cmd) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] = "AwaitingApproval"
|
|
/\ sessionPhase[s] = "Prompting"
|
|
/\ ApprovalIdentityTupleMatches(r)
|
|
/\ cmd \in Commands
|
|
/\ cmd = ApprovalCommand[r]
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "Approved"]
|
|
/\ approvalSource' = [approvalSource EXCEPT ![r] = "Developer"]
|
|
/\ approvedCommand' = [approvedCommand EXCEPT ![r] = cmd]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
sessionPhase, terminalRoute, connectionState, activeRequest, hostRunning
|
|
>>
|
|
|
|
DeveloperDeny(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] = "AwaitingApproval"
|
|
/\ sessionPhase[s] = "Prompting"
|
|
/\ ApprovalIdentityTupleMatches(r)
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "DenialPending"]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Attached"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Sandbox"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
connectionState, activeRequest, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
StartHostExecution(r) ==
|
|
LET s == ReqSession(r)
|
|
d == ReqDomain(r)
|
|
IN
|
|
/\ requestPhase[r] = "Approved"
|
|
/\ activeRequest[s] = r
|
|
/\ s \in connected[d]
|
|
/\ sessionPhase[s] \in {"Attached", "Prompting"}
|
|
/\ CommandContentSafe[approvedCommand[r]]
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "Executing"]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "HostExecuting"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "HostProcess"]
|
|
/\ hostRunning' = hostRunning \cup {r}
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
connectionState, activeRequest, approvalSource, approvedCommand
|
|
>>
|
|
|
|
CompleteHostExecution(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] = "Executing"
|
|
/\ r \in hostRunning
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "CompletionPending"]
|
|
/\ hostRunning' = hostRunning \ {r}
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Attached"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Sandbox"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
connectionState, activeRequest, approvalSource, approvedCommand
|
|
>>
|
|
|
|
TimeoutRequest(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] \in {"Verified", "AwaitingApproval", "Approved", "Executing"}
|
|
/\ activeRequest[s] = r
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "TimeoutPending"]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Attached"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Sandbox"]
|
|
/\ hostRunning' = hostRunning \ {r}
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
connectionState, activeRequest, approvalSource, approvedCommand
|
|
>>
|
|
|
|
CancelRequest(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] \in {
|
|
"Verified", "AwaitingApproval", "Approved", "Executing"
|
|
}
|
|
/\ activeRequest[s] = r
|
|
/\ connectionState[s] = "Connected"
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "CancellationPending"]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Attached"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Sandbox"]
|
|
/\ hostRunning' = hostRunning \ {r}
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
connectionState, activeRequest, approvalSource, approvedCommand
|
|
>>
|
|
|
|
FailHostExecution(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] = "Executing"
|
|
/\ activeRequest[s] = r
|
|
/\ connectionState[s] = "Connected"
|
|
/\ requestPhase' = [requestPhase EXCEPT ![r] = "FailurePending"]
|
|
/\ sessionPhase' = [sessionPhase EXCEPT ![s] = "Attached"]
|
|
/\ terminalRoute' = [terminalRoute EXCEPT ![s] = "Sandbox"]
|
|
/\ hostRunning' = hostRunning \ {r}
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
connectionState, activeRequest, approvalSource, approvedCommand
|
|
>>
|
|
|
|
DeliverResult(r) ==
|
|
LET s == ReqSession(r) IN
|
|
/\ requestPhase[r] \in PendingResultPhases
|
|
/\ activeRequest[s] = r
|
|
/\ connectionState[s] = "Connected"
|
|
/\ sessionPhase[s] = "Attached"
|
|
/\ requestPhase' = [requestPhase EXCEPT
|
|
![r] = DeliveredResultPhase(@)]
|
|
/\ activeRequest' = [activeRequest EXCEPT ![s] = NoRequest]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
sandboxState, trustReady, lockOwner, published, registered, connected,
|
|
sessionPhase, terminalRoute, connectionState, approvalSource,
|
|
approvedCommand, hostRunning
|
|
>>
|
|
|
|
(***************************************************************************
|
|
Failure and recovery
|
|
***************************************************************************)
|
|
|
|
FailDomain(d) ==
|
|
/\ domainPhase[d] \in {"Starting", "Ready", "Stopping"}
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Failed"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Failed"]
|
|
/\ trustReady' = [trustReady EXCEPT ![d] = FALSE]
|
|
/\ lockOwner' = [lockOwner EXCEPT ![d] = NoSession]
|
|
/\ published' = published \ {d}
|
|
/\ registered' = [registered EXCEPT ![d] = {}]
|
|
/\ connected' = [connected EXCEPT ![d] = {}]
|
|
/\ sessionPhase' = [s \in Sessions |->
|
|
IF Dom(s) = d /\ sessionPhase[s] \notin {"New", "Closed"}
|
|
THEN "Failed"
|
|
ELSE sessionPhase[s]]
|
|
/\ terminalRoute' = [s \in Sessions |->
|
|
IF Dom(s) = d THEN "Detached" ELSE terminalRoute[s]]
|
|
/\ connectionState' = [s \in Sessions |->
|
|
IF Dom(s) = d THEN "Disconnected" ELSE connectionState[s]]
|
|
/\ activeRequest' = [s \in Sessions |->
|
|
IF Dom(s) = d THEN NoRequest ELSE activeRequest[s]]
|
|
/\ requestPhase' = [r \in Requests |->
|
|
IF ReqDomain(r) = d /\ requestPhase[r] # "Unused" /\ ~IsTerminalRequest(r)
|
|
THEN "Failed"
|
|
ELSE requestPhase[r]]
|
|
/\ hostRunning' = hostRunning \ RequestsForDomain(d)
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, approvalSource,
|
|
approvedCommand
|
|
>>
|
|
|
|
BeginRecovery(d) ==
|
|
/\ domainPhase[d] = "Failed"
|
|
/\ registered[d] = {}
|
|
/\ connected[d] = {}
|
|
/\ hostRunning \cap RequestsForDomain(d) = {}
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Recovering"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Stopping"]
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, trustReady, lockOwner,
|
|
published, registered, connected, sessionPhase, terminalRoute,
|
|
connectionState, activeRequest, requestPhase, approvalSource,
|
|
approvedCommand, hostRunning
|
|
>>
|
|
|
|
RecoverSandbox(d) ==
|
|
/\ domainPhase[d] = "Recovering"
|
|
/\ sandboxState[d] # "Stopped"
|
|
/\ sandboxState' = [sandboxState EXCEPT ![d] = "Stopped"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sidecarState,
|
|
trustReady, lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
RecoverSidecar(d) ==
|
|
/\ domainPhase[d] = "Recovering"
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ sidecarState[d] # "Stopped"
|
|
/\ sidecarState' = [sidecarState EXCEPT ![d] = "Stopped"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, stateAnchorState, sandboxState,
|
|
trustReady, lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
RecoverStateAnchor(d) ==
|
|
/\ domainPhase[d] = "Recovering"
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ sidecarState[d] = "Stopped"
|
|
/\ stateAnchorState[d] = "Mounted"
|
|
/\ stateAnchorState' = [stateAnchorState EXCEPT ![d] = "Unmounted"]
|
|
/\ UNCHANGED <<
|
|
domainPhase, coordinatorState, sidecarState, sandboxState, trustReady,
|
|
lockOwner, published, registered, connected, sessionPhase,
|
|
terminalRoute, connectionState, activeRequest, requestPhase,
|
|
approvalSource, approvedCommand, hostRunning
|
|
>>
|
|
|
|
FinishRecovery(d) ==
|
|
/\ domainPhase[d] = "Recovering"
|
|
/\ stateAnchorState[d] = "Unmounted"
|
|
/\ sidecarState[d] = "Stopped"
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ domainPhase' = [domainPhase EXCEPT ![d] = "Absent"]
|
|
/\ coordinatorState' = [coordinatorState EXCEPT ![d] = "Absent"]
|
|
/\ lockOwner' = [lockOwner EXCEPT ![d] = NoSession]
|
|
/\ UNCHANGED <<
|
|
stateAnchorState, sidecarState, sandboxState, trustReady, published,
|
|
registered, connected, sessionPhase, terminalRoute, connectionState,
|
|
activeRequest, requestPhase, approvalSource, approvedCommand,
|
|
hostRunning
|
|
>>
|
|
|
|
DomainProgress(d) ==
|
|
\/ MountStateAnchor(d)
|
|
\/ CreateTrustAnchor(d)
|
|
\/ StartSidecar(d)
|
|
\/ StartSandbox(d)
|
|
\/ PublishDomain(d)
|
|
\/ BeginTeardown(d)
|
|
\/ StopSandbox(d)
|
|
\/ StopSidecar(d)
|
|
\/ UnmountStateAnchor(d)
|
|
\/ FinishTeardown(d)
|
|
\/ BeginRecovery(d)
|
|
\/ RecoverSandbox(d)
|
|
\/ RecoverSidecar(d)
|
|
\/ RecoverStateAnchor(d)
|
|
\/ FinishRecovery(d)
|
|
|
|
SessionProgress(s) ==
|
|
\/ StartNewDomain(s)
|
|
\/ StartReadySession(s)
|
|
\/ WaitForDomain(s)
|
|
\/ RestartWaitingDomain(s)
|
|
\/ AdvanceWaitingSession(s)
|
|
\/ RejectConfigurationMismatch(s)
|
|
\/ RegisterSession(s)
|
|
|
|
RequestProgress(r) ==
|
|
\/ AutoApprove(r)
|
|
\/ QueuePrompt(r)
|
|
\/ BeginPrompt(r)
|
|
\/ (\E cmd \in Commands : DeveloperApprove(r, cmd))
|
|
\/ DeveloperDeny(r)
|
|
\/ StartHostExecution(r)
|
|
\/ CompleteHostExecution(r)
|
|
\/ TimeoutRequest(r)
|
|
\/ CancelRequest(r)
|
|
\/ FailHostExecution(r)
|
|
\/ DeliverResult(r)
|
|
|
|
Next ==
|
|
\/ (\E s \in Sessions :
|
|
StartNewDomain(s) \/ StartReadySession(s) \/ WaitForDomain(s) \/
|
|
RestartWaitingDomain(s) \/ AdvanceWaitingSession(s) \/
|
|
RejectConfigurationMismatch(s) \/
|
|
RegisterSession(s) \/ DisconnectSession(s))
|
|
\/ (\E d \in Domains :
|
|
DomainProgress(d) \/ FailDomain(d))
|
|
\/ (\E r \in Requests :
|
|
ReceiveEscalation(r) \/ RequestProgress(r))
|
|
|
|
Spec ==
|
|
/\ Init
|
|
/\ [][Next]_vars
|
|
/\ \A d \in Domains : WF_vars(DomainProgress(d))
|
|
/\ \A s \in Sessions : WF_vars(SessionProgress(s))
|
|
/\ \A r \in Requests : WF_vars(RequestProgress(r))
|
|
|
|
(***************************************************************************
|
|
Safety properties
|
|
***************************************************************************)
|
|
|
|
TypeOK ==
|
|
/\ domainPhase \in [Domains -> DomainPhases]
|
|
/\ coordinatorState \in [Domains -> CoordinatorStates]
|
|
/\ stateAnchorState \in [Domains -> MountStates]
|
|
/\ sidecarState \in [Domains -> ResourceStates]
|
|
/\ sandboxState \in [Domains -> ResourceStates]
|
|
/\ trustReady \in [Domains -> BOOLEAN]
|
|
/\ lockOwner \in [Domains -> Sessions \cup {NoSession}]
|
|
/\ published \subseteq Domains
|
|
/\ registered \in [Domains -> SUBSET Sessions]
|
|
/\ connected \in [Domains -> SUBSET Sessions]
|
|
/\ sessionPhase \in [Sessions -> SessionPhases]
|
|
/\ terminalRoute \in [Sessions -> TerminalRoutes]
|
|
/\ connectionState \in [Sessions -> ConnectionStates]
|
|
/\ activeRequest \in [Sessions -> Requests \cup {NoRequest}]
|
|
/\ requestPhase \in [Requests -> RequestPhases]
|
|
/\ approvalSource \in [Requests -> ApprovalSources]
|
|
/\ approvedCommand \in [Requests -> Commands \cup {NoCommand}]
|
|
/\ hostRunning \subseteq Requests
|
|
|
|
ConfigurationConfinement ==
|
|
\A d \in Domains : domainPhase[d] # "Absent" => ConfigSafe[d]
|
|
|
|
SandboxNamespaceIsolation ==
|
|
\A d \in Domains : sandboxState[d] = "Ready" => SandboxIsolationSafe[d]
|
|
|
|
OrderedNetworkStartup ==
|
|
\A d \in Domains : sandboxState[d] = "Ready" => sidecarState[d] = "Ready"
|
|
|
|
PublishedDomainsReady ==
|
|
\A d \in published :
|
|
/\ domainPhase[d] = "Ready"
|
|
/\ coordinatorState[d] = "Ready"
|
|
/\ stateAnchorState[d] = "Mounted"
|
|
/\ sidecarState[d] = "Ready"
|
|
/\ sandboxState[d] = "Ready"
|
|
/\ trustReady[d]
|
|
|
|
ExclusiveBootstrapOwnership ==
|
|
\A d \in Domains : lockOwner[d] # NoSession =>
|
|
/\ domainPhase[d] = "Starting"
|
|
/\ coordinatorState[d] = "Starting"
|
|
/\ sessionPhase[lockOwner[d]] = "Waiting"
|
|
|
|
TeardownNotJoinable ==
|
|
\A d \in Domains : domainPhase[d] \in {"Stopping", "Failed", "Recovering"} =>
|
|
/\ d \notin published
|
|
/\ registered[d] = {}
|
|
/\ connected[d] = {}
|
|
|
|
RegisteredSessionsConnected ==
|
|
\A d \in Domains : registered[d] \subseteq connected[d]
|
|
|
|
AttachedSessionsValid ==
|
|
\A s \in Sessions :
|
|
sessionPhase[s] \in {"Attached", "Prompting", "HostExecuting"} =>
|
|
/\ s \in registered[Dom(s)]
|
|
/\ s \in connected[Dom(s)]
|
|
/\ domainPhase[Dom(s)] = "Ready"
|
|
/\ SessionFingerprint[s] = DomainFingerprint[Dom(s)]
|
|
|
|
AuthenticatedRequestsOnly ==
|
|
\A r \in Requests : requestPhase[r] # "Unused" =>
|
|
/\ RequestCredentialValid[r]
|
|
/\ RequestSignatureValid[r]
|
|
/\ RequestIdentityTupleMatches(r)
|
|
|
|
RuntimeRoleIdentitySeparation ==
|
|
/\ \A d \in Domains :
|
|
Cardinality({
|
|
DomainCoordinatorIdentity[d],
|
|
DomainSidecarIdentity[d],
|
|
DomainSandboxIdentity[d]
|
|
}) = 3
|
|
/\ \A s \in Sessions :
|
|
LET d == Dom(s) IN
|
|
SessionCliIdentity[s] \notin {
|
|
DomainCoordinatorIdentity[d],
|
|
DomainSidecarIdentity[d],
|
|
DomainSandboxIdentity[d]
|
|
}
|
|
|
|
RegisteredSessionIdentityUniqueness ==
|
|
\A s1, s2 \in Sessions :
|
|
/\ s1 # s2
|
|
/\ s1 \in registered[Dom(s1)]
|
|
/\ s2 \in registered[Dom(s2)]
|
|
=> /\ SessionCliIdentity[s1] # SessionCliIdentity[s2]
|
|
/\ SessionAnchorIdentity[s1] # SessionAnchorIdentity[s2]
|
|
|
|
LiveRequestIdentityAuthorized ==
|
|
\A r \in Requests :
|
|
requestPhase[r] \notin {"Unused"} \cup TerminalRequestPhases =>
|
|
/\ RuntimeIdentityTupleReady(ReqDomain(r))
|
|
/\ SessionIdentityTupleRegistered(ReqSession(r))
|
|
|
|
DeveloperApprovalAuthenticated ==
|
|
\A r \in Requests : approvalSource[r] = "Developer" =>
|
|
/\ ApprovalCliIdentity[r] = SessionCliIdentity[ReqSession(r)]
|
|
/\ ApprovalSessionAnchor[r] = SessionAnchorIdentity[ReqSession(r)]
|
|
/\ ApprovalSignatureValid[r]
|
|
/\ approvedCommand[r] = ApprovalCommand[r]
|
|
|
|
HostExecutionAuthorized ==
|
|
\A r \in hostRunning :
|
|
/\ requestPhase[r] = "Executing"
|
|
/\ approvalSource[r] \in {"AutoRule", "Developer"}
|
|
/\ approvedCommand[r] \in Commands
|
|
/\ CommandContentSafe[approvedCommand[r]]
|
|
|
|
AutoApprovalNoShell ==
|
|
\A r \in Requests : approvalSource[r] = "AutoRule" =>
|
|
/\ approvedCommand[r] = RequestCommand[r]
|
|
/\ ~CommandRequiresShell[approvedCommand[r]]
|
|
|
|
TerminalIsolation ==
|
|
\A s \in Sessions : sessionPhase[s] = "Prompting" =>
|
|
terminalRoute[s] = "Prompt"
|
|
|
|
NoOrphanHostProcess ==
|
|
\A r \in hostRunning :
|
|
LET s == ReqSession(r) IN
|
|
/\ activeRequest[s] = r
|
|
/\ sessionPhase[s] = "HostExecuting"
|
|
/\ connectionState[s] = "Connected"
|
|
|
|
StateAnchorOwnership ==
|
|
\A d \in Domains : stateAnchorState[d] = "Mounted" =>
|
|
coordinatorState[d] \in {"Starting", "Ready", "Stopping", "Failed"}
|
|
|
|
FailedDomainIsolation ==
|
|
\A d \in Domains : domainPhase[d] \in {"Failed", "Recovering"} =>
|
|
/\ d \notin published
|
|
/\ registered[d] = {}
|
|
/\ connected[d] = {}
|
|
/\ ~trustReady[d]
|
|
/\ hostRunning \cap RequestsForDomain(d) = {}
|
|
|
|
OrderedFailureRecovery ==
|
|
\A d \in Domains : domainPhase[d] = "Recovering" =>
|
|
/\ (sidecarState[d] = "Stopped" => sandboxState[d] = "Stopped")
|
|
/\ (stateAnchorState[d] = "Unmounted" =>
|
|
/\ sandboxState[d] = "Stopped"
|
|
/\ sidecarState[d] = "Stopped")
|
|
|
|
ResultDeliveryStateConsistent ==
|
|
/\ \A r \in Requests : requestPhase[r] \in PendingResultPhases =>
|
|
LET s == ReqSession(r) IN
|
|
/\ activeRequest[s] = r
|
|
/\ connectionState[s] = "Connected"
|
|
/\ sessionPhase[s] = "Attached"
|
|
/\ r \notin hostRunning
|
|
/\ \A r \in Requests : requestPhase[r] \in TerminalRequestPhases =>
|
|
/\ activeRequest[ReqSession(r)] # r
|
|
/\ r \notin hostRunning
|
|
|
|
Safety ==
|
|
/\ TypeOK
|
|
/\ ConfigurationConfinement
|
|
/\ SandboxNamespaceIsolation
|
|
/\ OrderedNetworkStartup
|
|
/\ PublishedDomainsReady
|
|
/\ ExclusiveBootstrapOwnership
|
|
/\ TeardownNotJoinable
|
|
/\ RegisteredSessionsConnected
|
|
/\ AttachedSessionsValid
|
|
/\ AuthenticatedRequestsOnly
|
|
/\ RuntimeRoleIdentitySeparation
|
|
/\ RegisteredSessionIdentityUniqueness
|
|
/\ LiveRequestIdentityAuthorized
|
|
/\ DeveloperApprovalAuthenticated
|
|
/\ HostExecutionAuthorized
|
|
/\ AutoApprovalNoShell
|
|
/\ TerminalIsolation
|
|
/\ NoOrphanHostProcess
|
|
/\ StateAnchorOwnership
|
|
/\ FailedDomainIsolation
|
|
/\ OrderedFailureRecovery
|
|
/\ ResultDeliveryStateConsistent
|
|
|
|
(***************************************************************************
|
|
Liveness properties. TLC configurations may check these separately from the
|
|
safety sweep when the state space grows.
|
|
***************************************************************************)
|
|
|
|
SessionEventuallyResolves ==
|
|
\A s \in Sessions :
|
|
sessionPhase[s] = "New" ~>
|
|
sessionPhase[s] \in {"Attached", "Closed", "Failed"}
|
|
|
|
RequestEventuallyResolves ==
|
|
\A r \in Requests :
|
|
requestPhase[r] = "Verified" ~>
|
|
requestPhase[r] \in TerminalRequestPhases
|
|
|
|
PromptEventuallyRestoresTerminal ==
|
|
\A s \in Sessions :
|
|
sessionPhase[s] \in {"Prompting", "HostExecuting"} ~>
|
|
terminalRoute[s] \in {"Sandbox", "Detached"}
|
|
|
|
EmptyDomainEventuallyStops ==
|
|
\A d \in Domains :
|
|
(<>[](Interested(d) = {})) => <>(domainPhase[d] = "Absent")
|
|
|
|
FailedDomainEventuallyRecovers ==
|
|
\A d \in Domains :
|
|
domainPhase[d] = "Failed" ~> domainPhase[d] = "Absent"
|
|
|
|
=============================================================================
|