diff --git a/pkg/scanners/cloudformation/parser/fn_ref.go b/pkg/scanners/cloudformation/parser/fn_ref.go index 98e911787..77ffddd8f 100644 --- a/pkg/scanners/cloudformation/parser/fn_ref.go +++ b/pkg/scanners/cloudformation/parser/fn_ref.go @@ -19,6 +19,10 @@ func ResolveReference(property *Property) (resolved *Property, success bool) { return property.deriveResolved(cftypes.String, pseudo.(string)), true } + if property.ctx == nil { + return property, false + } + var param *Parameter for k := range property.ctx.Parameters { if k == refValue { diff --git a/pkg/scanners/cloudformation/parser/parser.go b/pkg/scanners/cloudformation/parser/parser.go index b00c35ada..ccbb5a4c3 100644 --- a/pkg/scanners/cloudformation/parser/parser.go +++ b/pkg/scanners/cloudformation/parser/parser.go @@ -145,6 +145,11 @@ func (p *Parser) ParseFile(ctx context.Context, fs fs.FS, path string) (context p.debug.Log("Context loaded from source %s", path) + // the context must be set to conditions before resources + for _, c := range context.Conditions { + c.setContext(context) + } + for name, r := range context.Resources { r.ConfigureResource(name, fs, path, context) } diff --git a/pkg/scanners/cloudformation/parser/parser_test.go b/pkg/scanners/cloudformation/parser/parser_test.go index f630c199c..26da3a7a8 100644 --- a/pkg/scanners/cloudformation/parser/parser_test.go +++ b/pkg/scanners/cloudformation/parser/parser_test.go @@ -176,3 +176,54 @@ func createTestFileContext(t *testing.T, source string) *FileContext { require.Len(t, contexts, 1) return contexts[0] } + +func Test_parse_yaml_use_condition_in_resource(t *testing.T) { + source := `--- +AWSTemplateFormatVersion: "2010-09-09" +Description: some description +Parameters: + ServiceName: + Type: String + Description: The service name + EnvName: + Type: String + Description: Optional environment name to prefix all resources with + Default: "" + +Conditions: + SuffixResources: !Not [!Equals [!Ref EnvName, ""]] + +Resources: + ErrorTimedOutMetricFilter: + Type: AWS::Logs::MetricFilter + Properties: + FilterPattern: '?ERROR ?error ?Error ?"timed out"' # If log contains one of these error words or timed out + LogGroupName: + !If [ + SuffixResources, + !Sub "/aws/lambda/${ServiceName}-${EnvName}", + !Sub "/aws/lambda/${ServiceName}", + ] + MetricTransformations: + - MetricName: !Sub "${ServiceName}-ErrorLogCount" + MetricNamespace: market-LogMetrics + MetricValue: 1 + DefaultValue: 0 +` + + files, err := parseFile(t, source, "cf.yaml") + require.NoError(t, err) + assert.Len(t, files, 1) + ctx := files[0] + + assert.Len(t, ctx.Parameters, 2) + assert.Len(t, ctx.Conditions, 1) + assert.Len(t, ctx.Resources, 1) + + res := ctx.GetResourceByLogicalID("ErrorTimedOutMetricFilter") + assert.NotNil(t, res) + + refProp := res.GetProperty("LogGroupName") + assert.False(t, refProp.IsNil()) + assert.Equal(t, "/aws/lambda/${ServiceName}", refProp.AsString()) +}