Lint an RLS predicate for common issues. Returns a list of warnings (empty = clean).
(predicate: &super::predicate::RlsPredicate)
| 160 | /// |
| 161 | /// Returns a list of warnings (empty = clean). |
| 162 | pub fn lint_predicate(predicate: &super::predicate::RlsPredicate) -> Vec<String> { |
| 163 | let mut warnings = Vec::new(); |
| 164 | |
| 165 | match predicate { |
| 166 | super::predicate::RlsPredicate::AlwaysTrue => { |
| 167 | warnings.push("tautology: predicate is always true (no filtering)".into()); |
| 168 | } |
| 169 | super::predicate::RlsPredicate::AlwaysFalse => { |
| 170 | warnings.push("contradiction: predicate is always false (blocks everything)".into()); |
| 171 | } |
| 172 | super::predicate::RlsPredicate::Compare { value, .. } |
| 173 | if !value.is_auth_ref() |
| 174 | && matches!(value, super::predicate::PredicateValue::Literal(_)) => |
| 175 | { |
| 176 | warnings |
| 177 | .push("static predicate: no $auth reference — same result for all users".into()); |
| 178 | } |
| 179 | super::predicate::RlsPredicate::And(children) |
| 180 | | super::predicate::RlsPredicate::Or(children) => { |
| 181 | for child in children { |
| 182 | warnings.extend(lint_predicate(child)); |
| 183 | } |
| 184 | } |
| 185 | super::predicate::RlsPredicate::Not(inner) => { |
| 186 | warnings.extend(lint_predicate(inner)); |
| 187 | } |
| 188 | _ => {} |
| 189 | } |
| 190 | |
| 191 | warnings |
| 192 | } |
| 193 | |
| 194 | #[cfg(test)] |
| 195 | mod tests { |