snyk-nuget-plugin 1.8.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc CHANGED
@@ -25,7 +25,7 @@
25
25
  }
26
26
  ],
27
27
  "max-depth": [1, 3],
28
- "max-len": [1, 80],
28
+ "max-len": [1, 100],
29
29
  "max-statements": [1, 25],
30
30
  "new-cap": 0,
31
31
  "no-caller": 2,
package/README.md CHANGED
@@ -8,4 +8,4 @@ Snyk helps you find, fix and monitor for known vulnerabilities in your dependenc
8
8
 
9
9
  ## Snyk NuGet CLI Plugin
10
10
 
11
- The plugin provides dependency metadata for NuGet projects that manifest dependencies in `project.json` or `packages.config` files.
11
+ The plugin provides dependency metadata for NuGet projects that manifest dependencies in `project.json`, `packages.config` or `project.assets.json` files.
package/lib/index.js CHANGED
@@ -1,6 +1,7 @@
1
- var path = require('path');
2
- var dotnetParser = require('./dotnet-parser');
3
- var paketParser = require('snyk-paket-parser');
1
+ 'use strict';
2
+ const path = require('path');
3
+ const nugetParser = require('./nuget-parser');
4
+ const paketParser = require('snyk-paket-parser');
4
5
 
5
6
  function determineManifestType(filename) {
6
7
  switch (true) {
@@ -25,16 +26,15 @@ function determineManifestType(filename) {
25
26
  module.exports = {
26
27
  inspect: function (root, targetFile, options) {
27
28
  options = options || {};
28
- var fileContentPath = path.resolve(root || '.', targetFile || '.');
29
- var manifestType;
29
+ let manifestType;
30
30
  try {
31
31
  manifestType = determineManifestType(path.basename(targetFile || root));
32
32
  } catch (error) {
33
33
  return Promise.reject(error);
34
34
  }
35
35
 
36
- var createPackageTree = function (depTree) {
37
- var targetFramework = depTree.meta ? depTree.meta.targetFramework : undefined; // TODO implement for paket and more than one framework
36
+ const createPackageTree = function (depTree) {
37
+ const targetFramework = depTree.meta ? depTree.meta.targetFramework : undefined; // TODO implement for paket and more than one framework
38
38
  delete depTree.meta;
39
39
  return {
40
40
  package: depTree,
@@ -56,12 +56,11 @@ module.exports = {
56
56
  ).then(createPackageTree);
57
57
  }
58
58
 
59
- return dotnetParser.parse(
59
+ return nugetParser.buildDepTreeFromFiles(
60
60
  root,
61
61
  targetFile,
62
62
  options.packagesFolder,
63
- fileContentPath,
64
- manifestType).then(createPackageTree);
65
-
63
+ manifestType,
64
+ options['assets-project-name']).then(createPackageTree);
66
65
  },
67
66
  };
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const parseXML = require('xml2js').parseString;
5
+ const debug = require('debug')('snyk');
6
+ const _ = require('lodash');
7
+
8
+ function getTargetFrameworksFromProjFile(rootDir) {
9
+ debug('Looking for your .csproj file in ' + rootDir);
10
+ const csprojPath = findFile(rootDir, /.*\.csproj$/);
11
+ if (csprojPath) {
12
+ debug('Checking .net framework version in .csproj file ' + csprojPath);
13
+
14
+ const csprojContents = fs.readFileSync(csprojPath);
15
+
16
+ let frameworks = [];
17
+ parseXML(csprojContents, function (err, parsedCsprojContents) {
18
+ if (err) {
19
+ throw err;
20
+ }
21
+ const versionLoc = _.get(parsedCsprojContents, 'Project.PropertyGroup[0]');
22
+ const versions = _.compact(_.concat([],
23
+ _.get(versionLoc, 'TargetFrameworkVersion[0]') ||
24
+ _.get(versionLoc, 'TargetFramework[0]') ||
25
+ _.get(versionLoc, 'TargetFrameworks[0]', '').split(';')));
26
+
27
+ if (versions.length < 1) {
28
+ debug('Could not find TargetFrameworkVersion/TargetFramework' +
29
+ '/TargetFrameworks defined in the Project.PropertyGroup field of ' +
30
+ 'your .csproj file');
31
+ }
32
+ frameworks = _.compact(_.map(versions, toReadableFramework));
33
+ if (versions.length > 1 && frameworks.length < 1) {
34
+ debug('Could not find valid/supported .NET version in csproj file located at' + csprojPath);
35
+ }
36
+ });
37
+ return frameworks[0];
38
+ }
39
+ debug('.csproj file not found in ' + rootDir + '.');
40
+ }
41
+
42
+ function toReadableFramework(targetFramework) {
43
+ const typeMapping = {
44
+ v: '.NETFramework',
45
+ net: '.NETFramework',
46
+ netstandard: '.NETStandard',
47
+ netcoreapp: '.NETCore',
48
+ };
49
+
50
+ for (const type in typeMapping) {
51
+ if (new RegExp(type + /\d.?\d(.?\d)?$/.source).test(targetFramework)) {
52
+ return {
53
+ framework: typeMapping[type],
54
+ version: targetFramework.split(type)[1],
55
+ original: targetFramework,
56
+ };
57
+ }
58
+ }
59
+ }
60
+
61
+ function findFile(rootDir, filter) {
62
+ if (!fs.existsSync(rootDir)) {
63
+ throw new Error('No such path: ' + rootDir);
64
+ }
65
+ const files = fs.readdirSync(rootDir);
66
+ for (let i = 0; i < files.length; i++) {
67
+ const filename = path.resolve(rootDir, files[i]);
68
+
69
+ if (filter.test(filename)) {
70
+ return filename;
71
+ }
72
+ }
73
+ }
74
+
75
+ module.exports = getTargetFrameworksFromProjFile;
@@ -1,3 +1,4 @@
1
+ 'use strict';
1
2
  var debug = require('debug')('snyk');
2
3
 
3
4
  function Dependency(name, version) {
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
- var Dependency = require('../dependency');
3
- var debug = require('debug')('snyk');
4
- var _ = require('lodash');
2
+ const Dependency = require('../nuget-parser/dependency');
3
+ const debug = require('debug')('snyk');
4
+ const _ = require('lodash');
5
5
 
6
6
  // TODO: any convention for global vars? (gFreqDeps)
7
7
  let freqDeps = {};
@@ -84,16 +84,8 @@ function buildTreeRecursive(targetDeps, depName, parent, treeDepth) {
84
84
  });
85
85
  }
86
86
 
87
-
88
- function getFrameworkObjToRun(manifest) {
87
+ function getFrameworkToRun(manifest) {
89
88
  const frameworks = _.get(manifest, 'project.frameworks');
90
- if (!frameworks) {
91
- throw new Error('No frameworks were found in project.assets.json');
92
- }
93
-
94
- if (_.isEmpty(frameworks)) {
95
- throw new Error('0 frameworks were found in project.assets.json');
96
- }
97
89
 
98
90
  debug(`Available frameworks: '${Object.keys(frameworks)}'`);
99
91
 
@@ -101,19 +93,10 @@ function getFrameworkObjToRun(manifest) {
101
93
  // taking only the first 1
102
94
  const selectedFrameworkKey = Object.keys(frameworks)[0];
103
95
  debug(`Selected framework: '${selectedFrameworkKey}'`);
104
- return frameworks[selectedFrameworkKey];
96
+ return selectedFrameworkKey;
105
97
  }
106
98
 
107
-
108
99
  function getTargetObjToRun(manifest) {
109
- if (!manifest.targets) {
110
- throw new Error('No targets were found in project.assets.json');
111
- }
112
-
113
- if (_.isEmpty(manifest.targets)) {
114
- throw new Error('0 targets were found in project.assets.json');
115
- }
116
-
117
100
  debug(`Available targets: '${Object.keys(manifest.targets)}'`);
118
101
 
119
102
  let selectedTargetKey = Object.keys(manifest.targets)[0];
@@ -123,38 +106,70 @@ function getTargetObjToRun(manifest) {
123
106
  return manifest.targets[selectedTargetKey];
124
107
  }
125
108
 
126
-
127
- function parse(fileContent, packageTree) {
128
- const manifest = JSON.parse(fileContent);
129
-
109
+ function validateManifest(manifest) {
130
110
  if (!manifest.project) {
131
111
  throw new Error('Project field was not found in project.assets.json');
132
112
  }
133
113
 
134
- if (manifest.project.version) {
135
- packageTree.version = manifest.project.version;
114
+ if (!manifest.project.frameworks) {
115
+ throw new Error('No frameworks were found in project.assets.json');
136
116
  }
137
117
 
138
- const selectedFrameworkObj = getFrameworkObjToRun(manifest);
139
- const selectedTargetObj = getTargetObjToRun(manifest);
140
-
141
- initFreqDepsDict();
142
-
143
- const directDependencies = collectFlatList(selectedFrameworkObj.dependencies);
144
- debug(`directDependencies: '${directDependencies}'`);
118
+ if (_.isEmpty(manifest.project.frameworks)) {
119
+ throw new Error('0 frameworks were found in project.assets.json');
120
+ }
145
121
 
146
- directDependencies.forEach(function (directDep) {
147
- debug(`First order dep: '${directDep}'`);
148
- buildTreeRecursive(selectedTargetObj, directDep, packageTree, 0);
149
- });
122
+ if (!manifest.targets) {
123
+ throw new Error('No targets were found in project.assets.json');
124
+ }
150
125
 
151
- if (!_.isEmpty(freqDeps.dependencies.dependencies)) {
152
- packageTree.dependencies['freqSystemDependencies'] = freqDeps.dependencies;
126
+ if (_.isEmpty(manifest.targets)) {
127
+ throw new Error('0 targets were found in project.assets.json');
153
128
  }
154
- // to disconnect the object references inside the tree
155
- // JSON parse/stringify is used
156
- let pathedTree = JSON.parse(JSON.stringify(packageTree.dependencies));
157
- packageTree.dependencies = pathedTree;
158
129
  }
159
130
 
160
- module.exports = parse;
131
+ module.exports = {
132
+ parse: function (tree, manifest) {
133
+ return new Promise(function parseFileContents(resolve, reject) {
134
+ debug('Trying to parse dot-net-cli manifest');
135
+
136
+ try {
137
+ validateManifest(manifest);
138
+ } catch (err) {
139
+ debug('Invalid project.assets.json manifest file');
140
+ reject(err);
141
+ }
142
+
143
+ if (manifest.project.version) {
144
+ tree.version = manifest.project.version;
145
+ }
146
+
147
+ // If a targetFramework was not found in the proj file, we will extract it from the lock file
148
+ if (!tree.meta.targetFramework) {
149
+ tree.meta.targetFramework = getFrameworkToRun(manifest);
150
+ }
151
+ const selectedFrameworkObj = manifest.project.frameworks[tree.meta.targetFramework];
152
+
153
+ // We currently ignore the found targetFramework when looking for target dependencies
154
+ const selectedTargetObj = getTargetObjToRun(manifest);
155
+
156
+ initFreqDepsDict();
157
+
158
+ const directDependencies = collectFlatList(selectedFrameworkObj.dependencies);
159
+ debug(`directDependencies: '${directDependencies}'`);
160
+
161
+ directDependencies.forEach(function (directDep) {
162
+ debug(`First order dep: '${directDep}'`);
163
+ buildTreeRecursive(selectedTargetObj, directDep, tree, 0);
164
+ });
165
+
166
+ if (!_.isEmpty(freqDeps.dependencies.dependencies)) {
167
+ tree.dependencies['freqSystemDependencies'] = freqDeps.dependencies;
168
+ }
169
+ // to disconnect the object references inside the tree
170
+ // JSON parse/stringify is used
171
+ tree.dependencies = JSON.parse(JSON.stringify(tree.dependencies));
172
+ resolve(tree);
173
+ });
174
+ },
175
+ };
@@ -0,0 +1,140 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const debug = require('debug')('snyk');
4
+ const path = require('path');
5
+ const Dependency = require('./dependency');
6
+ const parseNuspec = require('./nuspec-parser');
7
+ const _ = require('lodash');
8
+
9
+ function injectPath(dep, packagesFolder) {
10
+ dep.path = dep.localPath ?
11
+ path.resolve(packagesFolder, dep.localPath)
12
+ : path.resolve(packagesFolder, dep.name + '.' + dep.version);
13
+ if (dep.localPath) {
14
+ delete dep.localPath;
15
+ }
16
+ }
17
+
18
+ function scanInstalled(installedPackages, packagesFolder) {
19
+ const flattenedPackageList = {};
20
+ debug('Located ' + installedPackages.length + ' packages in manifest');
21
+ installedPackages.forEach(function (entry) {
22
+ injectPath(entry, packagesFolder);
23
+ flattenedPackageList[entry.name] =
24
+ flattenedPackageList[entry.name] || entry;
25
+ debug('Entry: ' + entry.name + ' -> ' + entry.path);
26
+ });
27
+ try {
28
+ debug('Scanning local installed folders');
29
+ debug('Trying to read from installed packages folder: ' + packagesFolder);
30
+ fs.readdirSync(packagesFolder)
31
+ .map(function (folderName) {
32
+ try {
33
+ return Dependency.from.folderName(folderName);
34
+ } catch (err) {
35
+ debug('Unable to parse dependency from folder');
36
+ debug(err);
37
+ }
38
+ })
39
+ .forEach(function (dep) {
40
+ if (dep) {
41
+ injectPath(dep, packagesFolder);
42
+ // only add a package from packages folder if version is different
43
+ if (flattenedPackageList[dep.name] &&
44
+ flattenedPackageList[dep.name].version !== dep.version) {
45
+ // prefer found from packages folder (dep) over existing
46
+ debug('For package ' + dep.name + ' the version ' +
47
+ flattenedPackageList[dep.name].version +
48
+ ' was extracted from manifest file.' +
49
+ '\nWe are overwriting it with version ' + dep.version +
50
+ ' from the packages folder');
51
+ flattenedPackageList[dep.name] = dep;
52
+ }
53
+ }
54
+ });
55
+ } catch (err) {
56
+ debug('Could not complete packages folder scanning');
57
+ debug(err);
58
+ }
59
+ return flattenedPackageList;
60
+ }
61
+
62
+ function fetchNugetInformationFromPackages(flattenedPackageList, targetFramework) {
63
+ const nuspecParserChain = [];
64
+ // begin collecting information from .nuget files on installed packages
65
+ debug('Trying to analyze .nuspec files');
66
+ for (const name in flattenedPackageList) {
67
+ const dep = flattenedPackageList[name];
68
+ debug('...' + name);
69
+ nuspecParserChain.push(parseNuspec(dep, targetFramework));
70
+ }
71
+ return Promise.all(nuspecParserChain);
72
+ }
73
+
74
+ function processNugetInformation(nuspecResolutionChain) {
75
+ const nuspecResolutions = {};
76
+ nuspecResolutionChain.forEach(function (resolution) {
77
+ if (!resolution) {
78
+ return;
79
+ } // jscs:ignore
80
+ debug('.nuspec analyzed for ' + resolution.name);
81
+ nuspecResolutions[resolution.name] = resolution;
82
+ });
83
+ return nuspecResolutions;
84
+ }
85
+
86
+ module.exports = {
87
+ parse: function (tree, manifest, targetFramework, packagesFolder) {
88
+ if (!targetFramework) {
89
+ throw new Error('No valid Dotnet target framework found');
90
+ }
91
+
92
+ const flattenedPackageList = scanInstalled(manifest, packagesFolder);
93
+ return fetchNugetInformationFromPackages(flattenedPackageList, targetFramework)
94
+ .then(processNugetInformation)
95
+ .then(function buildDependencyTree(nuspecResolutions) {
96
+ // .nuget parsing is complete, returned as array of promise resolutions
97
+ // now the flat list should be rebuilt as a tree
98
+ debug('Building dependency tree');
99
+ function buildTree(node, requiredChildren, repository) {
100
+ requiredChildren.forEach(function (requiredChild) {
101
+ let transitiveDependency;
102
+ if (flattenedPackageList[requiredChild.name]) {
103
+ // fetch from repo
104
+ transitiveDependency =
105
+ flattenedPackageList[requiredChild.name].cloneShallow();
106
+ } else {
107
+ // create as new (uninstalled)
108
+ transitiveDependency = new Dependency(
109
+ requiredChild.name,
110
+ requiredChild.version);
111
+ }
112
+ const transitiveChildren =
113
+ (nuspecResolutions[transitiveDependency.name] &&
114
+ nuspecResolutions[transitiveDependency.name].children) || [];
115
+ buildTree(
116
+ transitiveDependency,
117
+ transitiveChildren,
118
+ repository);
119
+ node.dependencies[transitiveDependency.name] = transitiveDependency;
120
+ });
121
+ }
122
+
123
+ const _nugtKeyCount = Object.keys(nuspecResolutions).length;
124
+ Object.keys(flattenedPackageList).forEach(function (packageName) {
125
+ tree.dependencies[packageName] =
126
+ flattenedPackageList[packageName].cloneShallow();
127
+ });
128
+ if (_nugtKeyCount > 0) {
129
+ // local folders scanned, build list from .nuspec
130
+ for (const key in nuspecResolutions) {
131
+ const resolution = nuspecResolutions[key];
132
+ const node = flattenedPackageList[resolution.name].cloneShallow();
133
+ buildTree(node, resolution.children, flattenedPackageList);
134
+ tree.dependencies[node.name] = node;
135
+ }
136
+ }
137
+ return tree;
138
+ });
139
+ },
140
+ };
@@ -0,0 +1,88 @@
1
+ 'use strict';
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const debug = require('debug')('snyk');
5
+ const getTargetFrameworkFromProjFile = require('./csproj-parser');
6
+ const _ = require('lodash');
7
+
8
+ const dotnetCoreParser = require('./dotnet-core-parser');
9
+ const dotnetFrameworkParser = require('./dotnet-framework-parser');
10
+ const projectJsonParser = require('./project-json-parser');
11
+ const packagesConfigParser = require('./packages-config-parser');
12
+
13
+ const PARSERS = {
14
+ 'dotnet-core': {
15
+ depParser: dotnetCoreParser,
16
+ fileContentParser: JSON,
17
+ },
18
+ 'project.json': {
19
+ depParser: dotnetFrameworkParser,
20
+ fileContentParser: projectJsonParser,
21
+ },
22
+ 'packages.config': {
23
+ depParser: dotnetFrameworkParser,
24
+ fileContentParser: packagesConfigParser,
25
+ },
26
+ };
27
+
28
+ function getPackagesFolder(packagesFolder, projectRootFolder) {
29
+ if (packagesFolder) {
30
+ return path.resolve(process.cwd(), packagesFolder);
31
+ }
32
+ return path.resolve(projectRootFolder, 'packages');
33
+ }
34
+
35
+ module.exports = {
36
+ buildDepTreeFromFiles: function (root, targetFile, packagesFolderPath, manifestType, useProjectNameFromAssetsFile) {
37
+ const fileContentPath = path.resolve(root || '.', targetFile || '.');
38
+ let fileContent;
39
+ try {
40
+ fileContent = fs.readFileSync(fileContentPath).toString();
41
+ } catch (error) {
42
+ return Promise.reject(error);
43
+ }
44
+ const projectRootFolder = path.resolve(fileContentPath, '../../');
45
+ const packagesFolder = getPackagesFolder(packagesFolderPath, projectRootFolder);
46
+
47
+ const tree = {
48
+ name: path.basename(root || projectRootFolder),
49
+ version: '0.0.0',
50
+ packageFormatVersion: 'nuget:0.0.0',
51
+ dependencies: {},
52
+ };
53
+
54
+ let targetFramework;
55
+ try {
56
+ if (manifestType === 'dotnet-core') {
57
+ targetFramework = getTargetFrameworkFromProjFile(projectRootFolder);
58
+ } else {
59
+ // .csproj is in the same directory as packages.config or project.json
60
+ targetFramework = getTargetFrameworkFromProjFile(path.resolve(fileContentPath, '../'));
61
+ }
62
+ } catch (error) {
63
+ return Promise.reject(error);
64
+ }
65
+
66
+ tree.meta = {
67
+ targetFramework: targetFramework ? targetFramework.original : undefined, //TODO implement for more than one TF
68
+ };
69
+
70
+ const parser = PARSERS[manifestType];
71
+ let manifest = parser.fileContentParser.parse(fileContent, tree);
72
+
73
+ if (manifestType === 'dotnet-core' && useProjectNameFromAssetsFile) {
74
+ let projectName = _.get(manifest, 'project.restore.projectName');
75
+ if (projectName) {
76
+ tree.name = projectName;
77
+ } else {
78
+ debug("project.assets.json file doesn't contain a value for 'projectName'. Using default value: " + tree.name);
79
+ }
80
+ }
81
+
82
+ return parser.depParser.parse(
83
+ tree,
84
+ manifest,
85
+ targetFramework,
86
+ packagesFolder);
87
+ },
88
+ };
@@ -1,24 +1,25 @@
1
- var JSZip = require('jszip');
2
- var fs = require('fs');
3
- var path = require('path');
4
- var parseXML = require('xml2js').parseString;
5
- var Dependency = require('./dependency');
6
- var _ = require('lodash');
7
- var debug = require('debug')('snyk');
1
+ 'use strict';
2
+ const JSZip = require('jszip');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const parseXML = require('xml2js').parseString;
6
+ const Dependency = require('./dependency');
7
+ const _ = require('lodash');
8
+ const debug = require('debug')('snyk');
8
9
 
9
10
  const targetFrameworkRegex = /([.a-zA-Z]+)([.0-9]+)/;
10
11
 
11
- function parseNuspec(dep, targetFrameworks, sep) {
12
+ function parseNuspec(dep, targetFramework, sep) {
12
13
  return Promise.resolve()
13
14
  .then(function () {
14
- var pathSep = sep || '.';
15
- var nupkgPath =
15
+ const pathSep = sep || '.';
16
+ const nupkgPath =
16
17
  path.resolve(dep.path, dep.name + pathSep + dep.version + '.nupkg');
17
- var nupkgData = fs.readFileSync(nupkgPath);
18
+ const nupkgData = fs.readFileSync(nupkgPath);
18
19
  return JSZip.loadAsync(nupkgData);
19
20
  })
20
21
  .then(function (nuspecZipData) {
21
- var nuspecFile = Object.keys(nuspecZipData.files).find(function (file) {
22
+ const nuspecFile = Object.keys(nuspecZipData.files).find(function (file) {
22
23
  return (path.extname(file) === '.nuspec');
23
24
  });
24
25
  return nuspecZipData.files[nuspecFile].async('string');
@@ -30,7 +31,7 @@ function parseNuspec(dep, targetFrameworks, sep) {
30
31
  return reject(err);
31
32
  }
32
33
 
33
- var ownDeps = [];
34
+ let ownDeps = [];
34
35
  // We are only going to check the first targetFramework we encounter
35
36
  // in the future we may want to support multiple, but only once
36
37
  // we have dependency version conflict resolution implemented
@@ -40,7 +41,7 @@ function parseNuspec(dep, targetFrameworks, sep) {
40
41
 
41
42
  // Find and add target framework version specific dependencies
42
43
  const depsForTargetFramework =
43
- extractDepsForTargetFrameworks(rawDependency, targetFrameworks);
44
+ extractDepsForTargetFramework(rawDependency, targetFramework);
44
45
 
45
46
  if (depsForTargetFramework && depsForTargetFramework.group) {
46
47
  ownDeps = _.concat(ownDeps,
@@ -87,7 +88,7 @@ function extractDepsForPlainGroups(rawDependency) {
87
88
  });
88
89
  }
89
90
 
90
- function extractDepsForTargetFrameworks(rawDependency, targetFrameworks) {
91
+ function extractDepsForTargetFramework(rawDependency, targetFramework) {
91
92
  return rawDependency && _(rawDependency.group)
92
93
  .filter(function (group) {
93
94
  return group && group.$ && group.$.targetFramework &&
@@ -103,16 +104,16 @@ function extractDepsForTargetFrameworks(rawDependency, targetFrameworks) {
103
104
  })
104
105
  .orderBy(['framework', 'version'], ['asc', 'desc'])
105
106
  .find(function (group) {
106
- return targetFrameworks[0].framework === group.framework &&
107
- targetFrameworks[0].version >= group.version;
107
+ return targetFramework.framework === group.framework &&
108
+ targetFramework.version >= group.version;
108
109
  });
109
110
  }
110
111
 
111
112
  function extractDepsFromRaw(rawDependencies) {
112
- var deps = [];
113
+ const deps = [];
113
114
  _.forEach(rawDependencies, function (dependency) {
114
115
  if (dependency && dependency.$) {
115
- var dep = new Dependency(dependency.$.id, dependency.$.version);
116
+ const dep = new Dependency(dependency.$.id, dependency.$.version);
116
117
  deps.push(dep);
117
118
  }
118
119
  });
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+ const parseXML = require('xml2js').parseString;
3
+ const debug = require('debug')('snyk');
4
+ const Dependency = require('./dependency');
5
+
6
+ function parsePackagesConfigFileContents(fileContent) {
7
+ const installedPackages = [];
8
+ debug('Trying to parse packages.config manifest');
9
+ parseXML(fileContent, function (err, result) {
10
+ if (err) {
11
+ throw err;
12
+ } else {
13
+ const packages = result.packages.package || [];
14
+
15
+ packages.forEach(
16
+ function scanPackagesConfigNode(node) {
17
+ const installedDependency =
18
+ Dependency.from.packgesConfigEntry(node);
19
+ installedPackages.push(installedDependency);
20
+ });
21
+ }
22
+ });
23
+ return installedPackages;
24
+ }
25
+
26
+ module.exports = {
27
+ parse: parsePackagesConfigFileContents,
28
+ };
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+ const debug = require('debug')('snyk');
3
+ const Dependency = require('./dependency');
4
+
5
+ function scanForDependencies(obj, deps) {
6
+ deps = deps || {};
7
+ if (typeof obj !== 'object') {
8
+ return deps;
9
+ }
10
+ Object.keys(obj).forEach(function (key) {
11
+ if (key === 'dependencies') {
12
+ const dependencies = obj.dependencies;
13
+ Object.keys(dependencies).forEach(function (key) {
14
+ const depName = key;
15
+ let version = dependencies[key];
16
+ if (typeof version === 'object') {
17
+ version = version.version;
18
+ }
19
+ if (typeof version === 'undefined') {
20
+ version = 'unknown';
21
+ } else {
22
+ version = version.toString();
23
+ }
24
+ deps[depName] = version;
25
+ });
26
+ } else {
27
+ scanForDependencies(obj[key], deps);
28
+ }
29
+ });
30
+ return deps;
31
+ }
32
+
33
+ function parseJsonManifest(fileContent) {
34
+ const rawContent = JSON.parse(fileContent);
35
+ const result = {};
36
+ result.dependencies = scanForDependencies(rawContent, {});
37
+ if (typeof rawContent.project === 'object') {
38
+ const pData = rawContent.project;
39
+ const name = (pData.restore && pData.restore.projectName);
40
+ result.project = {
41
+ version: pData.version || '0.0.0',
42
+ };
43
+ if (name) {
44
+ result.project.name = name;
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+
50
+ function parseProjectJsonFileContents(fileContent, tree) {
51
+ const installedPackages = [];
52
+ debug('Trying to parse project.json format manifest');
53
+ const projectData = parseJsonManifest(fileContent);
54
+ const rawDependencies = projectData.dependencies;
55
+ debug(rawDependencies);
56
+ if (rawDependencies) {
57
+ for (const name in rawDependencies) {
58
+ // Array<{ "libraryName": "version" }>
59
+ const version = rawDependencies[name];
60
+ const newDependency = new Dependency(name, version, null);
61
+ installedPackages.push(newDependency);
62
+ }
63
+ }
64
+ if (projectData.project) {
65
+ tree.name = projectData.project.name;
66
+ tree.version = projectData.project.version;
67
+ }
68
+ return installedPackages;
69
+ }
70
+
71
+ module.exports = {
72
+ parse: parseProjectJsonFileContents,
73
+ };
package/package.json CHANGED
@@ -34,5 +34,5 @@
34
34
  "tap": "12.4.1",
35
35
  "tap-only": "0.0.5"
36
36
  },
37
- "version": "1.8.0"
37
+ "version": "1.10.0"
38
38
  }
@@ -1,231 +0,0 @@
1
- var fs = require('fs');
2
- var parseXML = require('xml2js').parseString;
3
- var Dependency = require('./dependency');
4
- var path = require('path');
5
- var parseNuspec = require('./nuspec-parser');
6
- var jsonManifestParser = require('./json-manifest-parser');
7
- var debug = require('debug')('snyk');
8
- var projectJsonFormatParser = require('./formats/dotnet-core-parser');
9
- var determineDotnetVersions = require('./proj-parser');
10
-
11
- function injectProjectData(tree, projectData) {
12
- tree.name = projectData.project.name;
13
- tree.version = projectData.project.version;
14
- }
15
-
16
- function injectPath(dep, packagesFolder) {
17
- dep.path =
18
- dep.localPath ?
19
- path.resolve(packagesFolder, dep.localPath)
20
- : path.resolve(packagesFolder, dep.name + '.' + dep.version);
21
- if (dep.localPath) {
22
- delete dep.localPath;
23
- }
24
- }
25
-
26
- function getPackagesFolder(packagesFolder, projectRootFolder) {
27
- if (packagesFolder) {
28
- return path.resolve(process.cwd(), packagesFolder);
29
- }
30
- return path.resolve(projectRootFolder, 'packages');
31
- }
32
-
33
- module.exports = {
34
- parse: function (root, targetFile, packagesFolder, fileContentPath, manifestType) {
35
- var fileContent;
36
- try {
37
- fileContent = fs.readFileSync(fileContentPath).toString();
38
- } catch (error) {
39
- return Promise.reject(error);
40
- }
41
- var projectRootFolder = path.resolve(fileContentPath, '../../');
42
- var packagesFolder = getPackagesFolder(packagesFolder, projectRootFolder);
43
- var dotnetVersions;
44
-
45
- try {
46
- if (manifestType === 'dotnet-core') {
47
- dotnetVersions = determineDotnetVersions(projectRootFolder);
48
- } else {
49
- // .csproj is in the same directory as packages.config or project.json
50
- dotnetVersions = determineDotnetVersions(path.resolve(fileContentPath, '../'));
51
- }
52
- } catch (error) {
53
- return Promise.reject(error);
54
- }
55
-
56
- debug('Loaded ' + targetFile + ' with manifest type '
57
- + manifestType + ' for .NET version ' + dotnetVersions);
58
-
59
- var flattendPackageList = {};
60
- var nuspecResolutions = {};
61
-
62
- var tree = {
63
- name: path.basename(root || projectRootFolder),
64
- version: '0.0.0',
65
- packageFormatVersion: 'nuget:0.0.0',
66
- dependencies: {},
67
- meta: {
68
- targetFramework: dotnetVersions[0].original, //TODO implement for more than one TF
69
- },
70
- };
71
-
72
- return new Promise(function parseFileContents(resolve, reject) {
73
- var installedPackages = [];
74
- switch (manifestType) {
75
- case 'dotnet-core': {
76
- debug('Trying to parse dot-net-cli manifest');
77
- projectJsonFormatParser(fileContent, tree);
78
- resolve([]); // skip installed dependencies parsing
79
- break;
80
- }
81
- case 'project.json': {
82
- debug('Trying to parse project.json format manifest');
83
- var projectData = jsonManifestParser.parse(fileContent);
84
- var rawDependencies = projectData.dependencies;
85
- debug(rawDependencies);
86
- if (rawDependencies) {
87
- for (var name in rawDependencies) {
88
- // Array<{ "libraryName": "version" }>
89
- var version = rawDependencies[name];
90
- var newDependency = new Dependency(name, version, null);
91
- installedPackages.push(newDependency);
92
- }
93
- }
94
- if (projectData.project) {
95
- injectProjectData(tree, projectData);
96
- }
97
- resolve(installedPackages);
98
- break;
99
- }
100
- case 'packages.config': {
101
- debug('Trying to parse packages.config manifest');
102
- parseXML(fileContent, function scanPackagesConfig(err, result) {
103
- if (err) {
104
- reject(err);
105
- } else {
106
- result.packages.package.forEach(
107
- function scanPackagesConfigNode(node) {
108
- var installedDependency =
109
- Dependency.from.packgesConfigEntry(node);
110
- installedPackages.push(installedDependency);
111
- });
112
- resolve(installedPackages);
113
- }
114
- });
115
- break;
116
- }
117
- }
118
- }).then(function scanInstalled(installedPackages) {
119
- if (manifestType !== 'dotnet-core') {
120
- debug('Located ' + installedPackages.length + ' packages in manifest');
121
- installedPackages.forEach(function (entry) {
122
- injectPath(entry, packagesFolder);
123
- flattendPackageList[entry.name] =
124
- flattendPackageList[entry.name] || entry;
125
- debug('Entry: ' + entry.name + ' -> ' + entry.path);
126
- });
127
- try {
128
- debug('Scanning local installed folders');
129
- debug('Trying to read from installed packages folder: ' +
130
- packagesFolder);
131
- fs.readdirSync(packagesFolder)
132
- .map(function (folderName) {
133
- return Dependency.from.folderName(folderName);
134
- })
135
- .forEach(function (dep) {
136
- injectPath(dep, packagesFolder);
137
- // only add a package from packages folder if version is different
138
- if (flattendPackageList[dep.name] &&
139
- flattendPackageList[dep.name].version !== dep.version) {
140
- // prefer found from packages folder (dep) over existing
141
- debug('For package ' + dep.name + ' the version ' +
142
- flattendPackageList[dep.name].version +
143
- ' was extracted from manifest file.' +
144
- '\nWe are overwriting it with version ' + dep.version +
145
- ' from the packages folder');
146
- flattendPackageList[dep.name] = dep;
147
- }
148
- });
149
- } catch (err) {
150
- debug('Could not complete packages folder scanning');
151
- debug(err);
152
- }
153
- } else {
154
- debug('Located ' +
155
- Object.keys(tree.dependencies).length + 'packages in manifest');
156
- var sorted = {};
157
- Object.keys(flattendPackageList).sort().forEach(function (key) {
158
- sorted[key] = flattendPackageList[key];
159
- });
160
- flattendPackageList = sorted;
161
- }
162
- }).then(function fetchNugetInformationFromPackages() {
163
- var nuspecParserChain = [];
164
- if (manifestType !== 'dotnet-core') {
165
- // begin collecting information from .nuget files on installed packages
166
- debug('Trying to analyze .nuspec files');
167
- for (var name in flattendPackageList) {
168
- var dep = flattendPackageList[name];
169
- debug('...' + name);
170
- nuspecParserChain.push(parseNuspec(dep, dotnetVersions));
171
- }
172
- }
173
- return Promise.all(nuspecParserChain);
174
- }).then(function processNugetInformation(nuspecResolutionChain) {
175
- if (manifestType !== 'dotnet-core') {
176
- nuspecResolutionChain.forEach(function (resolution) {
177
- if (!resolution) {
178
- return;
179
- } // jscs:ignore
180
- debug('.nuspec analyzed for ' + resolution.name);
181
- nuspecResolutions[resolution.name] = resolution;
182
- });
183
- }
184
- }).then(function buildDependencyTree() {
185
- // .nuget parsing is complete, returned as array of promise resolutions
186
- // now the flat list should be rebuilt as a tree
187
- debug('Building dependency tree');
188
- function buildTree(node, requiredChildren, repository) {
189
- requiredChildren.forEach(function (requiredChild) {
190
- var transitiveDependency;
191
- if (flattendPackageList[requiredChild.name]) {
192
- // fetch from repo
193
- transitiveDependency =
194
- flattendPackageList[requiredChild.name].cloneShallow();
195
- } else {
196
- // create as new (uninstalled)
197
- transitiveDependency = new Dependency(
198
- requiredChild.name,
199
- requiredChild.version);
200
- }
201
- var transitiveChildren =
202
- (nuspecResolutions[transitiveDependency.name] &&
203
- nuspecResolutions[transitiveDependency.name].children) || [];
204
- buildTree(
205
- transitiveDependency,
206
- transitiveChildren,
207
- repository);
208
- node.dependencies[transitiveDependency.name] = transitiveDependency;
209
- });
210
- }
211
-
212
- var _nugtKeyCount = Object.keys(nuspecResolutions).length;
213
- Object.keys(flattendPackageList).forEach(function (packageName) {
214
- tree.dependencies[packageName] =
215
- flattendPackageList[packageName].cloneShallow();
216
- });
217
- if (_nugtKeyCount > 0) {
218
- // local folders scanned, build list from .nuspec
219
- for (var key in nuspecResolutions) {
220
- var resolution = nuspecResolutions[key];
221
- var node = flattendPackageList[resolution.name].cloneShallow();
222
- buildTree(node, resolution.children, flattendPackageList);
223
- tree.dependencies[node.name] = node;
224
- }
225
- }
226
- return tree;
227
- })['catch'](function (err) {
228
- throw (err);
229
- });
230
- },
231
- };
@@ -1,16 +0,0 @@
1
- var path = require('path');
2
- var fs = require('fs');
3
-
4
- function findFolder(dir) {
5
- var parts = dir.split(path.sep);
6
- var testPath;
7
- while (parts.length > 0) {
8
- testPath = path.join(parts.join(path.sep), 'packages');
9
- if (fs.existsSync(testPath)) {
10
- return testPath;
11
- }
12
- return false;
13
- }
14
- }
15
-
16
- module.exports = findFolder;
@@ -1,46 +0,0 @@
1
- function scanForDependencies(obj, deps) {
2
- deps = deps || {};
3
- if (typeof obj !== 'object') {
4
- return deps;
5
- }
6
- Object.keys(obj).forEach(function (key) {
7
- if (key === 'dependencies') {
8
- var dependencies = obj.dependencies;
9
- Object.keys(dependencies).forEach(function (key) {
10
- var depName = key;
11
- var version = dependencies[key];
12
- if (typeof version === 'object') {
13
- version = version.version;
14
- }
15
- if (typeof version === 'undefined') {
16
- version = 'unknown';
17
- } else {
18
- version = version.toString();
19
- }
20
- deps[depName] = version;
21
- });
22
- } else {
23
- scanForDependencies(obj[key], deps);
24
- }
25
- });
26
- return deps;
27
- }
28
-
29
- module.exports = {
30
- parse: function parseJsonManifest(fileContent) {
31
- var rawContent = JSON.parse(fileContent);
32
- var result = {};
33
- result.dependencies = scanForDependencies(rawContent, {});
34
- if (typeof rawContent.project === 'object') {
35
- var pData = rawContent.project;
36
- var name = (pData.restore && pData.restore.projectName);
37
- result.project = {
38
- version: pData.version || '0.0.0',
39
- };
40
- if (name) {
41
- result.project.name = name;
42
- }
43
- }
44
- return result;
45
- },
46
- };
@@ -1,75 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const parseXML = require('xml2js').parseString;
4
- const debug = require('debug')('snyk');
5
- const _ = require('lodash');
6
-
7
- function determineDotnetVersions(rootDir) {
8
- debug('Looking for your .csproj file in ' + rootDir);
9
- const csprojPath = findFile(rootDir, /.*\.csproj$/);
10
- if (!csprojPath) {
11
- throw new Error('.csproj file not found in ' + rootDir + '. ' +
12
- 'Make sure project was built before running `snyk test`');
13
- }
14
- debug('Checking .net framework version in .csproj file ' + csprojPath);
15
-
16
- const csprojContents = fs.readFileSync(csprojPath);
17
-
18
- var frameworks = [];
19
- parseXML(csprojContents, function (err, parsedCsprojContents) {
20
- if (err) {
21
- throw err;
22
- }
23
- const versionLoc = _.get(parsedCsprojContents, 'Project.PropertyGroup[0]');
24
- const versions = _.compact(_.concat([],
25
- _.get(versionLoc, 'TargetFrameworkVersion[0]') ||
26
- _.get(versionLoc, 'TargetFramework[0]') ||
27
- _.get(versionLoc, 'TargetFrameworks[0]', '').split(';')));
28
-
29
- if (versions.length < 1) {
30
- throw new Error('Could not find TargetFrameworkVersion/TargetFramework' +
31
- '/TargetFrameworks defined in the Project.PropertyGroup field of ' +
32
- 'your .csproj file');
33
- }
34
- frameworks = _.compact(_.map(versions, toReadableFramework));
35
- });
36
- if (frameworks.length < 1) {
37
- throw new Error('Could not find valid/supported .NET version');
38
- }
39
- return frameworks;
40
- }
41
-
42
- function toReadableFramework(targetFramework) {
43
- const typeMapping = {
44
- v: '.NETFramework',
45
- net: '.NETFramework',
46
- netstandard: '.NETStandard',
47
- netcoreapp: '.NETCore',
48
- };
49
-
50
- for (var type in typeMapping) {
51
- if (new RegExp(type + /\d.?\d(.?\d)?$/.source).test(targetFramework)) {
52
- return {
53
- framework: typeMapping[type],
54
- version: targetFramework.split(type)[1],
55
- original: targetFramework,
56
- };
57
- }
58
- }
59
- }
60
-
61
- function findFile(rootDir, filter) {
62
- if (!fs.existsSync(rootDir)) {
63
- throw new Error('No such path: ' + rootDir);
64
- }
65
- const files = fs.readdirSync(rootDir);
66
- for (var i = 0; i < files.length; i++) {
67
- var filename = path.resolve(rootDir, files[i]);
68
-
69
- if (filter.test(filename)) {
70
- return filename;
71
- }
72
- }
73
- }
74
-
75
- module.exports = determineDotnetVersions;