Skip to main content

treetop_core/
lib.rs

1//! Usage example:
2//!
3//! Here we declare a policy that allows "alice" to create a host if and only if the following conditions are met:
4//! - The host's nameLabel set contains "example_domain". This is created via regular expressions on the name from
5//!   the `initialize_host_patterns` function.
6//! - The host's IP address is within the network "10.0.0.0/24".
7//! - The host's name contains the letter 'n'
8//!
9//! Note that we do not require the host to have the nameLabel "webserver" for "alice" to create it.
10//!
11//! ```rust
12//! use regex::Regex;
13//! use std::sync::Arc;
14//! use treetop_core::{Action, AttrValue, PolicyEngine, Request, Decision, User, Principal, Resource, RegexLabeler, LabelRegistryBuilder};
15//! use sha2::{Digest, Sha256};
16//!
17//! let policies = r#"
18//! permit (
19//!    principal == User::"alice",
20//!    action == Action::"create_host",
21//!    resource is Host
22//! ) when {
23//!     resource.nameLabels.contains("in_domain") &&
24//!     resource.ip.isInRange(ip("10.0.0.0/24")) &&
25//!     resource.name like "*n*"
26//! };
27//! "#;
28//!
29//! // Used to create attributes for hosts based on their names.
30//! let patterns = vec![
31//!     ("in_domain".to_string(), Regex::new(r"example\.com$").unwrap()),
32//!     ("webserver".to_string(), Regex::new(r"^web-\d+").unwrap()),
33//! ];
34//! let label_registry = LabelRegistryBuilder::new()
35//!     .add_labeler(Arc::new(RegexLabeler::new(
36//!         "Host",
37//!         "name",
38//!         "nameLabels",
39//!         patterns.into_iter().collect(),
40//!     )))
41//!     .build();
42//!
43//! let engine = PolicyEngine::new_from_str(&policies).unwrap()
44//!     .with_label_registry(label_registry);
45//!
46//! let request = Request {
47//!    principal: Principal::User(User::new("alice", None, None)), // No groups, no namespace
48//!    action: Action::new("create_host", None), // Action is not in a namespace
49//!    resource: Resource::new("Host", "hostname.example.com")
50//!     .with_attr("name", AttrValue::String("hostname.example.com".into()))
51//!     .with_attr("ip", AttrValue::Ip("10.0.0.1".into()))
52//! };
53//!
54//! let decision = engine.evaluate(&request).unwrap();
55//! assert!(matches!(decision, Decision::Allow { .. }));
56//!
57//! // List all of alice's policies
58//! let alice_policies = engine.list_policies_for_user("alice", &[], &[]).unwrap();
59//! // This value is also seralizable to JSON
60//! let json = serde_json::to_string(&alice_policies).unwrap();
61//!
62//! // Check that the policy running is the expected version
63//! let expected_hash = Sha256::digest(policies)
64//!     .iter()
65//!     .fold(String::with_capacity(64), |mut s, b| {
66//!         use std::fmt::Write;
67//!         write!(s, "{b:02x}").unwrap();
68//!         s
69//!     });
70//! assert_eq!(engine.current_version().hash.as_ref(), expected_hash);
71//!
72//! ```
73//!
74//! ## Thread-Safe Sharing
75//!
76//! For multithreaded applications, wrap `PolicyEngine` in `Arc` to share it across threads:
77//!
78//! ```rust,no_run
79//! use std::sync::Arc;
80//! use std::thread;
81//! # use treetop_core::{PolicyEngine, Request, Principal, User, Action, Resource, Decision};
82//! # let engine_base = PolicyEngine::new_from_str("permit(principal,action,resource);").unwrap();
83//!
84//! let engine = Arc::new(engine_base);
85//! let engine_clone = Arc::clone(&engine);
86//!
87//! let handle = thread::spawn(move || {
88//!     // Evaluate policies in a background thread
89//!     let request = Request {
90//!         principal: Principal::User(User::new("user", None, None)),
91//!         action: Action::new("read", None),
92//!         resource: Resource::new("Document", "doc1"),
93//!     };
94//!     let _decision = engine_clone.evaluate(&request);
95//! });
96//!
97//! handle.join().unwrap();
98//! ```
99//!
100
101pub use build_info::{BuildInfo, GitInfo, build_info};
102pub use cedar_policy::Schema;
103pub use engine::PolicyEngine;
104pub use error::PolicyError;
105pub use labels::{LabelRegistry, LabelRegistryBuilder, Labeler, RegexLabeler};
106pub use loader::{compile_policy, compile_policy_with_schema};
107pub use types::{
108    Action, AttrValue, CedarType, Decision, DecisionDiagnostics, Group, Groups, PermitPolicies,
109    PermitPolicy, PolicyEffectFilter, PolicyMatch, PolicyMatchReason, PolicyVersion, Principal,
110    Request, RequestContext, Resource, User, UserPolicies, action_entity_uid, group_entity_uid,
111    namespace_segments, resource_entity_uid, user_entity_uid,
112};
113
114#[cfg(feature = "observability")]
115pub use metrics::{
116    EvaluationObservation, EvaluationPhases, EvaluationStats, MetricsSink, ReloadStats, set_sink,
117};
118#[cfg(feature = "bench-internal")]
119pub mod bench_helpers;
120mod build_info;
121mod engine;
122mod error;
123mod labels;
124mod loader;
125#[cfg(feature = "observability")]
126pub mod metrics;
127#[cfg(all(not(feature = "observability"), feature = "bench-internal"))]
128mod metrics;
129mod policy_match;
130mod query;
131#[cfg(test)]
132mod tests;
133mod timers;
134mod traits;
135pub mod types;