sh_layer4/plugin_loader/
capabilities.rs1use serde::{Deserialize, Serialize};
6use std::collections::HashSet;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum Capability {
11 FsRead,
13 FsWrite,
15 NetworkOut,
17 ProcessExec,
19 EnvRead,
21 EnvWrite,
23 Clock,
25 Random,
27 MemoryLimit(u64),
29 CpuLimit(u64),
31}
32
33#[derive(Debug, Clone, Default)]
35pub struct CapabilitySet {
36 pub allowed: HashSet<Capability>,
38 pub denied: HashSet<Capability>,
40}
41
42impl CapabilitySet {
43 pub fn new() -> Self {
45 Self::default()
46 }
47
48 pub fn unrestricted() -> Self {
50 let mut allowed = HashSet::new();
51 allowed.insert(Capability::FsRead);
52 allowed.insert(Capability::FsWrite);
53 allowed.insert(Capability::NetworkOut);
54 allowed.insert(Capability::ProcessExec);
55 allowed.insert(Capability::EnvRead);
56 allowed.insert(Capability::EnvWrite);
57 allowed.insert(Capability::Clock);
58 allowed.insert(Capability::Random);
59 Self {
60 allowed,
61 denied: HashSet::new(),
62 }
63 }
64
65 pub fn sandboxed() -> Self {
67 let mut allowed = HashSet::new();
68 allowed.insert(Capability::Clock);
69 allowed.insert(Capability::Random);
70 allowed.insert(Capability::MemoryLimit(16 * 1024 * 1024)); allowed.insert(Capability::CpuLimit(5000)); Self {
73 allowed,
74 denied: HashSet::new(),
75 }
76 }
77
78 pub fn allow(&mut self, cap: Capability) -> &mut Self {
80 self.allowed.insert(cap.clone());
81 self.denied.remove(&cap);
82 self
83 }
84
85 pub fn deny(&mut self, cap: Capability) -> &mut Self {
87 self.denied.insert(cap.clone());
88 self.allowed.remove(&cap);
89 self
90 }
91
92 pub fn check(&self, cap: &Capability) -> bool {
94 self.allowed.contains(cap) && !self.denied.contains(cap)
95 }
96
97 pub fn merge(&mut self, other: &CapabilitySet) -> &mut Self {
99 for cap in &other.allowed {
100 if !self.denied.contains(cap) {
101 self.allowed.insert(cap.clone());
102 }
103 }
104 for cap in &other.denied {
105 self.allowed.remove(cap);
106 self.denied.insert(cap.clone());
107 }
108 self
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_empty_capability_set() {
118 let caps = CapabilitySet::new();
119 assert!(!caps.check(&Capability::FsRead));
120 assert!(!caps.check(&Capability::NetworkOut));
121 }
122
123 #[test]
124 fn test_unrestricted_capability_set() {
125 let caps = CapabilitySet::unrestricted();
126 assert!(caps.check(&Capability::FsRead));
127 assert!(caps.check(&Capability::NetworkOut));
128 assert!(caps.check(&Capability::ProcessExec));
129 }
130
131 #[test]
132 fn test_sandboxed_capability_set() {
133 let caps = CapabilitySet::sandboxed();
134 assert!(!caps.check(&Capability::FsRead));
135 assert!(!caps.check(&Capability::FsWrite));
136 assert!(caps.check(&Capability::Clock));
137 assert!(caps.check(&Capability::Random));
138 }
139
140 #[test]
141 fn test_deny_overrides_allow() {
142 let mut caps = CapabilitySet::unrestricted();
143 caps.deny(Capability::FsWrite);
144 assert!(!caps.check(&Capability::FsWrite));
145 assert!(caps.check(&Capability::FsRead));
146 }
147
148 #[test]
149 fn test_capability_merge() {
150 let mut caps1 = CapabilitySet::new();
151 caps1.allow(Capability::FsRead);
152
153 let caps2 = CapabilitySet::sandboxed();
154
155 caps1.merge(&caps2);
156 assert!(caps1.check(&Capability::FsRead));
157 assert!(caps1.check(&Capability::Clock));
158 }
159}