snyk-go-plugin
Advanced tools
Comparing version 1.9.0 to 1.10.0
@@ -11,3 +11,2 @@ "use strict"; | ||
const snyk_go_parser_1 = require("snyk-go-parser"); | ||
const go_mod_analysis_1 = require("./go-mod-analysis"); | ||
const debug = debugLib('snyk-go-plugin'); | ||
@@ -289,4 +288,2 @@ const VIRTUAL_ROOT_NODE_ID = '.'; | ||
} | ||
// For now, this only gets top-level package dependencies. | ||
// TODO(BST-652): indirect dependencies | ||
// TODO(kyegupov): move to a separate file | ||
@@ -300,5 +297,4 @@ function buildDepTreeFromImportsAndModules(root = '.') { | ||
packageFormatVersion: 'golang:0.0.1', | ||
dependencies: {}, | ||
}; | ||
const goDepsOutput = yield subProcess.execute('go list', ['-json', './...'], { cwd: root }); | ||
const goDepsOutput = yield subProcess.execute('go list', ['-json', '-deps', './...'], { cwd: root }); | ||
if (goDepsOutput.includes('matched no packages')) { | ||
@@ -309,47 +305,56 @@ return depTree; | ||
const goDeps = JSON.parse(goDepsString); | ||
const packageImports = extractImports(goDeps); | ||
const moduleGraph = yield go_mod_analysis_1.buildModuleGraph(root); | ||
const topLevelModuleVersions = {}; | ||
if (moduleGraph.root) { | ||
depTree.name = moduleGraph.root; | ||
for (const mv of moduleGraph.edges[moduleGraph.root]) { | ||
const [m, v] = mv.split('@'); | ||
topLevelModuleVersions[m] = v; | ||
} | ||
const packagesByName = {}; | ||
for (const gp of goDeps) { | ||
packagesByName[gp.ImportPath] = gp; // ImportPath is the fully qualified name | ||
} | ||
for (const packageImport of packageImports.values()) { | ||
let version = 'unknown'; | ||
if (isBuiltinPackage(packageImport)) { | ||
// We do not track vulns in Go standard library | ||
continue; | ||
const localPackages = goDeps.filter((gp) => !gp.DepOnly); | ||
if (localPackages[0].Module) { | ||
depTree.name = localPackages[0].Module.Path; | ||
} | ||
const topLevelDeps = extractAllImports(localPackages); | ||
buildTree(depTree, topLevelDeps, packagesByName); | ||
return depTree; | ||
}); | ||
} | ||
exports.buildDepTreeFromImportsAndModules = buildDepTreeFromImportsAndModules; | ||
function buildTree(depTreeNode, depPackages, packagesByName) { | ||
for (const packageImport of depPackages) { | ||
let version = 'unknown'; | ||
if (isBuiltinPackage(packageImport)) { | ||
// We do not track vulns in Go standard library | ||
continue; | ||
} | ||
else if (!packagesByName[packageImport].DepOnly) { | ||
// Do not include packages of this module | ||
continue; | ||
} | ||
else { | ||
const pkg = packagesByName[packageImport]; | ||
if (pkg.Module && pkg.Module.Version) { | ||
version = snyk_go_parser_1.toSnykVersion(snyk_go_parser_1.parseVersion(pkg.Module.Version)); | ||
} | ||
else if (moduleGraph.root && go_mod_analysis_1.isPackageInTheModule(packageImport, moduleGraph.root)) { | ||
// Do not include packages of this module | ||
continue; | ||
} | ||
else { | ||
// This is an O(n*m) algorightm, should be fine for top-level | ||
// TODO(kyegupov): optimize when we get to full trees | ||
const mod = Object.keys(topLevelModuleVersions).find((m) => go_mod_analysis_1.isPackageInTheModule(packageImport, m)); | ||
if (mod) { | ||
version = topLevelModuleVersions[mod]; | ||
} | ||
} | ||
depTree.dependencies[packageImport] = { | ||
const newNode = { | ||
name: packageImport, | ||
version, | ||
}; | ||
if (!depTreeNode.dependencies) { | ||
depTreeNode.dependencies = {}; | ||
} | ||
depTreeNode.dependencies[packageImport] = newNode; | ||
if (packagesByName[packageImport].Imports) { | ||
buildTree(newNode, packagesByName[packageImport].Imports, packagesByName); | ||
} | ||
} | ||
return depTree; | ||
}); | ||
} | ||
} | ||
exports.buildDepTreeFromImportsAndModules = buildDepTreeFromImportsAndModules; | ||
function extractImports(goDeps) { | ||
function extractAllImports(goDeps) { | ||
const goDepsImports = new Set(); | ||
for (const module of goDeps) { | ||
for (const packageImport of module.Imports) { | ||
goDepsImports.add(packageImport); | ||
for (const pkg of goDeps) { | ||
if (pkg.Imports) { | ||
for (const imp of pkg.Imports) { | ||
goDepsImports.add(imp); | ||
} | ||
} | ||
} | ||
return goDepsImports; | ||
return Array.from(goDepsImports); | ||
} | ||
@@ -356,0 +361,0 @@ // Better error message than JSON.parse |
@@ -10,4 +10,5 @@ import * as fs from 'fs'; | ||
import { parseGoPkgConfig, parseGoVendorConfig, GoPackageManagerType, GoProjectConfig } from 'snyk-go-parser'; | ||
import { buildModuleGraph, isPackageInTheModule } from './go-mod-analysis'; | ||
import { | ||
parseGoPkgConfig, parseGoVendorConfig, GoPackageManagerType, GoProjectConfig, toSnykVersion, parseVersion, | ||
} from 'snyk-go-parser'; | ||
@@ -415,3 +416,3 @@ const debug = debugLib('snyk-go-plugin'); | ||
// Dependency information | ||
Imports: string[]; // import paths used by this package | ||
Imports?: string[]; // import paths used by this package | ||
ImportMap: { string: string }; // map from source import to ImportPath (identity entries omitted) | ||
@@ -449,4 +450,6 @@ Deps: string[]; // all (recursively) imported dependencies | ||
// For now, this only gets top-level package dependencies. | ||
// TODO(BST-652): indirect dependencies | ||
interface GoPackagesByName { | ||
[name: string]: GoPackage; | ||
} | ||
// TODO(kyegupov): move to a separate file | ||
@@ -461,5 +464,4 @@ export async function buildDepTreeFromImportsAndModules(root: string = '.') { | ||
packageFormatVersion: 'golang:0.0.1', | ||
dependencies: {}, | ||
}; | ||
const goDepsOutput = await subProcess.execute('go list', ['-json', './...'], { cwd: root } ); | ||
const goDepsOutput = await subProcess.execute('go list', ['-json', '-deps', './...'], { cwd: root } ); | ||
if (goDepsOutput.includes('matched no packages')) { | ||
@@ -470,15 +472,23 @@ return depTree; | ||
const goDeps: GoPackage[] = JSON.parse(goDepsString); | ||
const packageImports = extractImports(goDeps); | ||
const packagesByName: GoPackagesByName = {}; | ||
for (const gp of goDeps) { | ||
packagesByName[gp.ImportPath] = gp; // ImportPath is the fully qualified name | ||
} | ||
const moduleGraph = await buildModuleGraph(root); | ||
const topLevelModuleVersions = {}; | ||
if (moduleGraph.root) { | ||
depTree.name = moduleGraph.root; | ||
for (const mv of moduleGraph.edges[moduleGraph.root]) { | ||
const [m, v] = mv.split('@'); | ||
topLevelModuleVersions[m] = v; | ||
} | ||
const localPackages = goDeps.filter((gp) => !gp.DepOnly); | ||
if (localPackages[0].Module) { | ||
depTree.name = localPackages[0].Module.Path; | ||
} | ||
for (const packageImport of packageImports.values()) { | ||
const topLevelDeps = extractAllImports(localPackages); | ||
buildTree(depTree, topLevelDeps, packagesByName); | ||
return depTree; | ||
} | ||
function buildTree( | ||
depTreeNode: DepTree, | ||
depPackages: string[], | ||
packagesByName: GoPackagesByName, | ||
) { | ||
for (const packageImport of depPackages) { | ||
let version = 'unknown'; | ||
@@ -488,31 +498,35 @@ if (isBuiltinPackage(packageImport)) { | ||
continue; | ||
} else if (moduleGraph.root && isPackageInTheModule(packageImport, moduleGraph.root)) { | ||
} else if (!packagesByName[packageImport].DepOnly) { | ||
// Do not include packages of this module | ||
continue; | ||
} else { | ||
// This is an O(n*m) algorightm, should be fine for top-level | ||
// TODO(kyegupov): optimize when we get to full trees | ||
const mod = Object.keys(topLevelModuleVersions).find((m) => isPackageInTheModule(packageImport, m)); | ||
if (mod) { | ||
version = topLevelModuleVersions[mod]; | ||
const pkg = packagesByName[packageImport]!; | ||
if (pkg.Module && pkg.Module.Version) { | ||
version = toSnykVersion(parseVersion(pkg.Module.Version)); | ||
} | ||
const newNode = { | ||
name: packageImport, | ||
version, | ||
}; | ||
if (!depTreeNode.dependencies) { | ||
depTreeNode.dependencies = {}; | ||
} | ||
depTreeNode.dependencies![packageImport] = newNode; | ||
if (packagesByName[packageImport].Imports) { | ||
buildTree(newNode, packagesByName[packageImport].Imports!, packagesByName); | ||
} | ||
} | ||
depTree.dependencies![packageImport] = { | ||
name: packageImport, | ||
version, | ||
}; | ||
} | ||
return depTree; | ||
} | ||
function extractImports(goDeps: GoPackage[]): Set<string> { | ||
function extractAllImports(goDeps: GoPackage[]): string[] { | ||
const goDepsImports = new Set<string>(); | ||
for (const module of goDeps) { | ||
for (const packageImport of module.Imports) { | ||
goDepsImports.add(packageImport); | ||
for (const pkg of goDeps) { | ||
if (pkg.Imports) { | ||
for (const imp of pkg.Imports) { | ||
goDepsImports.add(imp); | ||
} | ||
} | ||
} | ||
return goDepsImports; | ||
return Array.from(goDepsImports); | ||
} | ||
@@ -519,0 +533,0 @@ |
@@ -42,3 +42,3 @@ { | ||
}, | ||
"version": "1.9.0" | ||
"version": "1.10.0" | ||
} |
Sorry, the diff of this file is not supported yet
73146
23
1472