Skip to content

Commit

Permalink
fix: revert "feat: support snyk code test (#176)" (#179)
Browse files Browse the repository at this point in the history
This reverts commit e8d0ad7.
  • Loading branch information
bastiandoetsch authored Nov 9, 2023
1 parent e8d0ad7 commit 472df91
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 202 deletions.
80 changes: 12 additions & 68 deletions snykTask/src/__tests__/test-task-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
which I don't want to do. */

import { TaskArgs } from '../task-args';
import { Severity, TestType } from '../task-lib';
import { Severity } from '../task-lib';

function defaultTaskArgs(): TaskArgs {
return new TaskArgs({
Expand All @@ -44,23 +44,6 @@ test('ensure no problems if both targetFile and docker-file-path are both not se
expect(fileArg).toBe('');
});

test('ensure no problems if testType set to code and both targetFile and dockerImageName are both set', () => {
const args = defaultTaskArgs();
args.testType = TestType.CODE;
args.dockerImageName = 'some-docker-image';
args.targetFile = 'some-target-file';
args.dockerfilePath = null as any;

const fileArg = args.getFileParameter();
console.log(`fileArg: ${fileArg}`);
if (fileArg == null) {
console.log('fileArg is null');
}

expect(args.testType).toBe('code');
expect(fileArg).toBe('');
});

test("if dockerImageName is specified and (dockerfilePath is not specified but targetFile is and does not contain 'Dockerfile') then return empty string", () => {
const args = defaultTaskArgs();
args.dockerImageName = 'some-docker-image';
Expand Down Expand Up @@ -143,27 +126,17 @@ describe('TaskArgs.setMonitorWhen', () => {

args.setMonitorWhen('always');
expect(args.monitorWhen).toBe('always');

args.testType = TestType.CODE;
args.setMonitorWhen('always');
expect(args.monitorWhen).toBe('never');
});
});

describe('TaskArgs.validate', () => {
const args = defaultTaskArgs();
const testTypeSeverityThreshold = [
[
TestType.APPLICATION,
[Severity.CRITICAL, Severity.HIGH, Severity.MEDIUM, Severity.LOW],
],
[TestType.CODE, [Severity.HIGH, Severity.MEDIUM, Severity.LOW]],
[
TestType.CONTAINER_IMAGE,
[Severity.CRITICAL, Severity.HIGH, Severity.MEDIUM, Severity.LOW],
],
const validSeverityThresholds = [
Severity.CRITICAL,
Severity.HIGH,
Severity.MEDIUM,
Severity.LOW,
];

it('passes validation when correct combination of severity and fail on thresholds', () => {
args.severityThreshold = Severity.LOW;
args.failOnThreshold = Severity.HIGH;
Expand All @@ -180,51 +153,22 @@ describe('TaskArgs.validate', () => {
args.validate();
});

it('throws error if invalid severity threshold for blank testType defaulted to app', () => {
it('throws error if invalid severity threshold', () => {
expect(() => {
args.severityThreshold = 'hey';
args.validate();
}).toThrow(
new Error(
"If set, severityThreshold must be one from [critical,high,medium,low] (case insensitive). If not set, the default is 'low'.",
"If set, severityThreshold must be 'critical' or 'high' or 'medium' or 'low' (case insensitive). If not set, the default is 'low'.",
),
);
});

it('throws error if invalid severity threshold for container testType', () => {
expect(() => {
args.severityThreshold = 'hey';
args.testType = TestType.CONTAINER_IMAGE;
args.validate();
}).toThrow(
new Error(
"If set, severityThreshold must be one from [critical,high,medium,low] (case insensitive). If not set, the default is 'low'.",
),
);
});

it('throws error if invalid severity threshold for code', () => {
expect(() => {
args.codeSeverityThreshold = 'hey';
args.testType = TestType.CODE;
it.each(validSeverityThresholds)(
'passes validation for ${level}',
(level) => {
args.severityThreshold = level;
args.validate();
}).toThrow(
new Error(
"If set, severityThreshold must be one from [high,medium,low] (case insensitive). If not set, the default is 'low'.",
),
);
});

it.each(testTypeSeverityThreshold)(
'passes validation for each test type severity threshold',
(a, b) => {
args.testType = a as TestType;
for (const sev of b) {
args.severityThreshold = sev as Severity;
args.codeSeverityThreshold = sev as Severity;
args.failOnThreshold = sev as Severity;
args.validate();
}
},
);
});
Expand Down
54 changes: 5 additions & 49 deletions snykTask/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
HTML_ATTACHMENT_TYPE,
doVulnerabilitiesExistForFailureThreshold,
Severity,
TestType,
} from './task-lib';
import * as fs from 'fs';
import * as path from 'path';
Expand Down Expand Up @@ -75,7 +74,6 @@ function parseInputArgs(): TaskArgs {
failOnIssues: tl.getBoolInput('failOnIssues', true),
});

taskArgs.testType = tl.getInput('testType', false) || TestType.APPLICATION;
taskArgs.targetFile = tl.getInput('targetFile', false);
taskArgs.dockerImageName = tl.getInput('dockerImageName', false);
taskArgs.dockerfilePath = tl.getInput('dockerfilePath', false);
Expand All @@ -92,7 +90,6 @@ function parseInputArgs(): TaskArgs {
tl.getInput('additionalArguments', false) || '';
taskArgs.testDirectory = tl.getInput('testDirectory', false);
taskArgs.severityThreshold = tl.getInput('severityThreshold', false);
taskArgs.codeSeverityThreshold = tl.getInput('codeSeverityThreshold', false);
taskArgs.failOnThreshold =
tl.getInput('failOnThreshold', false) || Severity.LOW;
taskArgs.ignoreUnknownCA = tl.getBoolInput('ignoreUnknownCA', false);
Expand All @@ -107,14 +104,10 @@ function parseInputArgs(): TaskArgs {
}

const logAllTaskArgs = (taskArgs: TaskArgs) => {
console.log(`taskArgs.testType: ${taskArgs.testType}`);
console.log(`taskArgs.targetFile: ${taskArgs.targetFile}`);
console.log(`taskArgs.dockerImageName: ${taskArgs.dockerImageName}`);
console.log(`taskArgs.dockerfilePath: ${taskArgs.dockerfilePath}`);
console.log(`taskArgs.severityThreshold: ${taskArgs.severityThreshold}`);
console.log(
`taskArgs.codeSeverityThreshold: ${taskArgs.codeSeverityThreshold}`,
);
console.log(`taskArgs.failOnThreshold: ${taskArgs.failOnThreshold}`);
console.log(`taskArgs.projectName: ${taskArgs.projectName}`);
console.log(`taskArgs.organization: ${taskArgs.organization}`);
Expand Down Expand Up @@ -153,20 +146,12 @@ async function runSnykTest(

const snykTestToolRunner = tl
.tool(snykPath)
.argIf(taskArgs.testType == TestType.CODE, 'code')
.argIf(
taskArgs.dockerImageName || taskArgs.testType == TestType.CONTAINER_IMAGE,
'container',
)
.arg('test')
.argIf(
taskArgs.testType != TestType.CODE && taskArgs.severityThreshold,
taskArgs.severityThreshold,
`--severity-threshold=${taskArgs.severityThreshold}`,
)
.argIf(
taskArgs.testType == TestType.CODE && taskArgs.codeSeverityThreshold,
`--severity-threshold=${taskArgs.codeSeverityThreshold}`,
)
.argIf(taskArgs.dockerImageName, `--docker`)
.argIf(taskArgs.dockerImageName, `${taskArgs.dockerImageName}`)
.argIf(fileArg, `--file=${fileArg}`)
.argIf(taskArgs.ignoreUnknownCA, `--insecure`)
Expand Down Expand Up @@ -194,34 +179,9 @@ async function runSnykTest(
if (snykTestExitCode >= CLI_EXIT_CODE_INVALID_USE) {
code = snykTestExitCode;
errorMsg =
'failing task because `snyk` was improperly used or had other errors';
'failing task because `snyk test` was improperly used or had other errors';
}
const snykOutput: SnykOutput = { code: code, message: errorMsg };

// handle snyk code no-issues-found non-existent json by rerunning --json stdout to piped file
if (
taskArgs.testType == TestType.CODE &&
!fs.existsSync(jsonReportOutputPath) &&
snykTestExitCode === CLI_EXIT_CODE_SUCCESS
) {
const echoToolRunner = tl.tool('echo');
const snykCodeTestToolRunner = tl
.tool(snykPath)
.arg('code')
.arg('test')
.arg('--json')
.argIf(
taskArgs.codeSeverityThreshold,
`--severity-threshold=${taskArgs.codeSeverityThreshold}`,
)
.argIf(taskArgs.ignoreUnknownCA, `--insecure`)
.argIf(taskArgs.organization, `--org=${taskArgs.organization}`)
.argIf(taskArgs.projectName, `--project-name=${projectNameArg}`)
.line(taskArgs.additionalArguments)
.pipeExecOutputToTool(echoToolRunner, jsonReportOutputPath);
await snykCodeTestToolRunner.exec(options);
}

removeRegexFromFile(
jsonReportOutputPath,
regexForRemoveCommandLine,
Expand Down Expand Up @@ -255,7 +215,7 @@ const runSnykToHTML = async (
if (snykToHTMLExitCode >= CLI_EXIT_CODE_INVALID_USE) {
code = snykToHTMLExitCode;
errorMsg =
'failing task because `snyk` was improperly used or had other errors';
'failing task because `snyk test` was improperly used or had other errors';
}
const snykOutput: SnykOutput = { code: code, message: errorMsg };
removeRegexFromFile(
Expand All @@ -281,14 +241,10 @@ async function runSnykMonitor(
taskVersion,
snykToken,
);
// not handling snyk code cli upload which is still a closed beta
const snykMonitorToolRunner = tl
.tool(snykPath)
.argIf(
taskArgs.dockerImageName || taskArgs.testType == TestType.CONTAINER_IMAGE,
'container',
)
.arg('monitor')
.argIf(taskArgs.dockerImageName, `--docker`)
.argIf(taskArgs.dockerImageName, `${taskArgs.dockerImageName}`)
.argIf(fileArg, `--file=${fileArg}`)
.argIf(taskArgs.organization, `--org=${taskArgs.organization}`)
Expand Down
53 changes: 21 additions & 32 deletions snykTask/src/task-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import * as tl from 'azure-pipelines-task-lib';
import { Severity, TestType, testTypeSeverityThreshold } from './task-lib';
import { Severity } from './task-lib';
export type MonitorWhen = 'never' | 'noIssuesFound' | 'always';
class TaskArgs {
testType: string | undefined = '';
Expand All @@ -35,8 +35,6 @@ class TaskArgs {
testDirectory: string | undefined = '';
additionalArguments: string = '';
ignoreUnknownCA: boolean = false;
// Snyk Code severity with its own pickList (no critical)
codeSeverityThreshold: string | undefined = '';

delayAfterReportGenerationSeconds: number = 0;

Expand All @@ -48,10 +46,7 @@ class TaskArgs {
public setMonitorWhen(rawInput?: string) {
if (rawInput) {
const lowerCaseInput = rawInput.toLowerCase();
if (this.testType == TestType.CODE) {
console.log('Snyk Code publishes results using --report workflow');
this.monitorWhen = 'never';
} else if (lowerCaseInput === 'never' || lowerCaseInput === 'always') {
if (lowerCaseInput === 'never' || lowerCaseInput === 'always') {
this.monitorWhen = lowerCaseInput;
} else if (lowerCaseInput === 'noissuesfound') {
this.monitorWhen = 'noIssuesFound';
Expand All @@ -62,12 +57,8 @@ class TaskArgs {
}
}
}

// disallow snyk code monitor which follows --report workflow
public shouldRunMonitor(snykTestSuccess: boolean): boolean {
if (this.testType == TestType.CODE) {
return false;
} else if (this.monitorWhen === 'always') {
if (this.monitorWhen === 'always') {
return true;
} else if (this.monitorWhen === 'never') {
return false;
Expand Down Expand Up @@ -111,34 +102,32 @@ class TaskArgs {
return this.projectName;
}

// validate based on testTypeSeverityThreshold applicable thresholds
public validate() {
const taskTestType = this.testType || TestType.APPLICATION;
const taskTestTypeThreshold = testTypeSeverityThreshold.get(taskTestType);

if (this.failOnThreshold) {
if (
!taskTestTypeThreshold?.includes(this.failOnThreshold.toLowerCase())
) {
const errorMsg = `If set, failOnThreshold must be one from [${taskTestTypeThreshold}] (case insensitive). If not set, the default is '${Severity.LOW}'.`;
if (this.isNotValidThreshold(this.failOnThreshold)) {
const errorMsg = `If set, failOnThreshold must be '${Severity.CRITICAL}' or '${Severity.HIGH}' or '${Severity.MEDIUM}' or '${Severity.LOW}' (case insensitive). If not set, the default is '${Severity.LOW}'.`;
throw new Error(errorMsg);
}
}

if (
(this.severityThreshold &&
!taskTestTypeThreshold?.includes(
this.severityThreshold.toLowerCase(),
)) ||
(this.codeSeverityThreshold &&
!taskTestTypeThreshold?.includes(
this.codeSeverityThreshold.toLowerCase(),
))
) {
const errorMsg = `If set, severityThreshold must be one from [${taskTestTypeThreshold}] (case insensitive). If not set, the default is '${Severity.LOW}'.`;
throw new Error(errorMsg);
if (this.severityThreshold) {
if (this.isNotValidThreshold(this.severityThreshold)) {
const errorMsg = `If set, severityThreshold must be '${Severity.CRITICAL}' or '${Severity.HIGH}' or '${Severity.MEDIUM}' or '${Severity.LOW}' (case insensitive). If not set, the default is '${Severity.LOW}'.`;
throw new Error(errorMsg);
}
}
}

private isNotValidThreshold(threshold: string) {
const severityThresholdLowerCase = threshold.toLowerCase();

return (
severityThresholdLowerCase !== Severity.CRITICAL &&
severityThresholdLowerCase !== Severity.HIGH &&
severityThresholdLowerCase !== Severity.MEDIUM &&
severityThresholdLowerCase !== Severity.LOW
);
}
}

export function getAuthToken() {
Expand Down
18 changes: 0 additions & 18 deletions snykTask/src/task-lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,6 @@ export enum Severity {
LOW = 'low',
}

export enum TestType {
APPLICATION = 'app',
CODE = 'code',
CONTAINER_IMAGE = 'container',
}

export const testTypeSeverityThreshold = new Map<string, Array<string>>([
[
TestType.APPLICATION,
[Severity.CRITICAL, Severity.HIGH, Severity.MEDIUM, Severity.LOW],
],
[TestType.CODE, [Severity.HIGH, Severity.MEDIUM, Severity.LOW]],
[
TestType.CONTAINER_IMAGE,
[Severity.CRITICAL, Severity.HIGH, Severity.MEDIUM, Severity.LOW],
],
]);

export function getSeverityOrdinal(severity: string): number {
switch (severity) {
case Severity.CRITICAL:
Expand Down
Loading

0 comments on commit 472df91

Please sign in to comment.