Skip to main content

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