diff --git a/packages/cfn_guard_rs/python/cfn_guard_rs/api.py b/packages/cfn_guard_rs/python/cfn_guard_rs/api.py index dddb52f5..8baa3110 100644 --- a/packages/cfn_guard_rs/python/cfn_guard_rs/api.py +++ b/packages/cfn_guard_rs/python/cfn_guard_rs/api.py @@ -40,11 +40,12 @@ def run_checks(data: dict, rules: str) -> FileReport: """ try: raw_output = run_checks_rs(json.dumps(data), rules, False) + LOG.debug("Raw output: %s", raw_output) output = json.loads(raw_output) return FileReport.from_object(output) except json.JSONDecodeError as err: - LOG.debug( + LOG.info( "JSON decoding error when processing return value [%s] got error: %s", raw_output, err, @@ -55,9 +56,10 @@ def run_checks(data: dict, rules: str) -> FileReport: except CfnGuardParseError as err: raise errors.ParseError(str(err)) except Exception as err: - LOG.debug( + LOG.info( "Received unknown exception [%s] while running checks, got error: %s", type(err), err, + exc_info=True, ) raise errors.UnknownError(str(err)) diff --git a/packages/cfn_guard_rs/python/cfn_guard_rs/interface.py b/packages/cfn_guard_rs/python/cfn_guard_rs/interface.py index 1a2243ea..d9d9b916 100644 --- a/packages/cfn_guard_rs/python/cfn_guard_rs/interface.py +++ b/packages/cfn_guard_rs/python/cfn_guard_rs/interface.py @@ -29,7 +29,10 @@ class Messages: error_message: str | None = field(default=None) @classmethod - def from_object(cls, obj) -> "Messages": + def from_object(cls, obj) -> "Messages" | None: + if obj is None: + return None + return cls( custom_message=obj.get("custom_message"), error_message=obj.get("error_message"), @@ -49,7 +52,7 @@ class RuleReport: name: str = field() metadata: Dict[str, Any] = field() - messages: Messages = field() + messages: Messages | None = field() checks: Sequence[ClauseReport] = field() @classmethod @@ -70,11 +73,11 @@ class GuardBlockReport(ValueComparisons): """Guard Block Report""" context: str = field() - messages: Messages = field() + messages: Messages | None = field() unresolved: Any = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "GuardBlockReport" | None: if obj is None: return obj @@ -97,10 +100,10 @@ def value_to(self) -> Any: class DisjunctionsReport: """Disjunctions""" - checks: ClauseReport = field() + checks: ClauseReport | None = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "DisjunctionsReport" | None: if obj is None: return obj @@ -112,10 +115,13 @@ class UnaryComparison: """Unary Comparison""" value: Any = field() - comparison: Tuple[str, bool] = field() + comparison: Tuple[Any, ...] | None = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "UnaryComparison" | None: + if obj is None: + return None + return cls( value=obj.get("value"), comparison=tuple(obj.get("comparison")), @@ -131,7 +137,7 @@ class UnResolved: reason: Any = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "UnResolved" | None: if obj is None: return None return cls( @@ -147,7 +153,10 @@ class ValueUnResolved: comparison: Any = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "ValueUnResolved" | None: + if obj is None: + return None + return cls( value=obj.get("value"), comparison=obj.get("comparison"), @@ -163,7 +172,7 @@ class UnaryCheck(ValueComparisons): UnresolvedContext: Any | None = field(default=None) @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "UnaryCheck" | None: if obj is None: return obj @@ -191,11 +200,11 @@ class UnaryReport: """Unary Report""" context: str = field() - messages: Messages = field() - check: UnaryCheck = field() + messages: Messages | None = field() + check: UnaryCheck | None = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "UnaryReport" | None: if obj is None: return None @@ -213,7 +222,7 @@ class BinaryComparison: comparison: Any = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "BinaryComparison" | None: if obj is None: return None return cls( @@ -230,6 +239,9 @@ def __init__(self, **kwargs) -> None: @classmethod def from_object(cls, obj) -> "InComparison" | None: + if obj is None: + return None + return cls( from_=obj.get("from"), to_=obj.get("to"), @@ -244,7 +256,10 @@ class BinaryCheck(ValueComparisons): InResolved: Any = field(default=None) @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "BinaryCheck" | None: + if obj is None: + return None + return cls( Resolved=BinaryComparison.from_object(obj.get("Resolved")), UnResolved=UnResolved.from_object(obj.get("UnResolved")), @@ -271,11 +286,11 @@ def value_to(self) -> Any: @dataclass(eq=True, frozen=True) class BinaryReport: context: str = field() - messages: Messages = field() - check: BinaryCheck = field() + messages: Messages | None = field() + check: BinaryCheck | None = field() @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "BinaryReport" | None: if obj is None: return obj return cls( @@ -293,7 +308,7 @@ class GuardClauseReport(ValueComparisons): Binary: BinaryReport | None = field(default=None) @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "GuardClauseReport" | None: if obj is None: return obj @@ -345,7 +360,10 @@ class ClauseReport(ValueComparisons): Clause: GuardClauseReport | None = field(default=None) @classmethod - def from_object(cls, obj): + def from_object(cls, obj) -> "ClauseReport" | None: + if obj is None: + return None + return cls( Rule=RuleReport.from_object(obj.get("Rule")), Disjunctions=DisjunctionsReport.from_object(obj.get("Disjunctions")), diff --git a/packages/cfn_guard_rs_hook/cfn_guard_rs_hook/guard_hook.py b/packages/cfn_guard_rs_hook/cfn_guard_rs_hook/guard_hook.py index 29b95659..f6c4e92c 100644 --- a/packages/cfn_guard_rs_hook/cfn_guard_rs_hook/guard_hook.py +++ b/packages/cfn_guard_rs_hook/cfn_guard_rs_hook/guard_hook.py @@ -284,20 +284,28 @@ def __run_checks(self, template: dict, type_configuration: Any) -> ProgressEvent progress.errorCode = HandlerErrorCode.NonCompliant progress.message = "" for not_compliant in guard_result.not_compliant: + LOG.debug("Not Compliant: %s", not_compliant) rule = not_compliant.Rule if rule is None: progress.message += "Found not compliant without rule. " continue for err in rule.checks: - path = err.value_from.get("path") + LOG.debug("Rule check: %s", err) clause = err.Clause if clause is None: progress.message += "Found not compliant without a clause. " continue - progress.message += ( - f"Rule [{rule.name}] failed on " - f"property [{path}] and got error [{clause.messages}]. " - ) + if err.value_from: + progress.message += ( + f"Rule [{rule.name}] failed on " + f"property [{err.value_from.get('path')}] " + f"and got error [{clause.messages}]. " + ) + else: + progress.message += ( + f"Rule [{rule.name}] failed " + f"with error [{clause.messages}]. " + ) progress.message = progress.message.strip() LOG.debug("Progress Event: %s", progress) return progress