cratestack_sqlx/
record_policy.rs1mod open_check;
17
18use cratestack_core::{CratestackContext, CratestackError};
19
20pub use open_check::{may_read_some_row, refuse_unreadable_subscription};
21
22use crate::query::{PolicyDb, evaluate_create_policies};
23use crate::{PolicyExpr, ReadPolicy, ReadPredicate, SqlColumnValue, sqlx};
24
25pub async fn record_readable(
28 pool: &sqlx::PgPool,
29 allow: &[ReadPolicy],
30 deny: &[ReadPolicy],
31 values: &[SqlColumnValue],
32 ctx: &CratestackContext,
33) -> Result<bool, CratestackError> {
34 evaluate_create_policies(PolicyDb::Pool(pool), allow, deny, values, ctx).await
35}
36
37pub fn missing_policy_columns(
42 allow: &[ReadPolicy],
43 deny: &[ReadPolicy],
44 present: &[&str],
45) -> Vec<&'static str> {
46 let mut missing = Vec::new();
47 for policy in allow.iter().chain(deny) {
48 collect_columns(policy.expr, &mut missing);
49 }
50 missing.retain(|column| !present.contains(column));
51 missing.sort_unstable();
52 missing.dedup();
53 missing
54}
55
56fn collect_columns(expr: PolicyExpr, out: &mut Vec<&'static str>) {
57 match expr {
58 PolicyExpr::Predicate(predicate) => out.extend(predicate_column(predicate)),
59 PolicyExpr::And(exprs) | PolicyExpr::Or(exprs) => {
60 for expr in exprs {
61 collect_columns(*expr, out);
62 }
63 }
64 }
65}
66
67fn predicate_column(predicate: ReadPredicate) -> Option<&'static str> {
68 match predicate {
69 ReadPredicate::FieldIsTrue { column }
70 | ReadPredicate::FieldEqLiteral { column, .. }
71 | ReadPredicate::FieldNeLiteral { column, .. }
72 | ReadPredicate::FieldInLiterals { column, .. }
73 | ReadPredicate::FieldNotInLiterals { column, .. }
74 | ReadPredicate::FieldEqAuth { column, .. }
75 | ReadPredicate::FieldNeAuth { column, .. } => Some(column),
76 ReadPredicate::Relation { parent_column, .. } => Some(parent_column),
77 ReadPredicate::AuthNotNull
78 | ReadPredicate::AuthIsNull
79 | ReadPredicate::AuthIsSystem
80 | ReadPredicate::HasRole { .. }
81 | ReadPredicate::InTenant { .. }
82 | ReadPredicate::AuthFieldEqLiteral { .. }
83 | ReadPredicate::AuthFieldNeLiteral { .. } => None,
84 }
85}
86
87#[cfg(test)]
88mod tests;