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}