pub struct EvalTrace { /* private fields */ }Expand description
A tree of PolicyEvalResult nodes capturing every policy decision made
during an access evaluation.
Returned as part of AccessEvaluation. Use EvalTrace::format to render
a human-readable tree, useful for debugging and audit logging.
§Example
// An empty trace produces a fallback message:
let empty = EvalTrace::new();
assert_eq!(empty.format(), "No evaluation trace available");
// A trace built from a policy result renders a decision tree:
let trace = EvalTrace::with_root(PolicyEvalResult::Granted {
policy_type: "AdminPolicy".into(),
reason: Some("User is admin".into()),
});
assert!(trace.format().contains("AdminPolicy GRANTED"));Implementations§
Source§impl EvalTrace
impl EvalTrace
Sourcepub fn with_root(result: PolicyEvalResult) -> Self
pub fn with_root(result: PolicyEvalResult) -> Self
Creates a trace with the given PolicyEvalResult as the root node.
Sourcepub fn set_root(&mut self, result: PolicyEvalResult)
pub fn set_root(&mut self, result: PolicyEvalResult)
Sets (or replaces) the root node of the evaluation tree.
Sourcepub fn root(&self) -> Option<&PolicyEvalResult>
pub fn root(&self) -> Option<&PolicyEvalResult>
Returns a reference to the root PolicyEvalResult, if present.
Sourcepub fn format(&self) -> String
pub fn format(&self) -> String
Returns a formatted, indented representation of the evaluation tree.
Each node shows a ✔ or ✘ prefix, the policy name, and the reason.
Combined nodes indent their children for readability.
Examples found in repository?
examples/rbac_policy.rs (line 212)
186async fn test_access(
187 checker: &PermissionChecker<User, Document, ReadAction, EmptyContext>,
188 user_desc: &str,
189 user: &User,
190 doc_desc: &str,
191 doc: &Document,
192) {
193 let context = EmptyContext;
194 let action = ReadAction;
195
196 let result = checker.evaluate_access(user, &action, doc, &context).await;
197
198 println!(
199 "{} accessing {}: {}",
200 user_desc,
201 doc_desc,
202 if result.is_granted() {
203 "GRANTED ✓"
204 } else {
205 "DENIED ✗"
206 }
207 );
208
209 println!(
210 "Evaluation trace:\n{}\n",
211 match &result {
212 AccessEvaluation::Granted { trace, .. } => trace.format(),
213 AccessEvaluation::Denied { trace, .. } => trace.format(),
214 }
215 );
216}More examples
examples/actix_web.rs (line 298)
280pub async fn edit_post(
281 path: web::Path<Uuid>,
282 req: HttpRequest,
283 AuthenticatedUser(user): AuthenticatedUser,
284 checker: web::Data<PermissionChecker<User, Resource, Action, RequestContext>>,
285) -> impl Responder {
286 let overrides = PostOverrides::from_request(&req);
287 let post = load_post(*path, &overrides);
288 let ctx = RequestContext {
289 current_time: SystemTime::now(),
290 };
291
292 match checker
293 .evaluate_access(&user, &Action::Edit, &Resource::Post(post), &ctx)
294 .await
295 {
296 AccessEvaluation::Granted { .. } => HttpResponse::Ok().body("Post updated"),
297 AccessEvaluation::Denied { reason, trace } => {
298 HttpResponse::Forbidden().body(format!("Denied: {}\n{}", reason, trace.format()))
299 }
300 }
301}
302
303pub async fn publish_post(
304 path: web::Path<Uuid>,
305 req: HttpRequest,
306 AuthenticatedUser(user): AuthenticatedUser,
307 checker: web::Data<PermissionChecker<User, Resource, Action, RequestContext>>,
308) -> impl Responder {
309 let overrides = PostOverrides::from_request(&req);
310 let post = load_post(*path, &overrides);
311 let ctx = RequestContext {
312 current_time: SystemTime::now(),
313 };
314
315 match checker
316 .evaluate_access(&user, &Action::Publish, &Resource::Post(post), &ctx)
317 .await
318 {
319 AccessEvaluation::Granted { .. } => HttpResponse::Ok().body("Post published"),
320 AccessEvaluation::Denied { reason, trace } => {
321 HttpResponse::Forbidden().body(format!("Denied: {}\n{}", reason, trace.format()))
322 }
323 }
324}
325
326pub async fn view_post(
327 path: web::Path<Uuid>,
328 req: HttpRequest,
329 maybe_user: Option<AuthenticatedUser>,
330 checker: web::Data<PermissionChecker<User, Resource, Action, RequestContext>>,
331) -> impl Responder {
332 let user = maybe_user
333 .map(|AuthenticatedUser(user)| user)
334 .unwrap_or(User {
335 id: Uuid::nil(),
336 roles: vec![],
337 });
338
339 let overrides = PostOverrides::from_request(&req);
340 let post = load_published_post(*path, &overrides);
341 let ctx = RequestContext {
342 current_time: SystemTime::now(),
343 };
344
345 match checker
346 .evaluate_access(&user, &Action::View, &Resource::Post(post), &ctx)
347 .await
348 {
349 AccessEvaluation::Granted { .. } => HttpResponse::Ok().body("Here is your post"),
350 AccessEvaluation::Denied { reason, trace } => {
351 HttpResponse::Forbidden().body(format!("Denied: {}\n{}", reason, trace.format()))
352 }
353 }
354}examples/rebac_policy.rs (line 253)
227async fn test_access(
228 checker: &PermissionChecker<User, Project, EditAction, EmptyContext>,
229 user: &User,
230 project: &Project,
231) {
232 let context = EmptyContext;
233 let action = EditAction;
234
235 println!("\nChecking if {} can edit {}:", user.name, project.name);
236 let result = checker
237 .evaluate_access(user, &action, project, &context)
238 .await;
239
240 println!(
241 "Access {} for {}",
242 if result.is_granted() {
243 "GRANTED ✓"
244 } else {
245 "DENIED ✗"
246 },
247 user.name
248 );
249
250 println!(
251 "Evaluation trace:\n{}\n",
252 match &result {
253 AccessEvaluation::Granted { trace, .. } => trace.format(),
254 AccessEvaluation::Denied { trace, .. } => trace.format(),
255 }
256 );
257}Trait Implementations§
Auto Trait Implementations§
impl Freeze for EvalTrace
impl RefUnwindSafe for EvalTrace
impl Send for EvalTrace
impl Sync for EvalTrace
impl Unpin for EvalTrace
impl UnsafeUnpin for EvalTrace
impl UnwindSafe for EvalTrace
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more