Skip to content

Commit

Permalink
Merge pull request #2119 from snyk/fix/yaml-doc-indexes
Browse files Browse the repository at this point in the history
fix: IaC multi-doc yaml indexing
  • Loading branch information
Craig Furman committed Jul 28, 2021
2 parents 30cf469 + 7b45928 commit f0d86d3
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 34 deletions.
13 changes: 7 additions & 6 deletions src/cli/commands/test/iac-local-execution/extract-line-number.ts
@@ -1,4 +1,4 @@
import { IaCErrorCodes, IacFileScanResult, PolicyMetadata } from './types';
import { IaCErrorCodes } from './types';
import { CustomError } from '../../../../lib/errors';
import {
CloudConfigFileTypes,
Expand All @@ -25,14 +25,15 @@ function getFileTypeForLineNumber(fileType: string): CloudConfigFileTypes {
}

export function extractLineNumber(
scanResult: IacFileScanResult,
policy: PolicyMetadata,
fileContent: string,
fileType: string,
cloudConfigPath: string[],
): number {
try {
return issuesToLineNumbers(
scanResult.fileContent,
getFileTypeForLineNumber(scanResult.fileType),
policy.msg.split('.'), // parser defaults to docId:0 and checks for the rest of the path
fileContent,
getFileTypeForLineNumber(fileType),
cloudConfigPath,
);
} catch {
const err = new FailedToExtractLineNumberError();
Expand Down
43 changes: 18 additions & 25 deletions src/cli/commands/test/iac-local-execution/results-formatter.ts
Expand Up @@ -23,11 +23,18 @@ export function formatScanResults(
meta: TestMeta,
): FormattedResult[] {
try {
// Relevant only for multi-doc yaml files
const scannedResultsGroupedByDocId = groupMultiDocResults(scanResults);
return scannedResultsGroupedByDocId.map((iacScanResult) =>
formatScanResult(iacScanResult, meta, options),
);
const groupedByFile = scanResults.reduce((memo, scanResult) => {
const res = formatScanResult(scanResult, meta, options);
if (memo[scanResult.filePath]) {
memo[scanResult.filePath].result.cloudConfigResults.push(
...res.result.cloudConfigResults,
);
} else {
memo[scanResult.filePath] = res;
}
return memo;
}, {} as { [key: string]: FormattedResult });
return Object.values(groupedByFile);
} catch (e) {
throw new FailedToFormatResults();
}
Expand All @@ -48,7 +55,7 @@ function formatScanResult(
const formattedIssues = scanResult.violatedPolicies.map((policy) => {
const cloudConfigPath =
scanResult.docId !== undefined
? [`[DocId:${scanResult.docId}]`].concat(policy.msg.split('.'))
? [`[DocId: ${scanResult.docId}]`].concat(policy.msg.split('.'))
: policy.msg.split('.');

const flagsRequiringLineNumber = [
Expand All @@ -61,7 +68,11 @@ function formatScanResult(
(flag) => options[flag],
);
const lineNumber: number = shouldExtractLineNumber
? extractLineNumber(scanResult, policy)
? extractLineNumber(
scanResult.fileContent,
scanResult.fileType,
cloudConfigPath,
)
: -1;

return {
Expand Down Expand Up @@ -145,24 +156,6 @@ function computePaths(
};
}

function groupMultiDocResults(
scanResults: IacFileScanResult[],
): IacFileScanResult[] {
const groupedData = scanResults.reduce((memo, result) => {
if (memo[result.filePath]) {
memo[result.filePath].violatedPolicies = memo[
result.filePath
].violatedPolicies.concat(result.violatedPolicies);
} else {
memo[result.filePath] = result;
}

return memo;
}, {} as IacFileScanResult);

return Object.values(groupedData);
}

export function filterPoliciesBySeverity(
violatedPolicies: PolicyMetadata[],
severityThreshold?: SEVERITY,
Expand Down
22 changes: 22 additions & 0 deletions test/fixtures/iac/kubernetes/pod-privileged-multi.yaml
@@ -0,0 +1,22 @@
---
apiVersion: v1
kind: Pod
metadata:
name: example1
spec:
containers:
- name: example
image: example:latest
securityContext:
privileged: true
---
apiVersion: v1
kind: Pod
metadata:
name: example2
spec:
containers:
- name: example
image: example:latest
securityContext:
privileged: true
34 changes: 34 additions & 0 deletions test/jest/acceptance/iac/multidoc-yaml.spec.ts
@@ -0,0 +1,34 @@
import { startMockServer } from './helpers';
import { MappedIacTestResponse } from '../../../../src/lib/snyk-test/iac-test-result';
jest.setTimeout(50000);

describe('iac test --json file.yaml', () => {
let run: (
cmd: string,
) => Promise<{ stdout: string; stderr: string; exitCode: number }>;
let teardown: () => void;

beforeAll(async () => {
({ run, teardown } = await startMockServer());
});

afterAll(async () => teardown());

it('supports the correct line numbers for multi-doc YAML files', async () => {
// Test a multidoc YAML file with one "high" issue in each subdoc.
const { stdout } = await run(
`snyk iac test --json --severity-threshold=high ./iac/kubernetes/pod-privileged-multi.yaml`,
);

const result: MappedIacTestResponse = JSON.parse(stdout);
const issues = result.infrastructureAsCodeIssues;

expect(issues.length).toBe(2);

expect(issues[0].lineNumber).toBe(11);
expect(issues[1].lineNumber).toBe(22);

expect(issues[0].path[0]).toBe('[DocId: 0]');
expect(issues[1].path[0]).toBe('[DocId: 1]');
});
});
38 changes: 35 additions & 3 deletions test/jest/unit/iac-unit-tests/results-formatter.fixtures.ts
Expand Up @@ -28,7 +28,6 @@ export const policyStub: PolicyMetadata = {
subType: 'Deployment',
title: 'Container is running in privileged mode',
type: 'k8s',
documentation: 'https://snyk.io/security-rules/SNYK-CC-K8S-2',
};

const anotherPolicyStub: PolicyMetadata = {
Expand All @@ -38,6 +37,12 @@ const anotherPolicyStub: PolicyMetadata = {
publicId: 'SNYK-CC-K8S-2',
};

const yetAnotherPolicyStub: PolicyMetadata = {
...anotherPolicyStub,
id: '3',
publicId: 'SNYK-CC-K8S-3',
};

const relativeFilePath = 'dont-care.yaml';
const absoluteFilePath = path.resolve(relativeFilePath, '.');

Expand All @@ -63,6 +68,16 @@ export function generateScanResults(): Array<IacFileScanResult> {
filePath: relativeFilePath,
fileType: 'yaml',
},
{
violatedPolicies: [{ ...yetAnotherPolicyStub }],
jsonContent: { dontCare: null },
docId: 1,
projectType: IacProjectType.K8S,
engineType: EngineType.Kubernetes,
fileContent: 'dont-care',
filePath: relativeFilePath,
fileType: 'yaml',
},
];
}

Expand All @@ -80,7 +95,7 @@ export function generateCloudConfigResults(
...anotherPolicyStub,
id: anotherPolicyStub.publicId,
name: anotherPolicyStub.title,
cloudConfigPath: ['[DocId:0]'].concat(anotherPolicyStub.msg.split('.')),
cloudConfigPath: ['[DocId: 0]'].concat(anotherPolicyStub.msg.split('.')),
isIgnored: false,
iacDescription: {
issue: anotherPolicyStub.issue,
Expand All @@ -89,7 +104,24 @@ export function generateCloudConfigResults(
},
severity: anotherPolicyStub.severity,
lineNumber: withLineNumber ? 3 : -1,
documentation: anotherPolicyStub.documentation,
documentation: 'https://snyk.io/security-rules/SNYK-CC-K8S-2',
},
{
...yetAnotherPolicyStub,
id: yetAnotherPolicyStub.publicId,
name: yetAnotherPolicyStub.title,
cloudConfigPath: ['[DocId: 1]'].concat(
yetAnotherPolicyStub.msg.split('.'),
),
isIgnored: false,
iacDescription: {
issue: yetAnotherPolicyStub.issue,
impact: yetAnotherPolicyStub.impact,
resolve: yetAnotherPolicyStub.resolve,
},
severity: yetAnotherPolicyStub.severity,
lineNumber: withLineNumber ? 3 : -1,
documentation: 'https://snyk.io/security-rules/SNYK-CC-K8S-3',
},
];
}
Expand Down

0 comments on commit f0d86d3

Please sign in to comment.