snyk-docker-plugin
Version:
Snyk CLI docker plugin
206 lines • 8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildResponse = void 0;
const dep_graph_1 = require("@snyk/dep-graph");
// Module that provides functions to collect and build response after all
// analyses' are done.
const dockerfile_1 = require("./dockerfile");
async function buildResponse(depsAnalysis, dockerfileAnalysis, excludeBaseImageVulns) {
var _a, _b;
const deps = depsAnalysis.depTree.dependencies;
const dockerfilePkgs = collectDockerfilePkgs(dockerfileAnalysis, deps);
const finalDeps = excludeBaseImageDeps(deps, dockerfilePkgs, excludeBaseImageVulns);
/** WARNING! Mutates the depTree.dependencies! */
annotateLayerIds(finalDeps, dockerfilePkgs);
/** This must be called after all final changes to the DependencyTree. */
const depGraph = await dep_graph_1.legacy.depTreeToGraph(depsAnalysis.depTree, depsAnalysis.packageManager);
const additionalFacts = [];
const hashes = depsAnalysis.binaries;
if (hashes && hashes.length > 0) {
const keyBinariesHashesFact = {
type: "keyBinariesHashes",
data: hashes,
};
additionalFacts.push(keyBinariesHashesFact);
}
if (dockerfileAnalysis !== undefined) {
const dockerfileAnalysisFact = {
type: "dockerfileAnalysis",
data: dockerfileAnalysis,
};
additionalFacts.push(dockerfileAnalysisFact);
}
if (depsAnalysis.imageId) {
const imageIdFact = {
type: "imageId",
data: depsAnalysis.imageId,
};
additionalFacts.push(imageIdFact);
}
if (depsAnalysis.imageLayers && depsAnalysis.imageLayers.length > 0) {
const imageLayersFact = {
type: "imageLayers",
data: depsAnalysis.imageLayers,
};
additionalFacts.push(imageLayersFact);
}
if (depsAnalysis.imageLabels) {
const imageLabels = {
type: "imageLabels",
data: depsAnalysis.imageLabels,
};
additionalFacts.push(imageLabels);
}
if (depsAnalysis.imageCreationTime) {
const imageCreationTimeFact = {
type: "imageCreationTime",
data: depsAnalysis.imageCreationTime,
};
additionalFacts.push(imageCreationTimeFact);
}
if (depsAnalysis.rootFsLayers &&
Array.isArray(depsAnalysis.rootFsLayers) &&
depsAnalysis.rootFsLayers.length > 0) {
const rootFsFact = {
type: "rootFs",
data: depsAnalysis.rootFsLayers,
};
additionalFacts.push(rootFsFact);
}
if (depsAnalysis.depTree.targetOS.prettyName) {
const imageOsReleasePrettyNameFact = {
type: "imageOsReleasePrettyName",
data: depsAnalysis.depTree.targetOS.prettyName,
};
additionalFacts.push(imageOsReleasePrettyNameFact);
}
const manifestFiles = depsAnalysis.manifestFiles.length > 0
? depsAnalysis.manifestFiles
: undefined;
if (manifestFiles) {
const imageManifestFilesFact = {
type: "imageManifestFiles",
data: manifestFiles,
};
additionalFacts.push(imageManifestFilesFact);
}
const autoDetectedPackages = (_a = depsAnalysis.autoDetectedUserInstructions) === null || _a === void 0 ? void 0 : _a.dockerfilePackages;
const autoDetectedLayers = (_b = depsAnalysis.autoDetectedUserInstructions) === null || _b === void 0 ? void 0 : _b.dockerfileLayers;
if (autoDetectedPackages &&
Object.keys(autoDetectedPackages).length > 0 &&
autoDetectedLayers &&
Object.keys(autoDetectedLayers).length > 0) {
const autoDetectedPackagesWithChildren = getUserInstructionDeps(autoDetectedPackages, deps);
const autoDetectedUserInstructionsFact = {
type: "autoDetectedUserInstructions",
data: {
dockerfileLayers: autoDetectedLayers,
dockerfilePackages: autoDetectedPackagesWithChildren,
},
};
additionalFacts.push(autoDetectedUserInstructionsFact);
}
const applicationDependenciesScanResults = (depsAnalysis.applicationDependenciesScanResults || []).map((appDepsScanResult) => {
if (depsAnalysis.imageId) {
const imageIdFact = {
type: "imageId",
data: depsAnalysis.imageId,
};
appDepsScanResult.facts.push(imageIdFact);
}
return Object.assign(Object.assign({}, appDepsScanResult), { target: {
image: depGraph.rootPkg.name,
} });
});
const args = depsAnalysis.platform !== undefined
? { platform: depsAnalysis.platform }
: undefined;
const depGraphFact = {
type: "depGraph",
data: depGraph,
};
const scanResults = [
{
facts: [depGraphFact, ...additionalFacts],
target: {
image: depGraph.rootPkg.name,
},
identity: {
type: depGraph.pkgManager.name,
args,
},
},
...applicationDependenciesScanResults,
];
return {
scanResults,
};
}
exports.buildResponse = buildResponse;
function collectDockerfilePkgs(dockerAnalysis, deps) {
if (!dockerAnalysis) {
return;
}
return getUserInstructionDeps(dockerAnalysis.dockerfilePackages, deps);
}
// Iterate over the dependencies list; if one is introduced by the dockerfile,
// flatten its dependencies and append them to the list of dockerfile
// packages. This gives us a reference of all transitive deps installed via
// the dockerfile, and the instruction that installed it.
function getUserInstructionDeps(dockerfilePackages, dependencies) {
for (const dependencyName in dependencies) {
if (dependencies.hasOwnProperty(dependencyName)) {
const sourceOrName = dependencyName.split("/")[0];
const dockerfilePackage = dockerfilePackages[sourceOrName];
if (dockerfilePackage) {
for (const dep of collectDeps(dependencies[dependencyName])) {
dockerfilePackages[dep.split("/")[0]] = Object.assign({}, dockerfilePackage);
}
}
}
}
return dockerfilePackages;
}
function collectDeps(pkg) {
// ES5 doesn't have Object.values, so replace with Object.keys() and map()
return pkg.dependencies
? Object.keys(pkg.dependencies)
.map((name) => pkg.dependencies[name])
.reduce((allDeps, pkg) => {
return [...allDeps, ...collectDeps(pkg)];
}, Object.keys(pkg.dependencies))
: [];
}
// Skip processing if option disabled or dockerfilePkgs is undefined. We
// can't exclude anything in that case, because we can't tell which deps are
// from dockerfile and which from base image.
function excludeBaseImageDeps(deps, dockerfilePkgs, excludeBaseImageVulns) {
if (!excludeBaseImageVulns || !dockerfilePkgs) {
return deps;
}
return extractDockerfileDeps(deps, dockerfilePkgs);
}
function extractDockerfileDeps(allDeps, dockerfilePkgs) {
return Object.keys(allDeps)
.filter((depName) => dockerfilePkgs[depName])
.reduce((extractedDeps, depName) => {
extractedDeps[depName] = allDeps[depName];
return extractedDeps;
}, {});
}
function annotateLayerIds(deps, dockerfilePkgs) {
if (!dockerfilePkgs) {
return;
}
for (const dep of Object.keys(deps)) {
const pkg = deps[dep];
const dockerfilePkg = dockerfilePkgs[dep];
if (dockerfilePkg) {
pkg.labels = Object.assign(Object.assign({}, (pkg.labels || {})), { dockerLayerId: (0, dockerfile_1.instructionDigest)(dockerfilePkg.instruction) });
}
if (pkg.dependencies) {
annotateLayerIds(pkg.dependencies, dockerfilePkgs);
}
}
}
//# sourceMappingURL=response-builder.js.map
;