diff --git a/src/resources/expected/validation_reports6.json b/src/resources/expected/validation_reports6.json index 6bf9cbbc..aeb29d9a 100644 --- a/src/resources/expected/validation_reports6.json +++ b/src/resources/expected/validation_reports6.json @@ -828,6 +828,85 @@ } ] }, + "good/functions/split_get_stack_output.yaml": { + "filePath": "good/functions/split_get_stack_output.yaml", + "status": "OK", + "metadata": { + "resourcesScanned": 3, + "counts": { + "fatal": 0, + "errors": 0, + "warnings": 0, + "informational": 3, + "debug": 0 + }, + "suppressed": 0, + "strict": false, + "severityLevel": "DEBUG" + }, + "diagnostics": [ + { + "ruleId": "I9040", + "severity": "INFO", + "message": "Resource 'Bucket' of type 'AWS::S3::Bucket' supports Tags but none are configured", + "source": "ENGINE", + "entity": { + "logicalId": "Bucket", + "entityType": "Resource", + "resourceType": "AWS::S3::Bucket" + }, + "propertyPath": "Properties.Tags", + "suggestedFix": "Add Tags to improve resource organization and cost tracking", + "category": "Best Practice", + "startLine": 6, + "startColumn": 5, + "endLine": 6, + "endColumn": 15, + "ruleDescription": "Resource should have Tags", + "phase": "LINT" + }, + { + "ruleId": "I9040", + "severity": "INFO", + "message": "Resource 'AllHeaders' of type 'AWS::SSM::Parameter' supports Tags but none are configured", + "source": "ENGINE", + "entity": { + "logicalId": "AllHeaders", + "entityType": "Resource", + "resourceType": "AWS::SSM::Parameter" + }, + "propertyPath": "Properties.Tags", + "suggestedFix": "Add Tags to improve resource organization and cost tracking", + "category": "Best Practice", + "startLine": 21, + "startColumn": 5, + "endLine": 21, + "endColumn": 15, + "ruleDescription": "Resource should have Tags", + "phase": "LINT" + }, + { + "ruleId": "I9040", + "severity": "INFO", + "message": "Resource 'FirstHeader' of type 'AWS::SSM::Parameter' supports Tags but none are configured", + "source": "ENGINE", + "entity": { + "logicalId": "FirstHeader", + "entityType": "Resource", + "resourceType": "AWS::SSM::Parameter" + }, + "propertyPath": "Properties.Tags", + "suggestedFix": "Add Tags to improve resource organization and cost tracking", + "category": "Best Practice", + "startLine": 34, + "startColumn": 5, + "endLine": 34, + "endColumn": 15, + "ruleDescription": "Resource should have Tags", + "phase": "LINT" + } + ] + }, "good/functions/sub.yaml": { "filePath": "good/functions/sub.yaml", "status": "OK", @@ -16333,44 +16412,5 @@ "phase": "LINT" } ] - }, - "good/sam/function_dlq_valid.yaml": { - "filePath": "good/sam/function_dlq_valid.yaml", - "status": "OK", - "metadata": { - "resourcesScanned": 1, - "counts": { - "fatal": 0, - "errors": 0, - "warnings": 0, - "informational": 1, - "debug": 0 - }, - "suppressed": 0, - "strict": false, - "severityLevel": "DEBUG" - }, - "diagnostics": [ - { - "ruleId": "I9040", - "severity": "INFO", - "message": "Resource 'Fn' of type 'AWS::Serverless::Function' supports Tags but none are configured", - "source": "ENGINE", - "entity": { - "logicalId": "Fn", - "entityType": "Resource", - "resourceType": "AWS::Serverless::Function" - }, - "propertyPath": "Properties.Tags", - "suggestedFix": "Add Tags to improve resource organization and cost tracking", - "category": "Best Practice", - "startLine": 5, - "startColumn": 5, - "endLine": 5, - "endColumn": 15, - "ruleDescription": "Resource should have Tags", - "phase": "LINT" - } - ] } } diff --git a/src/resources/expected/validation_reports7.json b/src/resources/expected/validation_reports7.json index e01a396e..f6b6f24f 100644 --- a/src/resources/expected/validation_reports7.json +++ b/src/resources/expected/validation_reports7.json @@ -1,4 +1,43 @@ { + "good/sam/function_dlq_valid.yaml": { + "filePath": "good/sam/function_dlq_valid.yaml", + "status": "OK", + "metadata": { + "resourcesScanned": 1, + "counts": { + "fatal": 0, + "errors": 0, + "warnings": 0, + "informational": 1, + "debug": 0 + }, + "suppressed": 0, + "strict": false, + "severityLevel": "DEBUG" + }, + "diagnostics": [ + { + "ruleId": "I9040", + "severity": "INFO", + "message": "Resource 'Fn' of type 'AWS::Serverless::Function' supports Tags but none are configured", + "source": "ENGINE", + "entity": { + "logicalId": "Fn", + "entityType": "Resource", + "resourceType": "AWS::Serverless::Function" + }, + "propertyPath": "Properties.Tags", + "suggestedFix": "Add Tags to improve resource organization and cost tracking", + "category": "Best Practice", + "startLine": 5, + "startColumn": 5, + "endLine": 5, + "endColumn": 15, + "ruleDescription": "Resource should have Tags", + "phase": "LINT" + } + ] + }, "good/sam/function_image_valid.yaml": { "filePath": "good/sam/function_image_valid.yaml", "status": "OK", @@ -39176,136 +39215,5 @@ "phase": "LINT" } ] - }, - "quickstart/openshift_master.yaml": { - "filePath": "quickstart/openshift_master.yaml", - "status": "OK", - "metadata": { - "resourcesScanned": 2, - "counts": { - "fatal": 0, - "errors": 0, - "warnings": 0, - "informational": 6, - "debug": 0 - }, - "suppressed": 0, - "strict": false, - "severityLevel": "DEBUG" - }, - "diagnostics": [ - { - "ruleId": "I3011", - "severity": "INFO", - "message": "'DeletionPolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", - "source": "CFN_LINT", - "entity": { - "logicalId": "OpenShiftStack", - "entityType": "Resource", - "resourceType": "AWS::CloudFormation::Stack" - }, - "category": "Best Practice", - "startLine": 184, - "startColumn": 3, - "endLine": 184, - "endColumn": 17, - "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", - "phase": "LINT" - }, - { - "ruleId": "I3011", - "severity": "INFO", - "message": "'UpdateReplacePolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", - "source": "CFN_LINT", - "entity": { - "logicalId": "OpenShiftStack", - "entityType": "Resource", - "resourceType": "AWS::CloudFormation::Stack" - }, - "category": "Best Practice", - "startLine": 184, - "startColumn": 3, - "endLine": 184, - "endColumn": 17, - "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", - "phase": "LINT" - }, - { - "ruleId": "I3011", - "severity": "INFO", - "message": "'DeletionPolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", - "source": "CFN_LINT", - "entity": { - "logicalId": "VPCStack", - "entityType": "Resource", - "resourceType": "AWS::CloudFormation::Stack" - }, - "category": "Best Practice", - "startLine": 242, - "startColumn": 3, - "endLine": 242, - "endColumn": 11, - "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", - "phase": "LINT" - }, - { - "ruleId": "I3011", - "severity": "INFO", - "message": "'UpdateReplacePolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", - "source": "CFN_LINT", - "entity": { - "logicalId": "VPCStack", - "entityType": "Resource", - "resourceType": "AWS::CloudFormation::Stack" - }, - "category": "Best Practice", - "startLine": 242, - "startColumn": 3, - "endLine": 242, - "endColumn": 11, - "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", - "phase": "LINT" - }, - { - "ruleId": "I9040", - "severity": "INFO", - "message": "Resource 'OpenShiftStack' of type 'AWS::CloudFormation::Stack' supports Tags but none are configured", - "source": "ENGINE", - "entity": { - "logicalId": "OpenShiftStack", - "entityType": "Resource", - "resourceType": "AWS::CloudFormation::Stack" - }, - "propertyPath": "Properties.Tags", - "suggestedFix": "Add Tags to improve resource organization and cost tracking", - "category": "Best Practice", - "startLine": 185, - "startColumn": 5, - "endLine": 185, - "endColumn": 15, - "ruleDescription": "Resource should have Tags", - "phase": "LINT" - }, - { - "ruleId": "I9040", - "severity": "INFO", - "message": "Resource 'VPCStack' of type 'AWS::CloudFormation::Stack' supports Tags but none are configured", - "source": "ENGINE", - "entity": { - "logicalId": "VPCStack", - "entityType": "Resource", - "resourceType": "AWS::CloudFormation::Stack" - }, - "propertyPath": "Properties.Tags", - "suggestedFix": "Add Tags to improve resource organization and cost tracking", - "category": "Best Practice", - "startLine": 243, - "startColumn": 5, - "endLine": 243, - "endColumn": 15, - "ruleDescription": "Resource should have Tags", - "phase": "LINT" - } - ] } } diff --git a/src/resources/expected/validation_reports8.json b/src/resources/expected/validation_reports8.json index b3b9936e..ab54b9b5 100644 --- a/src/resources/expected/validation_reports8.json +++ b/src/resources/expected/validation_reports8.json @@ -1,4 +1,135 @@ { + "quickstart/openshift_master.yaml": { + "filePath": "quickstart/openshift_master.yaml", + "status": "OK", + "metadata": { + "resourcesScanned": 2, + "counts": { + "fatal": 0, + "errors": 0, + "warnings": 0, + "informational": 6, + "debug": 0 + }, + "suppressed": 0, + "strict": false, + "severityLevel": "DEBUG" + }, + "diagnostics": [ + { + "ruleId": "I3011", + "severity": "INFO", + "message": "'DeletionPolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", + "source": "CFN_LINT", + "entity": { + "logicalId": "OpenShiftStack", + "entityType": "Resource", + "resourceType": "AWS::CloudFormation::Stack" + }, + "category": "Best Practice", + "startLine": 184, + "startColumn": 3, + "endLine": 184, + "endColumn": 17, + "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", + "phase": "LINT" + }, + { + "ruleId": "I3011", + "severity": "INFO", + "message": "'UpdateReplacePolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", + "source": "CFN_LINT", + "entity": { + "logicalId": "OpenShiftStack", + "entityType": "Resource", + "resourceType": "AWS::CloudFormation::Stack" + }, + "category": "Best Practice", + "startLine": 184, + "startColumn": 3, + "endLine": 184, + "endColumn": 17, + "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", + "phase": "LINT" + }, + { + "ruleId": "I3011", + "severity": "INFO", + "message": "'DeletionPolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", + "source": "CFN_LINT", + "entity": { + "logicalId": "VPCStack", + "entityType": "Resource", + "resourceType": "AWS::CloudFormation::Stack" + }, + "category": "Best Practice", + "startLine": 242, + "startColumn": 3, + "endLine": 242, + "endColumn": 11, + "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", + "phase": "LINT" + }, + { + "ruleId": "I3011", + "severity": "INFO", + "message": "'UpdateReplacePolicy' is a required property (The default action when replacing/removing a resource is to delete it. Set explicit values for stateful resource)", + "source": "CFN_LINT", + "entity": { + "logicalId": "VPCStack", + "entityType": "Resource", + "resourceType": "AWS::CloudFormation::Stack" + }, + "category": "Best Practice", + "startLine": 242, + "startColumn": 3, + "endLine": 242, + "endColumn": 11, + "ruleDescription": "Check stateful resources have a set UpdateReplacePolicy/DeletionPolicy", + "phase": "LINT" + }, + { + "ruleId": "I9040", + "severity": "INFO", + "message": "Resource 'OpenShiftStack' of type 'AWS::CloudFormation::Stack' supports Tags but none are configured", + "source": "ENGINE", + "entity": { + "logicalId": "OpenShiftStack", + "entityType": "Resource", + "resourceType": "AWS::CloudFormation::Stack" + }, + "propertyPath": "Properties.Tags", + "suggestedFix": "Add Tags to improve resource organization and cost tracking", + "category": "Best Practice", + "startLine": 185, + "startColumn": 5, + "endLine": 185, + "endColumn": 15, + "ruleDescription": "Resource should have Tags", + "phase": "LINT" + }, + { + "ruleId": "I9040", + "severity": "INFO", + "message": "Resource 'VPCStack' of type 'AWS::CloudFormation::Stack' supports Tags but none are configured", + "source": "ENGINE", + "entity": { + "logicalId": "VPCStack", + "entityType": "Resource", + "resourceType": "AWS::CloudFormation::Stack" + }, + "propertyPath": "Properties.Tags", + "suggestedFix": "Add Tags to improve resource organization and cost tracking", + "category": "Best Practice", + "startLine": 243, + "startColumn": 5, + "endLine": 243, + "endColumn": 15, + "ruleDescription": "Resource should have Tags", + "phase": "LINT" + } + ] + }, "quickstart/test.yaml": { "filePath": "quickstart/test.yaml", "status": "OK", diff --git a/src/resources/templates/good/functions/split_get_stack_output.yaml b/src/resources/templates/good/functions/split_get_stack_output.yaml new file mode 100644 index 00000000..89590c49 --- /dev/null +++ b/src/resources/templates/good/functions/split_get_stack_output.yaml @@ -0,0 +1,43 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: Fn::Split over Fn::GetStackOutput, the shape of a weak string-list cross-stack reference +Resources: + Bucket: + Type: AWS::S3::Bucket + Properties: + CorsConfiguration: + CorsRules: + - AllowedMethods: + - GET + AllowedOrigins: + - "*" + ExposedHeaders: + Fn::Split: + - "||" + - Fn::GetStackOutput: + StackName: producer-stack + OutputName: ExportedHeaders + AllHeaders: + Type: AWS::SSM::Parameter + Properties: + Type: StringList + Value: + Fn::Join: + - "," + - Fn::Split: + - "||" + - Fn::GetStackOutput: + StackName: producer-stack + Region: us-east-1 + OutputName: ExportedHeaders + FirstHeader: + Type: AWS::SSM::Parameter + Properties: + Type: String + Value: + Fn::Select: + - 0 + - Fn::Split: + - "||" + - Fn::GetStackOutput: + StackName: producer-stack + OutputName: ExportedHeaders diff --git a/src/template-model/src/intrinsic_arg_shapes.rs b/src/template-model/src/intrinsic_arg_shapes.rs index 20efd8e1..c1e292d9 100644 --- a/src/template-model/src/intrinsic_arg_shapes.rs +++ b/src/template-model/src/intrinsic_arg_shapes.rs @@ -17,8 +17,19 @@ const SELECT_SOURCE_FUNCTIONS: &[&str] = &[FN_FIND_IN_MAP, FN_GET_ATT, FN_GET_AZ const SELECT_INDEX_FUNCTIONS: &[&str] = &[FN_REF, FN_FIND_IN_MAP]; const SELECT_INDEX_FUNCTIONS_EXT: &[&str] = &[FN_REF, FN_FIND_IN_MAP, FN_LENGTH]; -const SPLIT_SOURCE_FUNCTIONS: &[&str] = - &[FN_BASE64, FN_FIND_IN_MAP, FN_GET_ATT, FN_GET_AZS, FN_IF, FN_IMPORT_VALUE, FN_JOIN, FN_SELECT, FN_SUB, FN_REF]; +const SPLIT_SOURCE_FUNCTIONS: &[&str] = &[ + FN_BASE64, + FN_FIND_IN_MAP, + FN_GET_ATT, + FN_GET_AZS, + FN_GET_STACK_OUTPUT, + FN_IF, + FN_IMPORT_VALUE, + FN_JOIN, + FN_SELECT, + FN_SUB, + FN_REF, +]; const SUB_VARIABLE_FUNCTIONS: &[&str] = &[ FN_BASE64, @@ -302,6 +313,21 @@ mod tests { assert!(validate_intrinsic_arg_shapes(&arena, &[]).is_empty()); } + #[test] + fn split_source_get_stack_output_is_allowed() { + let mut arena = Arena::new(); + let delimiter = alloc_string(&mut arena, "||"); + let stack_name = alloc_string(&mut arena, "producer-stack"); + let output_name = alloc_string(&mut arena, "ExportedList"); + let source = alloc_intrinsic( + &mut arena, + IntrinsicFn::GetStackOutput(vec![("StackName".into(), stack_name), ("OutputName".into(), output_name)]), + ); + alloc_intrinsic(&mut arena, IntrinsicFn::Split(delimiter, source)); + + assert!(validate_intrinsic_arg_shapes(&arena, &[]).is_empty()); + } + #[test] fn sub_variable_cidr_fires() { let mut arena = Arena::new();