diff --git a/src/cli/commands/test/iac-local-execution/assert-iac-options-flag.ts b/src/cli/commands/test/iac-local-execution/assert-iac-options-flag.ts index d60efd7b7f9..c9ef97a4e7c 100644 --- a/src/cli/commands/test/iac-local-execution/assert-iac-options-flag.ts +++ b/src/cli/commands/test/iac-local-execution/assert-iac-options-flag.ts @@ -22,6 +22,10 @@ const keys: (keyof IaCTestFlags)[] = [ 'quiet', 'scan', 'legacy', + + // PolicyOptions + 'ignore-policy', + 'policy-path', ]; const allowed = new Set(keys); diff --git a/src/cli/commands/test/iac-local-execution/index.ts b/src/cli/commands/test/iac-local-execution/index.ts index 3eaa1dce30d..7c9956e1f50 100644 --- a/src/cli/commands/test/iac-local-execution/index.ts +++ b/src/cli/commands/test/iac-local-execution/index.ts @@ -9,6 +9,7 @@ import { } from './types'; import { addIacAnalytics } from './analytics'; import { TestLimitReachedError } from './usage-tracking'; +import { filterIgnoredIssues } from './policy'; import { TestResult } from '../../../../lib/snyk-test/legacy'; import { initLocalCache, @@ -24,6 +25,7 @@ import { import { isFeatureFlagSupportedForOrg } from '../../../../lib/feature-flags'; import { FlagError } from './assert-iac-options-flag'; import config = require('../../../../lib/config'); +import { findAndLoadPolicy } from '../../../../lib/policy/find-and-load-policy'; // this method executes the local processing engine and then formats the results to adapt with the CLI output. // this flow is the default GA flow for IAC scanning. @@ -38,6 +40,8 @@ export async function test( await initLocalCache({ customRulesPath }); + const policy = await findAndLoadPolicy(pathToScan, 'iac', options); + const filesToParse = await loadFiles(pathToScan, options); const { parsedFiles, failedFiles } = await parseFiles( filesToParse, @@ -65,8 +69,10 @@ export async function test( iacOrgSettings.meta, ); + const filteredResults = filterIgnoredIssues(policy, formattedResults); + try { - await trackUsage(formattedResults); + await trackUsage(filteredResults); } catch (e) { if (e instanceof TestLimitReachedError) { throw e; @@ -75,11 +81,11 @@ export async function test( // run their tests by squashing the error. } - addIacAnalytics(formattedResults); + addIacAnalytics(filteredResults); // TODO: add support for proper typing of old TestResult interface. return { - results: (formattedResults as unknown) as TestResult[], + results: (filteredResults as unknown) as TestResult[], // NOTE: No file or parsed file data should leave this function. failures: isLocalFolder(pathToScan) ? failedFiles.map(removeFileContent) diff --git a/src/cli/commands/test/iac-local-execution/policy.ts b/src/cli/commands/test/iac-local-execution/policy.ts new file mode 100644 index 00000000000..f96952f3637 --- /dev/null +++ b/src/cli/commands/test/iac-local-execution/policy.ts @@ -0,0 +1,87 @@ +import { FormattedResult, PolicyMetadata } from './types'; +import { Policy } from '../../../../lib/policy/find-and-load-policy'; + +export function filterIgnoredIssues( + policy: Policy | undefined, + results: FormattedResult[], +): FormattedResult[] { + if (!policy) { + return results; + } + return results + .map((res) => policy.filter(toIaCVulnAdapter(res))) + .map((vuln) => toFormattedResult(vuln)); +} + +type IacVulnAdapter = { + vulnerabilities: { + id: string; + from: string[]; + }[]; + originalResult: FormattedResult; +}; + +// This is a total cop-out. The type I really want is AnnotatedIacIssue from +// src/lib/snyk-test/iac-test-result.ts, but that appears to only be used in the +// legacy flow and I gave up on adapting it to work in both flows. By the time +// this code is called, cloudConfigPath is present on the result object. +type AnnotatedResult = PolicyMetadata & { + cloudConfigPath: string[]; +}; + +function toIaCVulnAdapter(result: FormattedResult): IacVulnAdapter { + return { + vulnerabilities: result.result.cloudConfigResults.map( + (cloudConfigResult) => { + const annotatedResult = cloudConfigResult as AnnotatedResult; + + // Copy the cloudConfigPath array to avoid modifying the original with + // splice. + // Insert the targetFile into the path so that it is taken into account + // when determining whether an ignore rule should be applied. + // Insert garbage into the first element because the policy library + // ignores it. + const path = [...annotatedResult.cloudConfigPath]; + path.splice(0, 0, 'GARBAGE', result.targetFile); + + return { + id: cloudConfigResult.id, + from: path, + }; + }, + ), + originalResult: result, + }; +} + +function toFormattedResult(adapter: IacVulnAdapter): FormattedResult { + const original = adapter.originalResult; + const filteredCloudConfigResults = original.result.cloudConfigResults.filter( + (res) => { + return adapter.vulnerabilities.some((vuln) => { + if (vuln.id !== res.id) { + return false; + } + + // Unfortunately we are forced to duplicate the logic in + // toIaCVulnAdapter so that we're comparing path components properly, + // including target file context. As that logic changes, so must this. + const annotatedResult = res as AnnotatedResult; + const significantPath = [...annotatedResult.cloudConfigPath]; + significantPath.splice(0, 0, 'GARBAGE', original.targetFile); + + if (vuln.from.length !== significantPath.length) { + return false; + } + for (let i = 0; i < vuln.from.length; i++) { + if (vuln.from[i] !== significantPath[i]) { + return false; + } + } + return true; + }); + }, + ); + original.result.cloudConfigResults = filteredCloudConfigResults; + return original; +} diff --git a/src/cli/commands/test/iac-local-execution/types.ts b/src/cli/commands/test/iac-local-execution/types.ts index a2cb35511c1..74abe825c94 100644 --- a/src/cli/commands/test/iac-local-execution/types.ts +++ b/src/cli/commands/test/iac-local-execution/types.ts @@ -9,6 +9,7 @@ import { IacFileInDirectory, Options, TestOptions, + PolicyOptions, } from '../../../../lib/types'; export interface IacFileData extends IacFileInDirectory { @@ -117,7 +118,7 @@ export interface PolicyMetadata { // Collection of all options supported by `iac test` command. // TODO: Needs to be fixed at the args module level. export type IaCTestFlags = Pick< - Options & TestOptions, + Options & TestOptions & PolicyOptions, | 'org' | 'insecure' | 'debug' @@ -126,6 +127,10 @@ export type IaCTestFlags = Pick< | 'severityThreshold' | 'json' | 'sarif' + + // PolicyOptions + | 'ignore-policy' + | 'policy-path' > & { // Supported flags not yet covered by Options or TestOptions 'json-file-output'?: string; diff --git a/src/lib/policy/find-and-load-policy.ts b/src/lib/policy/find-and-load-policy.ts index 4e8727769c1..0de740f6c28 100644 --- a/src/lib/policy/find-and-load-policy.ts +++ b/src/lib/policy/find-and-load-policy.ts @@ -11,11 +11,11 @@ const debug = debugModule('snyk'); export async function findAndLoadPolicy( root: string, - scanType: SupportedPackageManagers | 'docker', + scanType: SupportedPackageManagers | 'docker' | 'iac', options: PolicyOptions, pkg?: PackageExpanded, scannedProjectFolder?: string, -): Promise { +): Promise { const isDocker = scanType === 'docker'; const isNodeProject = ['npm', 'yarn'].includes(scanType); // monitor @@ -43,9 +43,13 @@ export async function findAndLoadPolicy( } catch (err) { // note: inline catch, to handle error from .load // if the .snyk file wasn't found, it is fine - if (err.code !== 'ENOENT') { + if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { throw err; } } return policy; } + +export interface Policy { + filter(vulns: any): any; +} diff --git a/test/jest/acceptance/iac/custom-rules.spec.ts b/test/jest/acceptance/iac/custom-rules.spec.ts index a3935eac88b..ef226cda751 100644 --- a/test/jest/acceptance/iac/custom-rules.spec.ts +++ b/test/jest/acceptance/iac/custom-rules.spec.ts @@ -22,12 +22,12 @@ describe('iac test --rules', () => { ); expect(exitCode).toBe(1); - expect(stdout).toContain('Testing sg_open_ssh.tf'); + expect(stdout).toContain('Testing ./iac/terraform/sg_open_ssh.tf'); expect(stdout).toContain('Infrastructure as code issues:'); expect(stdout).toContain('Missing tags'); expect(stdout).toContain('CUSTOM-123'); expect(stdout).toContain( - 'introduced by resource > aws_security_group[allow_ssh] > tags', + 'introduced by input > resource > aws_security_group[allow_ssh] > tags', ); }); diff --git a/test/jest/unit/iac-unit-tests/fixtures/formatted-results.json b/test/jest/unit/iac-unit-tests/fixtures/formatted-results.json new file mode 100644 index 00000000000..adef8ceeef4 --- /dev/null +++ b/test/jest/unit/iac-unit-tests/fixtures/formatted-results.json @@ -0,0 +1,827 @@ +[ + { + "result": { + "cloudConfigResults": [ + { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[denied].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[denied]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + { + "severity": "high", + "resolve": "Remove secret value from `user_data` attribute", + "id": "SNYK-CC-TF-123", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "msg": "resource.aws_instance[denied_2].user_data_base64[aws_access_key_id]", + "remediation": { + "cloudformation": "Remove secret value from `Properties.UserData` attribute", + "terraform": "Remove secret value from `user_data` attribute" + }, + "subType": "EC2", + "issue": "Secret keys have been hardcoded in user_data script", + "publicId": "SNYK-CC-TF-123", + "title": "Hard coded secrets in EC2 metadata", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html" + ], + "name": "Hard coded secrets in EC2 metadata", + "cloudConfigPath": [ + "resource", + "aws_instance[denied_2]", + "user_data_base64[aws_access_key_id]" + ], + "isIgnored": false, + "iacDescription": { + "issue": "Secret keys have been hardcoded in user_data script", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "resolve": "Remove secret value from `user_data` attribute" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-123" + }, + { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[denied_3].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[denied_3]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + { + "severity": "high", + "resolve": "Remove secret value from `user_data` attribute", + "id": "SNYK-CC-TF-123", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "msg": "resource.aws_instance[denied_3].user_data[aws_secret_access_key]", + "remediation": { + "cloudformation": "Remove secret value from `Properties.UserData` attribute", + "terraform": "Remove secret value from `user_data` attribute" + }, + "subType": "EC2", + "issue": "Secret keys have been hardcoded in user_data script", + "publicId": "SNYK-CC-TF-123", + "title": "Hard coded secrets in EC2 metadata", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html" + ], + "name": "Hard coded secrets in EC2 metadata", + "cloudConfigPath": [ + "resource", + "aws_instance[denied_3]", + "user_data[aws_secret_access_key]" + ], + "isIgnored": false, + "iacDescription": { + "issue": "Secret keys have been hardcoded in user_data script", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "resolve": "Remove secret value from `user_data` attribute" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-123" + }, + { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[allowed_3].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[allowed_3]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + { + "severity": "high", + "resolve": "Remove secret value from `user_data` attribute", + "id": "SNYK-CC-TF-123", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "msg": "resource.aws_instance[denied].user_data[aws_access_key_id]", + "remediation": { + "cloudformation": "Remove secret value from `Properties.UserData` attribute", + "terraform": "Remove secret value from `user_data` attribute" + }, + "subType": "EC2", + "issue": "Secret keys have been hardcoded in user_data script", + "publicId": "SNYK-CC-TF-123", + "title": "Hard coded secrets in EC2 metadata", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html" + ], + "name": "Hard coded secrets in EC2 metadata", + "cloudConfigPath": [ + "resource", + "aws_instance[denied]", + "user_data[aws_access_key_id]" + ], + "isIgnored": false, + "iacDescription": { + "issue": "Secret keys have been hardcoded in user_data script", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "resolve": "Remove secret value from `user_data` attribute" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-123" + }, + { + "severity": "high", + "resolve": "Remove secret value from `user_data` attribute", + "id": "SNYK-CC-TF-123", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "msg": "resource.aws_instance[denied_2].user_data_base64[aws_secret_access_key]", + "remediation": { + "cloudformation": "Remove secret value from `Properties.UserData` attribute", + "terraform": "Remove secret value from `user_data` attribute" + }, + "subType": "EC2", + "issue": "Secret keys have been hardcoded in user_data script", + "publicId": "SNYK-CC-TF-123", + "title": "Hard coded secrets in EC2 metadata", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html" + ], + "name": "Hard coded secrets in EC2 metadata", + "cloudConfigPath": [ + "resource", + "aws_instance[denied_2]", + "user_data_base64[aws_secret_access_key]" + ], + "isIgnored": false, + "iacDescription": { + "issue": "Secret keys have been hardcoded in user_data script", + "impact": "Anyone with access to VCS will be able to obtain the secret keys, and access the unauthorized resources", + "resolve": "Remove secret value from `user_data` attribute" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-123" + }, + { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[allowed].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[allowed]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[denied_2].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[denied_2]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[allowed_2].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[allowed_2]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + } + ], + "projectType": "terraformconfig" + }, + "meta": { + "isPrivate": true, + "isLicensesEnabled": false, + "ignoreSettings": null, + "org": "craig.furman", + "projectId": "", + "policy": "" + }, + "filesystemPolicy": false, + "vulnerabilities": [], + "dependencyCount": 0, + "licensesPolicy": null, + "ignoreSettings": null, + "targetFile": "aws_ec2_metadata_secrets.tf", + "projectName": "policies", + "org": "craig.furman", + "policy": "", + "isPrivate": true, + "targetFilePath": "/Users/craig/workspace/github.com/snyk/snyk/testdata/policies/aws_ec2_metadata_secrets.tf", + "packageManager": "terraformconfig" + }, + { + "result": { + "cloudConfigResults": [ + { + "severity": "low", + "resolve": "Set `DisableApiTermination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "Resources[BastionHost].Properties.DisableApiTermination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "[DocId: 0]", + "Resources[BastionHost]", + "Properties", + "DisableApiTermination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `DisableApiTermination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + { + "severity": "medium", + "resolve": "Set `BlockDeviceMappings.Encrypted` attribute of root device to `true`", + "id": "SNYK-CC-TF-53", + "impact": "That should someone gain unauthorized access to the data they would be able to read the contents.", + "msg": "Resources.BastionHost.Properties.BlockDeviceMappings", + "remediation": { + "cloudformation": "Set `BlockDeviceMappings.Encrypted` attribute of root device to `true`", + "terraform": "Set `root_block_device.encrypted` attribute to `true`" + }, + "subType": "EC2", + "issue": "The root block device for ec2 instance is not encrypted", + "publicId": "SNYK-CC-TF-53", + "title": "Non-Encrypted root block device", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/RootDeviceStorage.html", + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html", + "https://aws.amazon.com/premiumsupport/knowledge-center/cloudformation-root-volume-property/", + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html" + ], + "name": "Non-Encrypted root block device", + "cloudConfigPath": [ + "[DocId: 0]", + "Resources", + "BastionHost", + "Properties", + "BlockDeviceMappings" + ], + "isIgnored": false, + "iacDescription": { + "issue": "The root block device for ec2 instance is not encrypted", + "impact": "That should someone gain unauthorized access to the data they would be able to read the contents.", + "resolve": "Set `BlockDeviceMappings.Encrypted` attribute of root device to `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-53" + }, + { + "severity": "low", + "resolve": "Set `Properties.KmsKeyId` attribute with customer managed key id", + "id": "SNYK-CC-AWS-415", + "impact": "Scope of use of the key cannot be controlled via KMS/IAM policies", + "msg": "Resources[BastionSecureLogGroup].Properties.KmsKeyId", + "remediation": { + "cloudformation": "Set `Properties.KmsKeyId` attribute with customer managed key id", + "terraform": "Set `kms_key_id` attribute with customer managed key id" + }, + "subType": "CloudWatch", + "issue": "Log group is not encrypted with customer managed key", + "publicId": "SNYK-CC-AWS-415", + "title": "CloudWatch log group not encrypted with managed key", + "references": [ + "https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html", + "https://docs.aws.amazon.com/whitepapers/latest/kms-best-practices/aws-managed-and-customer-managed-cmks.html" + ], + "name": "CloudWatch log group not encrypted with managed key", + "cloudConfigPath": [ + "[DocId: 0]", + "Resources[BastionSecureLogGroup]", + "Properties", + "KmsKeyId" + ], + "isIgnored": false, + "iacDescription": { + "issue": "Log group is not encrypted with customer managed key", + "impact": "Scope of use of the key cannot be controlled via KMS/IAM policies", + "resolve": "Set `Properties.KmsKeyId` attribute with customer managed key id" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-415" + } + ], + "projectType": "cloudformationconfig" + }, + "meta": { + "isPrivate": true, + "isLicensesEnabled": false, + "ignoreSettings": null, + "org": "craig.furman", + "projectId": "", + "policy": "" + }, + "filesystemPolicy": false, + "vulnerabilities": [], + "dependencyCount": 0, + "licensesPolicy": null, + "ignoreSettings": null, + "targetFile": "bastion.yml", + "projectName": "policies", + "org": "craig.furman", + "policy": "", + "isPrivate": true, + "targetFilePath": "/Users/craig/workspace/github.com/snyk/snyk/testdata/policies/bastion.yml", + "packageManager": "cloudformationconfig" + }, + { + "result": { + "cloudConfigResults": [ + { + "severity": "medium", + "description": "", + "resolve": "Set `securityContext.runAsNonRoot` to `true`", + "id": "SNYK-CC-K8S-10", + "impact": "Container could be running with full administrative privileges", + "msg": "input.spec.template.spec.containers[web].securityContext.runAsNonRoot", + "subType": "Deployment", + "issue": "Container is running without root user control", + "publicId": "SNYK-CC-K8S-10", + "title": "Container is running without root user control", + "references": [ + "CIS Docker Benchmark 1.2.0 - 5.5 Ensure sensitive host system directories are not mounted on containers", + "https://kubernetes.io/docs/concepts/policy/pod-security-policy/#users-and-groups", + "https://kubernetes.io/blog/2016/08/security-best-practices-kubernetes-deployment/" + ], + "name": "Container is running without root user control", + "cloudConfigPath": [ + "[DocId: 0]", + "input", + "spec", + "template", + "spec", + "containers[web]", + "securityContext", + "runAsNonRoot" + ], + "isIgnored": false, + "iacDescription": { + "issue": "Container is running without root user control", + "impact": "Container could be running with full administrative privileges", + "resolve": "Set `securityContext.runAsNonRoot` to `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-K8S-10" + }, + { + "severity": "low", + "description": "", + "resolve": "Set `imagePullPolicy` attribute to `Always`", + "id": "SNYK-CC-K8S-42", + "impact": "The container may run with outdated or unauthorized image", + "msg": "spec.template.spec.containers[web].imagePullPolicy", + "subType": "Deployment", + "issue": "The image policy does not prevent image reuse", + "publicId": "SNYK-CC-K8S-42", + "title": "Container could be running with outdated image", + "references": [ + "5.27 Ensure that Docker commands always make use of the latest version of their image", + "https://kubernetes.io/docs/concepts/containers/images/", + "https://kubernetes.io/docs/concepts/configuration/overview/#container-images" + ], + "name": "Container could be running with outdated image", + "cloudConfigPath": [ + "[DocId: 0]", + "spec", + "template", + "spec", + "containers[web]", + "imagePullPolicy" + ], + "isIgnored": false, + "iacDescription": { + "issue": "The image policy does not prevent image reuse", + "impact": "The container may run with outdated or unauthorized image", + "resolve": "Set `imagePullPolicy` attribute to `Always`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-K8S-42" + }, + { + "severity": "medium", + "description": "", + "resolve": "Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`", + "id": "SNYK-CC-K8S-6", + "impact": "Containers are running with potentially unnecessary privileges", + "msg": "input.spec.template.spec.containers[web].securityContext.capabilities.drop", + "subType": "Deployment", + "issue": "All default capabilities are not explicitly dropped", + "publicId": "SNYK-CC-K8S-6", + "title": "Container does not drop all default capabilities", + "references": [ + "https://kubernetes.io/docs/tasks/configure-pod-container/security-context/", + "https://linux-audit.com/linux-capabilities-hardening-linux-binaries-by-removing-setuid/" + ], + "name": "Container does not drop all default capabilities", + "cloudConfigPath": [ + "[DocId: 0]", + "input", + "spec", + "template", + "spec", + "containers[web]", + "securityContext", + "capabilities", + "drop" + ], + "isIgnored": false, + "iacDescription": { + "issue": "All default capabilities are not explicitly dropped", + "impact": "Containers are running with potentially unnecessary privileges", + "resolve": "Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-K8S-6" + }, + { + "severity": "low", + "description": "", + "resolve": "Set `securityContext.readOnlyRootFilesystem` to `true`", + "id": "SNYK-CC-K8S-8", + "impact": "Compromised process could abuse writable root filesystem to elevate privileges", + "msg": "input.spec.template.spec.containers[web].securityContext.readOnlyRootFilesystem", + "subType": "Deployment", + "issue": "`readOnlyRootFilesystem` attribute is not set to `true`", + "publicId": "SNYK-CC-K8S-8", + "title": "Container is running with writable root filesystem", + "references": [ + "CIS Docker Benchmark 1.2.0 - Ensure that the container's root filesystem is mounted as read only", + "https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems", + "https://kubernetes.io/blog/2016/08/security-best-practices-kubernetes-deployment/" + ], + "name": "Container is running with writable root filesystem", + "cloudConfigPath": [ + "[DocId: 0]", + "input", + "spec", + "template", + "spec", + "containers[web]", + "securityContext", + "readOnlyRootFilesystem" + ], + "isIgnored": false, + "iacDescription": { + "issue": "`readOnlyRootFilesystem` attribute is not set to `true`", + "impact": "Compromised process could abuse writable root filesystem to elevate privileges", + "resolve": "Set `securityContext.readOnlyRootFilesystem` to `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-K8S-8" + }, + { + "severity": "medium", + "description": "", + "resolve": "Set `securityContext.allowPrivilegeEscalation` to `false`", + "id": "SNYK-CC-K8S-9", + "impact": "Processes could elevate current privileges via known vectors, for example SUID binaries", + "msg": "input.spec.template.spec.containers[web].securityContext.allowPrivilegeEscalation", + "subType": "Deployment", + "issue": "`allowPrivilegeEscalation` attribute is not set to `false`", + "publicId": "SNYK-CC-K8S-9", + "title": "Container is running without privilege escalation control", + "references": [ + "CIS Docker Benchmark 1.2.0 - 5.25 Ensure that the container is restricted from acquiring additional privileges", + "https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privilege-escalation", + "https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html" + ], + "name": "Container is running without privilege escalation control", + "cloudConfigPath": [ + "[DocId: 0]", + "input", + "spec", + "template", + "spec", + "containers[web]", + "securityContext", + "allowPrivilegeEscalation" + ], + "isIgnored": false, + "iacDescription": { + "issue": "`allowPrivilegeEscalation` attribute is not set to `false`", + "impact": "Processes could elevate current privileges via known vectors, for example SUID binaries", + "resolve": "Set `securityContext.allowPrivilegeEscalation` to `false`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-K8S-9" + }, + { + "severity": "low", + "description": "", + "resolve": "Add `container.apparmor.security.beta.kubernetes.io/` annotation with value `runtime/default` or `localhost/` annotation with value `runtime/default` or `localhost/ [DocId:0] > input > spec > template > spec > containers[web] > securityContext > privileged': + reason: None Given + created: 2021-07-26T13:09:08.459Z +patch: {} diff --git a/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-cloudformation.yml b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-cloudformation.yml new file mode 100644 index 00000000000..16f016c1965 --- /dev/null +++ b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-cloudformation.yml @@ -0,0 +1,9 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.19.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-CC-TF-53: + - 'bastion.yml > [DocId: 0] > Resources > BastionHost > Properties > BlockDeviceMappings': + reason: None Given + created: 2021-07-26T13:09:08.459Z +patch: {} diff --git a/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-kubernetes.yml b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-kubernetes.yml new file mode 100644 index 00000000000..66931556d8a --- /dev/null +++ b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-kubernetes.yml @@ -0,0 +1,9 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.19.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-CC-K8S-1: + - 'k8s.yaml > [DocId: 0] > input > spec > template > spec > containers[web] > securityContext > privileged': + reason: None Given + created: 2021-07-26T13:09:08.459Z +patch: {} diff --git a/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-non-matching.yml b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-non-matching.yml new file mode 100644 index 00000000000..6a1686a4afc --- /dev/null +++ b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-non-matching.yml @@ -0,0 +1,9 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.19.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-CC-K8S-1: + - 'k8s.yaml > [DocId:0] > input > spec > template > spec > containers[wrong] > securityContext > privileged': + reason: None Given + created: 2021-07-26T13:09:08.459Z +patch: {} diff --git a/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-terraform.yml b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-terraform.yml new file mode 100644 index 00000000000..d6c91078400 --- /dev/null +++ b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-resource-path-terraform.yml @@ -0,0 +1,9 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.19.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-CC-TF-123: + - 'aws_ec2_metadata_secrets.tf > resource > aws_instance[denied_2] > user_data_base64[aws_access_key_id]': + reason: None Given + created: 2021-07-26T13:09:08.459Z +patch: {} diff --git a/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-star.yml b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-star.yml new file mode 100644 index 00000000000..123d34c370e --- /dev/null +++ b/test/jest/unit/iac-unit-tests/fixtures/policy-ignore-star.yml @@ -0,0 +1,9 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.19.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-CC-K8S-1: + - '*': + reason: None Given + created: 2021-07-26T13:09:08.459Z +patch: {} diff --git a/test/jest/unit/iac-unit-tests/policy.spec.ts b/test/jest/unit/iac-unit-tests/policy.spec.ts new file mode 100644 index 00000000000..0d48602d90b --- /dev/null +++ b/test/jest/unit/iac-unit-tests/policy.spec.ts @@ -0,0 +1,118 @@ +import { filterIgnoredIssues } from '../../../../src/cli/commands/test/iac-local-execution/policy'; +import { FormattedResult } from '../../../../src/cli/commands/test/iac-local-execution/types'; +import fs = require('fs'); +import * as path from 'path'; +import * as snykPolicy from 'snyk-policy'; +const cloneDeep = require('lodash.clonedeep'); + +async function filterFixture(policyName: string) { + const policy = await loadPolicy(policyName); + + const fixtureContent = fs.readFileSync( + path.join(__dirname, 'fixtures', 'formatted-results.json'), + 'utf-8', + ); + const fixture: FormattedResult[] = JSON.parse(fixtureContent); + + // The policy library modifies its input. In order to write meaningful + // assertions, deep-clone the original fixture. + const filtered = filterIgnoredIssues(policy, cloneDeep(fixture)); + + return { fixture: fixture, filtered: filtered }; +} + +async function loadPolicy(policyName: string) { + if (policyName === '') { + return null; + } + const policyPath = path.join(__dirname, 'fixtures', policyName); + const policyText = fs.readFileSync(policyPath, 'utf-8'); + return await snykPolicy.loadFromText(policyText); +} + +function assertK8sPolicyPruned( + fixture: FormattedResult[], + filtered: FormattedResult[], +) { + expect(filtered[0]).toEqual(fixture[0]); + expect(filtered[1]).toEqual(fixture[1]); + const k8sFixture = fixture[2].result.cloudConfigResults; + const k8sResults = filtered[2].result.cloudConfigResults; + expect(k8sResults).toHaveLength(k8sFixture.length - 1); + expect(k8sResults.some((e) => e.id === 'SNYK-CC-K8S-1')).toEqual(false); +} + +describe('filtering ignored issues', () => { + it('returns the original issues when policy is not loaded', async () => { + const { fixture, filtered } = await filterFixture(''); + expect(filtered).toEqual(fixture); + }); + + it('filters ignored issues when path=*', async () => { + const { fixture, filtered } = await filterFixture('policy-ignore-star.yml'); + assertK8sPolicyPruned(fixture, filtered); + }); + + // This might seem paranoid, but given that our handling of resource paths is + // in a state of flux, e.g. to support multi-doc YAML properly, having some + // regression tests around each currently supported config type might be wise. + describe('filtering ignored issues by resource path', () => { + it('filters ignored issues when path is resource path (Kubernetes)', async () => { + const { fixture, filtered } = await filterFixture( + 'policy-ignore-resource-path-kubernetes.yml', + ); + assertK8sPolicyPruned(fixture, filtered); + }); + + it('filters ignored issues when path is resource path (CloudFormation)', async () => { + const { fixture, filtered } = await filterFixture( + 'policy-ignore-resource-path-cloudformation.yml', + ); + expect(filtered[0]).toEqual(fixture[0]); + expect(filtered[2]).toEqual(fixture[2]); + const cfFixture = fixture[1].result.cloudConfigResults; + const cfResults = filtered[1].result.cloudConfigResults; + expect(cfResults).toHaveLength(cfFixture.length - 1); + expect(cfResults.some((e) => e.id === 'SNYK-CC-TF-53')).toEqual(false); + }); + + it('filters ignored issues when path is resource path (Terraform)', async () => { + const { fixture, filtered } = await filterFixture( + 'policy-ignore-resource-path-terraform.yml', + ); + expect(filtered[1]).toEqual(fixture[1]); + expect(filtered[2]).toEqual(fixture[2]); + const tfFixture = fixture[0].result.cloudConfigResults; + const tfResults = filtered[0].result.cloudConfigResults; + expect(tfResults).toHaveLength(tfFixture.length - 1); + }); + }); + + it('filters no issues when path is non-matching resource path', async () => { + const { fixture, filtered } = await filterFixture( + 'policy-ignore-resource-path-non-matching.yml', + ); + expect(filtered).toEqual(fixture); + }); + + it('filters ignored issues when path is file path', async () => { + const { fixture, filtered } = await filterFixture( + 'policy-ignore-file-path.yml', + ); + assertK8sPolicyPruned(fixture, filtered); + }); + + it('filters no issues when path is non-matching file path', async () => { + const { fixture, filtered } = await filterFixture( + 'policy-ignore-file-path-non-matching.yml', + ); + expect(filtered).toEqual(fixture); + }); + + it('filters no issues when path is non-matching file path but matching resource path', async () => { + const { fixture, filtered } = await filterFixture( + 'policy-ignore-non-matching-file-matching-resource.yml', + ); + expect(filtered).toEqual(fixture); + }); +}); diff --git a/test/smoke/spec/iac/snyk_test_k8s_spec.sh b/test/smoke/spec/iac/snyk_test_k8s_spec.sh index 7692db79fd5..f370ed364b0 100644 --- a/test/smoke/spec/iac/snyk_test_k8s_spec.sh +++ b/test/smoke/spec/iac/snyk_test_k8s_spec.sh @@ -9,7 +9,7 @@ Describe "Snyk iac test command" It "finds issues in k8s file" When run snyk iac test ../fixtures/iac/kubernetes/pod-privileged.yaml --legacy The status should be failure # issues found - The output should include "Testing pod-privileged.yaml..." + The output should include "Testing ../fixtures/iac/kubernetes/pod-privileged.yaml..." # Outputs issues The output should include "Infrastructure as code issues:" @@ -23,13 +23,13 @@ Describe "Snyk iac test command" The output should include "Project name: kubernetes" The output should include "Open source: no" The output should include "Project path: ../fixtures/iac/kubernetes/pod-privileged.yaml" - The output should include "Tested pod-privileged.yaml for known issues, found" + The output should include "Tested ../fixtures/iac/kubernetes/pod-privileged.yaml for known issues, found" End It "filters out issues when using severity threshold" When run snyk iac test ../fixtures/iac/kubernetes/pod-privileged.yaml --severity-threshold=high --legacy The status should be failure # one issue found - The output should include "Testing pod-privileged.yaml..." + The output should include "Testing ../fixtures/iac/kubernetes/pod-privileged.yaml..." The output should include "Infrastructure as code issues:" The output should include "✗ " @@ -41,7 +41,7 @@ Describe "Snyk iac test command" The output should include "Project name: kubernetes" The output should include "Open source: no" The output should include "Project path: ../fixtures/iac/kubernetes/pod-privileged.yaml" - The output should include "Tested pod-privileged.yaml for known issues, found" + The output should include "Tested ../fixtures/iac/kubernetes/pod-privileged.yaml for known issues, found" End It "outputs an error for files with no valid k8s objects" diff --git a/test/smoke/spec/iac/snyk_test_local_exec_spec.sh b/test/smoke/spec/iac/snyk_test_local_exec_spec.sh index f01508d5258..1afc79ef599 100644 --- a/test/smoke/spec/iac/snyk_test_local_exec_spec.sh +++ b/test/smoke/spec/iac/snyk_test_local_exec_spec.sh @@ -30,7 +30,7 @@ Describe "Snyk iac local test command" It "finds issues in k8s YAML file" When run snyk iac test ../fixtures/iac/kubernetes/pod-privileged.yaml The status should equal 1 # issues found - The output should include "Testing pod-privileged.yaml..." + The output should include "Testing ../fixtures/iac/kubernetes/pod-privileged.yaml..." # Outputs issues The output should include "Infrastructure as code issues:" @@ -41,7 +41,7 @@ Describe "Snyk iac local test command" It "finds issues in k8s JSON file" When run snyk iac test ../fixtures/iac/kubernetes/pod-valid.json The status should equal 1 # issues found - The output should include "Testing pod-valid.json..." + The output should include "Testing ../fixtures/iac/kubernetes/pod-valid.json..." # Outputs issues The output should include "Infrastructure as code issues:" @@ -52,7 +52,7 @@ Describe "Snyk iac local test command" It "filters out issues when using severity threshold" When run snyk iac test ../fixtures/iac/kubernetes/pod-privileged.yaml --severity-threshold=high The status should equal 1 # one issue found - The output should include "Testing pod-privileged.yaml..." + The output should include "Testing ../fixtures/iac/kubernetes/pod-privileged.yaml..." The output should include "Infrastructure as code issues:" The output should include "✗ " @@ -94,7 +94,7 @@ Describe "Snyk iac local test command" It "finds issues in CloudFormation YAML file" When run snyk iac test ../fixtures/iac/cloudformation/aurora-valid.yml The status should equal 1 # issues found - The output should include "Testing aurora-valid.yml..." + The output should include "Testing ../fixtures/iac/cloudformation/aurora-valid.yml..." # Outputs issues The output should include "Infrastructure as code issues:" @@ -105,7 +105,7 @@ Describe "Snyk iac local test command" It "finds issues in CloudFormation JSON file" When run snyk iac test ../fixtures/iac/cloudformation/fargate-valid.json The status should equal 1 # issues found - The output should include "Testing fargate-valid.json..." + The output should include "Testing ../fixtures/iac/cloudformation/fargate-valid.json..." # Outputs issues The output should include "Infrastructure as code issues:" @@ -116,10 +116,10 @@ Describe "Snyk iac local test command" It "filters out issues when using severity threshold" When run snyk iac test ../fixtures/iac/cloudformation/aurora-valid.yml --severity-threshold=high The status should equal 0 # no issues found - The output should include "Testing aurora-valid.yml..." + The output should include "Testing ../fixtures/iac/cloudformation/aurora-valid.yml..." The output should include "Infrastructure as code issues:" - The output should include "Tested aurora-valid.yml for known issues, found" + The output should include "Tested ../fixtures/iac/cloudformation/aurora-valid.yml for known issues, found" End It "outputs an error for files with no valid YAML" @@ -149,7 +149,7 @@ Describe "Snyk iac local test command" It "finds issues in terraform file" When run snyk iac test ../fixtures/iac/terraform/sg_open_ssh.tf The status should equal 1 # issues found - The output should include "Testing sg_open_ssh.tf..." + The output should include "Testing ../fixtures/iac/terraform/sg_open_ssh.tf..." # Outputs issues The output should include "Infrastructure as code issues:" @@ -160,10 +160,10 @@ Describe "Snyk iac local test command" It "filters out issues when using severity threshold" When run snyk iac test ../fixtures/iac/terraform/sg_open_ssh.tf --severity-threshold=high The status should equal 0 # no issues found - The output should include "Testing sg_open_ssh.tf..." + The output should include "Testing ../fixtures/iac/terraform/sg_open_ssh.tf..." The output should include "Infrastructure as code issues:" - The output should include "Tested sg_open_ssh.tf for known issues, found" + The output should include "Tested ../fixtures/iac/terraform/sg_open_ssh.tf for known issues, found" End # TODO: currently skipped because the parser we're using doesn't fail on invalid terraform @@ -236,9 +236,9 @@ Describe "Snyk iac local test command" When run snyk iac test ../fixtures/iac/depth_detection/ --detection-depth=2 The status should equal 1 # issues found # Only File - The output should include "Testing one.tf..." + The output should include "Testing one/one.tf..." The output should include "Infrastructure as code issues:" - The output should include "Tested one.tf for known issues, found" + The output should include "Tested one/one.tf for known issues, found" # Second File The output should include "Testing root.tf..." @@ -310,7 +310,7 @@ Describe "Snyk iac local test command" It "finds issues in a Terraform plan file - full scan flag" When run snyk iac test ../fixtures/iac/terraform-plan/tf-plan-create.json --scan=planned-values The status should equal 1 # issues found - The output should include "Testing tf-plan-create.json" + The output should include "Testing ../fixtures/iac/terraform-plan/tf-plan-create.json" # Outputs issues The output should include "Infrastructure as code issues:" @@ -324,7 +324,7 @@ Describe "Snyk iac local test command" It "finds issues in a Terraform plan file - explicit delta scan with flag" When run snyk iac test ../fixtures/iac/terraform-plan/tf-plan-create.json --scan=resource-changes The status should equal 1 # issues found - The output should include "Testing tf-plan-create.json" + The output should include "Testing ../fixtures/iac/terraform-plan/tf-plan-create.json" # Outputs issues The output should include "Infrastructure as code issues:" diff --git a/test/smoke/spec/iac/snyk_test_terraform_spec.sh b/test/smoke/spec/iac/snyk_test_terraform_spec.sh index fb8e5366072..f732ee3125f 100644 --- a/test/smoke/spec/iac/snyk_test_terraform_spec.sh +++ b/test/smoke/spec/iac/snyk_test_terraform_spec.sh @@ -9,7 +9,7 @@ Describe "Snyk iac test command" It "finds issues in terraform file" When run snyk iac test ../fixtures/iac/terraform/sg_open_ssh.tf --legacy The status should be failure # issues found - The output should include "Testing sg_open_ssh.tf..." + The output should include "Testing ../fixtures/iac/terraform/sg_open_ssh.tf..." # Outputs issues The output should include "Infrastructure as code issues:" The output should include "✗ " @@ -22,13 +22,13 @@ Describe "Snyk iac test command" The output should include "Project name: terraform" The output should include "Open source: no" The output should include "Project path: ../fixtures/iac/terraform/sg_open_ssh.tf" - The output should include "Tested sg_open_ssh.tf for known issues, found" + The output should include "Tested ../fixtures/iac/terraform/sg_open_ssh.tf for known issues, found" End It "filters out issues when using severity threshold" When run snyk iac test ../fixtures/iac/terraform/sg_open_ssh.tf --severity-threshold=high --legacy The status should be success # no issues found - The output should include "Testing sg_open_ssh.tf..." + The output should include "Testing ../fixtures/iac/terraform/sg_open_ssh.tf..." # Outputs issues The output should include "Infrastructure as code issues:" @@ -39,7 +39,7 @@ Describe "Snyk iac test command" The output should include "Project name: terraform" The output should include "Open source: no" The output should include "Project path: ../fixtures/iac/terraform/sg_open_ssh.tf" - The output should include "Tested sg_open_ssh.tf for known issues, found" + The output should include "Tested ../fixtures/iac/terraform/sg_open_ssh.tf for known issues, found" End It "outputs an error for invalid hcl2 tf files"