safe_migrate/rules/
policies.rs1use crate::analysis::mutations::Mutation;
2use crate::analysis::state::{AnalysisState, CascadeResult, MutationResult};
3use crate::engine::config::Config;
4use crate::report::violations::{ObjectKind, OperationKind, Violation, ViolationTier};
5use crate::rules::Rule;
6
7pub struct RestrictivePolicyRule;
8
9impl Rule for RestrictivePolicyRule {
10 fn id(&self) -> &'static str {
11 "restrictive-policy"
12 }
13 fn default_tier(&self) -> ViolationTier {
14 ViolationTier::Tier2
15 }
16 fn recipe(&self) -> &'static str {
17 "Adding a RESTRICTIVE policy narrows access for all users. This can silently make rows invisible that were previously accessible."
18 }
19
20 fn evaluate(
21 &self,
22 mutation: &Mutation,
23 result: &MutationResult,
24 _pre_state: &crate::analysis::state::PreState,
25 _state: &AnalysisState,
26 _config: &Config,
27 _cascade: Option<&CascadeResult>,
28 ) -> Vec<Violation> {
29 if *result == MutationResult::Skipped {
30 return vec![];
31 }
32 let mut violations = Vec::new();
33
34 if let Mutation::CreatePolicy(policy) = mutation
35 && !policy.permissive
36 {
37 violations.push(Violation {
38 source_range: None,
39 rule_id: self.id(),
40 operation_kind: OperationKind::CreatePolicy,
41 object_kind: ObjectKind::Policy,
42 object_name: format!("{} on {}", policy.name, policy.table),
43 tier: self.default_tier(),
44 reason: format!(
45 "Adding RESTRICTIVE policy {} on {}",
46 policy.name, policy.table
47 ),
48 recipe: self.recipe(),
49 dedup_key: None,
50 sql: None,
51 fk_dependency_related: false,
52 });
53 }
54
55 violations
56 }
57}