#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Access {
Read,
Write,
}
impl Access {
pub fn is_write(self) -> bool {
self == Self::Write
}
}
const READ_ACTIONS: &[&str] = &["read", "list", "stat", "now", "bytes", "use"];
const WRITE_ACTIONS: &[&str] = &[
"write", "append", "create", "delete", "truncate", "exec", "egress",
];
pub fn classify(action: &str) -> Access {
if READ_ACTIONS.contains(&action) {
Access::Read
} else if WRITE_ACTIONS.contains(&action) {
Access::Write
} else {
Access::Write
}
}
pub fn is_known_action(action: &str) -> bool {
READ_ACTIONS.contains(&action) || WRITE_ACTIONS.contains(&action)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn observing_actions_are_reads() {
for a in ["read", "list", "stat", "now", "bytes", "use"] {
assert_eq!(classify(a), Access::Read, "{a} should be a read");
}
}
#[test]
fn mutating_actions_are_writes() {
for a in ["write", "append", "create", "delete", "exec", "egress"] {
assert_eq!(classify(a), Access::Write, "{a} should be a write");
}
}
#[test]
fn an_unknown_action_is_assumed_to_write() {
assert_eq!(classify("frobnicate"), Access::Write);
assert!(!is_known_action("frobnicate"));
assert!(is_known_action("read"));
}
#[test]
fn executing_a_process_counts_as_writing() {
assert_eq!(classify("exec"), Access::Write);
}
#[test]
fn network_egress_counts_as_writing() {
assert_eq!(classify("egress"), Access::Write);
}
#[test]
fn using_a_secret_counts_as_reading() {
assert_eq!(classify("use"), Access::Read);
}
}