Define Rust environment and toolchain
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
use std::ffi::OsString;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum StartupAction {
|
||||
Help,
|
||||
Version,
|
||||
ManagementUnavailable,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum StartupError {
|
||||
UnknownArguments,
|
||||
RootRequired,
|
||||
}
|
||||
|
||||
impl fmt::Display for StartupError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::UnknownArguments => write!(formatter, "unknown or unsupported arguments"),
|
||||
Self::RootRequired => write!(formatter, "management operations require root"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for StartupError {}
|
||||
|
||||
/// Resolves the supported command line and checks management privilege lazily.
|
||||
///
|
||||
/// The injected root check keeps this boundary testable without running tests as
|
||||
/// root. Help, version, and invalid arguments do not query process privileges.
|
||||
pub fn start(
|
||||
arguments: &[OsString],
|
||||
effective_uid_is_root: impl FnOnce() -> bool,
|
||||
) -> Result<StartupAction, StartupError> {
|
||||
match arguments {
|
||||
[] => {
|
||||
if effective_uid_is_root() {
|
||||
Ok(StartupAction::ManagementUnavailable)
|
||||
} else {
|
||||
Err(StartupError::RootRequired)
|
||||
}
|
||||
}
|
||||
[argument] if argument == "--help" => Ok(StartupAction::Help),
|
||||
[argument] if argument == "--version" => Ok(StartupAction::Version),
|
||||
_ => Err(StartupError::UnknownArguments),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{StartupAction, StartupError, start};
|
||||
use std::ffi::OsString;
|
||||
|
||||
#[test]
|
||||
fn help_and_version_do_not_query_root() {
|
||||
for (argument, expected) in [
|
||||
("--help", StartupAction::Help),
|
||||
("--version", StartupAction::Version),
|
||||
] {
|
||||
let result = start(&[OsString::from(argument)], || {
|
||||
panic!("root check must not run for {argument}")
|
||||
});
|
||||
assert_eq!(result, Ok(expected));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_root_is_rejected_before_management_startup() {
|
||||
let result = start(&[], || false);
|
||||
assert_eq!(result, Err(StartupError::RootRequired));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn root_management_startup_reports_unimplemented_without_side_effects() {
|
||||
let result = start(&[], || true);
|
||||
assert_eq!(result, Ok(StartupAction::ManagementUnavailable));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_or_extra_arguments_fail_without_root_check() {
|
||||
for arguments in [
|
||||
vec![OsString::from("--settings")],
|
||||
vec![OsString::from("--help"), OsString::from("unexpected")],
|
||||
] {
|
||||
let result = start(&arguments, || {
|
||||
panic!("root check must not run for invalid arguments")
|
||||
});
|
||||
assert_eq!(result, Err(StartupError::UnknownArguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user