snyk-mvn-plugin
Version:
Snyk CLI Maven plugin
213 lines • 8.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.debug = debug;
exports.getCommand = getCommand;
exports.inspect = inspect;
exports.buildArgs = buildArgs;
const os = require("os");
const fs = require("fs");
const path = require("path");
const parse_versions_1 = require("./parse-versions");
const subProcess = require("./sub-process");
const archive_1 = require("./archive");
const error_format_1 = require("./error-format");
const debugModule = require("debug");
const parse_1 = require("./parse");
const WRAPPERS = ['mvnw', 'mvnw.cmd'];
// To enable debugging output, use `snyk -d`
let logger = null;
function debug(...messages) {
if (logger === null) {
if (process.env.DEBUG) {
debugModule.enable(process.env.DEBUG);
}
logger = debugModule('snyk-mvn-plugin');
}
messages.forEach((m) => logger?.(m));
}
function getCommand(root, targetFile) {
if (!targetFile) {
return 'mvn';
}
const isWinLocal = /^win/.test(os.platform()); // local check, can be stubbed in tests
const wrapperScript = isWinLocal ? 'mvnw.cmd' : './mvnw';
// try to find a sibling wrapper script first
let pathToWrapper = path.resolve(root, path.dirname(targetFile), wrapperScript);
if (fs.existsSync(pathToWrapper)) {
return wrapperScript;
}
// now try to find a wrapper in the root
pathToWrapper = path.resolve(root, wrapperScript);
if (fs.existsSync(pathToWrapper)) {
return wrapperScript;
}
return 'mvn';
}
function getParentDirectory(p) {
return path.dirname(p);
}
// When we have `mvn`, we can run the subProcess from anywhere.
// However due to https://github.com/takari/maven-wrapper/issues/133, `mvnw` can only be run
// within the directory where `mvnw` exists
function findWrapper(mavenCommand, root, targetPath) {
if (mavenCommand === 'mvn') {
return root;
}
// In this branch we need to -find- the mvnw location;
// we start from the containing directory and climb up to the scanned-root-folder
let foundMVWLocation = false;
// Look for mvnw in the current directory. if not - climb one up
let currentFolder = targetPath;
do {
if (getParentDirectory(root) === currentFolder || !currentFolder.length) {
// if we climbed up the tree 1 level higher than our root directory
throw new Error("Couldn't find mvnw");
}
foundMVWLocation = !!WRAPPERS.map((name) => path.join(currentFolder, name)) // paths
.map(fs.existsSync) // since we're on the client's machine - check if the file exists
.filter(Boolean).length; // hope for truths & bolleanify
if (!foundMVWLocation) {
// if we couldn't find the file, go to the parent, or empty string for quick escape if needed
currentFolder = getParentDirectory(currentFolder);
}
} while (!foundMVWLocation);
return currentFolder;
}
async function inspect(root, targetFile, options, snykHttpClient) {
const targetPath = targetFile
? path.resolve(root, targetFile)
: path.resolve(root);
if (!fs.existsSync(targetPath)) {
throw new Error('Could not find file or directory ' + targetPath);
}
if (!options) {
options = {
dev: false,
scanAllUnmanaged: false,
'print-graph': false,
mavenVerboseIncludeAllVersions: false,
};
}
if (targetPath && (0, archive_1.isArchive)(targetPath)) {
debug(`Creating dep-graph from ${targetPath}`);
const depGraph = await (0, archive_1.createDepGraphFromArchive)(root, targetPath, snykHttpClient);
return {
plugin: {
name: 'bundled:maven',
runtime: 'unknown',
meta: {},
},
package: {}, // using dep-graph over depTree
dependencyGraph: depGraph,
};
}
if (options.scanAllUnmanaged) {
const archives = (0, archive_1.findArchives)(root);
if (archives.length > 0) {
debug(`Creating dep-graph from archives in ${root}`);
const depGraph = await (0, archive_1.createDepGraphFromArchives)(root, archives, snykHttpClient);
return {
plugin: {
name: 'bundled:maven',
runtime: 'unknown',
meta: {},
},
package: {}, // using dep-graph over depTree
dependencyGraph: depGraph,
};
}
else {
throw Error(`Could not find any supported files in '${root}'.`);
}
}
const mavenCommand = getCommand(root, targetFile);
const mvnWorkingDirectory = findWrapper(mavenCommand, root, targetPath);
const args = options.args || [];
const verboseEnabled = args.includes('-Dverbose') ||
args.includes('-Dverbose=true') ||
!!options['print-graph'];
const mvnArgs = buildArgs(root, mvnWorkingDirectory, targetFile, args, options.mavenAggregateProject, verboseEnabled);
let result;
try {
debug(`Maven command: ${mavenCommand} ${mvnArgs.join(' ')}`);
debug(`Maven working directory: ${mvnWorkingDirectory}`);
debug(`Verbose enabled: ${verboseEnabled}`);
debug(`Verbose enabled with all versions: ${options.mavenVerboseIncludeAllVersions}`);
result = await subProcess.execute(mavenCommand, mvnArgs, {
cwd: mvnWorkingDirectory,
});
const versionResult = await subProcess.execute(mavenCommand, ['--version'], {
cwd: mvnWorkingDirectory,
});
const parseResult = (0, parse_1.parse)(result, options.dev, verboseEnabled, options.mavenVerboseIncludeAllVersions);
const { javaVersion, mavenVersion } = (0, parse_versions_1.parseVersions)(versionResult);
const mavenPluginVersion = (0, parse_1.parsePluginVersionFromStdout)(result);
return {
plugin: {
name: 'bundled:maven',
runtime: 'unknown',
meta: {
versionBuildInfo: {
metaBuildVersion: {
mavenVersion,
javaVersion,
mavenPluginVersion,
},
},
},
},
...parseResult,
};
}
catch (err) {
if (result)
debug(`>>> Output from mvn: ${result}`);
if (err instanceof Error) {
const msg = (0, error_format_1.formatGenericPluginError)(err, mavenCommand, mvnArgs);
throw new Error(msg);
}
throw err;
}
}
function buildArgs(rootPath, executionPath, targetFile, mavenArgs, mavenAggregateProject = false, verboseEnabled = false) {
let args = [];
if (mavenAggregateProject && !verboseEnabled) {
// to workaround an issue in maven-dependency-tree plugin
// when unpublished artifacts do not exist in either a local or remote repository
// see https://stackoverflow.com/questions/1677473/maven-doesnt-recognize-sibling-modules-when-running-mvn-dependencytree
// addendum: if verboseEnabled we are already forcing a newer maven-dependency-plugin, so this is not required
args = args.concat('test-compile');
}
// when using verbose ensure maven-dependency-plugin version 3 is used
// lower versions do not work with -DoutputType=dot
const mavenDependencyPlugin = verboseEnabled
? 'org.apache.maven.plugins:maven-dependency-plugin:3.6.1:tree'
: 'dependency:tree';
// Requires Maven >= 2.2
args = args.concat([
mavenDependencyPlugin, // use dependency plugin to display a tree of dependencies
'-DoutputType=dot', // use 'dot' output format
'--batch-mode', // clean up output, disables output color and download progress
]);
if (!mavenAggregateProject) {
args = args.concat('--non-recursive'); // do not include modules unless performing aggregate project scan
}
if (targetFile && !mavenAggregateProject) {
// if we are where we can execute - we preserve the original path;
// if not - we rely on the executor (mvnw) to be spawned at the closest directory, leaving us w/ the file itself
if (rootPath === executionPath) {
args.push(`--file="${targetFile}"`);
}
else {
args.push(`--file="${path.basename(targetFile)}"`);
}
}
if (verboseEnabled &&
!mavenArgs.includes('-Dverbose') &&
!mavenArgs.includes('-Dverbose=true')) {
args = args.concat('-Dverbose');
}
args = args.concat(mavenArgs);
return args;
}
//# sourceMappingURL=index.js.map