Skip to content

Commit

Permalink
feat:improve iac test json output
Browse files Browse the repository at this point in the history
  • Loading branch information
rontalx committed Aug 11, 2020
1 parent b79f0cf commit 140625c
Show file tree
Hide file tree
Showing 14 changed files with 335 additions and 514 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ src/lib/snyk-test/iac-test-result.ts @snyk/cloudconfig
src/lib/snyk-test/payload-schema.ts @snyk/cloudconfig
src/lib/snyk-test/run-iac-test.ts @snyk/cloudconfig
test/acceptance/cli-test/cli-test.iac-k8s.spec.ts @snyk/cloudconfig
test/acceptance/cli-test/cli-test.iac-k8s.utils.ts @snyk/cloudconfig
src/lib/errors/invalid-iac-file.ts @snyk/cloudconfig
src/lib/errors/unsupported-options-iac-error.ts @snyk/cloudconfig
4 changes: 2 additions & 2 deletions src/cli/commands/test/formatters/format-test-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import chalk from 'chalk';
import { rightPadWithSpaces } from '../../../../lib/right-pad';
import { TestOptions, Options } from '../../../../lib/types';
import { TestResult } from '../../../../lib/snyk-test/legacy';
import { IacTestResult } from '../../../../lib/snyk-test/iac-test-result';
import { IacTestResponse } from '../../../../lib/snyk-test/iac-test-result';
import { capitalizePackageManager } from '../iac-output';

export function formatTestMeta(
res: TestResult | IacTestResult,
res: TestResult | IacTestResponse,
options: Options & TestOptions,
): string {
const padToLength = 19; // chars to align
Expand Down
10 changes: 6 additions & 4 deletions src/cli/commands/test/iac-output.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import chalk from 'chalk';
import * as Debug from 'debug';
import { IacTestResult } from '../../../lib/snyk-test/iac-test-result';
import {
IacTestResponse,
AnnotatedIacIssue,
} from '../../../lib/snyk-test/iac-test-result';
import { getSeverityValue } from './formatters';
import { printPath } from './formatters/remediation-based-format-issues';
import { AnnotatedIacIssue } from '../../../lib/snyk-test/iac-test-result';
import { titleCaseText } from './formatters/legacy-format-issue';
const debug = Debug('iac-output');

Expand Down Expand Up @@ -66,7 +68,7 @@ function extractOverview(description: string): string {
}

export function getIacDisplayedOutput(
res: IacTestResult,
iacTest: IacTestResponse,
testedInfoText: string,
meta: string,
prefix: string,
Expand All @@ -77,7 +79,7 @@ export function getIacDisplayedOutput(

const NotNew = false;

const issues: AnnotatedIacIssue[] = res.result.cloudConfigResults;
const issues: AnnotatedIacIssue[] = iacTest.result.cloudConfigResults;
debug(`iac display output - ${issues.length} issues`);

issues
Expand Down
29 changes: 7 additions & 22 deletions src/cli/commands/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import {
TestResult,
VulnMetaData,
} from '../../../lib/snyk-test/legacy';
import { IacTestResult } from '../../../lib/snyk-test/iac-test-result';
import {
IacTestResponse,
mapIacTestResult,
} from '../../../lib/snyk-test/iac-test-result';
import {
SupportedPackageManagers,
WIZARD_SUPPORTED_PACKAGE_MANAGERS,
Expand Down Expand Up @@ -181,7 +184,8 @@ async function test(...args: MethodArgs): Promise<TestCommandResult> {
// values depend on `options.json` value - string or object
const errorMappedResults = !options.iac
? createErrorMappedResultsForJsonOutput(results)
: createErrorMappedResultsForJsonOutputForIac(results);
: results.map(mapIacTestResult);

// backwards compat - strip array IFF only one result
const dataToSend =
errorMappedResults.length === 1
Expand Down Expand Up @@ -310,25 +314,6 @@ function createErrorMappedResultsForJsonOutput(results) {
return errorMappedResults;
}

function createErrorMappedResultsForJsonOutputForIac(results) {
const errorMappedResults = results.map((result) => {
// add json for when thrown exception
if (result instanceof Error) {
return {
ok: false,
error: result.message,
path: (result as any).path,
};
}
const res = { ...result, ...result.result };
delete res.result;
delete res.meta;
return res;
});

return errorMappedResults;
}

function shouldFail(vulnerableResults: any[], failOn: FailOn) {
// find reasons not to fail
if (failOn === 'all') {
Expand Down Expand Up @@ -488,7 +473,7 @@ function displayResult(

if (res.packageManager === 'k8sconfig') {
return getIacDisplayedOutput(
(res as any) as IacTestResult,
(res as any) as IacTestResponse,
testedInfoText,
meta,
prefix,
Expand Down
67 changes: 65 additions & 2 deletions src/lib/snyk-test/iac-test-result.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BasicResultData, SEVERITY } from './legacy';
import { BasicResultData, TestDepGraphMeta, SEVERITY } from './legacy';

export interface AnnotatedIacIssue {
id: string;
Expand All @@ -9,15 +9,78 @@ export interface AnnotatedIacIssue {
cloudConfigPath: string[];
type: string;
subType: string;
path: string[];
// Legacy fields from Registry, unused.
name?: string;
from?: string[];
}

export interface IacTestResult extends BasicResultData {
type FILTERED_OUT_FIELDS = 'cloudConfigPath' | 'name' | 'from';

export interface IacTestResponse extends BasicResultData {
targetFile: string;
projectName: string;
displayTargetFile: string; // used for display only
foundProjectCount: number;
meta: TestDepGraphMeta;
result: {
cloudConfigResults: AnnotatedIacIssue[];
projectType: string;
};
}

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,
};
}

const {
result: { projectType },
...filteredIacTest
} = iacTest;
return {
...filteredIacTest,
projectType,
[IAC_ISSUES_KEY]:
iacTest?.result?.cloudConfigResults.map(mapIacIssue) || [],
};
}

/**
* 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.
* The types above, IacTestResult & AnnotatedIacIssue, represent how the response from Registry actually is.
* These were introduced in order to prevent cascading complex changes caused by changing Registry's `test-iac` response.
*/
export interface IacTestError {
ok: boolean;
error: string;
path: string;
}

export interface MappedIacTestResponse extends Omit<IacTestResponse, 'result'> {
[IAC_ISSUES_KEY]: MappedAnnotatedIacIssue[];
projectType: string;
}

export interface MappedAnnotatedIacIssue
extends Omit<AnnotatedIacIssue, FILTERED_OUT_FIELDS> {
path: string[];
}

export function mapIacIssue(
iacIssue: AnnotatedIacIssue,
): MappedAnnotatedIacIssue {
// filters out & renames properties we're getting from registry and don't need for the JSON output.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { cloudConfigPath: path, name, from, ...mappedIacIssue } = iacIssue;
return { ...mappedIacIssue, path };
}
2 changes: 1 addition & 1 deletion src/lib/snyk-test/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ interface TestDepGraphResult {
remediation?: RemediationChanges;
}

interface TestDepGraphMeta {
export interface TestDepGraphMeta {
isPublic: boolean;
isLicensesEnabled: boolean;
licensesPolicy?: {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/snyk-test/run-iac-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as fs from 'fs';
import * as path from 'path';
import * as pathUtil from 'path';
import { TestResult } from './legacy';
import { IacTestResult } from './iac-test-result';
import { IacTestResponse } from './iac-test-result';
import * as snyk from '..';
import { isCI } from '../is-ci';
import * as common from './common';
Expand All @@ -14,7 +14,7 @@ import { SEVERITY } from './legacy';
import * as pathLib from 'path';

export async function parseIacTestResult(
res: IacTestResult,
res: IacTestResponse,
targetFile: string | undefined,
projectName: any,
severityThreshold?: SEVERITY,
Expand Down
6 changes: 3 additions & 3 deletions src/lib/snyk-test/run-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
convertTestDepGraphResultToLegacy,
LegacyVulnApiResult,
} from './legacy';
import { IacTestResult } from './iac-test-result';
import { IacTestResponse } from './iac-test-result';
import {
AuthFailedError,
InternalServerError,
Expand Down Expand Up @@ -79,7 +79,7 @@ async function sendAndParseResults(
if (options.iac) {
const iacScan: IacScan = payload.body as IacScan;
analytics.add('iac type', !!iacScan.type);
const res = (await sendTestPayload(payload)) as IacTestResult;
const res = (await sendTestPayload(payload)) as IacTestResponse;

const projectName =
iacScan.projectNameOverride || iacScan.originalProjectName;
Expand Down Expand Up @@ -267,7 +267,7 @@ async function parseRes(

function sendTestPayload(
payload: Payload,
): Promise<LegacyVulnApiResult | TestDepGraphResponse | IacTestResult> {
): Promise<LegacyVulnApiResult | TestDepGraphResponse | IacTestResponse> {
const filesystemPolicy = payload.body && !!payload.body.policy;
return new Promise((resolve, reject) => {
request(payload, (error, res, body) => {
Expand Down
Loading

0 comments on commit 140625c

Please sign in to comment.