Skip to main content

systemprompt_users/repository/
role_directory.rs

1//! The users domain's answer to the authz ingestion's "does anybody hold
2//! this role?" question, registered with the security crate at link time.
3//!
4//! Copyright (c) systemprompt.io — Business Source License 1.1.
5//! See <https://systemprompt.io> for licensing details.
6
7use std::sync::Arc;
8
9use async_trait::async_trait;
10use sqlx::PgPool;
11use systemprompt_security::authz::{AuthzError, RoleDirectory, SharedRoleDirectory};
12
13#[derive(Debug)]
14pub struct UsersRoleDirectory {
15    pool: Arc<PgPool>,
16}
17
18impl UsersRoleDirectory {
19    #[must_use]
20    pub fn shared(pool: Arc<PgPool>) -> SharedRoleDirectory {
21        Arc::new(Self { pool })
22    }
23}
24
25#[async_trait]
26impl RoleDirectory for UsersRoleDirectory {
27    async fn unknown_roles(&self, candidates: &[String]) -> Result<Vec<String>, AuthzError> {
28        let rows = sqlx::query!(
29            r#"
30            SELECT candidate AS "candidate!"
31            FROM UNNEST($1::text[]) AS candidate
32            WHERE NOT EXISTS (
33                SELECT 1 FROM users WHERE candidate = ANY(users.roles)
34            )
35            "#,
36            candidates,
37        )
38        .fetch_all(&*self.pool)
39        .await?;
40        Ok(rows.into_iter().map(|row| row.candidate).collect())
41    }
42}
43
44systemprompt_security::register_role_directory!(UsersRoleDirectory::shared);