Skip to content

Commit 1afa03b

Browse files
authored
New schemas for targetgroups (#4082)
- New rule E3681 to validate target group target type property restrictions - New rule E3683 to validate target group protocol property restrictions
1 parent 4716882 commit 1afa03b

File tree

11 files changed

+529
-0
lines changed

11 files changed

+529
-0
lines changed

.amazonq/rules/base.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
description: Amazon Q Rules Location
3+
globs: .amazonq/rules/**/*.md
4+
---
5+
# Amazon Q Rules Location
6+
7+
Rules for placing and organizing Amazon Q markdown files in the repository.
8+
9+
<rule>
10+
name: amazonq_rules_location
11+
description: Standards for placing Amazon Q markdown files in the correct directory
12+
filters:
13+
# Match any .md files
14+
- type: file_extension
15+
pattern: "\.md$"
16+
# Match file creation events
17+
- type: event
18+
pattern: "file_create"
19+
20+
actions:
21+
- type: reject
22+
conditions:
23+
- pattern: "^(?!\\.amazonq\\/rules\\/.*\\.md$)"
24+
message: "Amazon Q markdown files must be placed in the .amazonq/rules directory"
25+
26+
- type: suggest
27+
message: |
28+
When creating Amazon Q files:
29+
30+
1. Always place markdown files in PROJECT_ROOT/.amazonq/rules/:
31+
```
32+
.amazonq/rules/
33+
├── your-rule.md
34+
├── another-rule.md [[1]](https://docs.aws.amazon.com/amazonq/latest/api-reference/API_Rule.html)
35+
└── ...
36+
```
37+
38+
2. Follow the naming convention:
39+
- Use kebab-case for filenames
40+
- Always use .md extension
41+
- Make names descriptive of the file's purpose
42+
43+
3. Directory structure:
44+
```
45+
PROJECT_ROOT/
46+
├── .amazonq/
47+
│ └── rules/
48+
│ ├── your-rule.md
49+
│ └── ...
50+
└── ...
51+
```
52+
53+
4. Never place markdown files:
54+
- In the project root
55+
- In subdirectories outside .amazonq/rules
56+
- In any other location
57+
58+
examples:
59+
- input: |
60+
# Bad: File in wrong location
61+
rules/my-rule.md
62+
my-rule.md
63+
.rules/my-rule.md
64+
65+
# Good: File in correct location
66+
.amazonq/rules/my-rule.md
67+
output: "Correctly placed Amazon Q markdown file"
68+
69+
metadata:
70+
priority: high
71+
version: 1.0
72+
</rule>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
description: Guidelines for creating cfn-lint schema extensions
3+
globs: src/cfnlint/data/schemas/extensions/**/*.json
4+
---
5+
# Creating Schema Extensions for cfn-lint
6+
7+
<rule>
8+
name: schema_extension_creation
9+
description: Guidelines for creating and maintaining schema extensions for cfn-lint
10+
filters:
11+
- type: file_extension
12+
pattern: "\.json$"
13+
- type: path
14+
pattern: "src/cfnlint/data/schemas/extensions/"
15+
16+
actions:
17+
- type: suggest
18+
message: |
19+
When creating schema extensions for cfn-lint:
20+
21+
1. **Follow JSON Schema structure**:
22+
- Use standard JSON Schema with `if/then` conditional validation
23+
- Properly validate property types in the `if` clause
24+
- Use `false` as a schema value to disallow properties
25+
- Use descriptive file names that indicate what aspect is being validated
26+
27+
2. **Base extensions on AWS documentation**:
28+
- Read the official AWS CloudFormation documentation thoroughly
29+
- Focus on property constraints not covered by the base schema
30+
- Validate relationships between properties (e.g., when X is Y, Z must be A)
31+
- Document the source of the validation rule with comments or commit messages
32+
33+
3. **Organize extensions properly**:
34+
- Place extensions in the correct resource type directory
35+
- Create new directories for resource types if needed
36+
- Follow the existing naming conventions
37+
38+
4. **Test your extensions**:
39+
- Create test cases that should pass and fail
40+
- Ensure the error messages are clear and helpful
41+
42+
examples:
43+
- input: |
44+
{
45+
"if": {
46+
"properties": {
47+
"TargetType": {
48+
"enum": ["lambda"]
49+
}
50+
}
51+
},
52+
"then": {
53+
"properties": {
54+
"Protocol": {
55+
"enum": ["HTTP", "HTTPS"]
56+
}
57+
}
58+
}
59+
}
60+
output: |
61+
{
62+
"if": {
63+
"properties": {
64+
"TargetType": {
65+
"enum": ["lambda"]
66+
},
67+
"Protocol": {
68+
"type": "string"
69+
}
70+
},
71+
"required": ["TargetType"]
72+
},
73+
"then": {
74+
"properties": {
75+
"Protocol": false,
76+
"Port": false,
77+
"HealthCheckPath": false
78+
}
79+
}
80+
}
81+
82+
metadata:
83+
priority: high
84+
version: 1.0
85+
</rule>

src/cfnlint/data/schemas/extensions/aws_elasticloadbalancingv2_targetgroup/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"if": {
3+
"properties": {
4+
"Protocol": {
5+
"type": "string"
6+
}
7+
},
8+
"required": [
9+
"Protocol"
10+
]
11+
},
12+
"then": {
13+
"allOf": [
14+
{
15+
"else": {
16+
"properties": {
17+
"Matcher": false,
18+
"ProtocolVersion": false
19+
}
20+
},
21+
"if": {
22+
"properties": {
23+
"Protocol": {
24+
"enum": [
25+
"HTTP",
26+
"HTTPS"
27+
]
28+
}
29+
},
30+
"required": [
31+
"Protocol"
32+
]
33+
}
34+
},
35+
{
36+
"if": {
37+
"properties": {
38+
"Port": {
39+
"type": [
40+
"string",
41+
"integer"
42+
]
43+
},
44+
"Protocol": {
45+
"enum": [
46+
"GENEVE"
47+
]
48+
}
49+
},
50+
"required": [
51+
"Protocol"
52+
]
53+
},
54+
"then": {
55+
"properties": {
56+
"Port": {
57+
"enum": [
58+
6081,
59+
"6081"
60+
]
61+
}
62+
}
63+
}
64+
}
65+
]
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"if": {
3+
"properties": {
4+
"TargetType": {
5+
"type": "string"
6+
}
7+
},
8+
"required": [
9+
"TargetType"
10+
]
11+
},
12+
"then": {
13+
"else": {
14+
"required": [
15+
"Port",
16+
"Protocol",
17+
"VpcId"
18+
]
19+
},
20+
"if": {
21+
"properties": {
22+
"TargetType": {
23+
"enum": [
24+
"lambda"
25+
]
26+
}
27+
},
28+
"required": [
29+
"TargetType"
30+
]
31+
},
32+
"then": {
33+
"properties": {
34+
"HealthCheckPath": false,
35+
"HealthCheckPort": false,
36+
"HealthCheckProtocol": false,
37+
"Matcher": false,
38+
"Port": false,
39+
"Protocol": false,
40+
"ProtocolVersion": false
41+
}
42+
}
43+
}
44+
}

src/cfnlint/data/schemas/patches/providers/all/aws_elasticloadbalancingv2_targetgroup/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[
2+
{
3+
"op": "add",
4+
"path": "/properties/HealthCheckProtocol/enum",
5+
"value": [
6+
"HTTP",
7+
"HTTPS",
8+
"TCP"
9+
]
10+
}
11+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from typing import Any
7+
8+
import cfnlint.data.schemas.extensions.aws_elasticloadbalancingv2_targetgroup
9+
from cfnlint.jsonschema import ValidationResult, Validator
10+
from cfnlint.rules.jsonschema.CfnLintJsonSchema import CfnLintJsonSchema, SchemaDetails
11+
12+
13+
class TargetGroupProtocolRestrictions(CfnLintJsonSchema):
14+
id = "E3683"
15+
shortdesc = "Validate target group protocol property restrictions"
16+
description = (
17+
"When a TargetGroup protocol is HTTP/HTTPS or GENEVE "
18+
"there are different restrictions on properties."
19+
)
20+
tags = ["resources"]
21+
22+
def __init__(self) -> None:
23+
super().__init__(
24+
keywords=[
25+
"Resources/AWS::ElasticLoadBalancingV2::TargetGroup/Properties",
26+
],
27+
schema_details=SchemaDetails(
28+
module=cfnlint.data.schemas.extensions.aws_elasticloadbalancingv2_targetgroup,
29+
filename="protocol_restrictions.json",
30+
),
31+
all_matches=True,
32+
)
33+
34+
def validate(
35+
self, validator: Validator, keywords: Any, instance: Any, schema: dict[str, Any]
36+
) -> ValidationResult:
37+
for err in super().validate(validator, keywords, instance, schema):
38+
if not err.schema:
39+
err.message = (
40+
f"Additional properties are not allowed ({err.path[0]!r} "
41+
"was unexpected)"
42+
)
43+
err.validator = "additionalProperties"
44+
yield err
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
6+
from typing import Any
7+
8+
import cfnlint.data.schemas.extensions.aws_elasticloadbalancingv2_targetgroup
9+
from cfnlint.jsonschema import ValidationResult, Validator
10+
from cfnlint.rules.jsonschema.CfnLintJsonSchema import CfnLintJsonSchema, SchemaDetails
11+
12+
13+
class TargetGroupTargetTypeRestrictions(CfnLintJsonSchema):
14+
id = "E3681"
15+
shortdesc = "Validate target group target type property restrictions"
16+
description = (
17+
"When a TargetGroup target type is lambda or not "
18+
"there are different restrictions on properties."
19+
)
20+
tags = ["resources"]
21+
22+
def __init__(self) -> None:
23+
super().__init__(
24+
keywords=[
25+
"Resources/AWS::ElasticLoadBalancingV2::TargetGroup/Properties",
26+
],
27+
schema_details=SchemaDetails(
28+
module=cfnlint.data.schemas.extensions.aws_elasticloadbalancingv2_targetgroup,
29+
filename="targettype_restrictions.json",
30+
),
31+
all_matches=True,
32+
)
33+
34+
def validate(
35+
self, validator: Validator, keywords: Any, instance: Any, schema: dict[str, Any]
36+
) -> ValidationResult:
37+
for err in super().validate(validator, keywords, instance, schema):
38+
if not err.schema:
39+
err.message = (
40+
f"Additional properties are not allowed ({err.path[0]!r} "
41+
"was unexpected)"
42+
)
43+
err.validator = "additionalProperties"
44+
yield err

0 commit comments

Comments
 (0)