github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/cloudformation/parser/parser_test.go (about)

     1  package parser
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func parseFile(t *testing.T, source string, name string) (FileContexts, error) {
    14  	tmp, err := os.MkdirTemp(os.TempDir(), "defsec")
    15  	require.NoError(t, err)
    16  	defer func() { _ = os.RemoveAll(tmp) }()
    17  	require.NoError(t, os.WriteFile(filepath.Join(tmp, name), []byte(source), 0600))
    18  	fs := os.DirFS(tmp)
    19  	return New().ParseFS(context.TODO(), fs, ".")
    20  }
    21  
    22  func Test_parse_yaml(t *testing.T) {
    23  
    24  	source := `---
    25  Parameters:
    26    BucketName: 
    27      Type: String
    28      Default: naughty
    29    EncryptBucket:
    30      Type: Boolean
    31      Default: false
    32  Resources:
    33    S3Bucket:
    34      Type: 'AWS::S3::Bucket'
    35      Properties:
    36        BucketName: naughty
    37        BucketEncryption:
    38          ServerSideEncryptionConfiguration:
    39          - BucketKeyEnabled: 
    40              Ref: EncryptBucket`
    41  
    42  	files, err := parseFile(t, source, "cf.yaml")
    43  	require.NoError(t, err)
    44  	assert.Len(t, files, 1)
    45  	file := files[0]
    46  
    47  	assert.Len(t, file.Resources, 1)
    48  	assert.Len(t, file.Parameters, 2)
    49  
    50  	bucket, ok := file.Resources["S3Bucket"]
    51  	require.True(t, ok, "S3Bucket resource should be available")
    52  	assert.Equal(t, "cf.yaml", bucket.Range().GetFilename())
    53  	assert.Equal(t, 10, bucket.Range().GetStartLine())
    54  	assert.Equal(t, 17, bucket.Range().GetEndLine())
    55  }
    56  
    57  func Test_parse_json(t *testing.T) {
    58  	source := `{
    59    "Parameters": {
    60      "BucketName": {
    61        "Type": "String",
    62        "Default": "naughty"
    63      },
    64      "BucketKeyEnabled": {
    65        "Type": "Boolean",
    66        "Default": false
    67      }
    68    },
    69    "Resources": {
    70      "S3Bucket": {
    71        "Type": "AWS::S3::Bucket",
    72        "properties": {
    73          "BucketName": {
    74            "Ref": "BucketName"
    75          },
    76          "BucketEncryption": {
    77            "ServerSideEncryptionConfiguration": [
    78              {
    79                "BucketKeyEnabled": {
    80                    "Ref": "BucketKeyEnabled"
    81                }
    82              }
    83            ]
    84          }
    85        }
    86      }
    87    }
    88  }
    89  `
    90  
    91  	files, err := parseFile(t, source, "cf.json")
    92  	require.NoError(t, err)
    93  	assert.Len(t, files, 1)
    94  	file := files[0]
    95  
    96  	assert.Len(t, file.Resources, 1)
    97  	assert.Len(t, file.Parameters, 2)
    98  }
    99  
   100  func Test_parse_yaml_with_map_ref(t *testing.T) {
   101  
   102  	source := `---
   103  Parameters:
   104    BucketName: 
   105      Type: String
   106      Default: referencedBucket
   107    EncryptBucket:
   108      Type: Boolean
   109      Default: false
   110  Resources:
   111    S3Bucket:
   112      Type: 'AWS::S3::Bucket'
   113      Properties:
   114        BucketName:
   115          Ref: BucketName
   116        BucketEncryption:
   117          ServerSideEncryptionConfiguration:
   118          - BucketKeyEnabled: 
   119              Ref: EncryptBucket`
   120  
   121  	files, err := parseFile(t, source, "cf.yaml")
   122  	require.NoError(t, err)
   123  	assert.Len(t, files, 1)
   124  	file := files[0]
   125  
   126  	assert.Len(t, file.Resources, 1)
   127  	assert.Len(t, file.Parameters, 2)
   128  
   129  	res := file.GetResourceByLogicalID("S3Bucket")
   130  	assert.NotNil(t, res)
   131  
   132  	refProp := res.GetProperty("BucketName")
   133  	assert.False(t, refProp.IsNil())
   134  	assert.Equal(t, "referencedBucket", refProp.AsString())
   135  }
   136  
   137  func Test_parse_yaml_with_intrinsic_functions(t *testing.T) {
   138  
   139  	source := `---
   140  Parameters:
   141    BucketName: 
   142      Type: String
   143      Default: somebucket
   144    EncryptBucket:
   145      Type: Boolean
   146      Default: false
   147  Resources:
   148    S3Bucket:
   149      Type: 'AWS::S3::Bucket'
   150      Properties:
   151        BucketName: !Ref BucketName
   152        BucketEncryption:
   153          ServerSideEncryptionConfiguration:
   154          - BucketKeyEnabled: false
   155  `
   156  
   157  	files, err := parseFile(t, source, "cf.yaml")
   158  	require.NoError(t, err)
   159  	assert.Len(t, files, 1)
   160  	ctx := files[0]
   161  
   162  	assert.Len(t, ctx.Resources, 1)
   163  	assert.Len(t, ctx.Parameters, 2)
   164  
   165  	res := ctx.GetResourceByLogicalID("S3Bucket")
   166  	assert.NotNil(t, res)
   167  
   168  	refProp := res.GetProperty("BucketName")
   169  	assert.False(t, refProp.IsNil())
   170  	assert.Equal(t, "somebucket", refProp.AsString())
   171  }
   172  
   173  func createTestFileContext(t *testing.T, source string) *FileContext {
   174  	contexts, err := parseFile(t, source, "main.yaml")
   175  	require.NoError(t, err)
   176  	require.Len(t, contexts, 1)
   177  	return contexts[0]
   178  }
   179  
   180  func Test_parse_yaml_use_condition_in_resource(t *testing.T) {
   181  	source := `---
   182  AWSTemplateFormatVersion: "2010-09-09"
   183  Description: some description
   184  Parameters:
   185    ServiceName:
   186      Type: String
   187      Description: The service name
   188    EnvName:
   189      Type: String
   190      Description: Optional environment name to prefix all resources with
   191      Default: ""
   192  
   193  Conditions:
   194    SuffixResources: !Not [!Equals [!Ref EnvName, ""]]
   195  
   196  Resources:
   197    ErrorTimedOutMetricFilter:
   198      Type: AWS::Logs::MetricFilter
   199      Properties:
   200        FilterPattern: '?ERROR ?error ?Error ?"timed out"' # If log contains one of these error words or timed out
   201        LogGroupName:
   202          !If [
   203            SuffixResources,
   204            !Sub "/aws/lambda/${ServiceName}-${EnvName}",
   205            !Sub "/aws/lambda/${ServiceName}",
   206          ]
   207        MetricTransformations:
   208          - MetricName: !Sub "${ServiceName}-ErrorLogCount"
   209            MetricNamespace: market-LogMetrics
   210            MetricValue: 1
   211            DefaultValue: 0
   212  `
   213  
   214  	files, err := parseFile(t, source, "cf.yaml")
   215  	require.NoError(t, err)
   216  	assert.Len(t, files, 1)
   217  	ctx := files[0]
   218  
   219  	assert.Len(t, ctx.Parameters, 2)
   220  	assert.Len(t, ctx.Conditions, 1)
   221  	assert.Len(t, ctx.Resources, 1)
   222  
   223  	res := ctx.GetResourceByLogicalID("ErrorTimedOutMetricFilter")
   224  	assert.NotNil(t, res)
   225  
   226  	refProp := res.GetProperty("LogGroupName")
   227  	assert.False(t, refProp.IsNil())
   228  	assert.Equal(t, "/aws/lambda/${ServiceName}", refProp.AsString())
   229  }