auth-policy 0.0.2

Rust crate for evaluating authorization decisions against declarative policies
Documentation
use auth_policy::{
    decision::Effect,
    engine::PolicyEngine,
    policy::{Condition, Policy, Target},
    request::Request,
    Decision,
};

fn sample_policy() -> Policy {
    Policy::builder("document-read")
        .target(Target::action("document:read"))
        .condition(Condition::equals("resource.owner_id", "actor.id"))
        .effect(Effect::Permit)
        .build()
        .expect("policy should build")
}

#[test]
fn permits_when_condition_matches() {
    let engine = PolicyEngine::from_policies([sample_policy()]);

    let request = Request::new()
        .action("document:read")
        .actor_attr("id", "alice")
        .resource_attr("owner_id", "alice");

    let decision = engine.evaluate(&request).expect("decision should succeed");
    assert_eq!(decision, Decision::Permit);
}

#[test]
fn denies_when_condition_fails() {
    let engine = PolicyEngine::from_policies([sample_policy()]);

    let request = Request::new()
        .action("document:read")
        .actor_attr("id", "alice")
        .resource_attr("owner_id", "bob");

    let decision = engine.evaluate(&request).expect("decision should succeed");
    assert_eq!(decision, Decision::Deny);
}

#[test]
fn denies_when_target_does_not_match() {
    let engine = PolicyEngine::from_policies([sample_policy()]);

    let request = Request::new()
        .action("document:write")
        .actor_attr("id", "alice")
        .resource_attr("owner_id", "alice");

    let decision = engine.evaluate(&request).expect("decision should succeed");
    assert_eq!(decision, Decision::Deny);
}

#[test]
fn returns_error_when_attribute_missing() {
    let engine = PolicyEngine::from_policies([sample_policy()]);

    let request = Request::new()
        .action("document:read")
        .actor_attr("id", "alice");

    let err = engine.evaluate(&request).expect_err("should error");
    assert!(format!("{err}").contains("resource.owner_id"));
}