cfn-check 0.3.2__py3-none-any.whl → 0.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of cfn-check might be problematic. Click here for more details.

@@ -0,0 +1,13 @@
1
+ from typing import Any
2
+ from ruamel.yaml.comments import CommentedMap, CommentedSeq
3
+
4
+
5
+ def assign(parent: CommentedMap | CommentedSeq | None, key_or_index: Any, value: Any):
6
+ if parent is None:
7
+ return # root already set
8
+ if isinstance(parent, CommentedMap):
9
+ parent[key_or_index] = value
10
+ else:
11
+ # key_or_index is an int for sequences
12
+ # Ensure sequence large enough (iterative approach assigns in order, so append is fine)
13
+ parent.append(value)
cfn_check/rules/rule.py CHANGED
@@ -13,13 +13,16 @@ class Rule:
13
13
  self,
14
14
  query: str,
15
15
  name: str,
16
+ filters: list[Callable[[JsonValue], JsonValue]] | None = None
16
17
  ):
17
18
  self.query = query
18
19
  self.name = name
20
+ self.filters = filters
19
21
 
20
22
  def __call__(self, func: Callable[[T], None]):
21
23
  return Validator[T](
22
24
  func,
23
25
  self.query,
24
26
  self.name,
27
+ filters=self.filters,
25
28
  )
@@ -14,10 +14,12 @@ class Validator(Generic[T]):
14
14
  func: Callable[[T], None],
15
15
  query: str,
16
16
  name: str,
17
+ filters: list[Callable[[Data], Data]] | None = None
17
18
  ):
18
19
  self.func = func
19
20
  self.query = query
20
21
  self.name = name
22
+ self.filters = filters
21
23
 
22
24
  self.model: BaseModel | None = None
23
25
 
@@ -31,8 +33,16 @@ class Validator(Generic[T]):
31
33
 
32
34
  try:
33
35
  path, item = arg
36
+
37
+ if self.filters:
38
+ for filter in self.filters:
39
+ item = filter(item)
40
+
41
+ if item is None:
42
+ return
43
+
34
44
  if self.model and isinstance(item, dict):
35
- arg = self.model(**item)
45
+ item = self.model(**item)
36
46
 
37
47
  return self.func(item)
38
48
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cfn-check
3
- Version: 0.3.2
3
+ Version: 0.8.1
4
4
  Summary: Validate Cloud Formation
5
5
  Author-email: Ada Lundhe <adalundhe@lundhe.audio>
6
6
  License: MIT License
@@ -27,14 +27,15 @@ License: MIT License
27
27
 
28
28
  Project-URL: Homepage, https://github.com/adalundhe/cfn-check
29
29
  Keywords: cloud-formation,testing,aws,cli
30
+ Classifier: Programming Language :: Python :: 3.11
30
31
  Classifier: Programming Language :: Python :: 3.12
31
32
  Classifier: Programming Language :: Python :: 3.13
32
33
  Classifier: Operating System :: OS Independent
33
- Requires-Python: >=3.12
34
+ Requires-Python: >=3.11
34
35
  Description-Content-Type: text/markdown
35
36
  License-File: LICENSE
36
37
  Requires-Dist: pydantic
37
- Requires-Dist: pyyaml
38
+ Requires-Dist: ruamel.yaml
38
39
  Requires-Dist: hyperlight-cocoa
39
40
  Requires-Dist: async-logging
40
41
  Dynamic: license-file
@@ -50,7 +51,7 @@ Dynamic: license-file
50
51
 
51
52
  | Package | cfn-check |
52
53
  | ----------- | ----------- |
53
- | Version | 0.3.2 |
54
+ | Version | 0.8.0 |
54
55
  | Download | https://pypi.org/project/cfn-check/ |
55
56
  | Source | https://github.com/adalundhe/cfn-check |
56
57
  | Keywords | cloud-formation, testing, aws, cli |
@@ -70,15 +71,20 @@ problems inherint to `cfn-lint` more than `cfn-guard`, primarily:
70
71
  - Inability to parse non-resource wildcards
71
72
  - Inability to validate non-resource template data
72
73
  - Inabillity to use structured models to validate input
74
+ - Poor ability to parse and render CloudFormation Refs/Functions
73
75
 
74
76
  In comparison to `cfn-guard`, `cfn-check` is pure Python, thus
75
77
  avoiding YADSL (Yet Another DSL) headaches. It also proves
76
78
  significantly more configurable/modular/hackable as a result.
79
+ `cfn-check` can resolve _some_ (not all) CloudFormation Intrinsic
80
+ Functions and Refs.
77
81
 
78
82
  CFN-Check uses a combination of simple depth-first-search tree
79
83
  parsing, friendly `cfn-lint` like query syntax, `Pydantic` models,
80
84
  and `pytest`-like assert-driven checks to make validating your
81
85
  Cloud Formation easy while offering both CLI and Python API interfaces.
86
+ CFN-Check also uses a lightning-fast AST-parser to render your templates,
87
+ allowing you to validate policy, not just a YAML document.
82
88
 
83
89
  <br/>
84
90
 
@@ -447,7 +453,7 @@ Resources::*::Type
447
453
  Selects all `Resource` objects. If we convert the Wildcard Token in the query to a Wildcard Range Token:
448
454
 
449
455
  ```
450
- Resources::*::Type
456
+ Resources::[*]::Type
451
457
  ```
452
458
 
453
459
  The Rule will fail as below:
@@ -537,5 +543,100 @@ With Nested Ranges, this can be shortened to:
537
543
 
538
544
  ```
539
545
  Resources::AppendItemToListFunction::Properties::Code::ZipFile::[[]]
546
+ ```
540
547
 
541
548
  Which is both more concise *and* more representitave of our intention to select only the array.
549
+
550
+ <br/>
551
+
552
+ # Using Pydantic Models
553
+
554
+ In addition to traditional `pytest`-like assert statements, `cfn-lint` can validate results returned by queries via `Pydantic` models.
555
+
556
+ For example, consider again the initial example where we validate the `Type` field of `Resource` objects.
557
+
558
+ ```python
559
+ from cfn_check import Collection, Rule
560
+
561
+
562
+ class ValidateResourceType(Collection):
563
+
564
+ @Rule(
565
+ "Resources::*::Type",
566
+ "It checks Resource::Type is correctly definined",
567
+ )
568
+ def validate_test(self, value: str):
569
+ assert value is not None, '❌ Resource Type not defined'
570
+ assert isinstance(value, str), '❌ Resource Type not a string'
571
+ ```
572
+
573
+ Rather than explicitly querying for the type field and writing assertions, we can instead define a `Pydantic` schema, then pass all `Resource` objects to that schema by specifying it as a Python type hint in our `Rule` method's signature.
574
+
575
+ ```python
576
+ from cfn_check import Collection, Rule
577
+ from pydantic import BaseModel, StrictStr
578
+
579
+ class Resource(BaseModel):
580
+ Type: StrictStr
581
+
582
+
583
+ class ValidateResourceType(Collection):
584
+
585
+ @Rule(
586
+ "Resources::*",
587
+ "It checks Resource::Type is correctly definined",
588
+ )
589
+ def validate_test(self, value: Resource):
590
+ assert value is not None
591
+ ```
592
+
593
+ By deferring type and existence assertions to `Pydantic` models, you can focus your actual assertion logic on business/security policy checks.
594
+
595
+ <br/>
596
+
597
+ # The Rendering Engine
598
+
599
+ ### Overview
600
+
601
+ In Version 0.6.X, CFN-Check introduced a rendering engine, which allows it
602
+ to parse and execute Refs and all CloudFormation intrinsic functions via
603
+ either the CloudFormation document or user-supplied values. This additional
604
+ also resulted in the:
605
+
606
+ ```bash
607
+ cfn-check render <TEMPLATE_PATH >
608
+ ```
609
+
610
+ command being added, allowing you to effectively "dry run" render your
611
+ CloudFormation templates akin to the `helm template` command for Helm.
612
+
613
+ By default, `cfn-check render` outputs to stdout, however you can easily
614
+ save rendered output to a file via the `-o/--output-file` flag. For example:
615
+
616
+ ```bash
617
+ cfn-check render template.yml -o rendered.yml
618
+ ```
619
+
620
+ The `cfn-check render` command also offers the following options:
621
+
622
+ - `-a/--attributes`: A list of <key>=<value> input `!GetAtt` attributes to use
623
+ - `-m/--mappings`: A list of <key>=<value> input `Mappings` to use
624
+ - `-p/--parameters`: A list of <key>=<value> input `Parameters` to use
625
+ - `-l/--log-level`: The log level to use
626
+
627
+ ### The Rendering Engine during Checks
628
+
629
+ By default rendering is enabled when running `cfn-check` validation. You can
630
+ disable it by supplying `no-render` to the `-F/--flags` option as below:
631
+
632
+ ```bash
633
+ cfn-check validate -F no-render -r rules.py template.yaml
634
+ ```
635
+
636
+ Disabling rendering means CFN-Check will validate your template as-is, with
637
+ no additional pre-processing and no application of user input values.
638
+
639
+ > [!WARNING]
640
+ > CloudFormation documents are <b>not</b> "plain yaml" and disabling
641
+ > rendering means any dynamically determined values will likely fail
642
+ > to pass validation, resulting in false positives for failures!
@@ -0,0 +1,42 @@
1
+ cfn_check/__init__.py,sha256=ccUo2YxBmuEmak1M5o-8J0ECLXNkDDUsLJ4mkm31GvU,96
2
+ cfn_check/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ cfn_check/cli/config.py,sha256=khoxOcLBu-tPXA6U3QyySfLq41l9Z9wcghZ4tO5IAaM,416
4
+ cfn_check/cli/render.py,sha256=vsAk--RSIzRu4ebRlq4vfQSD-EqWp93GN029ck6-GO8,4551
5
+ cfn_check/cli/root.py,sha256=Fi-G3nP-HQMY4iPenF2xnkQF798x5cNWDqJZs9TH66A,1727
6
+ cfn_check/cli/validate.py,sha256=X8tlk3QIiUC4YiqEU8PQGgxbfh3EL51GaVhj2Ap-Mas,2376
7
+ cfn_check/cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ cfn_check/cli/utils/attributes.py,sha256=hEMWJfNcTOKqWrleS8idWlZP81wAq2J06yV-JQm_WNw,340
9
+ cfn_check/cli/utils/files.py,sha256=87F72INUuA61k3pQ1NNbg0vUwBYOY7-wn1rPqRWbrao,3357
10
+ cfn_check/cli/utils/stdout.py,sha256=dztgy5cBF03oGHRr5ITvMVVf5qdopPbAQm6Rp0cHZq4,423
11
+ cfn_check/collection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ cfn_check/collection/collection.py,sha256=Fl5ONtvosLrksJklRoxER9j-YN5RUdPN45yS02Yw5jU,1492
13
+ cfn_check/evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ cfn_check/evaluation/errors.py,sha256=yPJdtRYo67le4yMC9sYqcboCnkqKsJ3KPbSPFY2-Pi8,773
15
+ cfn_check/evaluation/evaluator.py,sha256=xKbqVES_mmPXVspagPibF-7J58OL-O1vcKwNEuXccuo,3224
16
+ cfn_check/evaluation/validate.py,sha256=hM4pkA1FVv6OPkxxkgOPvjxXMwiMhDLeU6l3YrHd4mo,2639
17
+ cfn_check/evaluation/parsing/__init__.py,sha256=s5TxU4mzsbNIpbMynbwibGR8ac0dTcf_2qUfGkAEDvQ,52
18
+ cfn_check/evaluation/parsing/query_parser.py,sha256=4J3CJQKAyb11gugfx6OZT-mfSdNDB5Al8Jiy9DbJZMw,3459
19
+ cfn_check/evaluation/parsing/token.py,sha256=nrg7Tca182WY0VhRqfsZ1UgpxsUX73vdLToSeK50DZE,7055
20
+ cfn_check/evaluation/parsing/token_type.py,sha256=E5AVBerinBszMLjjc7ejwSSWEc0p0Ju_CNFhpoZi63c,325
21
+ cfn_check/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ cfn_check/logging/models.py,sha256=-tBaK6p8mJ0cO8h2keEJ-VmtFX_VW4XzwAw2PtqbkF0,490
23
+ cfn_check/rendering/__init__.py,sha256=atcbddYun4YHyY7bVGA9CgEYzzXpYzvkx9_Kg-gnD5w,42
24
+ cfn_check/rendering/cidr_solver.py,sha256=aCUH3q9PvQ7-hkJd79VmUc175Ks-HifShPIMVnD8Ws8,1528
25
+ cfn_check/rendering/renderer.py,sha256=p4LV8qFav0wv4UVu467CGTLziRcE218BJHyFzTOwuyg,44162
26
+ cfn_check/rendering/utils.py,sha256=MNaKePylbJ9Bs4kjuoV0PpCmPJYttPXXvKQILemCrUI,489
27
+ cfn_check/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ cfn_check/rules/rule.py,sha256=_cKNQ5ciJgPj-exmtBUz31cU2lxWYxw2n2NWIlhYc3s,635
29
+ cfn_check/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ cfn_check/shared/types.py,sha256=-om3DyZsjK_tJd-I8SITkoE55W0nB2WA3LOc87Cs7xI,414
31
+ cfn_check/validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ cfn_check/validation/validator.py,sha256=Z6S6T_4yQW1IUa5Kv3ohR9U8NDrhTvBadW2FEM8TRL8,1478
33
+ cfn_check-0.8.1.dist-info/licenses/LICENSE,sha256=EbCpGNzOkyQ53ig7J2Iwgmy4Og0dgHe8COo3WylhIKk,1069
34
+ example/multitag.py,sha256=QQfcRERGEDgTUCGqWRqRbXHrLwSX4jEOFq8ED4NJnz8,636
35
+ example/pydantic_rules.py,sha256=6NFtDiaqmnYWt6oZIWB7AO_v5LJoZVOGXrmEe2_J_rI,4162
36
+ example/renderer_test.py,sha256=XG5PVTSHztYXHrBw4bpwVuuYt1JNZdtLGJ-DZ9wPjFM,741
37
+ example/rules.py,sha256=mWHB0DK283lb0CeSHgnyO5qiVTJJpybuwWXb4Yoa3zQ,3148
38
+ cfn_check-0.8.1.dist-info/METADATA,sha256=pCUvnxDUaPRqCx2Oy4kMNneY_zCuNQsY2EIbgpOgL-A,22448
39
+ cfn_check-0.8.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
40
+ cfn_check-0.8.1.dist-info/entry_points.txt,sha256=B4lCHoDHmwisABxKgRLShwqqFv7QwwDAFXoAChOnkwg,53
41
+ cfn_check-0.8.1.dist-info/top_level.txt,sha256=hUn9Ya50yY1fpgWxEhG5iMgfMDDVX7qWQnM1xrgZnhM,18
42
+ cfn_check-0.8.1.dist-info/RECORD,,
example/multitag.py ADDED
@@ -0,0 +1,21 @@
1
+ import ruamel.yaml
2
+ import sys
3
+
4
+ class MultiTaggedObject:
5
+ def __init__(self, value, tags):
6
+ self.value = value
7
+ self.tags = tags
8
+
9
+ def represent_multi_tagged_object(dumper, data):
10
+ return dumper.represent_mapping('!MultiTagged', {'value': data.value, 'tags': data.tags})
11
+
12
+ def construct_multi_tagged_object(constructor, node):
13
+ mapping = constructor.construct_mapping(node)
14
+ return MultiTaggedObject(mapping['value'], mapping['tags'])
15
+
16
+ yaml = ruamel.yaml.YAML()
17
+ yaml.register_class(MultiTaggedObject)
18
+
19
+ # Example usage:
20
+ data = MultiTaggedObject("some_value", ["tag1", "tag2"])
21
+ yaml.dump({'item': data}, sys.stdout)
@@ -0,0 +1,114 @@
1
+ from cfn_check import Collection, Rule
2
+ from pydantic import BaseModel, StrictStr, StrictInt, Field
3
+ from typing import Literal
4
+
5
+ class RDSDBProperties(BaseModel):
6
+ AvailabilityZone: StrictStr
7
+ BackupRetentionPeriod: StrictInt
8
+ DBInstanceClass: StrictStr = Field(pattern=r'^((db)\.(c6g|c6gd|c6gn|c6i|c6id|c7g|g5g|im4gn|is4gen|m6g|m6gd|r6g|r6gd|t4g|x2gd)\.(10xlarge|112xlarge|12xlarge|16xlarge|18xlarge|24xlarge|2xlarge|32xlarge|3xlarge|48xlarge|4xlarge|56xlarge|6xlarge|8xlarge|9xlarge|large|medium|metal|micro|nano|small|xlarge))')
9
+ StorageType: Literal['sc1', 'st1', 'gp3']
10
+
11
+ class RDSDBInstance(BaseModel):
12
+ Type: Literal["AWS::RDS::DBInstance"]
13
+
14
+ class EC2EbsDevice(BaseModel):
15
+ VolumeType: StrictStr
16
+ DeleteOnTermination: Literal[True]
17
+
18
+ class EC2BlockDeviceMappings(BaseModel):
19
+ Ebs: EC2EbsDevice
20
+
21
+ class EC2VolumeProperties(BaseModel):
22
+ VolumeType: Literal["sc1", "st1", "gp3"]
23
+ BlockDeviceMappings: EC2BlockDeviceMappings
24
+
25
+ class EC2Volume(BaseModel):
26
+ Type: Literal["AWS::EC2::Volume"]
27
+ Properties: EC2VolumeProperties
28
+
29
+ class EC2InstanceProperties(BaseModel):
30
+ InstanceType: StrictStr = Field(pattern=r'^((c6g|c6gd|c6gn|c6i|c6id|c7g|g5g|im4gn|is4gen|m6g|m6gd|r6g|r6gd|t4g|x2gd)\.(10xlarge|112xlarge|12xlarge|16xlarge|18xlarge|24xlarge|2xlarge|32xlarge|3xlarge|48xlarge|4xlarge|56xlarge|6xlarge|8xlarge|9xlarge|large|medium|metal|micro|nano|small|xlarge))')
31
+
32
+ class EC2Instance(BaseModel):
33
+ Type: Literal["AWS::EC2::Instance"]
34
+ Properties: EC2InstanceProperties
35
+
36
+ class LoggingGroupProperties(BaseModel):
37
+ LogGroupClass: Literal["Infrequent Access"]
38
+ RetentionInDays: StrictInt
39
+
40
+ class LoggingGroup(BaseModel):
41
+ Type: Literal["AWS::Logs::LogGroup"]
42
+ Properties: LoggingGroupProperties
43
+
44
+ class LambdaLoggingConfig(BaseModel):
45
+ LogGroup: StrictStr
46
+
47
+ class LambdaProperties(BaseModel):
48
+ LoggingConfig: LambdaLoggingConfig
49
+
50
+ class Lambda(BaseModel):
51
+ Type: Literal["AWS::Serverless::Function", "AWS::Lambda::Function"]
52
+ Properties: LambdaProperties
53
+
54
+ class Resource(BaseModel):
55
+ Type: StrictStr
56
+
57
+ class ValidateResourceType(Collection):
58
+
59
+ @Rule(
60
+ "Resources::*",
61
+ "It checks Resource::Type is correctly definined",
62
+ )
63
+ def validate_test(self, value: Resource):
64
+ assert isinstance(value, Resource), "Not a valid CloudFormation Resource"
65
+
66
+ @Rule(
67
+ "Resources::*",
68
+ "It validates a lambda is configured correctly",
69
+ filters=[
70
+ lambda data: data if data.get("Type") in ["AWS::Serverless::Function", "AWS::Lambda::Function"] else None,
71
+ ]
72
+ )
73
+ def validate_lambda(self, lambda_resource: Lambda):
74
+ assert isinstance(lambda_resource, Lambda), "Not a valid Lambda"
75
+
76
+ resources = self.query("Resources")
77
+ document = {}
78
+
79
+ for resource in resources:
80
+ document.update(resource)
81
+
82
+ lambda_logging_group = document.get(lambda_resource.Properties.LoggingConfig.LogGroup)
83
+ assert lambda_logging_group is not None, "No matching logging group found in Resources for Lambda"
84
+ LoggingGroup(**lambda_logging_group)
85
+
86
+ @Rule(
87
+ "Resources::*",
88
+ "It validates a logging group is configured correctly",
89
+ filters=[
90
+ lambda data: data if data.get("Type") == 'AWS::Logs::LogGroup' else None,
91
+ ]
92
+ )
93
+ def validate_logging_group(self, logging_group: LoggingGroup):
94
+ assert isinstance(logging_group, LoggingGroup), "Not a valid logging group"
95
+
96
+ @Rule(
97
+ "Resources::*",
98
+ "It validates an EC2 instance is configured correctly",
99
+ filters=[
100
+ lambda data: data if data.get("Type") == 'AWS::EC2::Instance' else None,
101
+ ]
102
+ )
103
+ def validate_ec2_instances(self, ec2_instance: EC2Instance):
104
+ assert isinstance(ec2_instance, EC2Instance)
105
+
106
+ @Rule(
107
+ "Resources::*",
108
+ "It validates an EC2 Volume is configured correctly",
109
+ filters=[
110
+ lambda data: data if data.get("Type") == 'AWS::EC2::Volume' else None,
111
+ ]
112
+ )
113
+ def validate_ec2_volumes(self, ec2_volume: EC2Volume):
114
+ assert isinstance(ec2_volume, EC2Volume), "Not a valid EC2 Volume"
@@ -0,0 +1,42 @@
1
+ import yaml
2
+ from cfn_check.rendering import Renderer
3
+ from cfn_check.cli.utils.files import open_template, Loader, create_tag
4
+ def test():
5
+
6
+ renderer = Renderer()
7
+ data = {}
8
+
9
+ tags = [
10
+ 'Ref',
11
+ 'Sub',
12
+ 'Join',
13
+ 'Select',
14
+ 'Split',
15
+ 'GetAtt',
16
+ 'GetAZs',
17
+ 'ImportValue',
18
+ 'Equals',
19
+ 'If',
20
+ 'Not',
21
+ 'And',
22
+ 'Or',
23
+ 'Condition',
24
+ 'FindInMap',
25
+ ]
26
+
27
+ for tag in tags:
28
+ new_tag = create_tag(tag)
29
+ Loader.add_constructor(f'!{tag}', new_tag)
30
+
31
+ _, template = open_template('template.yaml')
32
+
33
+ data = renderer.render(template)
34
+
35
+
36
+ with open('rendered.yaml', 'w') as yml:
37
+ yaml.safe_dump(data, yml)
38
+
39
+
40
+
41
+
42
+ test()
File without changes
@@ -1,21 +0,0 @@
1
- import yaml
2
- import pathlib
3
-
4
-
5
- class Loader(yaml.SafeLoader):
6
- pass
7
-
8
- def create_tag(tag):
9
- def constructor(loader: Loader, node):
10
- if isinstance(node, yaml.ScalarNode):
11
- return node.value
12
- elif isinstance(node, yaml.SequenceNode):
13
- return loader.construct_sequence(node)
14
- elif isinstance(node, yaml.MappingNode):
15
- return loader.construct_mapping(node)
16
- return constructor
17
-
18
-
19
- def find_templates(path, file_pattern):
20
- return list(pathlib.Path(path).rglob(file_pattern))
21
-
@@ -1,34 +0,0 @@
1
- cfn_check/__init__.py,sha256=ccUo2YxBmuEmak1M5o-8J0ECLXNkDDUsLJ4mkm31GvU,96
2
- cfn_check/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- cfn_check/cli/root.py,sha256=dHq9zzXyj-Wrj-fzirtFjptShzWbBGsO3n9tspm-pec,1688
4
- cfn_check/cli/validate.py,sha256=EY6-YgORApOxCgFAmPdwmfDg1UA80GLsRzQv44zSuY4,1954
5
- cfn_check/cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- cfn_check/cli/utils/attributes.py,sha256=iIUIgl6cT5XEUOW7D54-xxmMpTis84ySQY1b9osB47E,339
7
- cfn_check/cli/utils/files.py,sha256=QMYYR7C7mXdDx_6jj1Ye9w7ol1twAzUEZ9hxSa-O4-k,2563
8
- cfn_check/collection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- cfn_check/collection/collection.py,sha256=wNxahoOqQge3C56blz5VtOq6lX5MZ9F2JjQIyZ3_SxU,27
10
- cfn_check/evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- cfn_check/evaluation/errors.py,sha256=yPJdtRYo67le4yMC9sYqcboCnkqKsJ3KPbSPFY2-Pi8,773
12
- cfn_check/evaluation/evaluator.py,sha256=weFBAYKVc9TjTB2zNMIVX77Bi9kIaWp2KRJa1ISSLNs,2240
13
- cfn_check/evaluation/validate.py,sha256=yy8byYAoHxFqkS2HfewHup22B3bYtrUH2PhPuNAc--A,1547
14
- cfn_check/evaluation/parsing/__init__.py,sha256=s5TxU4mzsbNIpbMynbwibGR8ac0dTcf_2qUfGkAEDvQ,52
15
- cfn_check/evaluation/parsing/query_parser.py,sha256=4J3CJQKAyb11gugfx6OZT-mfSdNDB5Al8Jiy9DbJZMw,3459
16
- cfn_check/evaluation/parsing/token.py,sha256=_mf1hMnnu5TFXvnyfxAy-GjdVW9kvhgv1NLaSh4GF4k,6993
17
- cfn_check/evaluation/parsing/token_type.py,sha256=E5AVBerinBszMLjjc7ejwSSWEc0p0Ju_CNFhpoZi63c,325
18
- cfn_check/loader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- cfn_check/loader/loader.py,sha256=7yiDLLW_vNp_8O47erLXjQQtAB47fU3nimb91N5N_R8,532
20
- cfn_check/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- cfn_check/logging/models.py,sha256=-tBaK6p8mJ0cO8h2keEJ-VmtFX_VW4XzwAw2PtqbkF0,490
22
- cfn_check/rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- cfn_check/rules/rule.py,sha256=r6-eKCUdPaNIena2NDv3J_QlcWes1KLObI9ukRZZz1o,500
24
- cfn_check/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- cfn_check/shared/types.py,sha256=-om3DyZsjK_tJd-I8SITkoE55W0nB2WA3LOc87Cs7xI,414
26
- cfn_check/validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- cfn_check/validation/validator.py,sha256=FGPeb8Uc8lvX3Y5rs-fxeJKIOqzUXwXh_gCFcy6d3b0,1182
28
- cfn_check-0.3.2.dist-info/licenses/LICENSE,sha256=EbCpGNzOkyQ53ig7J2Iwgmy4Og0dgHe8COo3WylhIKk,1069
29
- example/rules.py,sha256=mWHB0DK283lb0CeSHgnyO5qiVTJJpybuwWXb4Yoa3zQ,3148
30
- cfn_check-0.3.2.dist-info/METADATA,sha256=aAqR3dS-h4J_kHL4K6vCtl2DSFgYvOCHps_PvoraX5Q,19047
31
- cfn_check-0.3.2.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
32
- cfn_check-0.3.2.dist-info/entry_points.txt,sha256=B4lCHoDHmwisABxKgRLShwqqFv7QwwDAFXoAChOnkwg,53
33
- cfn_check-0.3.2.dist-info/top_level.txt,sha256=hUn9Ya50yY1fpgWxEhG5iMgfMDDVX7qWQnM1xrgZnhM,18
34
- cfn_check-0.3.2.dist-info/RECORD,,