@peergrade/actions-common-scans
Version:
254 lines (220 loc) • 9.67 kB
JavaScript
const fs = require('fs');
const _ = require('lodash');
const readline = require('readline');
const AdmZip = require('adm-zip');
const request = require('request');
const artifact = require('@actions/artifact');
const { DEFAULT_OPTIONS } = require('./constants');
function createReadStreamSafe(filename, options) {
return new Promise((resolve, reject) => {
const fileStream = fs.createReadStream(filename, options);
fileStream.on('error', reject).on('open', () => {
resolve(fileStream);
});
});
}
let actionHelper = {
getRunnerID: ((body) => {
let results = body.match('RunnerID:\\d+');
if (results !== null && results.length !== 0) {
return results[0].split(':')[1];
}
return null;
}),
processLineByLine: (async (tsvFile) => {
let plugins = [];
try {
const fileStream = await createReadStreamSafe(tsvFile);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
if (line.charAt(0) !== '#') {
let tmp = line.split('\t');
if (tmp[0].trim() !== '' && tmp[1].trim().toUpperCase() === 'IGNORE') {
plugins.push(tmp[0].trim());
}
}
}
} catch (err) {
console.log(`Error when reading the rules file: ${tsvFile}`)
}
return plugins;
}),
createMessage: ((sites, runnerID, runnerLink) => {
const NXT_LINE = '\n';
const TAB = "\t";
const BULLET = "-";
let msg = '';
let instanceCount = 5;
sites.forEach((site => {
msg = msg + `${BULLET} Site: [${site["@name"]}](${site["@name"]}) ${NXT_LINE}`;
if (site.hasOwnProperty('alerts')) {
if (site.alerts.length !== 0) {
msg = `${msg} ${TAB} **New Alerts** ${NXT_LINE}`;
site.alerts.forEach((alert) => {
msg = msg + TAB + `${BULLET} **${alert.name}** [${alert.pluginid}] total: ${alert.instances.length}: ${NXT_LINE}`
for (let i = 0; i < alert['instances'].length; i++) {
if (i >= instanceCount) {
msg = msg + TAB + TAB + `${BULLET} .. ${NXT_LINE}`;
break
}
let instance = alert['instances'][i];
msg = msg + TAB + TAB + `${BULLET} [${instance.uri}](${instance.uri}) ${NXT_LINE}`;
}
});
msg = msg + NXT_LINE
}
}
if (site.hasOwnProperty('removedAlerts')) {
if (site.removedAlerts.length !== 0) {
msg = `${msg} ${TAB} **Resolved Alerts** ${NXT_LINE}`;
site.removedAlerts.forEach((alert) => {
msg = msg + TAB + `${BULLET} **${alert.name}** [${alert.pluginid}] total: ${alert.instances.length}: ${NXT_LINE}`
});
msg = msg + NXT_LINE
}
}
if (site.hasOwnProperty('ignoredAlerts')) {
if (site.ignoredAlerts.length !== 0) {
msg = `${msg} ${TAB} **Ignored Alerts** ${NXT_LINE}`;
site.ignoredAlerts.forEach((alert) => {
msg = msg + TAB + `${BULLET} **${alert.name}** [${alert.pluginid}] total: ${alert.instances.length}: ${NXT_LINE}`
});
msg = msg + NXT_LINE
}
}
msg = msg + NXT_LINE
}));
if (msg.trim() !== '') {
msg = msg + NXT_LINE + runnerLink;
msg = msg + NXT_LINE + runnerID;
}
return msg
}),
generateDifference: ((newReport, oldReport) => {
newReport.updated = false;
let siteClone = [];
newReport.site.forEach((newReportSite) => {
// Check if the new report site already exists in the previous report
let previousSite = _.filter(oldReport.site, s => s['@name'] === newReportSite['@name']);
// If does not exists add it to the array without further processing
if (previousSite.length === 0) {
newReport.updated = true;
siteClone.push(newReportSite);
} else {
// deep clone the variable for further processing
let newSite = JSON.parse(JSON.stringify(newReportSite));
let currentAlerts = newReportSite.alerts;
let previousAlerts = previousSite[0].alerts;
let newAlerts = _.differenceBy(currentAlerts, previousAlerts, 'pluginid');
let removedAlerts = _.differenceBy(previousAlerts, currentAlerts, 'pluginid');
let ignoredAlerts = [];
if (newReportSite.hasOwnProperty('ignoredAlerts') && previousSite[0].hasOwnProperty('ignoredAlerts')) {
ignoredAlerts = _.differenceBy(newReportSite['ignoredAlerts'], previousSite[0]['ignoredAlerts'], 'pluginid');
}else if(newReportSite.hasOwnProperty('ignoredAlerts')){
ignoredAlerts = newReportSite['ignoredAlerts']
}
removedAlerts = _.differenceBy(removedAlerts, ignoredAlerts, 'pluginid');
newSite.alerts = newAlerts;
newSite.removedAlerts = removedAlerts;
newSite.ignoredAlerts = ignoredAlerts;
siteClone.push(newSite);
if (newAlerts.length !== 0 || removedAlerts.length !== 0 || ignoredAlerts.length !== 0) {
newReport.updated = true;
}
}
});
return siteClone;
}),
readMDFile: (async (reportName) => {
let res = '';
try {
res = fs.readFileSync(reportName, {encoding: 'base64'});
} catch (err) {
console.log('error while reading the markdown file!')
}
return res;
}),
checkIfAlertsExists: ((jsonReport) => {
return jsonReport.site.some((s) => {
return (s.hasOwnProperty('alerts') && s.alerts.length !== 0);
});
}),
filterReport: (async (jsonReport, plugins) => {
jsonReport.site.forEach((s) => {
if (s.hasOwnProperty('alerts') && s.alerts.length !== 0) {
console.log(`starting to filter the alerts for site: ${s['@name']}`);
let newAlerts = s.alerts.filter(function (e) {
return !plugins.includes(e.pluginid)
});
let removedAlerts = s.alerts.filter(function (e) {
return plugins.includes(e.pluginid)
});
s.alerts = newAlerts;
s.ignoredAlerts = removedAlerts;
console.log(`#${newAlerts.length} alerts have been identified` +
` and #${removedAlerts.length} alerts have been ignored for the site.`);
}
});
return jsonReport;
}),
readPreviousReport: (async (octokit, owner, repo, workSpace, runnerID, { artifactName } = DEFAULT_OPTIONS) => {
let previousReport;
try{
let artifactList = await octokit.actions.listWorkflowRunArtifacts({
owner: owner,
repo: repo,
run_id: runnerID
});
let artifacts = artifactList.data.artifacts;
let artifactID;
if (artifacts.length !== 0) {
artifacts.forEach((a => {
if (a['name'] === artifactName) {
artifactID = a['id']
}
}));
}
if (artifactID !== undefined) {
let download = await octokit.actions.downloadArtifact({
owner: owner,
repo: repo,
artifact_id: artifactID,
archive_format: 'zip'
});
await new Promise(resolve =>
request(download.url)
.pipe(fs.createWriteStream(`${workSpace}/${artifactName}.zip`))
.on('finish', () => {
resolve();
}));
let zip = new AdmZip(`${workSpace}/${artifactName}.zip`);
let zipEntries = zip.getEntries();
await zipEntries.forEach(function (zipEntry) {
if (zipEntry.entryName === "report_json.json") {
previousReport = JSON.parse(zipEntry.getData().toString('utf8'));
}
});
}
}catch (e) {
console.log(`Error occurred while downloading the artifacts!`)
}
return previousReport;
}),
uploadArtifacts: (async (rootDir, mdReport, jsonReport, htmlReport, { artifactName } = DEFAULT_OPTIONS) => {
const artifactClient = artifact.create();
const files = [
`${rootDir}/${mdReport}`,
`${rootDir}/${jsonReport}`,
`${rootDir}/${htmlReport}`,
];
const rootDirectory = rootDir;
const options = {
continueOnError: true
};
await artifactClient.uploadArtifact(artifactName, files, rootDirectory, options)
})
};
module.exports = actionHelper;