yeti_types/plugins/auth.rs
1//! Identity → access resolution.
2//!
3//! Replaces the legacy `AuthHook::on_resolve_role` trait. Plugins
4//! that want to override default role resolution register a
5//! `tower::Service<ResolveRequest, Response = ResolveResponse>`.
6//!
7//! The host runs the registered pipeline; the first plugin to
8//! return `Some(access)` wins. Plugins that don't have an opinion
9//! return `Ok(None)` and dispatch falls through to the next.
10//!
11//! Closed-enum boundary (2026-05-14): `ResolveResponse` carries an
12//! [`Access`] value, not a `dyn AccessControl` trait object — the
13//! request hot path stays devirtualized. Plugins that need to
14//! produce a custom RBAC role construct it as `Access::User(Arc::new(
15//! User { username, role: Role { ... } }))`; the role's
16//! [`Permission`](crate::auth::Permission) tree expresses the same
17//! RBAC matrix the deleted trait used to.
18
19use std::sync::Arc;
20
21use crate::auth::{Access, AuthIdentity};
22
23/// Input to the auth resolver pipeline.
24#[derive(Debug, Clone)]
25pub struct ResolveRequest {
26 /// The authenticated identity (from cookie, OAuth session,
27 /// JWT, basic auth, mTLS — whichever provider populated it).
28 pub identity: AuthIdentity,
29 /// The target app id this request is being routed to.
30 pub app_id: Arc<str>,
31}
32
33/// Output of the auth resolver pipeline. `Some(access)` short-circuits
34/// the pipeline; `None` means "I don't have an opinion, fall through."
35pub type ResolveResponse = Option<Access>;