Skip to main content

cfn_guard/rules/
errors.rs

1use std::convert::Infallible;
2use std::fmt::{Debug, Formatter};
3use std::string::FromUtf8Error;
4use thiserror::Error;
5use wasm_bindgen::JsValue;
6
7use crate::rules::parser::{ParserError, Span};
8
9#[derive(Debug, Error)]
10#[allow(clippy::enum_variant_names)]
11pub enum Error {
12    #[error("Error parsing incoming JSON context {0}")]
13    JsonError(#[from] serde_json::Error),
14    #[error("Error parsing incoming YAML context {0}")]
15    YamlError(#[from] serde_yaml::Error),
16    #[error("Formatting error when writing {0}")]
17    FormatError(#[from] std::fmt::Error),
18    #[error("I/O error when reading {0}")]
19    IoError(#[from] std::io::Error),
20    #[error("Parser Error when parsing `{0}`")]
21    ParseError(String),
22    #[error("Regex expression parse error for rules file {0}")]
23    RegexError(#[from] Box<fancy_regex::Error>),
24    #[error(
25        "Could not evaluate clause for a rule with missing property for incoming context `{0}`"
26    )]
27    MissingProperty(String),
28    #[error("There was no variable or value object to resolve. Error = `{0}`")]
29    MissingValue(String),
30    #[error("Could not retrieve data from incoming context. Error = `{0}`")]
31    RetrievalError(String),
32    #[error("Variable assignment could not be resolved in rule file or incoming context `{0}`")]
33    MissingVariable(String),
34    #[error("Conflicting rule or variable assignments inside the same scope `{0}`")]
35    MultipleValues(String),
36    #[error("Types or variable assignments have incompatible types to retrieve `{0}`")]
37    IncompatibleRetrievalError(String),
38    #[error("Types or variable assignments are incompatible `{0}`")]
39    IncompatibleError(String),
40    #[error("Comparing incoming context with literals or dynamic results wasn't possible `{0}`")]
41    NotComparable(String),
42    #[error("Could not convert in JSON value object {0}")]
43    ConversionError(#[from] Infallible),
44    #[error("The path `{0}` does not exist")]
45    FileNotFoundError(String),
46    #[error(transparent)]
47    Errors(#[from] Errors),
48    #[error("{0}")]
49    IllegalArguments(String),
50    #[error("Error occurred while attempting to write junit report")]
51    XMLError(#[from] quick_xml::Error),
52    #[error("{0}")]
53    InternalError(#[from] InternalError),
54}
55
56#[derive(Debug, Error)]
57pub enum InternalError {
58    #[error("non string type detected for key in a map at {0}, cfn-guard only supports keys that are string types")]
59    InvalidKeyType(String),
60    #[error("internal error {0}")]
61    UnresolvedKeyForReporter(String),
62    #[error("{0}")]
63    FromUtf8Error(#[from] FromUtf8Error),
64    #[error("{0}")]
65    IncompatibleWriterError(String),
66    #[error("{0}")]
67    UnsupportedBufferError(String),
68    #[error("{0}")]
69    UnsupportedOperationError(String),
70}
71
72#[derive(Debug, Error)]
73pub struct Errors(pub Vec<Error>);
74
75impl std::fmt::Display for Errors {
76    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
77        let vec = self
78            .0
79            .iter()
80            .map(|e| format!("{e:#?}"))
81            .collect::<Vec<String>>();
82
83        let formatted = format!("{:?}", &vec);
84        write!(f, "{}", formatted)
85    }
86}
87
88impl<'a> From<nom::Err<(Span<'a>, nom::error::ErrorKind)>> for Error {
89    fn from(err: nom::Err<(Span<'a>, nom::error::ErrorKind)>) -> Self {
90        let msg = match err {
91            nom::Err::Incomplete(_) => "More bytes required for parsing".to_string(),
92            nom::Err::Failure((s, _k)) | nom::Err::Error((s, _k)) => {
93                let span = s as Span;
94                format!(
95                    "Error parsing file {} at line {} at column {}, remaining {}",
96                    span.extra,
97                    span.location_line(),
98                    span.get_utf8_column(),
99                    *span.fragment()
100                )
101            }
102        };
103        Error::ParseError(msg)
104    }
105}
106
107impl<'a> From<nom::Err<ParserError<'a>>> for Error {
108    fn from(err: nom::Err<ParserError<'a>>) -> Self {
109        let msg = match err {
110            nom::Err::Failure(e) | nom::Err::Error(e) => format!("Parsing Error {e}"),
111            nom::Err::Incomplete(_) => "More bytes required for parsing".to_string(),
112        };
113        Error::ParseError(msg)
114    }
115}
116
117impl From<JsValue> for Error {
118    fn from(err: JsValue) -> Self {
119        err.into()
120    }
121}