Skip to main content

agent_core_runtime/permissions/
level.rs

1//! Permission levels for the grant system.
2//!
3//! Permission levels form a hierarchy where higher levels imply lower levels:
4//! `Admin > Execute > Write > Read > None`
5
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9/// Permission level that determines what operations are allowed.
10///
11/// Levels are hierarchical: a higher level automatically grants all lower levels.
12/// For example, `Write` permission implies `Read` permission.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
14#[repr(u8)]
15pub enum PermissionLevel {
16    /// No permission granted
17    None = 0,
18    /// Read-only access: view contents, list directories, search
19    Read = 1,
20    /// Read + create/modify: includes all Read operations plus file creation and modification
21    Write = 2,
22    /// Read + Write + execute: includes running commands and scripts
23    Execute = 3,
24    /// Full access: includes all operations plus dangerous ones (delete, system commands)
25    Admin = 4,
26}
27
28impl PermissionLevel {
29    /// Returns the numeric value of this permission level.
30    pub fn as_u8(self) -> u8 {
31        self as u8
32    }
33
34    /// Creates a permission level from a numeric value.
35    ///
36    /// Returns `None` if the value is out of range (> 4).
37    pub fn from_u8(value: u8) -> Option<Self> {
38        match value {
39            0 => Some(Self::None),
40            1 => Some(Self::Read),
41            2 => Some(Self::Write),
42            3 => Some(Self::Execute),
43            4 => Some(Self::Admin),
44            _ => None,
45        }
46    }
47
48    /// Checks if this permission level satisfies a required level.
49    ///
50    /// A level satisfies another if it is greater than or equal to the required level.
51    /// This implements the permission hierarchy where higher levels imply lower levels.
52    ///
53    /// # Examples
54    ///
55    /// ```
56    /// use agent_core_runtime::permissions::PermissionLevel;
57    ///
58    /// assert!(PermissionLevel::Write.satisfies(PermissionLevel::Read));
59    /// assert!(PermissionLevel::Admin.satisfies(PermissionLevel::Execute));
60    /// assert!(!PermissionLevel::Read.satisfies(PermissionLevel::Write));
61    /// ```
62    pub fn satisfies(self, required: Self) -> bool {
63        self >= required
64    }
65
66    /// Returns all permission levels that this level implies.
67    ///
68    /// For example, `Write` implies both `Write` and `Read`.
69    pub fn implied_levels(self) -> Vec<Self> {
70        match self {
71            Self::None => vec![Self::None],
72            Self::Read => vec![Self::None, Self::Read],
73            Self::Write => vec![Self::None, Self::Read, Self::Write],
74            Self::Execute => vec![Self::None, Self::Read, Self::Write, Self::Execute],
75            Self::Admin => vec![
76                Self::None,
77                Self::Read,
78                Self::Write,
79                Self::Execute,
80                Self::Admin,
81            ],
82        }
83    }
84
85    /// Returns all permission levels as a slice.
86    pub fn all() -> &'static [Self] {
87        &[
88            Self::None,
89            Self::Read,
90            Self::Write,
91            Self::Execute,
92            Self::Admin,
93        ]
94    }
95}
96
97impl fmt::Display for PermissionLevel {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        match self {
100            Self::None => write!(f, "None"),
101            Self::Read => write!(f, "Read"),
102            Self::Write => write!(f, "Write"),
103            Self::Execute => write!(f, "Execute"),
104            Self::Admin => write!(f, "Admin"),
105        }
106    }
107}
108
109impl Default for PermissionLevel {
110    fn default() -> Self {
111        Self::None
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_level_ordering() {
121        assert!(PermissionLevel::Admin > PermissionLevel::Execute);
122        assert!(PermissionLevel::Execute > PermissionLevel::Write);
123        assert!(PermissionLevel::Write > PermissionLevel::Read);
124        assert!(PermissionLevel::Read > PermissionLevel::None);
125    }
126
127    #[test]
128    fn test_satisfies() {
129        // Same level satisfies itself
130        assert!(PermissionLevel::Read.satisfies(PermissionLevel::Read));
131        assert!(PermissionLevel::Write.satisfies(PermissionLevel::Write));
132
133        // Higher level satisfies lower
134        assert!(PermissionLevel::Write.satisfies(PermissionLevel::Read));
135        assert!(PermissionLevel::Execute.satisfies(PermissionLevel::Write));
136        assert!(PermissionLevel::Admin.satisfies(PermissionLevel::Execute));
137
138        // Admin satisfies all
139        assert!(PermissionLevel::Admin.satisfies(PermissionLevel::None));
140        assert!(PermissionLevel::Admin.satisfies(PermissionLevel::Read));
141        assert!(PermissionLevel::Admin.satisfies(PermissionLevel::Write));
142        assert!(PermissionLevel::Admin.satisfies(PermissionLevel::Execute));
143        assert!(PermissionLevel::Admin.satisfies(PermissionLevel::Admin));
144
145        // Lower level does not satisfy higher
146        assert!(!PermissionLevel::Read.satisfies(PermissionLevel::Write));
147        assert!(!PermissionLevel::Write.satisfies(PermissionLevel::Execute));
148        assert!(!PermissionLevel::Execute.satisfies(PermissionLevel::Admin));
149        assert!(!PermissionLevel::None.satisfies(PermissionLevel::Read));
150    }
151
152    #[test]
153    fn test_from_u8() {
154        assert_eq!(PermissionLevel::from_u8(0), Some(PermissionLevel::None));
155        assert_eq!(PermissionLevel::from_u8(1), Some(PermissionLevel::Read));
156        assert_eq!(PermissionLevel::from_u8(2), Some(PermissionLevel::Write));
157        assert_eq!(PermissionLevel::from_u8(3), Some(PermissionLevel::Execute));
158        assert_eq!(PermissionLevel::from_u8(4), Some(PermissionLevel::Admin));
159        assert_eq!(PermissionLevel::from_u8(5), None);
160    }
161
162    #[test]
163    fn test_implied_levels() {
164        assert_eq!(
165            PermissionLevel::Write.implied_levels(),
166            vec![
167                PermissionLevel::None,
168                PermissionLevel::Read,
169                PermissionLevel::Write
170            ]
171        );
172    }
173
174    #[test]
175    fn test_display() {
176        assert_eq!(format!("{}", PermissionLevel::Read), "Read");
177        assert_eq!(format!("{}", PermissionLevel::Admin), "Admin");
178    }
179
180    #[test]
181    fn test_serialization() {
182        let level = PermissionLevel::Write;
183        let json = serde_json::to_string(&level).unwrap();
184        assert_eq!(json, "\"Write\"");
185
186        let deserialized: PermissionLevel = serde_json::from_str(&json).unwrap();
187        assert_eq!(deserialized, level);
188    }
189}