aws-cloudformation / aws-cloudformation/cloudformation-guard

Error messages need to be set for each check

Open
#355 3 comments 0 reactions 0 assignees View on GitHub
enhancement
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.