Skip to main content

agentic_reality/security/
mod.rs

1//! Security module — auth, authz, encryption, audit logging.
2
3use crate::types::error::{RealityError, RealityResult};
4use std::collections::HashMap;
5
6/// Authentication manager.
7pub struct AuthManager {
8    token: Option<String>,
9    sessions: HashMap<String, SessionBinding>,
10    failed_attempts: u32,
11    rate_limit: u32,
12}
13
14impl AuthManager {
15    pub fn new() -> Self {
16        let token = std::env::var("AGENTIC_AUTH_TOKEN").ok();
17        Self {
18            token,
19            sessions: HashMap::new(),
20            failed_attempts: 0,
21            rate_limit: 100,
22        }
23    }
24
25    pub fn authenticate(&mut self, provided_token: &str) -> RealityResult<String> {
26        if self.failed_attempts >= self.rate_limit {
27            return Err(RealityError::Authentication("rate limited".into()));
28        }
29        match &self.token {
30            Some(expected) => {
31                if constant_time_eq::constant_time_eq(
32                    expected.as_bytes(),
33                    provided_token.as_bytes(),
34                ) {
35                    self.failed_attempts = 0;
36                    let session_id = uuid::Uuid::new_v4().to_string();
37                    self.sessions.insert(
38                        session_id.clone(),
39                        SessionBinding {
40                            session_id: session_id.clone(),
41                            created_at: chrono::Utc::now().timestamp(),
42                            last_activity: chrono::Utc::now().timestamp(),
43                            permissions: Permissions::default(),
44                        },
45                    );
46                    Ok(session_id)
47                } else {
48                    self.failed_attempts += 1;
49                    Err(RealityError::Authentication("invalid token".into()))
50                }
51            }
52            None => {
53                // No token configured — auth disabled
54                Ok("anonymous".to_string())
55            }
56        }
57    }
58
59    pub fn is_auth_required(&self) -> bool {
60        self.token.is_some()
61    }
62}
63
64impl Default for AuthManager {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70/// Session binding.
71#[derive(Debug, Clone)]
72pub struct SessionBinding {
73    pub session_id: String,
74    pub created_at: i64,
75    pub last_activity: i64,
76    pub permissions: Permissions,
77}
78
79/// Per-domain read/write permissions.
80#[derive(Debug, Clone)]
81pub struct Permissions {
82    pub deployment_read: bool,
83    pub deployment_write: bool,
84    pub environment_read: bool,
85    pub environment_write: bool,
86    pub resource_read: bool,
87    pub resource_write: bool,
88    pub reality_read: bool,
89    pub reality_write: bool,
90    pub topology_read: bool,
91    pub topology_write: bool,
92    pub temporal_read: bool,
93    pub temporal_write: bool,
94    pub stakes_read: bool,
95    pub stakes_write: bool,
96    pub admin: bool,
97}
98
99impl Default for Permissions {
100    fn default() -> Self {
101        Self {
102            deployment_read: true,
103            deployment_write: true,
104            environment_read: true,
105            environment_write: true,
106            resource_read: true,
107            resource_write: true,
108            reality_read: true,
109            reality_write: true,
110            topology_read: true,
111            topology_write: true,
112            temporal_read: true,
113            temporal_write: true,
114            stakes_read: true,
115            stakes_write: true,
116            admin: false,
117        }
118    }
119}
120
121/// Audit logger.
122pub struct AuditLogger {
123    log_path: Option<String>,
124}
125
126impl AuditLogger {
127    pub fn new() -> Self {
128        Self {
129            log_path: std::env::var("AGENTIC_AUDIT_LOG").ok(),
130        }
131    }
132
133    pub fn log_operation(&self, operation: &str, session: &str, success: bool) {
134        if let Some(path) = &self.log_path {
135            let entry = serde_json::json!({
136                "timestamp": chrono::Utc::now().to_rfc3339(),
137                "operation": operation,
138                "session": session,
139                "success": success,
140            });
141            if let Ok(mut file) = std::fs::OpenOptions::new()
142                .create(true)
143                .append(true)
144                .open(path)
145            {
146                use std::io::Write;
147                let _ = writeln!(file, "{}", entry);
148            }
149        }
150    }
151}
152
153impl Default for AuditLogger {
154    fn default() -> Self {
155        Self::new()
156    }
157}