axum_gate/permissions/
errors.rs

1//! Permission-category native errors.
2//!
3//! This module defines category-native errors for permission concerns,
4//! focused on collision detection. Use these errors directly in handlers,
5//! services, and middleware.
6//!
7//! # Overview
8//!
9//! - `PermissionsError`: category-native error enum for permission issues
10//!
11//! # Examples
12//!
13//! Detect a permission hash collision:
14//! ```rust
15//! use axum_gate::permissions::PermissionsError;
16//! use axum_gate::errors::UserFriendlyError;
17//!
18//! let err = PermissionsError::collision(42, vec!["read:alpha".into(), "read:beta".into()]);
19//! assert!(err.support_code().starts_with("PERM-COLLISION-"));
20//! assert_eq!(err.severity(), axum_gate::errors::ErrorSeverity::Critical);
21//! ```
22
23use crate::errors::{ErrorSeverity, UserFriendlyError};
24use thiserror::Error;
25
26/// Category-native permission errors.
27///
28/// These errors model permission-related problems.
29/// Use directly in permission validation and authorization flows.
30#[derive(Debug, Error)]
31#[non_exhaustive]
32pub enum PermissionsError {
33    /// Permission collision detected when multiple permissions hash to the same value.
34    #[error("Permission collision: {collision_count} permissions map to hash {hash_id}")]
35    Collision {
36        /// Number of permissions that collide.
37        collision_count: usize,
38        /// The 64-bit hash ID that has collisions.
39        hash_id: u64,
40        /// List of permission names that collide.
41        permissions: Vec<String>,
42    },
43}
44
45impl PermissionsError {
46    /// Create a permission collision error with collision details.
47    ///
48    /// This constructor calculates the `collision_count` from the provided list.
49    pub fn collision(hash_id: u64, permissions: Vec<String>) -> Self {
50        PermissionsError::Collision {
51            collision_count: permissions.len(),
52            hash_id,
53            permissions,
54        }
55    }
56
57    /// Generate a deterministic support code based on error content.
58    fn support_code_inner(&self) -> String {
59        match self {
60            PermissionsError::Collision { hash_id, .. } => {
61                format!("PERM-COLLISION-{}", hash_id)
62            }
63        }
64    }
65}
66
67impl UserFriendlyError for PermissionsError {
68    fn user_message(&self) -> String {
69        match self {
70            PermissionsError::Collision { .. } => {
71                "There's a technical issue with your account permissions. Our support team has been notified and will resolve this shortly. Please contact support if you need immediate assistance.".to_string()
72            }
73        }
74    }
75
76    fn developer_message(&self) -> String {
77        match self {
78            PermissionsError::Collision {
79                collision_count,
80                hash_id,
81                permissions,
82            } => {
83                format!(
84                    "Permission collision detected: {} permissions [{}] map to hash ID {}. This indicates a critical hash collision in the permission system requiring immediate administrator attention.",
85                    collision_count,
86                    permissions.join(", "),
87                    hash_id
88                )
89            }
90        }
91    }
92
93    fn support_code(&self) -> String {
94        self.support_code_inner()
95    }
96
97    fn severity(&self) -> ErrorSeverity {
98        match self {
99            PermissionsError::Collision { .. } => ErrorSeverity::Critical,
100        }
101    }
102
103    fn suggested_actions(&self) -> Vec<String> {
104        match self {
105            PermissionsError::Collision { .. } => vec![
106                "Contact our support team immediately with the reference code below".to_string(),
107                "Do not attempt to retry this operation".to_string(),
108                "This is a critical system issue requiring immediate administrator attention"
109                    .to_string(),
110            ],
111        }
112    }
113
114    fn is_retryable(&self) -> bool {
115        match self {
116            PermissionsError::Collision { .. } => false, // Critical system-level issue
117        }
118    }
119}