Skip to main content

safe_migrate/rules/
policies.rs

1use 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}