Skip to content

Commit

Permalink
feat: snyk protect upgrade notification for test command
Browse files Browse the repository at this point in the history
  • Loading branch information
maxjeffos committed Nov 30, 2021
1 parent e92f1b2 commit bed640a
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 0 deletions.
6 changes: 6 additions & 0 deletions packages/snyk-protect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ If you already have Snyk Protect set up, you can migrate to `@snyk/protect` by a
}
```

We have also created the [@snyk/cli-protect-upgrade](https://www.npmjs.com/package/@snyk/cli-protect-upgrade) npx script which you can use to update your project automatically. To use it, `cd` to the location containing the package.json to be updated and run:

```
npx @snyk/cli-protect-upgrade
```

---

Made with 💜 by Snyk
27 changes: 27 additions & 0 deletions src/cli/commands/test/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Debug from 'debug';
import { EOL } from 'os';
const cloneDeep = require('lodash.clonedeep');
const assign = require('lodash.assign');
import chalk from 'chalk';
Expand Down Expand Up @@ -32,6 +33,12 @@ import { setDefaultTestOptions } from './set-default-test-options';
import { processCommandArgs } from '../process-command-args';
import { formatTestError } from './format-test-error';
import { displayResult } from '../../../lib/formatters/test/display-result';
import * as analytics from '../../../lib/analytics';

import {
getPackageJsonPathsContainingSnykDependency,
getProtectUpgradeWarningForPaths,
} from '../../../lib/protect-update-notification';

const debug = Debug('snyk-test');
const SEPARATOR = '\n-------------------------------------------------------\n';
Expand All @@ -46,6 +53,16 @@ export default async function test(
validateTestOptions(options);
validateCredentials(options);

const packageJsonPathsWithSnykDepForProtect: string[] = getPackageJsonPathsContainingSnykDependency(
options.file,
paths,
);

analytics.add(
'upgradable-snyk-protect-paths',
packageJsonPathsWithSnykDepForProtect.length,
);

// Handles no image arg provided to the container command until
// a validation interface is implemented in the docker plugin.
if (options.docker && paths.length === 0) {
Expand Down Expand Up @@ -255,6 +272,11 @@ export default async function test(
if (!fail) {
// return here to prevent throwing failure
response += chalk.bold.green(summaryMessage);
response += EOL + EOL;
response += getProtectUpgradeWarningForPaths(
packageJsonPathsWithSnykDepForProtect,
);

return TestCommandResult.createHumanReadableTestCommandResult(
response,
stringifiedJsonData,
Expand All @@ -277,6 +299,11 @@ export default async function test(
}

response += chalk.bold.green(summaryMessage);
response += EOL + EOL;
response += getProtectUpgradeWarningForPaths(
packageJsonPathsWithSnykDepForProtect,
);

return TestCommandResult.createHumanReadableTestCommandResult(
response,
stringifiedJsonData,
Expand Down
116 changes: 116 additions & 0 deletions src/lib/protect-update-notification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { EOL } from 'os';
import * as theme from './theme';
import * as fs from 'fs';
import * as path from 'path';
import * as createDebug from 'debug';

const debug = createDebug('snyk-protect-update-notification');

export function getProtectUpgradeWarningForPaths(
packageJsonPaths: string[],
): string {
try {
if (packageJsonPaths?.length > 0) {
let message = theme.color.status.warn(
`${theme.icon.WARNING} WARNING: It looks like you have the \`snyk\` dependency in the \`package.json\` file(s) at the following path(s):` +
EOL,
);

packageJsonPaths.forEach((p) => {
message += theme.color.status.warn(` - ${p}` + EOL);
});

const githubReadmeUrlShort = 'https://snyk.co/ud1cR'; // https://github.com/snyk/snyk/tree/master/packages/snyk-protect#migrating-from-snyk-protect-to-snykprotect

message += theme.color.status.warn(
`For more information and migration instructions, see ${githubReadmeUrlShort}` +
EOL,
);

return message;
} else {
return '';
}
} catch (e) {
debug('Error in getProtectUpgradeWarningForPaths()', e);
return '';
}
}

export function packageJsonFileExistsInDirectory(
directoryPath: string,
): boolean {
try {
const packageJsonPath = path.resolve(directoryPath, 'package.json');
const fileExists = fs.existsSync(packageJsonPath);
return fileExists;
} catch (e) {
debug('Error in packageJsonFileExistsInDirectory()', e);
return false;
}
}

export function checkPackageJsonForSnykDependency(
packageJsonPath: string,
): boolean {
try {
const fileExists = fs.existsSync(packageJsonPath);
if (fileExists) {
const packageJson = fs.readFileSync(packageJsonPath, 'utf8');
const packageJsonObject = JSON.parse(packageJson);
const snykDependency = packageJsonObject.dependencies['snyk'];
if (snykDependency) {
return true;
}
}
} catch (e) {
debug('Error in checkPackageJsonForSnykDependency()', e);
}
return false;
}

export function getPackageJsonPathsContainingSnykDependency(
fileOption: string | undefined,
paths: string[],
): string[] {
const packageJsonPathsWithSnykDepForProtect: string[] = [];

try {
if (fileOption) {
if (
fileOption.endsWith('package.json') ||
fileOption.endsWith('package-lock.json')
) {
const directoryWithPackageJson = path.dirname(fileOption);
if (packageJsonFileExistsInDirectory(directoryWithPackageJson)) {
const packageJsonPath = path.resolve(
directoryWithPackageJson,
'package.json',
);
const packageJsonContainsSnykDep = checkPackageJsonForSnykDependency(
packageJsonPath,
);
if (packageJsonContainsSnykDep) {
packageJsonPathsWithSnykDepForProtect.push(packageJsonPath);
}
}
}
} else {
paths.forEach((testPath) => {
if (packageJsonFileExistsInDirectory(testPath)) {
const packageJsonPath = path.resolve(testPath, 'package.json');
const packageJsonContainsSnykDep = checkPackageJsonForSnykDependency(
packageJsonPath,
);
if (packageJsonContainsSnykDep) {
packageJsonPathsWithSnykDepForProtect.push(packageJsonPath);
}
}
});
}
} catch (e) {
debug('Error in getPackageJsonPathsContainingSnykDependency()', e);
}

return packageJsonPathsWithSnykDepForProtect;
}
1 change: 1 addition & 0 deletions src/lib/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const icon = {
export const color = {
status: {
error: (text: string) => chalk.red(text),
warn: (text: string) => chalk.yellow(text),
success: (text: string) => chalk.green(text),
},
severity: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
placeholder file so that the `no-package-json` folder which contains this file exists for testing

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "test",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"snyk": "^1.773.0"
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "test",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"snyk": "^1.773.0"
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "test",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
}
}
Loading

0 comments on commit bed640a

Please sign in to comment.