Skip to content

Commit

Permalink
feat: exit code 0 if nothing is vulnerable
Browse files Browse the repository at this point in the history
Improve exit code to help action `snyk fix` output.
If `snyk test` failed => error
If `snyk test` returned no vulnerable results => success
If `snyk fix` had some errors and nothing was fixed => error
If `snyk fix` fixed anyrying at all => success
  • Loading branch information
lili2311 committed May 5, 2021
1 parent 8e4862d commit a04a1a9
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 4 deletions.
19 changes: 17 additions & 2 deletions src/cli/commands/fix/index.ts
Expand Up @@ -37,14 +37,29 @@ async function fix(...args: MethodArgs): Promise<string> {
validateCredentials(options);
const results: snykFix.EntityToFix[] = [];
results.push(...(await runSnykTestLegacy(options, paths)));

// fix
debug(
`Organization has ${snykFixFeatureFlag} feature flag enabled for experimental Snyk fix functionality`,
);
const vulnerableResults = results.filter(
(res) => Object.keys(res.testResult.issues).length,
);
const { dryRun, quiet } = options;
const { fixSummary, meta } = await snykFix.fix(results, { dryRun, quiet });
if (meta.fixed === 0) {

// `snyk test` did not return any test results
if (results.length === 0) {
throw new Error(fixSummary);
}
// `snyk test` returned no vulnerable results, so nothing to fix
if (vulnerableResults.length === 0) {
return fixSummary;
}
// `snyk test` returned vulnerable results
// however some errors occurred during `snyk fix` and nothing was fixed in the end
const anyFailed = meta.failed > 0;
const noneFixed = meta.fixed === 0;
if (anyFailed && noneFixed) {
throw new Error(fixSummary);
}
return fixSummary;
Expand Down
20 changes: 20 additions & 0 deletions test/fixtures/snyk-fix/test-result-pip-no-vulns.json
@@ -0,0 +1,20 @@
{
"vulnerabilities": [],
"ok": true,
"dependencyCount": 2,
"org": "bananaq",
"policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.19.0\nignore: {}\npatch: {}\n",
"isPrivate": true,
"licensesPolicy": {},
"packageManager": "pip",
"ignoreSettings": null,
"summary": "Tested 1 project, no vulnerable paths were found.",
"filesystemPolicy": false,
"filtered": {
"ignore": [],
"patch": []
},
"uniqueCount": 4,
"projectName": "pip-app",
"foundProjectCount": 23
}
51 changes: 49 additions & 2 deletions test/jest/unit/lib/commands/fix/fix.spec.ts
Expand Up @@ -50,6 +50,19 @@ const pipWithRemediation = JSON.parse(
),
);

const pipNoIssues = JSON.parse(
fs.readFileSync(
pathLib.resolve(
__dirname,
'../../../../../',
'fixtures',
'snyk-fix',
'test-result-pip-no-vulns.json',
),
'utf8',
),
);

describe('snyk fix (functional tests)', () => {
let origStdWrite;
let snykFixSpy: jest.SpyInstance;
Expand Down Expand Up @@ -167,7 +180,7 @@ describe('snyk fix (functional tests)', () => {
);

it(
'snyk fix continues to fix when 1 path fails to test with `snyk fix path1 path2`',
'snyk fix continues to fix when 1 path fails to test with `snyk fix path1 path2` (exit code 0)',
async () => {
// read data from console.log
let stdoutMessages = '';
Expand Down Expand Up @@ -205,7 +218,7 @@ describe('snyk fix (functional tests)', () => {
);

it(
'snyk fails to fix when all path fails to test with `snyk fix path1 path2`',
'snyk fails to fix when all path fails to test with `snyk fix path1 path2` (non 0 error code)',
async () => {
// read data from console.log
let stdoutMessages = '';
Expand Down Expand Up @@ -241,4 +254,38 @@ describe('snyk fix (functional tests)', () => {
},
testTimeout,
);

it(
'snyk succeeds to fix when no vulns `snyk fix path1` (exit code 0)',
async () => {
// read data from console.log
let stdoutMessages = '';
let stderrMessages = '';
jest
.spyOn(console, 'log')
.mockImplementation((msg: string) => (stdoutMessages += msg));
jest
.spyOn(console, 'error')
.mockImplementation((msg: string) => (stderrMessages += msg));

jest.spyOn(snyk, 'test').mockResolvedValue({
...pipNoIssues,
// pip plugin does not return targetFile, instead fix will fallback to displayTargetFile
displayTargetFile: pipRequirementsTxt,
});
const res = await cli.fix(pipAppWorkspace, {
dryRun: true, // prevents write to disc
quiet: true,
});
expect(snykFixSpy).toHaveBeenCalledTimes(1);
expect(snykFixSpy.mock.calls[0][1]).toEqual({
dryRun: true,
quiet: true,
});
expect(stripAnsi(res)).toMatch('No successful fixes');
expect(stdoutMessages).toEqual('');
expect(stderrMessages).toEqual('');
},
testTimeout,
);
});

0 comments on commit a04a1a9

Please sign in to comment.