Skip to content

Commit

Permalink
feat: apply resolutions to all yarn workspaces in a project
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesPatrickGill committed Oct 1, 2021
1 parent 6b8dd6b commit 33c50be
Show file tree
Hide file tree
Showing 9 changed files with 831 additions and 67 deletions.
88 changes: 26 additions & 62 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
"snyk-gradle-plugin": "3.16.2",
"snyk-module": "3.1.0",
"snyk-mvn-plugin": "2.26.2",
"snyk-nodejs-lockfile-parser": "1.37.0",
"snyk-nodejs-lockfile-parser": "1.37.1",
"snyk-nuget-plugin": "1.22.1",
"snyk-php-plugin": "1.9.2",
"snyk-policy": "^1.22.1",
Expand Down
16 changes: 15 additions & 1 deletion src/lib/plugins/nodejs-plugin/yarn-workspaces-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export async function processYarnWorkspaces(
},
scannedProjects: [],
};
let rootWorkspaceManifestContent = {};
// the folders must be ordered highest first
for (const directory of Object.keys(yarnTargetFiles)) {
let isYarnWorkspacePackage = false;
Expand All @@ -92,6 +93,7 @@ export async function processYarnWorkspaces(
}
if (packageJsonFileName === workspaceRoot) {
isRootPackageJson = true;
rootWorkspaceManifestContent = JSON.parse(packageJson.content);
}
}

Expand All @@ -100,8 +102,20 @@ export async function processYarnWorkspaces(
? path.dirname(yarnWorkspacesFilesMap[packageJsonFileName].root)
: path.dirname(packageJsonFileName);
const rootYarnLockfileName = path.join(rootDir, 'yarn.lock');

const yarnLock = await getFileContents(root, rootYarnLockfileName);

if (
rootWorkspaceManifestContent.hasOwnProperty('resolutions') &&
lockFileParser.getYarnLockfileType(yarnLock.content) ===
lockFileParser.LockfileType.yarn2
) {
const parsedManifestContent = JSON.parse(packageJson.content);
packageJson.content = JSON.stringify({
...parsedManifestContent,
resolutions: rootWorkspaceManifestContent['resolutions'],
});
}

const res = await lockFileParser.buildDepTree(
packageJson.content,
yarnLock.content,
Expand Down
51 changes: 48 additions & 3 deletions test/acceptance/cli-test/cli-test.yarn-workspaces.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,52 @@ export const YarnWorkspacesTests: AcceptanceTests = {
'no vulnerable paths found as both policies detected and applied.',
);
},
'test --yarn-workspaces --detection-depth=5 --strict-out-of-sync=false (yarn v2 with resolutions)': (
params,
utils,
) => async (t) => {
// Yarn workspaces for Yarn 2 is only supported on Node 10+
utils.chdirWorkspaces();
const result = await params.cli.test('yarn-workspaces-v2-resolutions', {
yarnWorkspaces: true,
detectionDepth: 5,
strictOutOfSync: false,
printDeps: true,
});
const loadPlugin = sinon.spy(params.plugins, 'loadPlugin');
// the parser is used directly
t.ok(loadPlugin.withArgs('yarn').notCalled, 'skips load plugin');
t.teardown(() => {
loadPlugin.restore();
});
console.log(result.getDisplayResults());
t.match(
result.getDisplayResults(),
'✔ Tested 1 dependencies for known vulnerabilities, no vulnerable paths found.',
'correctly showing dep number',
);
t.match(result.getDisplayResults(), 'Package manager: yarn\n');
t.match(
result.getDisplayResults(),
'Project name: package.json',
'yarn project in output',
);
t.match(
result.getDisplayResults(),
'Project name: tomatoes',
'yarn project in output',
);
t.match(
result.getDisplayResults(),
'Project name: apples',
'yarn project in output',
);
t.match(
result.getDisplayResults(),
'Tested 3 projects, no vulnerable paths were found.',
'no vulnerable paths found as both policies detected and applied.',
);
},
'test --yarn-workspaces --detection-depth=5 multiple workspaces found': (
params,
utils,
Expand Down Expand Up @@ -240,11 +286,10 @@ export const YarnWorkspacesTests: AcceptanceTests = {
'Project name: apples',
'yarn project in output',
);
console.log(result.getDisplayResults());
t.match(
result.getDisplayResults(),
'Tested 10 projects, no vulnerable paths were found.',
'Tested 10 projects',
'Tested 13 projects, no vulnerable paths were found.',
'Tested 13 projects',
);
let policyCount = 0;
const applesWorkspace =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"private": true,
"workspaces": [
"packages/*"
],
"engines": {
"node": "^10.11.0",
"yarn": "1.10.1"
},
"devDependencies": {
"wsrun": "^3.6.2"
},
"dependencies": {
"node-fetch": "^2.3.0"
},
"resolutions": {
"node-uuid": "1.3.0"
},
"packageManager": "yarn@2.4.3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.14.1
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
ignore:
'npm:node-uuid:20160328':
- '*':
reason: None Given
expires: 2020-07-17T17:21:53.744Z
'npm:node-uuid:20111130':
- '*':
reason: None Given
expires: 2020-07-17T21:40:21.917Z
patch: {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "apples",
"version": "1.0.0",
"license": "UNLICENSED",
"main": "./src/index.js",
"scripts": {
"precommit": "lint-staged"
},
"dependencies": {
"node-uuid": "1.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "tomatoes",
"version": "1.0.0",
"license": "UNLICENSED",
"main": "./src/index.js",
"dependencies": {
"node-fetch": "2.2.0",
"object-assign": "4.1.1"
}
}
Loading

0 comments on commit 33c50be

Please sign in to comment.