Add summary, submit sources correctly
# Conflicts: # mythx.js
This commit is contained in:
parent
7e9d7a1eae
commit
25d1fac037
|
@ -150,7 +150,7 @@ class MythXIssues {
|
||||||
const sourceLocation = this.sourceMappingDecoder.atIndex(instNum, this.deployedSourceMap);
|
const sourceLocation = this.sourceMappingDecoder.atIndex(instNum, this.deployedSourceMap);
|
||||||
assert(sourceLocation, 'sourceMappingDecoder.atIndex() should not return null');
|
assert(sourceLocation, 'sourceMappingDecoder.atIndex() should not return null');
|
||||||
const loc = this.sourceMappingDecoder
|
const loc = this.sourceMappingDecoder
|
||||||
.convertOffsetToLineColumn(sourceLocation, lineBreakPositions);
|
.convertOffsetToLineColumn(sourceLocation, lineBreakPositions || []);
|
||||||
|
|
||||||
if (loc.start) {
|
if (loc.start) {
|
||||||
loc.start.line++;
|
loc.start.line++;
|
||||||
|
@ -172,7 +172,7 @@ class MythXIssues {
|
||||||
start: parseInt(ary[0], 10),
|
start: parseInt(ary[0], 10),
|
||||||
};
|
};
|
||||||
const loc = this.sourceMappingDecoder
|
const loc = this.sourceMappingDecoder
|
||||||
.convertOffsetToLineColumn(sourceLocation, lineBreakPositions);
|
.convertOffsetToLineColumn(sourceLocation, lineBreakPositions || []);
|
||||||
if (loc.start) {
|
if (loc.start) {
|
||||||
loc.start.line++;
|
loc.start.line++;
|
||||||
}
|
}
|
||||||
|
@ -271,6 +271,7 @@ function doReport(config, objects, errors, notAnalyzedContracts) {
|
||||||
const eslintIssuesByBaseName = groupEslintIssuesByBasename(eslintIssues);
|
const eslintIssuesByBaseName = groupEslintIssuesByBasename(eslintIssues);
|
||||||
|
|
||||||
const uniqueIssues = getUniqueIssues(eslintIssuesByBaseName);
|
const uniqueIssues = getUniqueIssues(eslintIssuesByBaseName);
|
||||||
|
printSummary(objects, uniqueIssues, config.logger);
|
||||||
const formatter = getFormatter(config.style);
|
const formatter = getFormatter(config.style);
|
||||||
const report = formatter(uniqueIssues);
|
const report = formatter(uniqueIssues);
|
||||||
config.logger.info(report);
|
config.logger.info(report);
|
||||||
|
@ -317,6 +318,29 @@ function doReport(config, objects, errors, notAnalyzedContracts) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function printSummary(objects, uniqueIssues, logger) {
|
||||||
|
if (objects && objects.length) {
|
||||||
|
logger.info('\nMythX Report Summary'.underline.bold);
|
||||||
|
|
||||||
|
const groupBy = 'groupId';
|
||||||
|
const groups = objects.reduce((accum, curr) => {
|
||||||
|
const issue = uniqueIssues.find((issue) => issue.filePath === curr.buildObj.mainSource);
|
||||||
|
const issueCount = issue.errorCount + issue.warningCount;
|
||||||
|
const marking = issueCount > 0 ? '✖'.red : '✔︎'.green;
|
||||||
|
(accum[curr[groupBy]] = accum[curr[groupBy]] || []).push(` ${marking} ${issue.filePath.cyan}: ${issueCount} issues ${curr.uuid.dim.bold}`);
|
||||||
|
return accum;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
Object.keys(groups).forEach((groupId) => {
|
||||||
|
logger.info(` ${++count}. Group ${groupId.bold.dim}:`);
|
||||||
|
Object.values(groups[groupId]).forEach((contract) => {
|
||||||
|
logger.info(contract);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getFormatter(style) {
|
function getFormatter(style) {
|
||||||
const formatterName = style || 'stylish';
|
const formatterName = style || 'stylish';
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -47,14 +47,20 @@ const buildRequestData = contractObjects => {
|
||||||
const contractFile = contractObjects.contracts[fileKey];
|
const contractFile = contractObjects.contracts[fileKey];
|
||||||
|
|
||||||
Object.keys(contractFile).forEach(function(contractKey, index) {
|
Object.keys(contractFile).forEach(function(contractKey, index) {
|
||||||
const contractJSON = contractFile[contractKey]
|
const contractJSON = contractFile[contractKey];
|
||||||
|
const sourcesToInclude = Object.keys(JSON.parse(contractJSON.metadata).sources);
|
||||||
|
const sourcesFiltered = Object.entries(allSources).filter(([filename, { ast }]) => sourcesToInclude.includes(ast.absolutePath));
|
||||||
|
const sources = {};
|
||||||
|
sourcesFiltered.forEach(([key, value]) => {
|
||||||
|
sources[key] = value;
|
||||||
|
});
|
||||||
const contract = {
|
const contract = {
|
||||||
contractName: contractKey,
|
contractName: contractKey,
|
||||||
bytecode: contractJSON.evm.bytecode.object,
|
bytecode: contractJSON.evm.bytecode.object,
|
||||||
deployedBytecode: contractJSON.evm.deployedBytecode.object,
|
deployedBytecode: contractJSON.evm.deployedBytecode.object,
|
||||||
sourceMap: contractJSON.evm.bytecode.sourceMap,
|
sourceMap: contractJSON.evm.bytecode.sourceMap,
|
||||||
deployedSourceMap: contractJSON.evm.deployedBytecode.sourceMap,
|
deployedSourceMap: contractJSON.evm.deployedBytecode.sourceMap,
|
||||||
sources: allSources,
|
sources,
|
||||||
sourcePath: fileKey
|
sourcePath: fileKey
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,7 +168,7 @@ const cleanAnalyzeDataEmptyProps = (data, debug, logger) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug && unusedFields.length > 0) {
|
if (debug && unusedFields.length > 0) {
|
||||||
logger(`${props.contractName}: Empty JSON data fields from compilation - ${unusedFields.join(', ')}`);
|
logger.debug(`${props.contractName}: Empty JSON data fields from compilation - ${unusedFields.join(', ')}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
45
mythx.js
45
mythx.js
|
@ -9,6 +9,18 @@ const { MythXIssues, doReport } = require('./lib/issues2eslint');
|
||||||
|
|
||||||
const defaultConcurrentAnalyses = 4
|
const defaultConcurrentAnalyses = 4
|
||||||
|
|
||||||
|
function checkEnvVariables(embark) {
|
||||||
|
if (process.env.MYTHX_ETH_ADDRESS) {
|
||||||
|
process.env.MYTHX_USERNAME = process.env.MYTHX_ETH_ADDRESS;
|
||||||
|
embark.logger.warn("The environment variable MYTHX_ETH_ADDRESS has been deprecated in favour of MYTHX_USERNAME and will be removed in future versions. Please update your .env file or your environment variables accordingly.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to MythX via armlet
|
||||||
|
if (!process.env.MYTHX_USERNAME || !process.env.MYTHX_PASSWORD) {
|
||||||
|
throw new Error("Environment variables 'MYTHX_USERNAME' and 'MYTHX_PASSWORD' not found. Place these in a .env file in the root of your ÐApp, add them in the CLI command, ie 'MYTHX_USERNAME=xyz MYTHX_PASSWORD=123 embark run', or add them to your system's environment variables.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function analyse(contracts, cfg, embark) {
|
async function analyse(contracts, cfg, embark) {
|
||||||
|
|
||||||
cfg.logger = embark.logger
|
cfg.logger = embark.logger
|
||||||
|
@ -25,15 +37,7 @@ async function analyse(contracts, cfg, embark) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.MYTHX_ETH_ADDRESS) {
|
checkEnvVariables(embark);
|
||||||
process.env.MYTHX_USERNAME = process.env.MYTHX_ETH_ADDRESS;
|
|
||||||
embark.logger.warn("The environment variable MYTHX_ETH_ADDRESS in favour of MYTHX_USERNAME and will be removed in future versions. Please update your .env file or your environment variables accordingly.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to MythX via armlet
|
|
||||||
if(!process.env.MYTHX_USERNAME || !process.env.MYTHX_PASSWORD) {
|
|
||||||
throw new Error("Environment variables 'MYTHX_USERNAME' and 'MYTHX_PASSWORD' not found. Place these in a .env file in the root of your ÐApp, add them in the CLI command, ie 'MYTHX_USERNAME=xyz MYTHX_PASSWORD=123 embark run', or add them to your system's environment variables.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const armletClient = new armlet.Client(
|
const armletClient = new armlet.Client(
|
||||||
{
|
{
|
||||||
|
@ -83,16 +87,20 @@ async function analyse(contracts, cfg, embark) {
|
||||||
|
|
||||||
async function getStatus(uuid, embark) {
|
async function getStatus(uuid, embark) {
|
||||||
|
|
||||||
|
checkEnvVariables(embark);
|
||||||
|
|
||||||
// Connect to MythX via armlet
|
// Connect to MythX via armlet
|
||||||
const armletClient = new armlet.Client(
|
const armletClient = new armlet.Client(
|
||||||
{
|
{
|
||||||
clientToolName: "embark-mythx",
|
clientToolName: "embark-mythx",
|
||||||
password: process.env.MYTHX_PASSWORD,
|
password: process.env.MYTHX_PASSWORD,
|
||||||
ethAddress: process.env.MYTHX_USERNAME,
|
ethAddress: process.env.MYTHX_USERNAME,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
await armletClient.login();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = await armletClient.getIssues(uuid);
|
const results = await armletClient.getIssues(uuid.toLowerCase());
|
||||||
return ghettoReport(embark.logger, results);
|
return ghettoReport(embark.logger, results);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
embark.logger.warn(err);
|
embark.logger.warn(err);
|
||||||
|
@ -115,7 +123,7 @@ const doAnalysis = async (armletClient, config, contracts, contractNames = null,
|
||||||
initialDelay
|
initialDelay
|
||||||
};
|
};
|
||||||
|
|
||||||
analyzeOpts.data = mythXUtil.cleanAnalyzeDataEmptyProps(obj.buildObj, config.debug, config.logger.debug);
|
analyzeOpts.data = mythXUtil.cleanAnalyzeDataEmptyProps(obj.buildObj, config.debug, config.logger);
|
||||||
analyzeOpts.data.analysisMode = config.full ? "full" : "quick";
|
analyzeOpts.data.analysisMode = config.full ? "full" : "quick";
|
||||||
if (config.debug > 1) {
|
if (config.debug > 1) {
|
||||||
config.logger.debug("analyzeOpts: " + `${util.inspect(analyzeOpts, {depth: null})}`);
|
config.logger.debug("analyzeOpts: " + `${util.inspect(analyzeOpts, {depth: null})}`);
|
||||||
|
@ -125,8 +133,9 @@ const doAnalysis = async (armletClient, config, contracts, contractNames = null,
|
||||||
try {
|
try {
|
||||||
//TODO: Call analyze/analyzeWithStatus asynchronously
|
//TODO: Call analyze/analyzeWithStatus asynchronously
|
||||||
config.logger.info("Submitting '" + obj.contractName + "' for " + analyzeOpts.data.analysisMode + " analysis...")
|
config.logger.info("Submitting '" + obj.contractName + "' for " + analyzeOpts.data.analysisMode + " analysis...")
|
||||||
const {issues, status} = await armletClient.analyzeWithStatus(analyzeOpts);
|
const { issues, status } = await armletClient.analyzeWithStatus(analyzeOpts);
|
||||||
obj.uuid = status.uuid;
|
obj.uuid = status.uuid;
|
||||||
|
obj.groupId = status.groupId;
|
||||||
|
|
||||||
if (status.status === 'Error') {
|
if (status.status === 'Error') {
|
||||||
return [status, null];
|
return [status, null];
|
||||||
|
|
Loading…
Reference in New Issue