Skip to content

Commit 6a5f009

Browse files
authored
Add rule E3061 to validate Bucket tiering configurations (#3994)
1 parent 7a71d09 commit 6a5f009

File tree

3 files changed

+153
-2
lines changed

3 files changed

+153
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from __future__ import annotations
7+
8+
from collections import deque
9+
from typing import Any
10+
11+
from cfnlint.jsonschema import ValidationResult, Validator
12+
from cfnlint.rules.helpers import get_value_from_path
13+
from cfnlint.rules.jsonschema.CfnLintKeyword import CfnLintKeyword
14+
15+
16+
class BucketTieringConfiguration(CfnLintKeyword):
17+
id = "E3061"
18+
shortdesc = "Validate the days for tierings in IntelligentTieringConfigurations"
19+
description = (
20+
"When using AWS::S3::Bucket to configure IntelligentTieringConfigurations "
21+
"the Tierings have minimum and maximum values"
22+
)
23+
source_url = "https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html"
24+
tags = ["resources", "s3"]
25+
26+
def __init__(self):
27+
super().__init__(
28+
[
29+
"Resources/AWS::S3::Bucket/Properties/IntelligentTieringConfigurations/*/Tierings/*"
30+
]
31+
)
32+
33+
self._tierings = {
34+
"ARCHIVE_ACCESS": {
35+
"minimum": 90,
36+
"maximum": 730,
37+
},
38+
"DEEP_ARCHIVE_ACCESS": {
39+
"minimum": 180,
40+
"maximum": 730,
41+
},
42+
}
43+
44+
def validate(
45+
self, validator: Validator, _, instance: Any, schema: dict[str, Any]
46+
) -> ValidationResult:
47+
48+
for archive_access, archive_access_validator in get_value_from_path(
49+
validator, instance, deque(["AccessTier"])
50+
):
51+
if not validator.is_type(archive_access, "string"):
52+
continue
53+
for days, days_validator in get_value_from_path(
54+
archive_access_validator, instance, deque(["Days"])
55+
):
56+
if validator.is_type(days, "string"):
57+
try:
58+
days = int(days)
59+
except Exception:
60+
return
61+
62+
if not validator.is_type(days, "integer"):
63+
continue
64+
65+
days_validator = validator.evolve(
66+
schema=self._tierings.get(archive_access, {})
67+
)
68+
69+
for err in days_validator.iter_errors(days):
70+
err.path = deque(["Days"])
71+
err.rule = self
72+
yield err

test/unit/rules/resources/ec2/test_vpc_subnet_overlap.py

-2
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,6 @@ def test_validate(name, instance, starting_subnets, expected, rule, validator):
175175
rule._subnets = starting_subnets
176176
errs = list(rule.validate(validator, "", instance, {}))
177177

178-
for err in errs:
179-
print(err.path)
180178
assert (
181179
errs == expected
182180
), f"Expected test {name!r} to have {expected!r} but got {errs!r}"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from collections import deque
7+
8+
import pytest
9+
10+
from cfnlint.jsonschema import ValidationError
11+
from cfnlint.rules.resources.s3.BucketTieringConfiguration import (
12+
BucketTieringConfiguration,
13+
)
14+
15+
16+
@pytest.fixture(scope="module")
17+
def rule():
18+
rule = BucketTieringConfiguration()
19+
yield rule
20+
21+
22+
@pytest.mark.parametrize(
23+
"instance,expected",
24+
[
25+
(
26+
{},
27+
[],
28+
),
29+
(
30+
{"AccessTier": "ARCHIVE_ACCESS"},
31+
[],
32+
),
33+
(
34+
{
35+
"AccessTier": "ARCHIVE_ACCESS",
36+
"Days": "90",
37+
},
38+
[],
39+
),
40+
(
41+
{
42+
"AccessTier": "ARCHIVE_ACCESS",
43+
"Days": "a",
44+
},
45+
[],
46+
),
47+
(
48+
{
49+
"AccessTier": "ARCHIVE_ACCESS",
50+
"Days": 1,
51+
},
52+
[
53+
ValidationError(
54+
("1 is less than the minimum of 90"),
55+
path=deque(["Days"]),
56+
validator="minimum",
57+
schema_path=deque(["minimum"]),
58+
rule=BucketTieringConfiguration(),
59+
)
60+
],
61+
),
62+
(
63+
{
64+
"AccessTier": "ARCHIVE_ACCESS",
65+
"Days": 99999,
66+
},
67+
[
68+
ValidationError(
69+
("99999 is greater than the maximum of 730"),
70+
path=deque(["Days"]),
71+
validator="maximum",
72+
schema_path=deque(["maximum"]),
73+
rule=BucketTieringConfiguration(),
74+
)
75+
],
76+
),
77+
],
78+
)
79+
def test_validate(instance, expected, rule, validator):
80+
errs = list(rule.validate(validator, "", instance, {}))
81+
assert errs == expected, f"Expected {expected} got {errs}"

0 commit comments

Comments
 (0)