snyk-docker-plugin
Version:
Snyk CLI docker plugin
160 lines • 6 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildTree = void 0;
/** @deprecated Should implement a new function to build a dependency graph instead. */
function buildTree(targetImage, depType, depInfosList, targetOS) {
// A tag can only occur in the last section of a docker image name, so
// check any colon separator after the final '/'. If there are no '/',
// which is common when using Docker's official images such as
// "debian:stretch", just check for ':'
const finalSlash = targetImage.lastIndexOf("/");
const hasVersion = (finalSlash >= 0 && targetImage.slice(finalSlash).includes(":")) ||
targetImage.includes(":");
// Defaults for simple images from dockerhub, like "node" or "centos"
let imageName = targetImage;
let imageVersion = "latest";
// If we have a version, split on the last ':' to avoid the optional
// port on a hostname (i.e. localhost:5000)
if (hasVersion) {
const versionSeparator = targetImage.lastIndexOf(":");
imageName = targetImage.slice(0, versionSeparator);
imageVersion = targetImage.slice(versionSeparator + 1);
}
if (imageName.endsWith(".tar")) {
imageVersion = "";
}
const shaString = "@sha256";
if (imageName.endsWith(shaString)) {
imageName = imageName.slice(0, imageName.length - shaString.length);
imageVersion = "";
}
const root = {
// don't use the real image name to avoid scanning it as an issue
name: "docker-image|" + imageName,
version: imageVersion,
targetOS,
packageFormatVersion: depType + ":0.0.1",
dependencies: {},
};
const depsMap = depInfosList.reduce((acc, depInfo) => {
const name = depInfo.Name;
acc[name] = depInfo;
return acc;
}, {});
const virtualDepsMap = depInfosList.reduce((acc, depInfo) => {
const providesNames = depInfo.Provides || [];
for (const name of providesNames) {
acc[name] = depInfo;
}
return acc;
}, {});
const depsCounts = {};
for (const depInfo of depInfosList) {
countDepsRecursive(depInfo.Name, new Set(), depsMap, virtualDepsMap, depsCounts);
}
const DEP_FREQ_THRESHOLD = 100;
const tooFrequentDepNames = Object.keys(depsCounts).filter((depName) => {
return depsCounts[depName] > DEP_FREQ_THRESHOLD;
});
const attachDeps = (depInfos) => {
const depNamesToSkip = new Set(tooFrequentDepNames);
for (const depInfo of depInfos) {
const subtree = buildTreeRecursive(depInfo.Name, new Set(), depsMap, virtualDepsMap, depNamesToSkip);
if (subtree) {
root.dependencies[subtree.name] = subtree;
}
}
};
// attach (as direct deps) pkgs not marked auto-installed:
const manuallyInstalledDeps = depInfosList.filter((depInfo) => {
return !depInfo.AutoInstalled;
});
attachDeps(manuallyInstalledDeps);
// attach (as direct deps) pkgs marked as auto-insatalled,
// but not dependant upon:
const notVisitedDeps = depInfosList.filter((depInfo) => {
const depName = depInfo.Name;
return !depsMap[depName]._visited;
});
attachDeps(notVisitedDeps);
// group all the "too frequest" deps under a meta package:
if (tooFrequentDepNames.length > 0) {
const tooFrequentDeps = tooFrequentDepNames.map((name) => {
return depsMap[name];
});
const metaSubtree = {
name: "meta-common-packages",
version: "meta",
dependencies: {},
};
for (const depInfo of tooFrequentDeps) {
const pkg = {
name: depFullName(depInfo),
version: depInfo.Version,
};
metaSubtree.dependencies[pkg.name] = pkg;
}
root.dependencies[metaSubtree.name] = metaSubtree;
}
return root;
}
exports.buildTree = buildTree;
function buildTreeRecursive(depName, ancestors, depsMap, virtualDepsMap, depNamesToSkip) {
const depInfo = depsMap[depName] || virtualDepsMap[depName];
if (!depInfo) {
return null;
}
// "realName" as the argument depName might be a virtual pkg
const realName = depInfo.Name;
const fullName = depFullName(depInfo);
if (ancestors.has(fullName) || depNamesToSkip.has(realName)) {
return null;
}
const tree = {
name: fullName,
version: depInfo.Version,
};
if (depInfo._visited) {
return tree;
}
depInfo._visited = true;
const newAncestors = new Set(ancestors).add(fullName);
const deps = depInfo.Deps || {};
for (const name of Object.keys(deps)) {
const subTree = buildTreeRecursive(name, newAncestors, depsMap, virtualDepsMap, depNamesToSkip);
if (subTree) {
if (!tree.dependencies) {
tree.dependencies = {};
}
if (!tree.dependencies[subTree.name]) {
tree.dependencies[subTree.name] = subTree;
}
}
}
return tree;
}
function countDepsRecursive(depName, ancestors, depsMap, virtualDepsMap, depCounts) {
const depInfo = depsMap[depName] || virtualDepsMap[depName];
if (!depInfo) {
return;
}
// "realName" as the argument depName might be a virtual pkg
const realName = depInfo.Name;
if (ancestors.has(realName)) {
return;
}
depCounts[realName] = (depCounts[realName] || 0) + 1;
const newAncestors = new Set(ancestors).add(realName);
const deps = depInfo.Deps || {};
for (const name of Object.keys(deps)) {
countDepsRecursive(name, newAncestors, depsMap, virtualDepsMap, depCounts);
}
}
function depFullName(depInfo) {
let fullName = depInfo.Name;
if (depInfo.Source) {
fullName = depInfo.Source + "/" + fullName;
}
return fullName;
}
//# sourceMappingURL=index.js.map
;