aws-cloudformation / aws-cloudformation/cloudformation-guard
Error messages need to be set for each check
- Dominant language
- Rust
- Stars
- 1.4k
- Forks
- 196
- Avg merge
- 3d 6h
- Merged PRs (30d)
- 5
Description
### What is the problem?
When writing a rule, any error message needs to be applied to _every_ check.
So for example the [s3_bucket_versioning_enabled](https://github.com/aws-cloudformation/aws-guard-rules-registry/blob/main/rules/aws/amazon_s3/s3_bucket_versioning_enabled.guard) rule is written like this:
```
rule S3_BUCKET_VERSIONING_ENABLED when %s3_buckets_versioning_enabled !empty {
%s3_buckets_versioning_enabled.Properties.VersioningConfiguration exists
%s3_buckets_versioning_enabled.Properties.VersioningConfiguration.Status == 'Enabled'
<<
Violation: S3 Bucket Versioning must be enabled.
Fix: Set the S3 Bucket property VersioningConfiguration.Status to 'Enabled' .
>>
}
```
The custom message there will only be shown in the JSON response for the `%s3_buckets_versioning_enabled.Properties.VersioningConfiguration.Status == 'Enabled'` check. If it fails at the `exists` check then the error message won't be shown.
### Reproduction Steps
template
```json
{
"Resources": {
"MyBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {}
}
}
```
rule [s3_bucket_versioning_enabled](https://github.com/aws-cloudformation/aws-guard-rules-registry/blob/main/rules/aws/amazon_s3/s3_bucket_versioning_enabled.guard)
```
rule S3_BUCKET_VERSIONING_ENABLED when %s3_buckets_versioning_enabled !empty {
%s3_buckets_versioning_enabled.Properties.VersioningConfiguration exists
%s3_buckets_versioning_enabled.Properties.VersioningConfiguration.Status == 'Enabled'
<<
Violation: S3 Bucket Versioning must be enabled.
Fix: Set the S3 Bucket property VersioningConfiguration.Status to 'Enabled' .
>>
}
```
cfn-guard validate --data path/to/template --rules /path/to/rule
### What did you expect to happen?
I would expect the output for each check to contain the custom error message.
### What actually happened?
```json
{
"name": "",
"metadata": {},
"status": "FAIL",
"not_compliant": [
{
"Rule": {
"name": "S3_BUCKET_VERSIONING_ENABLED",
"metadata": {},
"messages": {
"custom_message": null,
"error_message": null
},
"checks": [
{
"Clause": {
"Unary": {
"context": " %s3_buckets_versioning_enabled[*].Properties.VersioningConfiguration EXISTS ",
"messages": {
"custom_message": "",
"error_message": "Check was not compliant as property [VersioningConfiguration] is missing. Value traversed to [Path=/Resources/MyConstructBucketA5944A03/Properties[L:4,C:17] Value={\"PublicAccessBlockConfiguration\":{\"BlockPublicAcls\":false,\"BlockPublicPolicy\":false,\"IgnorePublicAcls\":false,\"RestrictPublicBuckets\":false}}]."
},
"check": {
"UnResolved": {
"value": {
"traversed_to": {
"path": "/Resources/MyConstructBucketA5944A03/Properties",
"value": {
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": false,
"BlockPublicPolicy": false,
"IgnorePublicAcls": false,
"RestrictPublicBuckets": false
}
}
},
"remaining_query": "VersioningConfiguration",
"reason": "Could not find key VersioningConfiguration inside struct at path /Resources/MyConstructBucketA5944A03/Properties[L:4,C:17]"
},
"comparison": [
"Exists",
false
]
}
}
}
}
},
{
"Clause": {
"Binary": {
"context": " %s3_buckets_versioning_enabled[*].Properties.VersioningConfiguration.Status EQUALS \"Enabled\"",
"messages": {
"custom_message": "; Violation: S3 Bucket Versioning must be enabled.; Fix: Set the S3 Bucket property VersioningConfiguration.Status to 'Enabled' .; ",
"error_message": "Check was not compliant as property [VersioningConfiguration.Status] to compare from is missing. Value traversed to [Path=/Resources/MyConstructBucketA5944A03/Properties[L:4,C:17] Value={\"PublicAccessBlockConfiguration\":{\"BlockPublicAcls\":false,\"BlockPublicPolicy\":false,\"IgnorePublicAcls\":false,\"RestrictPublicBuckets\":false}}]."
},
"check": {
"UnResolved": {
"value": {
"traversed_to": {
"path": "/Resources/MyConstructBucketA5944A03/Properties",
"value": {
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": false,
"BlockPublicPolicy": false,
"IgnorePublicAcls": false,
"RestrictPublicBuckets": false
}
}
},
"remaining_query": "VersioningConfiguration.Status",
"reason": "Could not find key VersioningConfiguration inside struct at path /Resources/MyConstructBucketA5944A03/Properties[L:4,C:17]"
},
"comparison": [
"Eq",
false
]
}
}
}
}
}
]
}
}
],
"not_applicable": [],
"compliant": []
}
```
### CloudFormation Guard Version
2.1.3
### OS
Ubuntu
### OS Version
_No response_
### Other information
One solution is to wrap all the checks inside a rule check (example from [Control Tower rules](https://docs.aws.amazon.com/controltower/latest/userguide/s3-rules.html#ct-s3-pr-3-description))
```
rule s3_version_lifecycle_policy_check %s3_buckets not empty {
check(%s3_buckets.Properties)
<<
[CT.S3.PR.3]: Require an Amazon S3 buckets to have versioning configured and a lifecycle policy
[FIX]: Configure versioning-enabled buckets with at least one active lifecycle rule.
>>
}
rule check(s3_bucket) {
%s3_bucket {
VersioningConfiguration exists
VersioningConfiguration is_struct
VersioningConfiguration {
Status exists
Status == "Enabled"
}
}
}
```
Contributor guide
Research direction
Start with the reproduction using the linked s3_bucket_versioning_enabled.guard rule and the supplied JSON template, then trace how rule checks receive custom messages during validation. Done means each failed check in the JSON response contains the rule's custom error message, including when an earlier exists check fails.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100