Skip to main content

chio_kernel_core/
guard.rs

1//! Sync guard trait for portable evaluation.
2//!
3//! This matches the legacy `chio_kernel::Guard` surface byte-for-byte so
4//! existing guard implementations can be lifted into the core with no
5//! behavioural change:
6//!
7//! ```ignore
8//! pub trait Guard: Send + Sync {
9//!     fn name(&self) -> &str;
10//!     fn evaluate(&self, ctx: &GuardContext) -> Result<Verdict, KernelCoreError>;
11//! }
12//! ```
13//!
14//! The error type is [`crate::evaluate::KernelCoreError`] instead of the
15//! legacy `chio_kernel::KernelError` because the full error enum carries
16//! std/tokio/sqlite-flavoured variants that are not portable. The legacy
17//! adapter in `chio-kernel::kernel` bridges the two.
18
19use alloc::string::String;
20
21use chio_core_types::capability::ChioScope;
22
23use crate::Verdict;
24
25/// Sync guard trait. Preserved signature-for-signature from legacy
26/// `chio_kernel::Guard`.
27pub trait Guard: Send + Sync {
28    /// Human-readable guard name (e.g. `forbidden-path`).
29    fn name(&self) -> &str;
30
31    /// Evaluate this guard against a tool-call context.
32    ///
33    /// Returns `Ok(Verdict::Allow)` to pass, `Ok(Verdict::Deny)` to block,
34    /// or `Err(KernelCoreError)` to signal an internal guard failure (which
35    /// the kernel core treats as a fail-closed deny).
36    fn evaluate(&self, ctx: &GuardContext<'_>) -> Result<Verdict, crate::KernelCoreError>;
37}
38
39/// Inputs a guard sees when it runs inside the core evaluate pipeline.
40///
41/// Mirrors `chio_kernel::GuardContext` with two deliberate restrictions:
42///
43/// - `request` carries only the portable shape (no `dpop_proof`,
44///   `governed_intent`, `approval_token`, or `model_metadata` -- those are
45///   full-kernel concerns). The legacy adapter in `chio-kernel` builds a
46///   temporary [`PortableToolCallRequest`] when it runs the core evaluate
47///   pipeline.
48/// - `session_filesystem_roots` stays in the portable surface so the
49///   filesystem-roots guard (today the only session-aware guard) can run
50///   unchanged on every platform.
51pub struct GuardContext<'a> {
52    /// The tool call request being evaluated.
53    pub request: &'a PortableToolCallRequest,
54    /// The verified capability scope.
55    pub scope: &'a ChioScope,
56    /// The agent making the request.
57    pub agent_id: &'a str,
58    /// The target server.
59    pub server_id: &'a str,
60    /// Session-scoped enforceable filesystem roots, when the request is being
61    /// evaluated through the supported session-backed runtime path.
62    pub session_filesystem_roots: Option<&'a [String]>,
63    /// Index of the matched grant in the capability's scope, populated by
64    /// [`crate::evaluate`] before guards run.
65    pub matched_grant_index: Option<usize>,
66}
67
68/// Portable projection of an `chio_kernel::runtime::ToolCallRequest`.
69///
70/// Contains only the fields the sync core evaluate pipeline needs. Guards
71/// that want DPoP/governed/approval inputs must stay in `chio-kernel`.
72#[derive(Debug, Clone)]
73pub struct PortableToolCallRequest {
74    /// Unique request identifier.
75    pub request_id: String,
76    /// The tool to invoke.
77    pub tool_name: String,
78    /// The server hosting the tool.
79    pub server_id: String,
80    /// The calling agent's identifier (hex-encoded public key).
81    pub agent_id: String,
82    /// Tool arguments as canonical JSON.
83    pub arguments: serde_json::Value,
84}