@nodesecure/vulnera
Version:
NodeSecure vulnerabilities strategies
81 lines • 3.49 kB
JavaScript
// Import Internal Dependencies
import * as utils from "../utils.js";
import { VULN_MODE } from "../constants.js";
import { formatVulnsPayload } from "../formats/index.js";
import { Sonatype } from "../database/index.js";
// CONSTANTS
const kRatelimitChunkSize = 128;
export function SonatypeStrategy(options) {
const { credential } = options;
const sonatype = new Sonatype({ credential });
return {
strategy: VULN_MODE.SONATYPE,
hydratePayloadDependencies: hydratePayloadDependencies.bind(null, sonatype)
};
}
/**
* If the package name contains a scope, it must be percent encoded to be spec compliant.
* Otherwise, the Package URL is simply <package-name>@<package-version>.
* See: https://github.com/package-url/purl-spec
*/
function toPackageURL(fullPackageName, packageVersion) {
const isPackageNameScoped = fullPackageName.includes("/");
if (isPackageNameScoped) {
const [scope, packageName] = fullPackageName.split("/");
// Each scope segment must be a percent-encoded string
const scopeEncoded = encodeURIComponent(scope);
return `pkg:npm/${scopeEncoded}/${packageName}@${packageVersion}`;
}
return `pkg:npm/${fullPackageName}@${packageVersion}`;
}
/**
* Coordinates are Sonatype's component identifiers, we must build them
* using package's name and different package's versions
*/
function createPackageURLCoordinates([dependencyName, dependencyPayload]) {
const { versions } = dependencyPayload;
return Object.keys(versions).map((version) => toPackageURL(dependencyName, version));
}
async function fetchDataForPackageURLs(sonatype, unchunkedCoordinates) {
try {
const chunkedCoordinates = [
...utils.chunkArray(unchunkedCoordinates, kRatelimitChunkSize)
];
return sonatype.findMany({ coordinates: chunkedCoordinates });
}
catch {
return [];
}
}
/**
* When targetting npm repositories, the specification is the following:
* pkg:npm/<package-name>@<package-version> such as: pkg:npm/foobar@12.3.1
* For further reading see: https://github.com/package-url/purl-spec
*/
function extractNameFromPackageURL(purl) {
const [, packageData] = purl.split("npm/");
const [packageName] = packageData.split("@");
return decodeURIComponent(packageName);
}
/**
* Package's name is not part of the vulnerability description returned back
* by Sonatype. Given that the package name is required in the NodeSecure
* vulnerability standard format, we must be sure to provide it back after
* reaching the API.
*/
function vulnWithPackageName(packageName) {
return function provideNameToVulnPayload(vuln) {
return { ...vuln, package: packageName };
};
}
async function hydratePayloadDependencies(sonatype, dependencies, options = {}) {
const packageURLsData = await fetchDataForPackageURLs(sonatype, Array.from(dependencies).flatMap(createPackageURLCoordinates));
const formatVulnerabilities = formatVulnsPayload(options.useFormat);
for (const sonatypeResponse of packageURLsData) {
const packageName = extractNameFromPackageURL(sonatypeResponse.coordinates);
const formattedVulnerabilities = formatVulnerabilities(VULN_MODE.SONATYPE, sonatypeResponse.vulnerabilities.map(vulnWithPackageName(packageName)));
const { vulnerabilities } = dependencies.get(packageName);
vulnerabilities.push(...formattedVulnerabilities);
}
}
//# sourceMappingURL=sonatype.js.map