Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- Simplify v3 Guard result json #230

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/cfn_guard_rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/cfn_guard_rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cfn_guard_rs"
version = "0.3.1"
version = "0.3.2"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
114 changes: 109 additions & 5 deletions packages/cfn_guard_rs/python/cfn_guard_rs/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,22 @@
"""
from __future__ import annotations

import abc
from dataclasses import dataclass, field
from typing import Any, List, Dict, Sequence, Tuple

# pylint: disable=missing-class-docstring,missing-function-docstring,invalid-name
class ValueComparisons(abc.ABC):
@property
@abc.abstractmethod
def value_from(self) -> Any:
pass

@property
@abc.abstractmethod
def value_to(self) -> Any:
pass


@dataclass(eq=True, frozen=True)
class Messages:
Expand All @@ -23,6 +35,13 @@ def from_object(cls, obj) -> "Messages":
error_message=obj.get("error_message"),
)

def __repr__(self) -> str:
if self.custom_message:
return self.custom_message
if self.error_message:
return self.error_message
return ""


@dataclass(eq=True, frozen=True)
class RuleReport:
Expand All @@ -47,7 +66,7 @@ def from_object(cls, obj) -> "RuleReport" | None:


@dataclass(eq=True, frozen=True)
class GuardBlockReport:
class GuardBlockReport(ValueComparisons):
"""Guard Block Report"""

context: str = field()
Expand All @@ -65,6 +84,14 @@ def from_object(cls, obj):
unresolved=obj.get("resolved"),
)

@property
def value_from(self) -> Any:
return None

@property
def value_to(self) -> Any:
return None


@dataclass(eq=True, frozen=True)
class DisjunctionsReport:
Expand All @@ -79,6 +106,7 @@ def from_object(cls, obj):

return cls(checks=ClauseReport.from_object(obj.get("checks")))


@dataclass(eq=True, frozen=True)
class UnaryComparison:
"""Unary Comparison"""
Expand Down Expand Up @@ -127,7 +155,7 @@ def from_object(cls, obj):


@dataclass(eq=True, frozen=True)
class UnaryCheck:
class UnaryCheck(ValueComparisons):
"""Unary Check"""

Resolved: UnaryComparison | None = field(default=None)
Expand All @@ -145,6 +173,18 @@ def from_object(cls, obj):
UnresolvedContext=obj.get("UnresolvedContext"),
)

@property
def value_from(self) -> Any:
if self.Resolved is not None:
return self.Resolved.value
if self.UnResolved is not None:
return self.UnResolved.traversed_to
return None

@property
def value_to(self) -> Any:
return None


@dataclass(eq=True, frozen=True)
class UnaryReport:
Expand Down Expand Up @@ -198,7 +238,7 @@ def from_object(cls, obj) -> "InComparison" | None:


@dataclass(eq=True, frozen=True)
class BinaryCheck:
class BinaryCheck(ValueComparisons):
Resolved: BinaryComparison | None = field(default=None)
UnResolved: UnResolved | None = field(default=None)
InResolved: Any = field(default=None)
Expand All @@ -211,6 +251,22 @@ def from_object(cls, obj):
InResolved=obj.get("InResolved"),
)

@property
def value_from(self) -> Any:
if self.Resolved is not None:
return self.Resolved.from_
if self.InResolved is not None:
return self.InResolved.from_
if self.UnResolved is not None:
return self.UnResolved.traversed_to
return None

@property
def value_to(self) -> Any:
if self.Resolved is not None:
return self.Resolved.to_
return None


@dataclass(eq=True, frozen=True)
class BinaryReport:
Expand All @@ -230,7 +286,7 @@ def from_object(cls, obj):


@dataclass(eq=True, frozen=True)
class GuardClauseReport:
class GuardClauseReport(ValueComparisons):
"""Guard Clause Report"""

Unary: UnaryReport | None = field(default=None)
Expand All @@ -246,9 +302,41 @@ def from_object(cls, obj):
Binary=BinaryReport.from_object(obj.get("Binary")),
)

@property
def context(self) -> str | None:
if self.Unary is not None:
return self.Unary.context
if self.Binary is not None:
return self.Binary.context
return None

@property
def messages(self) -> Messages | None:
if self.Unary is not None:
return self.Unary.messages
if self.Binary is not None:
return self.Binary.messages
return None

@property
def value_from(self):
if self.Unary is not None:
return self.Unary.check.value_from
if self.Binary is not None:
return self.Binary.check.value_from
return None

@property
def value_to(self):
if self.Unary is not None:
return self.Unary.check.value_to
if self.Binary is not None:
return self.Binary.check.value_to
return None


@dataclass(eq=True, frozen=True)
class ClauseReport:
class ClauseReport(ValueComparisons):
"""Clause Report"""

Rule: RuleReport | None = field(default=None)
Expand All @@ -273,6 +361,22 @@ def from_array(cls, items):

return results

@property
def value_from(self) -> Any:
if self.GuardBlock is not None:
return self.GuardBlock.value_from
if self.Clause is not None:
return self.Clause.value_from
return None

@property
def value_to(self) -> Any:
if self.GuardBlock is not None:
return self.GuardBlock.value_to
if self.Clause is not None:
return self.Clause.value_to
return None


# pylint: disable=too-many-instance-attributes
@dataclass(eq=True, frozen=True)
Expand Down
32 changes: 28 additions & 4 deletions packages/cfn_guard_rs/python/tests/test_cfn_guard_rs.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@


@pytest.mark.parametrize(
"template,rules,expected",
"template,rules,expected,values_from,values_to",
[
(
"python/tests/fixtures/templates/s3_bucket_name_valid.yaml",
Expand All @@ -38,6 +38,8 @@
not_applicable=[],
compliant=["default"],
),
[],
[],
),
(
"python/tests/fixtures/templates/s3_bucket_name_invalid.yaml",
Expand Down Expand Up @@ -89,6 +91,13 @@
not_applicable=[],
compliant=[],
),
[
{
"path": "/Resources/Bucket/Properties/BucketName",
"value": 1,
}
],
[None],
),
(
"python/tests/fixtures/templates/s3_bucket_public_access_valid.yaml",
Expand All @@ -103,6 +112,8 @@
not_applicable=[],
compliant=["S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED"],
),
[],
[],
),
(
"python/tests/fixtures/templates/s3_bucket_public_access_invalid.yaml",
Expand Down Expand Up @@ -163,20 +174,33 @@
not_applicable=[],
compliant=[],
),
[
{
"path": (
"/Resources/Bucket/Properties/"
"PublicAccessBlockConfiguration/BlockPublicAcls"
),
"value": "false",
}
],
[{"path": "", "value": "true"}],
),
],
)
def test_run_checks(template, rules, expected):
def test_run_checks(template, rules, expected, values_from, values_to):
"""Test transactions against run_checks"""
with open(template, encoding="utf8") as file:
template_str = yaml.safe_load(file)
with open(rules, encoding="utf8") as file:
rules = file.read()

result = run_checks(template_str, rules)
print(result)
print(expected)
assert result == expected
for i, value_from in enumerate(values_from):
assert result.not_compliant[0].Rule.checks[i].value_from == value_from

for i, value_to in enumerate(values_to):
assert result.not_compliant[i].Rule.checks[i].value_to == value_to


@pytest.mark.parametrize(
Expand Down
10 changes: 5 additions & 5 deletions packages/cfn_guard_rs_hook/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/cfn_guard_rs_hook/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ authors = ["Kevin DeJong <kddejong@amazon.com>"]
[tool.poetry.dependencies]
python = "^3.7.2"
cloudformation-cli-python-lib = "^2.1.12"
cfn-guard-rs = "^0.2.1"
cfn-guard-rs = "~0.2.3"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be ~0.3.2 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not until its published into pypi

that will be the next PR

pyyaml = "~6.0.1"
Jinja2 = "^3.0.0"
jsonpath-rw = "^1.0.0"
Expand Down