1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! `authz-core` — Zanzibar-style Fine-Grained Authorization engine.
//!
//! This crate is the database- and transport-agnostic core of an authorization system.
//! It provides everything needed to define, parse, and evaluate an authorization model
//! without depending on any specific datastore or runtime.
//!
//! # Overview
//!
//! The main workflow:
//!
//! 1. **Write a model** in the built-in DSL (OpenFGA-inspired syntax).
//! 2. **Parse** it with [`model_parser::parse_dsl`] into a [`model_ast::ModelFile`].
//! 3. **Build** a [`type_system::TypeSystem`] from the parsed model.
//! 4. **Implement** the [`traits::TupleReader`] trait for your datastore.
//! 5. **Construct** a [`core_resolver::CoreResolver`] and call
//! [`resolver::CheckResolver::resolve_check`] to evaluate permissions.
//!
//! # Example
//!
//! ```rust,no_run
//! use authz_core::model_parser::parse_dsl;
//! use authz_core::type_system::TypeSystem;
//! use authz_core::policy_provider::StaticPolicyProvider;
//! use authz_core::core_resolver::CoreResolver;
//! use authz_core::resolver::{CheckResolver, CheckResult, ResolveCheckRequest};
//!
//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
//! let model = parse_dsl(r#"
//! type user {}
//! type document {
//! relations
//! define owner: [user]
//! define viewer: [user]
//! permissions
//! define can_view = viewer + owner
//! }
//! "#)?;
//!
//! let type_system = TypeSystem::new(model);
//! let provider = StaticPolicyProvider::new(type_system);
//!
//! // `MyStore` implements TupleReader — connect to your real datastore here.
//! # use authz_core::traits::{Tuple, TupleFilter, TupleReader};
//! # use authz_core::error::AuthzError;
//! # #[derive(Clone)]
//! # struct MyStore;
//! # #[async_trait::async_trait]
//! # impl TupleReader for MyStore {
//! # async fn read_tuples(&self, _: &TupleFilter) -> Result<Vec<Tuple>, AuthzError> { Ok(vec![]) }
//! # async fn read_user_tuple(&self, _: &str, _: &str, _: &str, _: &str, _: &str) -> Result<Option<Tuple>, AuthzError> { Ok(None) }
//! # async fn read_userset_tuples(&self, _: &str, _: &str, _: &str) -> Result<Vec<Tuple>, AuthzError> { Ok(vec![]) }
//! # async fn read_starting_with_user(&self, _: &str, _: &str) -> Result<Vec<Tuple>, AuthzError> { Ok(vec![]) }
//! # async fn read_user_tuple_batch(&self, _: &str, _: &str, _: &[String], _: &str, _: &str) -> Result<Option<Tuple>, AuthzError> { Ok(None) }
//! # }
//! let resolver = CoreResolver::new(MyStore, provider);
//!
//! let req = ResolveCheckRequest::new(
//! "document".into(), "doc-42".into(), "can_view".into(),
//! "user".into(), "alice".into(),
//! );
//!
//! match resolver.resolve_check(req).await? {
//! CheckResult::Allowed => println!("allowed"),
//! CheckResult::Denied => println!("denied"),
//! CheckResult::ConditionRequired(params) => println!("need: {:?}", params),
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # Modules
//!
//! | Module | Purpose |
//! |---|---|
//! | [`model_ast`] | AST types produced by the parser |
//! | [`model_parser`] | Parse the model DSL into a [`model_ast::ModelFile`] |
//! | [`model_validator`] | Semantic validation of a parsed model |
//! | [`type_system`] | In-memory model index; tuple validation |
//! | [`traits`] | Core data types and async datastore traits |
//! | [`resolver`] | [`resolver::CheckResolver`] trait and request/result types |
//! | [`core_resolver`] | Built-in graph-walking resolver implementation |
//! | [`policy_provider`] | Policy loading abstraction + [`policy_provider::StaticPolicyProvider`] |
//! | [`dispatcher`] | Fan-out dispatcher trait + [`dispatcher::LocalDispatcher`] |
//! | [`cache`] | Pluggable cache abstraction + [`cache::NoopCache`] |
//! | [`cel`] | CEL (Common Expression Language) condition evaluation |
//! | [`tenant_schema`] | [`tenant_schema::ChangelogReader`] for the Watch API |
//! | [`error`] | [`error::AuthzError`] — all error variants |
//!
//! # Feature flags
//!
//! This crate has no optional feature flags. All components are always compiled.
//!
//! # MSRV
//!
//! Rust **1.85** or later (edition 2024).