byteflow/scheduler/
link_admin.rs1use crate::bytecode::{Cap, CapTarget, CapRights, RevocationCell};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum LinkError {
11 WrongTarget,
12 MissingRight,
13 CapRevoked,
14}
15
16impl std::fmt::Display for LinkError {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 match self {
19 LinkError::WrongTarget => f.write_str("cap does not target this flow"),
20 LinkError::MissingRight => f.write_str("cap lacks LINK/MONITOR right"),
21 LinkError::CapRevoked => f.write_str("capability revoked"),
22 }
23 }
24}
25
26impl std::error::Error for LinkError {}
27
28pub fn check_link(cap: &Cap, cell: &RevocationCell, target: u64) -> Result<(), LinkError> {
29 if !cap.is_valid(cell) {
30 return Err(LinkError::CapRevoked);
31 }
32 if cap.target != CapTarget::Flow(target) {
33 return Err(LinkError::WrongTarget);
34 }
35 if !cap.rights.contains(CapRights::LINK) {
36 return Err(LinkError::MissingRight);
37 }
38 Ok(())
39}
40
41pub fn check_monitor(cap: &Cap, cell: &RevocationCell, target: u64) -> Result<(), LinkError> {
42 if !cap.is_valid(cell) {
43 return Err(LinkError::CapRevoked);
44 }
45 if cap.target != CapTarget::Flow(target) {
46 return Err(LinkError::WrongTarget);
47 }
48 if !cap.rights.contains(CapRights::MONITOR) {
49 return Err(LinkError::MissingRight);
50 }
51 Ok(())
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum AdminError {
56 MissingRight,
57 CapRevoked,
58 WrongTarget,
59}
60
61impl std::fmt::Display for AdminError {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 match self {
64 AdminError::MissingRight => f.write_str("cap lacks ADMIN right"),
65 AdminError::CapRevoked => f.write_str("capability revoked"),
66 AdminError::WrongTarget => f.write_str("ADMIN requires CapTarget::Scheduler"),
67 }
68 }
69}
70
71impl std::error::Error for AdminError {}
72
73pub fn check_admin(cap: &Cap, cell: &RevocationCell) -> Result<(), AdminError> {
75 if !cap.is_valid(cell) {
76 return Err(AdminError::CapRevoked);
77 }
78 if cap.target != CapTarget::Scheduler {
79 return Err(AdminError::WrongTarget);
80 }
81 if !cap.rights.contains(CapRights::ADMIN) {
82 return Err(AdminError::MissingRight);
83 }
84 Ok(())
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn knowing_flow_id_alone_is_not_enough_to_link() {
93 let cell = RevocationCell::new();
94 let cap = Cap::root(CapTarget::Flow(1), CapRights::SEND, None, &cell);
95 assert!(matches!(
96 check_link(&cap, &cell, 1),
97 Err(LinkError::MissingRight)
98 ));
99 let cap2 = Cap::root(CapTarget::Flow(2), CapRights::LINK, None, &cell);
100 assert!(matches!(
101 check_link(&cap2, &cell, 1),
102 Err(LinkError::WrongTarget)
103 ));
104 }
105
106 #[test]
107 fn admin_requires_scheduler_target_and_right() {
108 let cell = RevocationCell::new();
109 let cap = Cap::root(CapTarget::Scheduler, CapRights::ADMIN, None, &cell);
110 assert!(check_admin(&cap, &cell).is_ok());
111 let cap2 = Cap::root(CapTarget::Flow(1), CapRights::ADMIN, None, &cell);
112 assert!(matches!(
113 check_admin(&cap2, &cell),
114 Err(AdminError::WrongTarget)
115 ));
116 }
117}