diff --git a/src/lib/iac/test/v2/json.ts b/src/lib/iac/test/v2/json.ts index 0355c4ef73..22114de14e 100644 --- a/src/lib/iac/test/v2/json.ts +++ b/src/lib/iac/test/v2/json.ts @@ -2,11 +2,14 @@ // fields must be produced in the JSON output, and they must have those values // to keep backwards compatibility. -import { Resource, ScanError, TestOutput, Vulnerability } from './scan/results'; +import { Resource, TestOutput, Vulnerability } from './scan/results'; import * as path from 'path'; -import { createErrorMappedResultsForJsonOutput } from '../../../formatters/test/format-test-results'; import { IacProjectType, iacRemediationTypes } from '../../constants'; import { State } from './scan/policy-engine'; +import { + IacTestError, + mapIacTestError, +} from '../../../snyk-test/iac-test-result'; export interface Result { meta: Meta; @@ -92,7 +95,7 @@ export function convertEngineToJsonResults({ }: { results: TestOutput; projectName: string; -}): Array { +}): Array { const vulnerabilityGroups = groupVulnerabilitiesByFile(results); // all vulns groups by file const resourceGroups = groupResourcesByFile(results); // all resources grouped by file const filesWithoutIssues = findFilesWithoutIssues( @@ -100,10 +103,10 @@ export function convertEngineToJsonResults({ vulnerabilityGroups, ); // all resources without issues grouped by file - const output: Array = []; + const output: Array = []; if (results.errors) { - output.push(...createErrorMappedResultsForJsonOutput(results.errors)); + output.push(...results.errors.map((e) => mapIacTestError(e))); } for (const [file, resources] of Object.entries(filesWithoutIssues)) { diff --git a/src/lib/snyk-test/iac-test-result.ts b/src/lib/snyk-test/iac-test-result.ts index a6586c403f..244d5ba366 100644 --- a/src/lib/snyk-test/iac-test-result.ts +++ b/src/lib/snyk-test/iac-test-result.ts @@ -1,4 +1,5 @@ import pick = require('lodash.pick'); +import { CustomError } from '../errors'; import { BasicResultData, SEVERITY, TestDepGraphMeta } from './legacy'; export interface AnnotatedIacIssue { @@ -40,6 +41,7 @@ type FILTERED_OUT_FIELDS = 'cloudConfigPath' | 'name' | 'from'; export interface IacTestResponse extends BasicResultData { path: string; + code?: number; targetFile: string; projectName: string; displayTargetFile: string; // used for display only @@ -56,12 +58,8 @@ const IAC_ISSUES_KEY = 'infrastructureAsCodeIssues'; export function mapIacTestResult( iacTest: IacTestResponse, ): MappedIacTestResponse | IacTestError { - if (iacTest instanceof Error) { - return { - ok: false, - error: iacTest.message, - path: (iacTest as any).path, - }; + if (iacTest instanceof CustomError) { + return mapIacTestError(iacTest); } const infrastructureAsCodeIssues = @@ -78,6 +76,15 @@ export function mapIacTestResult( }; } +export function mapIacTestError(error: CustomError) { + return { + ok: false, + code: error.code, + error: error.message, + path: (error as any).path, + }; +} + /** * The following types represent manipulations to the data structure returned from Registry's `test-iac`. * These manipulations are being done prior to outputing as JSON, for renaming fields only. diff --git a/test/fixtures/iac/output-formats/test-error-json-schema.json b/test/fixtures/iac/output-formats/test-error-json-schema.json index c4ee351767..8127807c52 100644 --- a/test/fixtures/iac/output-formats/test-error-json-schema.json +++ b/test/fixtures/iac/output-formats/test-error-json-schema.json @@ -2,9 +2,10 @@ "type": "object", "properties": { "ok": { "type": "boolean" }, + "code": {"type": "integer"}, "error": { "type": "string" }, "path": { "type": "string" } }, - "required": ["ok", "error", "path"], + "required": ["ok", "code", "error", "path"], "additionalProperties": false } diff --git a/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts b/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts index a4e05b5d17..9584ef3ddc 100644 --- a/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts +++ b/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts @@ -139,9 +139,9 @@ describe('test', () => { formattedUserMessage: "Test Failures\n\n The Snyk CLI couldn't find any valid IaC configuration files to scan\n Path: invalid_file.txt", json: - '[\n {\n "ok": false,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', jsonStringifiedResults: - '[\n {\n "ok": false,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', sarifStringifiedResults: `{\n "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",\n "version": "2.1.0",\n "runs": [\n {\n "originalUriBaseIds": {\n "PROJECTROOT": {\n "uri": "${ pathToFileURL(path.join(process.cwd(), '/')).href }",\n "description": {\n "text": "The root directory for all project files."\n }\n }\n },\n "tool": {\n "driver": {\n "name": "Snyk IaC",\n "fullName": "Snyk Infrastructure as Code",\n "version": "1.0.0-monorepo",\n "informationUri": "https://docs.snyk.io/products/snyk-infrastructure-as-code",\n "rules": []\n }\n },\n "automationDetails": {\n "id": "snyk-iac"\n },\n "results": []\n }\n ]\n}`, @@ -189,9 +189,9 @@ describe('test', () => { `"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"`, ), jsonStringifiedResults: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', json: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', }), ); }); @@ -250,13 +250,13 @@ describe('test', () => { strCode: 'NO_FILES_TO_SCAN_ERROR', innerError: undefined, userMessage: - '[\n {\n "ok": false,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', formattedUserMessage: - '[\n {\n "ok": false,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', json: - '[\n {\n "ok": false,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', jsonStringifiedResults: - '[\n {\n "ok": false,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', sarifStringifiedResults: `{\n "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",\n "version": "2.1.0",\n "runs": [\n {\n "originalUriBaseIds": {\n "PROJECTROOT": {\n "uri": "${ pathToFileURL(path.join(process.cwd(), '/')).href }",\n "description": {\n "text": "The root directory for all project files."\n }\n }\n },\n "tool": {\n "driver": {\n "name": "Snyk IaC",\n "fullName": "Snyk Infrastructure as Code",\n "version": "1.0.0-monorepo",\n "informationUri": "https://docs.snyk.io/products/snyk-infrastructure-as-code",\n "rules": []\n }\n },\n "automationDetails": {\n "id": "snyk-iac"\n },\n "results": []\n }\n ]\n}`, @@ -292,7 +292,7 @@ describe('test', () => { expect.objectContaining({ name: 'NoLoadableInputError', message: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', code: 1010, strCode: 'NO_FILES_TO_SCAN_ERROR', fields: { @@ -300,16 +300,16 @@ describe('test', () => { }, path: 'path/to/test', userMessage: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', formattedUserMessage: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', sarifStringifiedResults: expect.stringContaining( `"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"`, ), jsonStringifiedResults: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', json: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', }), ); }); @@ -371,7 +371,7 @@ describe('test', () => { pathToFileURL(path.join(process.cwd(), '/')).href }",\n "description": {\n "text": "The root directory for all project files."\n }\n }\n },\n "tool": {\n "driver": {\n "name": "Snyk IaC",\n "fullName": "Snyk Infrastructure as Code",\n "version": "1.0.0-monorepo",\n "informationUri": "https://docs.snyk.io/products/snyk-infrastructure-as-code",\n "rules": []\n }\n },\n "automationDetails": {\n "id": "snyk-iac"\n },\n "results": []\n }\n ]\n}`, jsonStringifiedResults: - '[\n {\n "ok": false,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "",\n "path": "invalid_file.txt"\n }\n]', sarifStringifiedResults: `{\n "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",\n "version": "2.1.0",\n "runs": [\n {\n "originalUriBaseIds": {\n "PROJECTROOT": {\n "uri": "${ pathToFileURL(path.join(process.cwd(), '/')).href }",\n "description": {\n "text": "The root directory for all project files."\n }\n }\n },\n "tool": {\n "driver": {\n "name": "Snyk IaC",\n "fullName": "Snyk Infrastructure as Code",\n "version": "1.0.0-monorepo",\n "informationUri": "https://docs.snyk.io/products/snyk-infrastructure-as-code",\n "rules": []\n }\n },\n "automationDetails": {\n "id": "snyk-iac"\n },\n "results": []\n }\n ]\n}`, @@ -425,7 +425,7 @@ describe('test', () => { `"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"`, ), jsonStringifiedResults: - '[\n {\n "ok": false,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', + '[\n {\n "ok": false,\n "code": 2114,\n "error": "no loadable input: path/to/test",\n "path": "path/to/test"\n }\n]', json: expect.stringContaining( `"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"`, ), diff --git a/test/jest/unit/iac/process-results/fixtures/integrated-json-output.json b/test/jest/unit/iac/process-results/fixtures/integrated-json-output.json index 16fd379d57..f237db786e 100644 --- a/test/jest/unit/iac/process-results/fixtures/integrated-json-output.json +++ b/test/jest/unit/iac/process-results/fixtures/integrated-json-output.json @@ -1,6 +1,7 @@ [ { "ok": false, + "code": 2114, "error": "", "path": "invalid_file.txt" },