1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::convert::Infallible;
use std::fmt::{Debug, Formatter};
use thiserror::Error;

use crate::rules::parser::{ParserError, Span};

#[derive(Debug, Error)]
#[allow(clippy::enum_variant_names)]
pub enum Error {
    #[error("Error parsing incoming JSON context {0}")]
    JsonError(#[from] serde_json::Error),
    #[error("Error parsing incoming YAML context {0}")]
    YamlError(#[from] serde_yaml::Error),
    #[error("Formatting error when writing {0}")]
    FormatError(#[from] std::fmt::Error),
    #[error("I/O error when reading {0}")]
    IoError(#[from] std::io::Error),
    #[error("Parser Error when parsing `{0}`")]
    ParseError(String),
    #[error("Regex expression parse error for rules file {0}")]
    RegexError(#[from] Box<fancy_regex::Error>),
    #[error(
        "Could not evaluate clause for a rule with missing property for incoming context `{0}`"
    )]
    MissingProperty(String),
    #[error("There was no variable or value object to resolve. Error = `{0}`")]
    MissingValue(String),
    #[error("Could not retrieve data from incoming context. Error = `{0}`")]
    RetrievalError(String),
    #[error("Variable assignment could not be resolved in rule file or incoming context `{0}`")]
    MissingVariable(String),
    #[error("Conflicting rule or variable assignments inside the same scope `{0}`")]
    MultipleValues(String),
    #[error("Types or variable assignments have incompatible types to retrieve `{0}`")]
    IncompatibleRetrievalError(String),
    #[error("Types or variable assignments are incompatible `{0}`")]
    IncompatibleError(String),
    #[error("Comparing incoming context with literals or dynamic results wasn't possible `{0}`")]
    NotComparable(String),
    #[error("Could not convert in JSON value object {0}")]
    ConversionError(#[from] Infallible),
    #[error("The path `{0}` does not exist")]
    FileNotFoundError(String),
    #[error(transparent)]
    Errors(#[from] Errors),
    #[error("{0}")]
    IllegalArguments(String),
    #[error("Error occurred while attempting to write junit report")]
    XMLError(#[from] quick_xml::Error),
    #[error("{0}")]
    InternalError(InternalError),
}

#[derive(Debug, Error)]
pub enum InternalError {
    #[error("non string type detected for key in a map at {0}, cfn-guard only supports keys that are string types")]
    InvalidKeyType(String),
    #[error("internal error {0}")]
    UnresolvedKeyForReporter(String),
}

#[derive(Debug, Error)]
pub struct Errors(pub Vec<Error>);

impl std::fmt::Display for Errors {
    fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
        let vec = self
            .0
            .iter()
            .map(|e| format!("{e:#?}"))
            .collect::<Vec<String>>();

        format!("{:?}", &vec);

        Ok(())
    }
}

impl<'a> From<nom::Err<(Span<'a>, nom::error::ErrorKind)>> for Error {
    fn from(err: nom::Err<(Span<'a>, nom::error::ErrorKind)>) -> Self {
        let msg = match err {
            nom::Err::Incomplete(_) => "More bytes required for parsing".to_string(),
            nom::Err::Failure((s, _k)) | nom::Err::Error((s, _k)) => {
                let span = s as Span;
                format!(
                    "Error parsing file {} at line {} at column {}, remaining {}",
                    span.extra,
                    span.location_line(),
                    span.get_utf8_column(),
                    *span.fragment()
                )
            }
        };
        Error::ParseError(msg)
    }
}

impl<'a> From<nom::Err<ParserError<'a>>> for Error {
    fn from(err: nom::Err<ParserError<'a>>) -> Self {
        let msg = match err {
            nom::Err::Failure(e) | nom::Err::Error(e) => format!("Parsing Error {e}"),
            nom::Err::Incomplete(_) => "More bytes required for parsing".to_string(),
        };
        Error::ParseError(msg)
    }
}