Skip to main content

anda_engine/
management.rs

1//! Engine visibility and caller management policies.
2//!
3//! Management policies decide which principals can administer an engine and who
4//! can access exported agents and tools. The default [`BaseManagement`] policy
5//! makes engines private to the controller and explicit managers.
6
7use anda_core::BoxError;
8use async_trait::async_trait;
9use candid::Principal;
10use ic_auth_verifier::ANONYMOUS_PRINCIPAL;
11use std::collections::BTreeSet;
12
13/// Root cache and storage namespace reserved for engine system data.
14pub static SYSTEM_PATH: &str = "_";
15
16/// Authorization policy used by [`Engine`](crate::engine::Engine).
17#[async_trait]
18pub trait Management: Send + Sync {
19    /// Returns whether `caller` is the engine controller.
20    fn is_controller(&self, caller: &Principal) -> bool;
21
22    /// Returns whether `caller` can manage private engine state.
23    fn is_manager(&self, caller: &Principal) -> bool;
24
25    /// Validates access and returns the current engine visibility.
26    fn check_visibility(&self, caller: &Principal) -> Result<Visibility, BoxError>;
27}
28
29/// Basic principal-list management policy for an engine.
30pub struct BaseManagement {
31    /// Principal that controls the engine.
32    pub controller: Principal,
33
34    /// Additional principals with manager privileges.
35    pub managers: BTreeSet<Principal>,
36
37    /// Public access level for non-manager callers.
38    pub visibility: Visibility,
39}
40
41/// Engine visibility for exported agents and tools.
42#[derive(Clone, Copy, PartialEq, Eq)]
43pub enum Visibility {
44    /// Only the controller and managers can access the engine.
45    Private = 0,
46
47    /// Managers can access the engine; non-manager access requires an external
48    /// policy to grant permission before execution.
49    Protected = 1,
50
51    /// Any caller, including anonymous callers, can access exported functions.
52    Public = 2,
53}
54
55#[async_trait]
56impl Management for BaseManagement {
57    /// Returns true if the caller is the controller of the engine.
58    fn is_controller(&self, caller: &Principal) -> bool {
59        caller == &self.controller
60    }
61
62    /// Returns true if the caller is the controller or a manager of the engine.
63    fn is_manager(&self, caller: &Principal) -> bool {
64        caller == &self.controller || self.managers.contains(caller)
65    }
66
67    /// Checks anonymous access and private visibility rules.
68    fn check_visibility(&self, caller: &Principal) -> Result<Visibility, BoxError> {
69        if self.visibility != Visibility::Public && caller == &ANONYMOUS_PRINCIPAL {
70            return Err("anonymous caller not allowed".into());
71        }
72
73        if self.visibility == Visibility::Private && !self.is_manager(caller) {
74            return Err("caller is not allowed".into());
75        }
76
77        Ok(self.visibility)
78    }
79}