arcature 2026.2.1

Arcature application framework: a high-level Application facade over the certified Arcature subsystems, with the low-level Axum/Tower escape hatch preserved.
Documentation
//! `Policy<M>` — explicit authorization (A9).
//!
//! Authorization stays explicit (PROGRAM.md). A policy is a type that
//! decides whether a user may perform an action on a resource. The
//! application writes the policy methods; the framework provides the
//! `Auth::authorize` seam.
//!
//! # Example
//!
//! ```ignore
//! #[policy(Link)]
//! pub struct LinkPolicy;
//!
//! impl LinkPolicy {
//!     pub fn view(user: &User, _link: &Link) -> bool { true }
//!     pub fn update(user: &User, link: &Link) -> bool { user.id == link.user_id }
//! }
//!
//! impl arcature::Policy<Link> for LinkPolicy {
//!     type User = User;
//!     fn check(user: &User, action: &str, link: &Link) -> bool {
//!         match action {
//!             "view" => Self::view(user, link),
//!             "update" => Self::update(user, link),
//!             _ => false,
//!         }
//!     }
//! }
//!
//! async fn show(auth: Auth<User>, link: Bound<Link>) -> Result<Page<ShowLinkPage>> {
//!     auth.authorize::<LinkPolicy>("view", &link)?;
//!     // ...
//! }
//! ```
//!
//! # Binding does NOT imply authorization
//!
//! `Bound<T>` loads the model; `Auth::authorize` checks the policy. These
//! are separate steps. Authorization is never automatic.

use crate::dx::DxComponent;

/// A typed authorization error.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuthzError {
    /// The policy denied the action.
    Forbidden,
}

impl std::fmt::Display for AuthzError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Forbidden => write!(f, "forbidden: policy denied the action"),
        }
    }
}

impl std::error::Error for AuthzError {}

impl axum::response::IntoResponse for AuthzError {
    fn into_response(self) -> axum::response::Response {
        (axum::http::StatusCode::FORBIDDEN, "Forbidden").into_response()
    }
}

/// A policy for resource type `M`.
///
/// The application implements this for its policy type. The `check` method
/// receives the authenticated user, an action name (e.g. `"view"`,
/// `"update"`), and the resource, and returns whether the action is
/// allowed.
///
/// The policy type also implements [`DxComponent`] (generated by the
/// `#[policy]` macro) so `arc services` / `arc check` can inspect it
/// without runtime reflection.
pub trait Policy<M>: DxComponent + Send + Sync + 'static {
    /// The user type this policy authorizes for.
    type User: crate::dx::auth_user::AuthUser;

    /// Check whether `user` may perform `action` on `resource`.
    ///
    /// Returns `true` if allowed, `false` if denied. The caller
    /// (`Auth::authorize`) maps `false` to `AuthzError::Forbidden`.
    fn check(user: &Self::User, action: &str, resource: &M) -> bool;
}