Own the patched runsc artifact and bind recovery identity

This commit is contained in:
ms2k 2026-07-26 18:01:03 +09:00
commit 2c420012bd
5 changed files with 1967 additions and 130 deletions

View file

@ -89,6 +89,8 @@ digest_identity!(
DerivedPolicyDigest,
ReadinessFingerprint,
BundleDigest,
RunscBuildId,
RunscDigest,
SelectedManifestDigest,
IdMapDigest,
CertificateDigest,

View file

@ -10,8 +10,9 @@ use crate::identity::{
GuestProcessGroupId, GuestProcessId, GuestProcessStartTimeTicks, HostPath, IdMapDigest,
InodeId, MountIdentity, NamespaceIdentity, NetworkSidecarId, PidfsProcessAuthorityV1,
PidfsProcessIdentityV1, PolicyId, PrepareOperationId, PreparedArtifactId, ProtocolCredentialId,
ReadinessFingerprint, RequestDigest, RequestId, SandboxId, SelectedManifestDigest,
SessionAnchorId, SessionId, SourceIdentity, StreamDigest, TrustManifestDigest,
ReadinessFingerprint, RequestDigest, RequestId, RunscBuildId, RunscDigest, SandboxId,
SelectedManifestDigest, SessionAnchorId, SessionId, SourceIdentity, StreamDigest,
TrustManifestDigest,
};
mod configuration;

View file

@ -4,8 +4,8 @@ use super::{
DeviceId, DomainId, FileDescriptor, GenerationId, GuestProcessGroupId, GuestProcessId,
GuestProcessStartTimeTicks, HostPath, InodeId, MountIdentity, NamespaceIdentity,
NetworkReadinessEvidence, NetworkSidecarId, PidfsProcessIdentityV1, PreparedArtifactId,
ReadinessFingerprint, RecordInvariantError, RecordTransitionError, RequestId,
STORAGE_CATALOG_SCHEMA_ID, STORAGE_CATALOG_SCHEMA_VERSION, SandboxId, Serialize,
ReadinessFingerprint, RecordInvariantError, RecordTransitionError, RequestId, RunscBuildId,
RunscDigest, STORAGE_CATALOG_SCHEMA_ID, STORAGE_CATALOG_SCHEMA_VERSION, SandboxId, Serialize,
SessionAnchorId, SessionId, SourceIdentity, fmt,
};
@ -212,6 +212,18 @@ pub enum PersistedHostProcessOwnership {
Unassigned,
Staged(PidfsProcessIdentityV1),
Committed(HostProcessIdentity),
Runsc {
build_id: RunscBuildId,
digest: RunscDigest,
process: RunscProcessOwnership,
},
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum RunscProcessOwnership {
Unassigned,
Staged(PidfsProcessIdentityV1),
Committed(HostProcessIdentity),
}
impl PersistedHostProcessOwnership {
@ -230,23 +242,103 @@ impl PersistedHostProcessOwnership {
Self::Committed(HostProcessIdentity::pidfs_v1(identity))
}
#[must_use]
pub const fn runsc_unassigned(build_id: RunscBuildId, digest: RunscDigest) -> Self {
Self::Runsc {
build_id,
digest,
process: RunscProcessOwnership::Unassigned,
}
}
#[must_use]
pub const fn stage_runsc(&self, identity: PidfsProcessIdentityV1) -> Option<Self> {
match self {
Self::Runsc {
build_id,
digest,
process: RunscProcessOwnership::Unassigned,
} => Some(Self::Runsc {
build_id: *build_id,
digest: *digest,
process: RunscProcessOwnership::Staged(identity),
}),
_ => None,
}
}
#[must_use]
pub const fn commit_runsc(&self, identity: PidfsProcessIdentityV1) -> Option<Self> {
match self {
Self::Runsc {
build_id,
digest,
process: RunscProcessOwnership::Staged(_),
} => Some(Self::Runsc {
build_id: *build_id,
digest: *digest,
process: RunscProcessOwnership::Committed(HostProcessIdentity::pidfs_v1(identity)),
}),
_ => None,
}
}
#[must_use]
pub const fn runsc_identity(&self) -> Option<(RunscBuildId, RunscDigest)> {
match self {
Self::Runsc {
build_id, digest, ..
} => Some((*build_id, *digest)),
_ => None,
}
}
#[must_use]
pub const fn is_staged(&self) -> bool {
matches!(self, Self::Staged(_))
matches!(
self,
Self::Staged(_)
| Self::Runsc {
process: RunscProcessOwnership::Staged(_),
..
}
)
}
#[must_use]
pub const fn is_unassigned(&self) -> bool {
matches!(self, Self::Unassigned)
matches!(
self,
Self::Unassigned
| Self::Runsc {
process: RunscProcessOwnership::Unassigned,
..
}
)
}
#[must_use]
pub const fn is_current_committed(&self) -> bool {
matches!(self, Self::Committed(_))
matches!(
self,
Self::Committed(_)
| Self::Runsc {
process: RunscProcessOwnership::Committed(_),
..
}
)
}
const fn is_initial_acquisition(&self) -> bool {
matches!(self, Self::Unassigned | Self::Staged(_))
matches!(
self,
Self::Unassigned
| Self::Staged(_)
| Self::Runsc {
process: RunscProcessOwnership::Unassigned | RunscProcessOwnership::Staged(_),
..
}
)
}
const fn is_initial_or_current_committed(&self) -> bool {
@ -257,9 +349,21 @@ impl PersistedHostProcessOwnership {
/// Unassigned ownership has no positive authority.
pub fn authoritative_pidfs(&self) -> Result<&PidfsProcessIdentityV1, ProcessAuthorityRefusal> {
match self {
Self::Unassigned => Err(ProcessAuthorityRefusal::Unassigned),
Self::Staged(identity) => Ok(identity),
Self::Committed(identity) => Ok(identity.pidfs()),
Self::Unassigned
| Self::Runsc {
process: RunscProcessOwnership::Unassigned,
..
} => Err(ProcessAuthorityRefusal::Unassigned),
Self::Staged(identity)
| Self::Runsc {
process: RunscProcessOwnership::Staged(identity),
..
} => Ok(identity),
Self::Committed(identity)
| Self::Runsc {
process: RunscProcessOwnership::Committed(identity),
..
} => Ok(identity.pidfs()),
}
}
@ -267,9 +371,21 @@ impl PersistedHostProcessOwnership {
/// Unassigned or staged ownership is not serviceable.
pub fn serviceable_pidfs(&self) -> Result<&PidfsProcessIdentityV1, ProcessOwnershipRefusal> {
match self {
Self::Unassigned => Err(ProcessOwnershipRefusal::Unassigned),
Self::Staged(_) => Err(ProcessOwnershipRefusal::Staged),
Self::Committed(identity) => Ok(identity.pidfs()),
Self::Unassigned
| Self::Runsc {
process: RunscProcessOwnership::Unassigned,
..
} => Err(ProcessOwnershipRefusal::Unassigned),
Self::Staged(_)
| Self::Runsc {
process: RunscProcessOwnership::Staged(_),
..
} => Err(ProcessOwnershipRefusal::Staged),
Self::Committed(identity)
| Self::Runsc {
process: RunscProcessOwnership::Committed(identity),
..
} => Ok(identity.pidfs()),
}
}
}

View file

@ -640,6 +640,24 @@ pub(super) fn validate_process_progress(
old: &PersistedHostProcessOwnership,
next: &PersistedHostProcessOwnership,
) -> Result<(), RecordTransitionError> {
if let (
PersistedHostProcessOwnership::Runsc {
build_id: old_build,
digest: old_digest,
process: old_process,
},
PersistedHostProcessOwnership::Runsc {
build_id: next_build,
digest: next_digest,
process: next_process,
},
) = (old, next)
{
if old_build != next_build || old_digest != next_digest {
return Err(RecordTransitionError::EvidenceChanged);
}
return validate_runsc_process_progress(old_process, next_process);
}
match (old, next) {
(
PersistedHostProcessOwnership::Unassigned,
@ -672,6 +690,24 @@ pub(super) fn validate_process_progress(
}
}
fn validate_runsc_process_progress(
old: &super::RunscProcessOwnership,
next: &super::RunscProcessOwnership,
) -> Result<(), RecordTransitionError> {
use super::RunscProcessOwnership::{Committed, Staged, Unassigned};
match (old, next) {
(Unassigned, Unassigned | Staged(_)) => Ok(()),
(Unassigned, Committed(_)) => Err(RecordTransitionError::ProcessStageSkipped),
(Staged(_) | Committed(_), Unassigned) | (Committed(_), Staged(_)) => {
Err(RecordTransitionError::EvidenceLost)
}
(Staged(old), Staged(next)) if old == next => Ok(()),
(Staged(old), Committed(next)) if old == next.pidfs() => Ok(()),
(Committed(old), Committed(next)) if old == next => Ok(()),
_ => Err(RecordTransitionError::EvidenceChanged),
}
}
pub(super) fn validate_existing_process_progress(
old: &PersistedHostProcessOwnership,
next: &PersistedHostProcessOwnership,

View file

@ -16,12 +16,12 @@ use super::{
PreparedLowerOwnership, ProcessOwnershipCommitAck, ProcessOwnershipMessageVersion,
ProtocolCredential, ProtocolCredentialRole, ProtocolPublicationIdentity, PtyIdentity,
PublicationOwnership, ResolvedAutoApprovalRule, ResolvedVolume, Resolver, ResultStream,
SandboxCredentialBundle, SandboxOwnership, Session, SessionBinding, SessionClose, SessionExit,
SessionExitOutcome, SessionRegistrationRequest, SessionRegistrationResponse,
SessionRequestCapability, SessionTerminal, SessionTerminalEvent, SessionTerminalMessage,
SessionTerminalState, SignedProtocolRecord, StagedProcessOwnership, StateAnchorOwnership,
StateAnchorReleaseEvidence, StorageCatalog, StorageCatalogMetadata, StoreMetadata,
TerminalInput, TerminalOutput, TerminalPrompt, TerminalResize, TerminalSignal,
RunscProcessOwnership, SandboxCredentialBundle, SandboxOwnership, Session, SessionBinding,
SessionClose, SessionExit, SessionExitOutcome, SessionRegistrationRequest,
SessionRegistrationResponse, SessionRequestCapability, SessionTerminal, SessionTerminalEvent,
SessionTerminalMessage, SessionTerminalState, SignedProtocolRecord, StagedProcessOwnership,
StateAnchorOwnership, StateAnchorReleaseEvidence, StorageCatalog, StorageCatalogMetadata,
StoreMetadata, TerminalInput, TerminalOutput, TerminalPrompt, TerminalResize, TerminalSignal,
TerminalSignalKind, TlsCredential, TlsRole, TrustManifest, TrustedHostConfigurationV1,
};
use crate::protocol::{BootstrapWaitOutcome, BootstrapWaitRequest};
@ -60,6 +60,7 @@ schema_types!(
"PidfsProcessIdentityV1" => PidfsProcessIdentityV1,
"HostProcessIdentity" => HostProcessIdentity,
"PersistedHostProcessOwnership" => PersistedHostProcessOwnership,
"RunscProcessOwnership" => RunscProcessOwnership,
"HostProcessOwnershipSlot" => HostProcessOwnershipSlot,
"ProcessOwnershipMessageVersion" => ProcessOwnershipMessageVersion,
"StagedProcessOwnership" => StagedProcessOwnership,