Skip to main content

EvalTrace

Struct EvalTrace 

Source
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

Source

pub fn new() -> Self

Creates an empty trace with no evaluation results.

Source

pub fn with_root(result: PolicyEvalResult) -> Self

Creates a trace with the given PolicyEvalResult as the root node.

Source

pub fn set_root(&mut self, result: PolicyEvalResult)

Sets (or replaces) the root node of the evaluation tree.

Source

pub fn root(&self) -> Option<&PolicyEvalResult>

Returns a reference to the root PolicyEvalResult, if present.

Source

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
Hide additional 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§

Source§

impl Clone for EvalTrace

Source§

fn clone(&self) -> EvalTrace

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EvalTrace

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for EvalTrace

Source§

fn default() -> EvalTrace

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more