uqa_sql/catalog/security/
dependencies.rs1use super::{database::DatabaseAclEntry, TableAclEntry, TableSecurity};
10use std::collections::BTreeSet;
11use uqa_core::{catalog_schema::SchemaAclEntry, catalog_sequence::SequenceAclEntry};
12
13pub trait AclRoleReferences {
14 fn role_references(&self) -> (Option<&str>, Option<&str>);
15}
16
17impl AclRoleReferences for TableAclEntry {
18 fn role_references(&self) -> (Option<&str>, Option<&str>) {
19 (self.role.role_name(), self.grantor.as_deref())
20 }
21}
22
23impl AclRoleReferences for SchemaAclEntry {
24 fn role_references(&self) -> (Option<&str>, Option<&str>) {
25 (self.role.role_name(), self.grantor.as_deref())
26 }
27}
28
29impl AclRoleReferences for SequenceAclEntry {
30 fn role_references(&self) -> (Option<&str>, Option<&str>) {
31 (self.role.role_name(), self.grantor.as_deref())
32 }
33}
34
35impl AclRoleReferences for DatabaseAclEntry {
36 fn role_references(&self) -> (Option<&str>, Option<&str>) {
37 (self.role.role_name(), self.grantor.as_deref())
38 }
39}
40
41fn acl_roles<'a, T: AclRoleReferences>(acl: &'a [T], owner: &'a str) -> BTreeSet<&'a str> {
42 acl.iter()
43 .flat_map(|entry| {
44 let (role, grantor) = entry.role_references();
45 [role, Some(grantor.unwrap_or(owner))].into_iter().flatten()
46 })
47 .filter(|role| *role != owner)
48 .collect()
49}
50
51pub fn added_acl_roles<T: AclRoleReferences>(
52 before: &[T],
53 before_owner: &str,
54 after: &[T],
55 after_owner: &str,
56 added: &mut BTreeSet<String>,
57) {
58 let old = acl_roles(before, before_owner);
59 let new = acl_roles(after, after_owner);
60 added.extend(new.difference(&old).map(|role| (*role).to_owned()));
61}
62
63pub fn added_table_acl_roles(
65 before: &TableSecurity,
66 after: &TableSecurity,
67 added: &mut BTreeSet<String>,
68) {
69 let mut compare = |old: &[TableAclEntry], new: &[TableAclEntry]| {
70 added_acl_roles(old, &before.role_owner, new, &after.role_owner, added);
71 };
72 compare(
73 before.acl.as_deref().unwrap_or_default(),
74 after.acl.as_deref().unwrap_or_default(),
75 );
76 for (column, acl) in &after.column_acls {
77 compare(
78 before.column_acls.get(column).map_or(&[], Vec::as_slice),
79 acl,
80 );
81 }
82}
83
84#[cfg(test)]
85mod tests;