Replace lexical Rust fragments with real modules
This commit is contained in:
parent
f8849cdb5f
commit
247819250b
8 changed files with 3302 additions and 2671 deletions
|
|
@ -18,6 +18,8 @@ use crate::records::{
|
|||
ResolvedNetworkReadinessV1, ResolvedVolume, TRUSTED_HOST_CONFIGURATION_SCHEMA_ID,
|
||||
TrustedHostConfigurationV1, VolumeAccess, VolumeKind,
|
||||
};
|
||||
use confined_io::{io_error, open_absolute_directory, validate_executable};
|
||||
use validation::validate_sandbox_path;
|
||||
|
||||
pub const MAX_CONFIGURATION_BYTES: usize = 1_048_576;
|
||||
|
||||
|
|
@ -714,7 +716,12 @@ impl ResolvedDomainConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
include!("configuration/loading.rs");
|
||||
include!("configuration/validation.rs");
|
||||
include!("configuration/confined_io.rs");
|
||||
include!("configuration/tests.rs");
|
||||
mod confined_io;
|
||||
mod loading;
|
||||
mod validation;
|
||||
|
||||
pub use loading::{load_trusted_configuration, parse_trusted_configuration};
|
||||
pub use validation::{derive_configuration_fingerprint, derive_domain_id};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,18 @@
|
|||
fn validate_host_base(path: &Path, name: &str) -> Result<(), ConfigurationError> {
|
||||
use super::validation::{
|
||||
validate_declared_host_path, validate_environment_name, validate_sandbox_path,
|
||||
};
|
||||
use super::{
|
||||
AsRawFd, BTreeMap, BTreeSet, ConfigurationError, ConfigurationErrorKind,
|
||||
ConfigurationLoadRequest, ConfinedPathPlan, ConfinedPathType, EnvironmentReference,
|
||||
EnvironmentValue, File, FileType, HostPath, Ipv4Prefix, MAX_CONFIGURATION_BYTES, Mode,
|
||||
NetworkProbeTargetConfigurationV1, NetworkReadinessConfigurationV1, OFlags, OsStrExt, OsString,
|
||||
OwnedFd, Path, PathBuf, ProfileConfigurationV1, Read, ResolveFlags, ResolvedAutoApprovalRule,
|
||||
ResolvedDnsProbeTargetV1, ResolvedNetworkProbeTargetV1, ResolvedNetworkReadinessV1,
|
||||
ResolvedVolume, Seek, SeekFrom, Stat, TrustedHostConfigurationV1, VolumeAccess, VolumeKind,
|
||||
fmt, openat2,
|
||||
};
|
||||
|
||||
pub(super) fn validate_host_base(path: &Path, name: &str) -> Result<(), ConfigurationError> {
|
||||
if !path.is_absolute()
|
||||
|| path.as_os_str().is_empty()
|
||||
|| path.as_os_str().as_bytes().contains(&0)
|
||||
|
|
@ -11,7 +25,7 @@ fn validate_host_base(path: &Path, name: &str) -> Result<(), ConfigurationError>
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn config_home(request: &ConfigurationLoadRequest) -> PathBuf {
|
||||
pub(super) fn config_home(request: &ConfigurationLoadRequest) -> PathBuf {
|
||||
request
|
||||
.xdg_config_home
|
||||
.as_ref()
|
||||
|
|
@ -20,7 +34,7 @@ fn config_home(request: &ConfigurationLoadRequest) -> PathBuf {
|
|||
.unwrap_or_else(|| request.home.join(".config"))
|
||||
}
|
||||
|
||||
fn data_home(request: &ConfigurationLoadRequest) -> PathBuf {
|
||||
pub(super) fn data_home(request: &ConfigurationLoadRequest) -> PathBuf {
|
||||
request
|
||||
.xdg_data_home
|
||||
.as_ref()
|
||||
|
|
@ -29,7 +43,7 @@ fn data_home(request: &ConfigurationLoadRequest) -> PathBuf {
|
|||
.unwrap_or_else(|| request.home.join(".local/share"))
|
||||
}
|
||||
|
||||
fn expand_host_path(
|
||||
pub(super) fn expand_host_path(
|
||||
declaration: &str,
|
||||
home: &Path,
|
||||
profile: Option<&Path>,
|
||||
|
|
@ -49,7 +63,9 @@ fn expand_host_path(
|
|||
Ok(PathBuf::from(declaration))
|
||||
}
|
||||
|
||||
fn read_stable_configuration(plan: &ConfinedPathPlan) -> Result<Vec<u8>, ConfigurationError> {
|
||||
pub(super) fn read_stable_configuration(
|
||||
plan: &ConfinedPathPlan,
|
||||
) -> Result<Vec<u8>, ConfigurationError> {
|
||||
let path_descriptor = plan.open_authority()?;
|
||||
let before = rustix::fs::fstat(&path_descriptor).map_err(io_error)?;
|
||||
validate_configuration_stat(&before)?;
|
||||
|
|
@ -93,7 +109,7 @@ fn read_stable_configuration(plan: &ConfinedPathPlan) -> Result<Vec<u8>, Configu
|
|||
Ok(first)
|
||||
}
|
||||
|
||||
fn validate_configuration_stat(stat: &Stat) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn validate_configuration_stat(stat: &Stat) -> Result<(), ConfigurationError> {
|
||||
let uid = rustix::process::getuid().as_raw();
|
||||
if !FileType::from_raw_mode(stat.st_mode).is_file()
|
||||
|| stat.st_nlink != 1
|
||||
|
|
@ -130,7 +146,7 @@ fn same_file_snapshot(left: &Stat, right: &Stat) -> bool {
|
|||
&& left.st_ctime_nsec == right.st_ctime_nsec
|
||||
}
|
||||
|
||||
fn confined_existing(
|
||||
pub(super) fn confined_existing(
|
||||
canonical: &Path,
|
||||
expected: ConfinedPathType,
|
||||
executable: bool,
|
||||
|
|
@ -147,7 +163,7 @@ fn confined_existing(
|
|||
Ok(plan)
|
||||
}
|
||||
|
||||
fn open_absolute_directory(path: &Path) -> Result<OwnedFd, ConfigurationError> {
|
||||
pub(super) fn open_absolute_directory(path: &Path) -> Result<OwnedFd, ConfigurationError> {
|
||||
openat2(
|
||||
rustix::fs::CWD,
|
||||
path,
|
||||
|
|
@ -158,7 +174,7 @@ fn open_absolute_directory(path: &Path) -> Result<OwnedFd, ConfigurationError> {
|
|||
.map_err(io_error)
|
||||
}
|
||||
|
||||
fn ensure_owned_directory(path: &Path, uid: u32) -> Result<PathBuf, ConfigurationError> {
|
||||
pub(super) fn ensure_owned_directory(path: &Path, uid: u32) -> Result<PathBuf, ConfigurationError> {
|
||||
validate_host_base(path, "Lazaret root")?;
|
||||
if path.exists() {
|
||||
let canonical = std::fs::canonicalize(path).map_err(io_error)?;
|
||||
|
|
@ -235,7 +251,7 @@ fn validate_owned_directory(descriptor: &OwnedFd, uid: u32) -> Result<(), Config
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_persistent_destinations(
|
||||
pub(super) fn validate_persistent_destinations(
|
||||
destinations: &[String],
|
||||
protected: &BTreeSet<String>,
|
||||
) -> Result<Vec<String>, ConfigurationError> {
|
||||
|
|
@ -250,7 +266,7 @@ fn validate_persistent_destinations(
|
|||
Ok(destinations.to_vec())
|
||||
}
|
||||
|
||||
fn require_clear_of_protected(
|
||||
pub(super) fn require_clear_of_protected(
|
||||
destination: &str,
|
||||
protected: &BTreeSet<String>,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
|
|
@ -267,7 +283,7 @@ fn require_clear_of_protected(
|
|||
}
|
||||
}
|
||||
|
||||
fn require_strict_child_of_one(
|
||||
pub(super) fn require_strict_child_of_one(
|
||||
destination: &str,
|
||||
parents: &[String],
|
||||
) -> Result<(), ConfigurationError> {
|
||||
|
|
@ -285,7 +301,7 @@ fn require_strict_child_of_one(
|
|||
}
|
||||
}
|
||||
|
||||
fn require_pairwise_non_ancestral<'a>(
|
||||
pub(super) fn require_pairwise_non_ancestral<'a>(
|
||||
paths: impl IntoIterator<Item = &'a str>,
|
||||
kind: ConfigurationErrorKind,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
|
|
@ -319,7 +335,7 @@ fn sandbox_is_strict_descendant(child: &str, parent: &str) -> bool {
|
|||
.is_some_and(|suffix| suffix.starts_with('/'))
|
||||
}
|
||||
|
||||
fn require_pairwise_disjoint(
|
||||
pub(super) fn require_pairwise_disjoint(
|
||||
paths: &[&Path],
|
||||
authorities: &[&ConfinedPathPlan],
|
||||
kind: ConfigurationErrorKind,
|
||||
|
|
@ -343,15 +359,15 @@ fn require_pairwise_disjoint(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn paths_intersect(left: &Path, right: &Path) -> bool {
|
||||
pub(super) fn paths_intersect(left: &Path, right: &Path) -> bool {
|
||||
left == right || left.starts_with(right) || right.starts_with(left)
|
||||
}
|
||||
|
||||
fn is_strict_descendant(child: &Path, parent: &Path) -> bool {
|
||||
pub(super) fn is_strict_descendant(child: &Path, parent: &Path) -> bool {
|
||||
child != parent && child.starts_with(parent)
|
||||
}
|
||||
|
||||
fn resolve_network(
|
||||
pub(super) fn resolve_network(
|
||||
configuration: &TrustedHostConfigurationV1,
|
||||
selected: &ProfileConfigurationV1,
|
||||
) -> Result<(Vec<Ipv4Prefix>, Vec<Ipv4Prefix>), ConfigurationError> {
|
||||
|
|
@ -386,7 +402,7 @@ fn resolve_network(
|
|||
}
|
||||
|
||||
const MAX_READINESS_TARGETS: usize = 32;
|
||||
fn resolve_network_readiness(
|
||||
pub(super) fn resolve_network_readiness(
|
||||
readiness: &NetworkReadinessConfigurationV1,
|
||||
allow: &[Ipv4Prefix],
|
||||
deny: &[Ipv4Prefix],
|
||||
|
|
@ -552,7 +568,7 @@ fn prefix_contains(prefix: Ipv4Prefix, address: [u8; 4]) -> bool {
|
|||
u32::from_be_bytes(address) & mask == u32::from_be_bytes(prefix.address)
|
||||
}
|
||||
|
||||
fn parse_ipv4_prefix(value: &str) -> Result<Ipv4Prefix, ConfigurationError> {
|
||||
pub(super) fn parse_ipv4_prefix(value: &str) -> Result<Ipv4Prefix, ConfigurationError> {
|
||||
let (address, prefix) = value.split_once('/').ok_or_else(|| {
|
||||
ConfigurationError::new(
|
||||
ConfigurationErrorKind::InvalidNetwork,
|
||||
|
|
@ -595,7 +611,7 @@ fn parse_ipv4_prefix(value: &str) -> Result<Ipv4Prefix, ConfigurationError> {
|
|||
})
|
||||
}
|
||||
|
||||
fn resolve_environment_references(
|
||||
pub(super) fn resolve_environment_references(
|
||||
selected: &ProfileConfigurationV1,
|
||||
) -> Result<Vec<EnvironmentReference>, ConfigurationError> {
|
||||
selected
|
||||
|
|
@ -618,7 +634,7 @@ fn resolve_environment_references(
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn resolve_environment_values(
|
||||
pub(super) fn resolve_environment_values(
|
||||
references: &[EnvironmentReference],
|
||||
environment: &BTreeMap<String, OsString>,
|
||||
) -> Result<BTreeMap<String, EnvironmentValue>, ConfigurationError> {
|
||||
|
|
@ -645,7 +661,10 @@ fn resolve_environment_values(
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn validate_executable(descriptor: &OwnedFd, uid: u32) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn validate_executable(
|
||||
descriptor: &OwnedFd,
|
||||
uid: u32,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
let stat = rustix::fs::fstat(descriptor).map_err(io_error)?;
|
||||
let executable_by_invoking_user = if stat.st_uid == uid {
|
||||
stat.st_mode & 0o100 != 0
|
||||
|
|
@ -673,7 +692,7 @@ fn validate_executable(descriptor: &OwnedFd, uid: u32) -> Result<(), Configurati
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn encode_volume(volume: &ResolvedVolume) -> Result<Vec<u8>, ConfigurationError> {
|
||||
pub(super) fn encode_volume(volume: &ResolvedVolume) -> Result<Vec<u8>, ConfigurationError> {
|
||||
let mut encoded = Vec::new();
|
||||
push_bytes(&mut encoded, volume.canonical_host_source.as_bytes())?;
|
||||
push_bytes(&mut encoded, volume.container_path.as_bytes())?;
|
||||
|
|
@ -689,7 +708,9 @@ fn encode_volume(volume: &ResolvedVolume) -> Result<Vec<u8>, ConfigurationError>
|
|||
Ok(encoded)
|
||||
}
|
||||
|
||||
fn encode_auto_approval(rule: &ResolvedAutoApprovalRule) -> Result<Vec<u8>, ConfigurationError> {
|
||||
pub(super) fn encode_auto_approval(
|
||||
rule: &ResolvedAutoApprovalRule,
|
||||
) -> Result<Vec<u8>, ConfigurationError> {
|
||||
let mut encoded = Vec::new();
|
||||
push_bytes(&mut encoded, rule.canonical_executable.as_bytes())?;
|
||||
push_declared_list(
|
||||
|
|
@ -704,18 +725,18 @@ fn encode_auto_approval(rule: &ResolvedAutoApprovalRule) -> Result<Vec<u8>, Conf
|
|||
Ok(encoded)
|
||||
}
|
||||
|
||||
fn push_bytes(target: &mut Vec<u8>, bytes: &[u8]) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn push_bytes(target: &mut Vec<u8>, bytes: &[u8]) -> Result<(), ConfigurationError> {
|
||||
let length = u32::try_from(bytes.len()).map_err(|_| fingerprint_overflow())?;
|
||||
target.extend_from_slice(&length.to_be_bytes());
|
||||
target.extend_from_slice(bytes);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn push_bool(target: &mut Vec<u8>, value: bool) {
|
||||
pub(super) fn push_bool(target: &mut Vec<u8>, value: bool) {
|
||||
target.push(u8::from(value));
|
||||
}
|
||||
|
||||
fn push_sorted_list(
|
||||
pub(super) fn push_sorted_list(
|
||||
target: &mut Vec<u8>,
|
||||
items: impl IntoIterator<Item = Result<Vec<u8>, ConfigurationError>>,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
|
|
@ -748,11 +769,11 @@ fn fingerprint_overflow() -> ConfigurationError {
|
|||
)
|
||||
}
|
||||
|
||||
fn host_path(path: &Path) -> HostPath {
|
||||
pub(super) fn host_path(path: &Path) -> HostPath {
|
||||
HostPath::new(path.as_os_str().as_bytes().to_vec())
|
||||
}
|
||||
|
||||
fn hex_lower(bytes: &[u8]) -> String {
|
||||
pub(super) fn hex_lower(bytes: &[u8]) -> String {
|
||||
const HEX: &[u8; 16] = b"0123456789abcdef";
|
||||
let mut output = String::with_capacity(bytes.len() * 2);
|
||||
for byte in bytes {
|
||||
|
|
@ -762,6 +783,6 @@ fn hex_lower(bytes: &[u8]) -> String {
|
|||
output
|
||||
}
|
||||
|
||||
fn io_error(error: impl fmt::Display) -> ConfigurationError {
|
||||
pub(super) fn io_error(error: impl fmt::Display) -> ConfigurationError {
|
||||
ConfigurationError::new(ConfigurationErrorKind::Io, error.to_string())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,22 @@
|
|||
use super::confined_io::{
|
||||
config_home, confined_existing, data_home, ensure_owned_directory, expand_host_path, hex_lower,
|
||||
host_path, io_error, is_strict_descendant, paths_intersect, read_stable_configuration,
|
||||
require_clear_of_protected, require_pairwise_disjoint, require_pairwise_non_ancestral,
|
||||
require_strict_child_of_one, resolve_environment_references, resolve_environment_values,
|
||||
resolve_network, resolve_network_readiness, validate_configuration_stat, validate_executable,
|
||||
validate_host_base, validate_persistent_destinations,
|
||||
};
|
||||
use super::validation::{
|
||||
validate_profile_name, validate_sandbox_path, validate_structural_configuration, validate_text,
|
||||
};
|
||||
use super::{
|
||||
ConfigurationError, ConfigurationErrorKind, ConfigurationFingerprintRecordV1,
|
||||
ConfigurationLoadRequest, ConfinedPathPlan, ConfinedPathType, MAX_CONFIGURATION_BYTES, OFlags,
|
||||
OsStrExt, PathBuf, ResolvedAutoApproval, ResolvedAutoApprovalRule, ResolvedDomainConfiguration,
|
||||
ResolvedVolume, ResolvedVolumeAuthority, TrustedHostConfigurationV1, VolumeKind,
|
||||
derive_configuration_fingerprint, derive_domain_id,
|
||||
};
|
||||
|
||||
/// Parses the closed trusted-host configuration document without resolving host authority.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
|
|||
|
|
@ -1,37 +1,35 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{DescriptorIdentity, descriptor_identities_alias, validate_path_suffix};
|
||||
use super::validation::validate_path_suffix;
|
||||
use super::{DescriptorIdentity, descriptor_identities_alias};
|
||||
|
||||
#[test]
|
||||
fn bind_mount_identity_aliases_across_distinct_mount_ids() {
|
||||
let original = DescriptorIdentity {
|
||||
device: 7,
|
||||
inode: 11,
|
||||
mount_id: 13,
|
||||
};
|
||||
let bind_alias = DescriptorIdentity {
|
||||
mount_id: 17,
|
||||
..original
|
||||
};
|
||||
let distinct = DescriptorIdentity {
|
||||
inode: 19,
|
||||
..original
|
||||
};
|
||||
assert!(descriptor_identities_alias(original, bind_alias));
|
||||
assert!(!descriptor_identities_alias(original, distinct));
|
||||
}
|
||||
#[test]
|
||||
fn bind_mount_identity_aliases_across_distinct_mount_ids() {
|
||||
let original = DescriptorIdentity {
|
||||
device: 7,
|
||||
inode: 11,
|
||||
mount_id: 13,
|
||||
};
|
||||
let bind_alias = DescriptorIdentity {
|
||||
mount_id: 17,
|
||||
..original
|
||||
};
|
||||
let distinct = DescriptorIdentity {
|
||||
inode: 19,
|
||||
..original
|
||||
};
|
||||
assert!(descriptor_identities_alias(original, bind_alias));
|
||||
assert!(!descriptor_identities_alias(original, distinct));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn path_suffix_rejects_every_expansion_and_shell_metacharacter() {
|
||||
for metacharacter in [
|
||||
'*', '?', '[', ']', '{', '}', '$', '~', '\\', '`', '\'', '"', ';', '|', '&', '<', '>',
|
||||
'(', ')', '!', '\n', '\r', '\t',
|
||||
] {
|
||||
assert!(
|
||||
validate_path_suffix(&format!("safe{metacharacter}suffix")).is_err(),
|
||||
"{metacharacter:?} must be rejected"
|
||||
);
|
||||
}
|
||||
assert!(validate_path_suffix("safe path/with+literal@characters").is_ok());
|
||||
#[test]
|
||||
fn path_suffix_rejects_every_expansion_and_shell_metacharacter() {
|
||||
for metacharacter in [
|
||||
'*', '?', '[', ']', '{', '}', '$', '~', '\\', '`', '\'', '"', ';', '|', '&', '<', '>', '(',
|
||||
')', '!', '\n', '\r', '\t',
|
||||
] {
|
||||
assert!(
|
||||
validate_path_suffix(&format!("safe{metacharacter}suffix")).is_err(),
|
||||
"{metacharacter:?} must be rejected"
|
||||
);
|
||||
}
|
||||
assert!(validate_path_suffix("safe path/with+literal@characters").is_ok());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,13 @@
|
|||
use super::confined_io::{
|
||||
encode_auto_approval, encode_volume, parse_ipv4_prefix, push_bool, push_bytes,
|
||||
push_sorted_list, require_pairwise_non_ancestral,
|
||||
};
|
||||
use super::{
|
||||
ConfigurationError, ConfigurationErrorKind, ConfigurationFingerprint,
|
||||
ConfigurationFingerprintRecordV1, Digest, DomainId, Sha256,
|
||||
TRUSTED_HOST_CONFIGURATION_SCHEMA_ID, TrustedHostConfigurationV1,
|
||||
};
|
||||
|
||||
/// Derives the specification-framed v1 Domain ID.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
@ -96,7 +106,7 @@ pub fn derive_configuration_fingerprint(
|
|||
))
|
||||
}
|
||||
|
||||
fn validate_structural_configuration(
|
||||
pub(super) fn validate_structural_configuration(
|
||||
configuration: &TrustedHostConfigurationV1,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
if configuration.schema_id() != TRUSTED_HOST_CONFIGURATION_SCHEMA_ID {
|
||||
|
|
@ -186,7 +196,7 @@ fn validate_image_reference(reference: &str) -> Result<(), ConfigurationError> {
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_profile_name(name: &str) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn validate_profile_name(name: &str) -> Result<(), ConfigurationError> {
|
||||
let bytes = name.as_bytes();
|
||||
let valid = (1..=64).contains(&bytes.len())
|
||||
&& bytes[0].is_ascii_alphanumeric()
|
||||
|
|
@ -204,7 +214,7 @@ fn validate_profile_name(name: &str) -> Result<(), ConfigurationError> {
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_environment_name(name: &str) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn validate_environment_name(name: &str) -> Result<(), ConfigurationError> {
|
||||
let mut bytes = name.bytes();
|
||||
let valid = bytes
|
||||
.next()
|
||||
|
|
@ -220,7 +230,7 @@ fn validate_environment_name(name: &str) -> Result<(), ConfigurationError> {
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_text(value: &str, field: &str) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn validate_text(value: &str, field: &str) -> Result<(), ConfigurationError> {
|
||||
if value.contains('\0') {
|
||||
Err(ConfigurationError::new(
|
||||
ConfigurationErrorKind::InvalidProfile,
|
||||
|
|
@ -231,7 +241,7 @@ fn validate_text(value: &str, field: &str) -> Result<(), ConfigurationError> {
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_declared_host_path(
|
||||
pub(super) fn validate_declared_host_path(
|
||||
declaration: &str,
|
||||
allow_profile: bool,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
|
|
@ -256,7 +266,7 @@ fn validate_declared_host_path(
|
|||
validate_path_suffix(suffix)
|
||||
}
|
||||
|
||||
fn validate_sandbox_path(path: &str) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn validate_sandbox_path(path: &str) -> Result<(), ConfigurationError> {
|
||||
validate_text(path, "sandbox path")?;
|
||||
let suffix = path.strip_prefix('/').ok_or_else(|| {
|
||||
ConfigurationError::new(
|
||||
|
|
@ -267,7 +277,7 @@ fn validate_sandbox_path(path: &str) -> Result<(), ConfigurationError> {
|
|||
validate_path_suffix(suffix)
|
||||
}
|
||||
|
||||
fn validate_path_suffix(suffix: &str) -> Result<(), ConfigurationError> {
|
||||
pub(super) fn validate_path_suffix(suffix: &str) -> Result<(), ConfigurationError> {
|
||||
if suffix.is_empty()
|
||||
|| suffix.ends_with('/')
|
||||
|| suffix
|
||||
|
|
|
|||
|
|
@ -845,4 +845,14 @@ pub struct DomainStore {
|
|||
pub session_terminals: Vec<SessionTerminal>,
|
||||
pub mailboxes: Vec<Mailbox>,
|
||||
}
|
||||
include!("lifecycle/ownership.rs");
|
||||
mod ownership;
|
||||
|
||||
pub use ownership::{
|
||||
GitRoutingOwnership, HelperOwnership, NetworkOwnership, ParticipantOwnership,
|
||||
PreparedLowerOwnership, PublicationOwnership, SandboxOwnership, StateAnchorOwnership,
|
||||
StateAnchorReleaseEvidence,
|
||||
};
|
||||
use ownership::{
|
||||
validate_existing_process_progress, validate_option_progress, validate_participant_activation,
|
||||
validate_participant_progress, validate_participant_release, validate_process_progress,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
use super::{
|
||||
BundleDigest, ContainerId, DerivedPolicyDigest, Deserialize, DeviceId, GenerationId, HostPath,
|
||||
InodeId, MountIdentity, NamespaceIdentity, NetworkReadinessEvidence, NetworkSidecarId,
|
||||
ParticipantRole, ParticipantState, PersistedHostProcessOwnership, PidfsProcessIdentityV1,
|
||||
PreparedArtifactId, ReadinessFingerprint, RecordTransitionError, Serialize, SourceIdentity,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub enum ParticipantOwnership {
|
||||
PreparedLower(PreparedLowerOwnership),
|
||||
|
|
@ -49,7 +56,7 @@ impl ParticipantOwnership {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_intent(&self) -> bool {
|
||||
pub(super) fn is_intent(&self) -> bool {
|
||||
match self {
|
||||
Self::PreparedLower(ownership) => ownership
|
||||
.lease_state
|
||||
|
|
@ -58,7 +65,7 @@ impl ParticipantOwnership {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_release_intent(&self) -> bool {
|
||||
pub(super) fn is_release_intent(&self) -> bool {
|
||||
match self {
|
||||
Self::PreparedLower(ownership) => ownership
|
||||
.lease_state
|
||||
|
|
@ -67,7 +74,11 @@ impl ParticipantOwnership {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_active_for(&self, state: ParticipantState, generation_id: GenerationId) -> bool {
|
||||
pub(super) fn is_active_for(
|
||||
&self,
|
||||
state: ParticipantState,
|
||||
generation_id: GenerationId,
|
||||
) -> bool {
|
||||
match (self, state) {
|
||||
(Self::PreparedLower(ownership), ParticipantState::LeaseHeld) => {
|
||||
ownership.is_lease_held()
|
||||
|
|
@ -84,7 +95,7 @@ impl ParticipantOwnership {
|
|||
}
|
||||
}
|
||||
|
||||
fn cleared(&self) -> Self {
|
||||
pub(super) fn cleared(&self) -> Self {
|
||||
Self::empty(self.role())
|
||||
}
|
||||
|
||||
|
|
@ -564,7 +575,7 @@ impl PublicationOwnership {
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_participant_progress(
|
||||
pub(super) fn validate_participant_progress(
|
||||
old: Option<&ParticipantOwnership>,
|
||||
next: Option<&ParticipantOwnership>,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
|
|
@ -577,7 +588,7 @@ fn validate_participant_progress(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_participant_release(
|
||||
pub(super) fn validate_participant_release(
|
||||
old: Option<&ParticipantOwnership>,
|
||||
next: Option<&ParticipantOwnership>,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
|
|
@ -587,7 +598,7 @@ fn validate_participant_release(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_participant_activation(
|
||||
pub(super) fn validate_participant_activation(
|
||||
old: Option<&ParticipantOwnership>,
|
||||
next: Option<&ParticipantOwnership>,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
|
|
@ -613,7 +624,7 @@ fn validate_prepared_lower_lease_progress(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_option_progress<T: Eq>(
|
||||
pub(super) fn validate_option_progress<T: Eq>(
|
||||
old: Option<&T>,
|
||||
next: Option<&T>,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
|
|
@ -625,7 +636,7 @@ fn validate_option_progress<T: Eq>(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_process_progress(
|
||||
pub(super) fn validate_process_progress(
|
||||
old: &PersistedHostProcessOwnership,
|
||||
next: &PersistedHostProcessOwnership,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
|
|
@ -661,7 +672,7 @@ fn validate_process_progress(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_existing_process_progress(
|
||||
pub(super) fn validate_existing_process_progress(
|
||||
old: &PersistedHostProcessOwnership,
|
||||
next: &PersistedHostProcessOwnership,
|
||||
) -> Result<(), RecordTransitionError> {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,11 @@ struct TestTree(PathBuf);
|
|||
impl TestTree {
|
||||
fn new() -> Self {
|
||||
let sequence = NEXT_TREE.fetch_add(1, Ordering::Relaxed);
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
let parent = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../../target/test-artifacts/configuration");
|
||||
fs::create_dir_all(&parent).unwrap();
|
||||
let parent = parent.canonicalize().unwrap();
|
||||
let path = parent.join(format!(
|
||||
"lazaret-configuration-{}-{sequence}",
|
||||
std::process::id()
|
||||
));
|
||||
|
|
|
|||
Loading…
Reference in a new issue