const moment = require('moment')
const { summary } = require('@actions/core/lib/summary');
const kicsLogo = "https://user-images.githubusercontent.com/111127232/203838108-ad537fea-4573-495a-9619-18500ee81dd9.png"
const severityOrder = ["CRITICAL","HIGH", "MEDIUM", "LOW", "INFO", "TRACE"];
const severityIcons = {
"CRITICAL": "https://github.com/Checkmarx/kics-github-action/assets/153724638/fde32f53-95ac-4ca5-acca-46879bbbf36a",
"HIGH": "https://user-images.githubusercontent.com/23239410/92157087-97285600-ee32-11ea-988f-0aca12c4c126.png",
"MEDIUM": "https://user-images.githubusercontent.com/23239410/92157093-98598300-ee32-11ea-83d7-af52251a011b.png",
"LOW": "https://user-images.githubusercontent.com/23239410/92157091-98598300-ee32-11ea-8498-19bd7d62019b.png",
"INFO": "https://user-images.githubusercontent.com/75368139/137872145-b13b5200-6919-43c2-a49b-d3fdbbc20f63.png",
"TRACE": "https://user-images.githubusercontent.com/23239410/92157090-97c0ec80-ee32-11ea-9b2e-aa6b32b03d54.png",
}
const emptyIcon = "https://user-images.githubusercontent.com/75368139/137874724-5118ebc4-9769-4eb2-923d-e4ca479f747f.png"
function createComment(results, withQueries = false, excludedColumnsForCommentsWithQueries) {
let message = "\n";
message += `\n**KICS version: ${results['kics_version']}**\n`
message += "
\n";
message += "
\n";
message += "\n\n";
message += "| | Category | Results |\n";
message += "| --- |--- | --- |\n";
let severityCounters = results['severity_counters']
for (let severity of severityOrder) {
if (severity in severityCounters) {
message += `|  | ${severity.toUpperCase()} | ${severityCounters[severity.toUpperCase()]} |\n`;
}
else {
//const imageTag = ` `;
message += `|  | ${severity.toUpperCase()} | 0 |\n`;
}
}
message += `|  | TOTAL | ${results['total_counter']} |`;
message += "\n\n | \n\n";
message += "| Metric | Values |\n";
message += "| --- | --- |\n";
message += `| Files scanned  | ${results['files_scanned']}\n`;
message += `| Files parsed  | ${results['files_parsed']}\n`;
message += `| Files failed to scan  | ${results['files_failed_to_scan']}\n`;
message += `| Total executed queries  | ${results['queries_total']}\n`;
message += `| Queries failed to execute  | ${results['queries_failed_to_execute']}\n`;
message += `| Execution time  | ${moment(results['end']).diff(moment(results['start']), 'seconds')}\n`;
message += "\n |
\n
\n\n";
if (withQueries === false) {
return message;
}
message += "### Queries Results\n"
message += "\n";
message += "
\n";
message += "| \n\n";
const flattenedQueries = computeFlattenedQueries(results)
const headers = computeHeaders(flattenedQueries)
const excludedColumns = [
"query_url",
... excludedColumnsForCommentsWithQueries
]
// display header
for (let i in headers) {
if (excludedColumns.includes(headers[i])) {
continue
}
let title = headers[i]
.match(/([^\W_]+)/g)
.map(v => v.charAt(0).toUpperCase() + v.substr(1).toLowerCase())
.join(" ")
message += `| ${title}`
}
message += "|\n"
// display line separation
for (let i in headers) {
if (excludedColumns.includes(headers[i])) {
continue
}
message += "|:---"
}
message += "|\n"
flattenedQueries.forEach(function (query) {
headers.forEach(function (header) {
if (excludedColumns.includes(header)) {
return
}
if (query[header] === undefined) {
message += "| "
return
}
if (header === "query_name") {
message += `| [${query[header]}](${query["query_url"]})`
return
}
message += `| ${query[header].toString().replace("\n", " ")}`
})
message += "|\n"
})
message += "\n |
\n
\n\n";
return message;
}
function computeFlattenedQueries(results) {
let flattenedQueries = []
for (let index in results["queries"]) {
let value = results["queries"][index]
const { ['files']: files, ...valueWithoutFiles } = value
for (let idx in value["files"]) {
flattenedQueries.push({...valueWithoutFiles, ...value["files"][idx]})
}
}
return flattenedQueries
}
function computeHeaders(flattenedQueries) {
let tmpHeader = []
for (let ft in flattenedQueries) {
tmpHeader = [
... tmpHeader,
... Object.entries(flattenedQueries[ft]).map(v => v[0])
]
}
return [...new Set(tmpHeader.map(v => v))]
}
async function postPRComment(results, repo, prNumber, octokit, commentWithQueries = false, excludedColumnsForCommentsWithQueries) {
const message = createComment(results, commentWithQueries, excludedColumnsForCommentsWithQueries);
const {data: comments} = await octokit.rest.issues.listComments({
...repo,
issue_number: prNumber,
});
const comment = comments.find((comment) => {
return (
comment.user.login === "github-actions[bot]" &&
comment.body.startsWith("
);
});
if (comment) {
await octokit.rest.issues.updateComment({
...repo,
comment_id: comment.id,
body: message
});
} else {
await octokit.rest.issues.createComment({
...repo,
issue_number: prNumber,
body: message
});
}
}
async function postJobSummary(results, commentWithQueries = false, excludedColumnsForCommentsWithQueries) {
const message = createComment(results, commentWithQueries, excludedColumnsForCommentsWithQueries);
await summary.addRaw(message).write()
}
module.exports = {
postPRComment,
postJobSummary
};