github.com/aquasecurity/trivy-iac@v0.8.1-0.20240127024015-3d8e412cf0ab/pkg/scanners/terraform/scanner_integration_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "testing" 8 9 "github.com/aquasecurity/defsec/pkg/scanners/options" 10 "github.com/aquasecurity/trivy-iac/test/testutil" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func Test_ScanRemoteModule(t *testing.T) { 16 if testing.Short() { 17 t.Skip("skipping integration test in short mode") 18 } 19 fs := testutil.CreateFS(t, map[string]string{ 20 "main.tf": ` 21 module "s3_bucket" { 22 source = "terraform-aws-modules/s3-bucket/aws" 23 24 bucket = "my-s3-bucket" 25 } 26 `, 27 "/rules/bucket_name.rego": ` 28 # METADATA 29 # schemas: 30 # - input: schema.input 31 # custom: 32 # avd_id: AVD-AWS-0001 33 # input: 34 # selector: 35 # - type: cloud 36 # subtypes: 37 # - service: s3 38 # provider: aws 39 package defsec.test.aws1 40 deny[res] { 41 bucket := input.aws.s3.buckets[_] 42 bucket.name.value == "" 43 res := result.new("The name of the bucket must not be empty", bucket) 44 }`, 45 }) 46 47 debugLog := bytes.NewBuffer([]byte{}) 48 49 scanner := New( 50 options.ScannerWithDebug(debugLog), 51 options.ScannerWithPolicyFilesystem(fs), 52 options.ScannerWithPolicyDirs("rules"), 53 options.ScannerWithEmbeddedPolicies(false), 54 options.ScannerWithEmbeddedLibraries(false), 55 options.ScannerWithRegoOnly(true), 56 ScannerWithAllDirectories(true), 57 ScannerWithSkipCachedModules(true), 58 ) 59 60 results, err := scanner.ScanFS(context.TODO(), fs, ".") 61 require.NoError(t, err) 62 63 assert.Len(t, results.GetPassed(), 1) 64 65 if t.Failed() { 66 fmt.Printf("Debug logs:\n%s\n", debugLog.String()) 67 } 68 } 69 70 func Test_ScanChildUseRemoteModule(t *testing.T) { 71 if testing.Short() { 72 t.Skip("skipping integration test in short mode") 73 } 74 fs := testutil.CreateFS(t, map[string]string{ 75 "main.tf": ` 76 module "this" { 77 source = "./modules/s3" 78 bucket = "my-s3-bucket" 79 } 80 `, 81 "modules/s3/main.tf": ` 82 variable "bucket" { 83 type = string 84 } 85 86 module "s3_bucket" { 87 source = "github.com/terraform-aws-modules/terraform-aws-s3-bucket?ref=v3.15.1" 88 bucket = var.bucket 89 } 90 `, 91 "rules/bucket_name.rego": ` 92 # METADATA 93 # schemas: 94 # - input: schema.input 95 # custom: 96 # avd_id: AVD-AWS-0001 97 # input: 98 # selector: 99 # - type: cloud 100 # subtypes: 101 # - service: s3 102 # provider: aws 103 package defsec.test.aws1 104 deny[res] { 105 bucket := input.aws.s3.buckets[_] 106 bucket.name.value == "" 107 res := result.new("The name of the bucket must not be empty", bucket) 108 }`, 109 }) 110 111 debugLog := bytes.NewBuffer([]byte{}) 112 113 scanner := New( 114 options.ScannerWithDebug(debugLog), 115 options.ScannerWithPolicyFilesystem(fs), 116 options.ScannerWithPolicyDirs("rules"), 117 options.ScannerWithEmbeddedPolicies(false), 118 options.ScannerWithEmbeddedLibraries(false), 119 options.ScannerWithRegoOnly(true), 120 ScannerWithAllDirectories(true), 121 ScannerWithSkipCachedModules(true), 122 ) 123 124 results, err := scanner.ScanFS(context.TODO(), fs, ".") 125 require.NoError(t, err) 126 127 assert.Len(t, results.GetPassed(), 1) 128 129 if t.Failed() { 130 fmt.Printf("Debug logs:\n%s\n", debugLog.String()) 131 } 132 } 133 134 func Test_OptionWithSkipDownloaded(t *testing.T) { 135 if testing.Short() { 136 t.Skip("skipping integration test in short mode") 137 } 138 139 fs := testutil.CreateFS(t, map[string]string{ 140 "test/main.tf": ` 141 module "s3-bucket" { 142 source = "terraform-aws-modules/s3-bucket/aws" 143 version = "3.14.0" 144 bucket = "mybucket" 145 create_bucket = true 146 } 147 `, 148 // creating our own rule for the reliability of the test 149 "/rules/test.rego": ` 150 package defsec.abcdefg 151 152 __rego_input__ := { 153 "combine": false, 154 "selector": [{"type": "defsec", "subtypes": [{"service": "s3", "provider": "aws"}]}], 155 } 156 157 deny[cause] { 158 bucket := input.aws.s3.buckets[_] 159 bucket.name.value == "mybucket" 160 cause := bucket.name 161 }`, 162 }) 163 164 t.Run("without skip", func(t *testing.T) { 165 scanner := New( 166 options.ScannerWithPolicyDirs("rules"), 167 options.ScannerWithRegoOnly(true), 168 options.ScannerWithEmbeddedPolicies(false), 169 options.ScannerWithEmbeddedLibraries(true), 170 ) 171 results, err := scanner.ScanFS(context.TODO(), fs, "test") 172 require.NoError(t, err) 173 174 assert.Len(t, results, 1) 175 assert.Len(t, results.GetFailed(), 1) 176 }) 177 178 t.Run("with skip", func(t *testing.T) { 179 scanner := New( 180 ScannerWithSkipDownloaded(true), 181 options.ScannerWithPolicyDirs("rules"), 182 options.ScannerWithRegoOnly(true), 183 options.ScannerWithEmbeddedPolicies(false), 184 options.ScannerWithEmbeddedLibraries(true), 185 ) 186 results, err := scanner.ScanFS(context.TODO(), fs, "test") 187 require.NoError(t, err) 188 189 assert.Len(t, results, 1) 190 assert.Len(t, results.GetIgnored(), 1) 191 }) 192 } 193 194 func Test_OptionWithSkipDownloadedIAMDocument(t *testing.T) { 195 if testing.Short() { 196 t.Skip("skipping integration test in short mode") 197 } 198 199 fs := testutil.CreateFS(t, map[string]string{ 200 "test/main.tf": ` 201 module "karpenter" { 202 source = "terraform-aws-modules/eks/aws//modules/karpenter" 203 version = "19.21.0" 204 205 cluster_name = "test" 206 irsa_oidc_provider_arn = "example" 207 } 208 `, 209 // creating our own rule for the reliability of the test 210 "/rules/test.rego": ` 211 package defsec.abcdefg 212 213 __rego_input__ := { 214 "combine": false, 215 "selector": [{"type": "defsec", "subtypes": [{"service": "iam", "provider": "aws"}]}], 216 } 217 218 allows_permission(statements, permission, effect) { 219 statement := statements[_] 220 statement.Effect == effect 221 action = statement.Action[_] 222 action == permission 223 } 224 225 deny[res] { 226 policy := input.aws.iam.policies[_] 227 value = json.unmarshal(policy.document.value) 228 statements = value.Statement 229 not allows_permission(statements, "iam:PassRole", "Deny") 230 allows_permission(statements, "iam:PassRole", "Allow") 231 res = result.new("IAM policy allows 'iam:PassRole' action", policy.document) 232 } 233 `, 234 }) 235 236 scanner := New( 237 ScannerWithSkipDownloaded(true), 238 options.ScannerWithPolicyDirs("rules"), 239 options.ScannerWithRegoOnly(true), 240 options.ScannerWithEmbeddedLibraries(true), 241 options.ScannerWithEmbeddedPolicies(false), 242 ) 243 results, err := scanner.ScanFS(context.TODO(), fs, "test") 244 require.NoError(t, err) 245 assert.Len(t, results, 1) 246 247 ignored := results.GetIgnored() 248 assert.Len(t, ignored, 1) 249 assert.NotNil(t, ignored[0].Metadata().Parent()) 250 }