Skip to main content

oxicode_sdk/security/
context.rs

1//! Agent security context — unforgeable identity token.
2//!
3//! `AgentContext` is proof that the system has authenticated an agent.
4//! It carries agent identity + capability space for access control.
5
6use std::sync::Arc;
7
8use crate::security::capability::types::CSpace;
9use uuid::Uuid;
10
11/// Agent security context — unforgeable proof of agent identity.
12///
13/// Construct this when an agent enters a managed lifecycle.
14/// Tools that require access control accept `&AgentContext`.
15#[derive(Debug, Clone)]
16pub struct AgentContext {
17    /// Unique agent identifier.
18    pub agent_id: Uuid,
19    /// Human-readable name for permission lookups.
20    pub agent_name: String,
21    /// Agent's capability space.
22    pub cspace: Arc<CSpace>,
23}
24
25impl AgentContext {
26    /// Create a new context for a named agent with the given CSpace.
27    pub fn new(agent_name: String, cspace: CSpace) -> Self {
28        let agent_id = cspace.agent_id;
29        Self {
30            agent_id,
31            agent_name,
32            cspace: Arc::new(cspace),
33        }
34    }
35
36    /// Create a context from a template by name.
37    pub fn from_template(agent_name: &str, template_name: &str) -> Self {
38        let id = Uuid::new_v4();
39        let cspace = crate::security::capability::resolve::resolve_cspace(
40            Some(template_name),
41            None,
42            None,
43            id,
44        );
45        Self {
46            agent_id: id,
47            agent_name: agent_name.to_string(),
48            cspace: Arc::new(cspace),
49        }
50    }
51}
52
53impl std::fmt::Display for AgentContext {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        write!(f, "agent:{}:{}", self.agent_name, self.agent_id)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::security::capability::types::{ResourceRef, Rights};
63
64    #[test]
65    fn test_from_template() {
66        let ctx = AgentContext::from_template("test", "standard");
67        assert_eq!(ctx.agent_name, "test");
68        assert!(!ctx.agent_id.is_nil());
69        // Standard template has memory read
70        assert!(ctx.cspace.can(
71            &ResourceRef::KernelDomain {
72                domain: "memory".into()
73            },
74            Rights::Read
75        ));
76    }
77
78    #[test]
79    fn test_display() {
80        let ctx = AgentContext::from_template("my-agent", "worker");
81        let s = format!("{}", ctx);
82        assert!(s.starts_with("agent:my-agent:"));
83    }
84}