2025-05-26 22:08:21 -07:00
|
|
|
use std::collections::HashSet;
|
|
|
|
|
|
2025-08-04 13:59:42 -07:00
|
|
|
use anyhow::Result;
|
2025-09-14 16:19:44 -04:00
|
|
|
use interim_models::{
|
|
|
|
|
client::AppDbClient,
|
|
|
|
|
workspace_user_perm::{self, WorkspaceUserPerm},
|
|
|
|
|
};
|
2025-07-08 16:54:51 -07:00
|
|
|
use interim_pgtypes::{
|
2025-09-14 16:19:44 -04:00
|
|
|
client::WorkspaceClient,
|
2025-07-08 16:54:51 -07:00
|
|
|
pg_acl::PgPrivilegeType,
|
|
|
|
|
pg_database::PgDatabase,
|
|
|
|
|
pg_role::{PgRole, RoleTree, user_id_from_rolname},
|
|
|
|
|
};
|
2025-08-04 13:59:42 -07:00
|
|
|
use sqlx::query;
|
2025-05-26 22:08:21 -07:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
|
2025-09-14 16:19:44 -04:00
|
|
|
/// Derive workspace access control permissions from the permission grants of
|
|
|
|
|
/// a workspace's backing database.
|
|
|
|
|
pub(crate) async fn sync_for_workspace(
|
|
|
|
|
workspace_id: Uuid,
|
2025-08-04 13:59:42 -07:00
|
|
|
app_db: &mut AppDbClient,
|
2025-09-14 16:19:44 -04:00
|
|
|
workspace_client: &mut WorkspaceClient,
|
|
|
|
|
db_role_prefix: &str,
|
2025-05-26 22:08:21 -07:00
|
|
|
) -> Result<()> {
|
2025-09-14 16:19:44 -04:00
|
|
|
let db = PgDatabase::current().fetch_one(workspace_client).await?;
|
2025-08-04 13:59:42 -07:00
|
|
|
let explicit_roles = PgRole::with_name_in(
|
2025-05-26 22:08:21 -07:00
|
|
|
db.datacl
|
2025-08-04 13:59:42 -07:00
|
|
|
.unwrap_or_default()
|
2025-05-26 22:08:21 -07:00
|
|
|
.into_iter()
|
|
|
|
|
.filter(|item| {
|
|
|
|
|
item.privileges
|
|
|
|
|
.iter()
|
|
|
|
|
.any(|privilege| privilege.privilege == PgPrivilegeType::Connect)
|
|
|
|
|
})
|
|
|
|
|
.map(|item| item.grantee)
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-09-14 16:19:44 -04:00
|
|
|
.fetch_all(workspace_client)
|
2025-05-26 22:08:21 -07:00
|
|
|
.await?;
|
|
|
|
|
let mut all_roles: HashSet<PgRole> = HashSet::new();
|
|
|
|
|
for explicit_role in explicit_roles {
|
2025-08-09 00:14:58 -07:00
|
|
|
if let Some(role_tree) = RoleTree::members_of_oid(explicit_role.oid)
|
2025-09-14 16:19:44 -04:00
|
|
|
.fetch_tree(workspace_client)
|
2025-08-04 13:59:42 -07:00
|
|
|
.await?
|
|
|
|
|
{
|
2025-05-26 22:08:21 -07:00
|
|
|
for implicit_role in role_tree.flatten_inherited() {
|
|
|
|
|
all_roles.insert(implicit_role.clone());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let user_ids: Vec<Uuid> = all_roles
|
|
|
|
|
.iter()
|
2025-09-14 16:19:44 -04:00
|
|
|
.filter_map(|role| user_id_from_rolname(&role.rolname, db_role_prefix).ok())
|
2025-05-26 22:08:21 -07:00
|
|
|
.collect();
|
|
|
|
|
query!(
|
2025-09-14 16:19:44 -04:00
|
|
|
"delete from workspace_user_perms where workspace_id = $1 and not (user_id = any($2))",
|
|
|
|
|
workspace_id,
|
2025-05-26 22:08:21 -07:00
|
|
|
user_ids.as_slice(),
|
|
|
|
|
)
|
2025-08-04 13:59:42 -07:00
|
|
|
.execute(app_db.get_conn())
|
2025-05-26 22:08:21 -07:00
|
|
|
.await?;
|
|
|
|
|
for user_id in user_ids {
|
2025-09-14 16:19:44 -04:00
|
|
|
WorkspaceUserPerm::insert()
|
|
|
|
|
.workspace_id(workspace_id)
|
|
|
|
|
.user_id(user_id)
|
|
|
|
|
.perm(workspace_user_perm::PermissionValue::Connect)
|
|
|
|
|
.build()?
|
|
|
|
|
.execute(app_db)
|
|
|
|
|
.await?;
|
2025-05-26 22:08:21 -07:00
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|