systemprompt_security/authz/
keep.rs1use std::collections::HashSet;
15
16use systemprompt_identifiers::UserId;
17
18use super::error::AuthzResult;
19use super::parent_chain::{ParentChainIndex, ResolveBase};
20use super::repository::AccessControlRepository;
21use super::subject::{SubjectAttributes, SubjectDimension};
22use super::types::EntityKind;
23
24#[derive(Debug, Clone, Copy)]
26pub struct BulkKeepQuery<'a> {
27 pub user_id: &'a UserId,
28 pub roles: &'a [String],
29 pub kind: EntityKind,
30 pub ids: &'a [String],
31 pub chains: &'a ParentChainIndex,
32 pub attributes: &'a SubjectAttributes,
33 pub dimensions: &'a [SubjectDimension],
34}
35
36pub async fn allowed_ids(
37 repo: &AccessControlRepository,
38 query: BulkKeepQuery<'_>,
39) -> AuthzResult<HashSet<String>> {
40 if query.ids.is_empty() {
41 return Ok(HashSet::new());
42 }
43 let rules = repo.list_rules_bulk(query.kind, query.ids).await?;
44 let entities = repo.list_entities_bulk(query.kind, query.ids).await?;
45 let mut keep = HashSet::with_capacity(query.ids.len());
46 for id in query.ids {
47 let entity_rules = rules.get(id).map_or(&[][..], Vec::as_slice);
48 let default_included = entities.get(id).map(|e| e.default_included);
49 let decision = query.chains.resolve(
50 query.kind,
51 id,
52 ResolveBase {
53 rules: entity_rules,
54 user_id: query.user_id,
55 user_roles: query.roles,
56 default_included,
57 attributes: query.attributes,
58 dimensions: query.dimensions,
59 },
60 );
61 if decision.permits() {
62 keep.insert(id.clone());
63 }
64 }
65 Ok(keep)
66}