pub(crate) fn is_rc_safe_user(user: &str) -> bool {
let mut chars = user.chars();
chars
.next()
.is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
&& user.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Privilege {
Root,
Unprivileged,
}
pub(super) fn privilege() -> Privilege {
if nix::unistd::geteuid().is_root() {
Privilege::Root
} else {
Privilege::Unprivileged
}
}
#[cfg(test)]
mod tests {
use super::super::step_execution::{ABSENT, remove};
use crate::exit::ExitCode;
use crate::output::Streams;
use super::super::testing::*;
use super::*;
use crate::cli::Format;
#[test]
fn an_absent_unit_is_an_absent_row_and_a_success() {
let dir = tempfile::tempdir().unwrap();
let home = dir.path().join(".shep");
let mut out = Vec::new();
let mut err = Vec::new();
let code = {
let mut streams = Streams::bare(&mut out, &mut err, Format::Table);
remove(&mut streams, &plan_for_test(&home), Privilege::Unprivileged)
};
assert_eq!(code, ExitCode::Success);
let printed = String::from_utf8(out).unwrap();
assert!(printed.contains(ABSENT), "{printed}");
}
#[test]
fn a_user_name_that_cannot_be_a_shell_variable_is_refused() {
for ok in ["deploy", "www", "_shep", "app2"] {
assert!(is_rc_safe_user(ok), "{ok} should be accepted");
}
for bad in ["web-app", "deploy.svc", "2fast", "", "ünicode"] {
assert!(!is_rc_safe_user(bad), "{bad} should be refused");
}
}
}