Skip to main content

vellaveto_engine/
error.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4//
5// Copyright 2026 Paolo Vella
6// SPDX-License-Identifier: MPL-2.0
7
8//! Error types for the policy engine.
9//!
10//! This module defines the error types used throughout the policy evaluation process.
11
12use thiserror::Error;
13
14/// Errors that can occur during policy evaluation.
15#[derive(Error, Debug)]
16pub enum EngineError {
17    /// No policies are defined, evaluation cannot proceed.
18    #[error("No policies defined")]
19    NoPolicies,
20
21    /// A general evaluation error occurred.
22    #[error("Evaluation error: {0}")]
23    EvaluationError(String),
24
25    /// An invalid condition was found in a policy.
26    #[error("Invalid condition in policy '{policy_id}': {reason}")]
27    InvalidCondition {
28        /// The ID of the policy containing the invalid condition.
29        policy_id: String,
30        /// A description of why the condition is invalid.
31        reason: String,
32    },
33
34    /// A JSON parsing or serialization error occurred.
35    #[error("JSON error: {0}")]
36    JsonError(#[from] serde_json::Error),
37
38    /// Path normalization failed (fail-closed behavior).
39    #[error("Path normalization failed (fail-closed): {reason}")]
40    PathNormalization {
41        /// A description of why path normalization failed.
42        reason: String,
43    },
44}
45
46/// Error during policy compilation at load time.
47///
48/// This error is returned when a policy cannot be compiled due to invalid
49/// configuration, such as malformed regex patterns or invalid constraint types.
50#[derive(Debug, Clone)]
51pub struct PolicyValidationError {
52    /// The unique identifier of the policy that failed validation.
53    pub policy_id: String,
54    /// The human-readable name of the policy.
55    pub policy_name: String,
56    /// A description of why validation failed.
57    pub reason: String,
58}
59
60impl std::fmt::Display for PolicyValidationError {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(
63            f,
64            "Policy '{}' ({}): {}",
65            self.policy_name, self.policy_id, self.reason
66        )
67    }
68}
69
70impl std::error::Error for PolicyValidationError {}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_engine_error_display() {
78        let err = EngineError::NoPolicies;
79        assert_eq!(err.to_string(), "No policies defined");
80
81        let err = EngineError::EvaluationError("test error".to_string());
82        assert_eq!(err.to_string(), "Evaluation error: test error");
83
84        let err = EngineError::InvalidCondition {
85            policy_id: "p1".to_string(),
86            reason: "bad pattern".to_string(),
87        };
88        assert_eq!(
89            err.to_string(),
90            "Invalid condition in policy 'p1': bad pattern"
91        );
92
93        let err = EngineError::PathNormalization {
94            reason: "null byte".to_string(),
95        };
96        assert_eq!(
97            err.to_string(),
98            "Path normalization failed (fail-closed): null byte"
99        );
100    }
101
102    #[test]
103    fn test_policy_validation_error_display() {
104        let err = PolicyValidationError {
105            policy_id: "p1".to_string(),
106            policy_name: "Test Policy".to_string(),
107            reason: "invalid regex".to_string(),
108        };
109        assert_eq!(err.to_string(), "Policy 'Test Policy' (p1): invalid regex");
110    }
111}