Merge pull request #50 from jycamier/feat/queries-comment

feat(reports): add reports in the pull request comment
This commit is contained in:
Rafaela Soares
2022-05-27 09:13:54 +01:00
committed by GitHub
5 changed files with 130 additions and 31 deletions

View File

@ -20,5 +20,7 @@ jobs:
output_formats: sarif
ignore_on_exit: results
enable_comments: true
comments_with_queries: true
excluded_column_for_comments_with_queries: "description_id,similarity_id,search_line,search_value,cis_description_id,cis_description_title,cis_description_text,cloud_provider"
- run: ls -la && ls -la myoutput
if: always()

View File

@ -51,32 +51,34 @@ And official documentation page <a href="https://docs.kics.io">docs.kics.io</a>
## Inputs
| Variable | Example Value &nbsp; | Description &nbsp; | Type | Required | Default |
| ------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -------- | --------------------------------------------- |
| enable_comment | true | Enable pull request report comments | Boolean | No | false |
| path | terraform/main.tf,Dockerfile | paths to a file or directories to scan, comma separated list | String | Yes | N/A |
| ignore_on_exit | results | defines which non-zero exit codes should be ignored (all, results, errors, none) | String | No | none |
| fail_on | high,medium | comma separated list of which severities returns exit code !=0 | String | No | high,medium,low,info |
| timeout | 75 | number of seconds the query has to execute before being canceled | String | No | 60 |
| profiling | CPU | turns on profiler that prints resource consumption in the logs during the execution (CPU, MEM) | String | No | N/A |
| config_path | ./kics.config | path to configuration file | String | No | N/A |
| platform_type | terraform,ansible | case insensitive list of platform types to scan | String | No | All platforms |
| exclude_paths | ./shouldNotScan/*,somefile.txt | exclude paths from scan, supports glob, comma separated list | String | No | N/A |
| exclude_queries | a227ec01-f97a-4084-91a4-47b350c1db54 | exclude queries by providing the query ID, comma separated list | String | No | N/A |
| exclude_categories | 'Observability,Networking and Firewall' | exclude categories by providing its name, comma separated list | String | No | N/A |
| exclude_results | 'd4a1fa80-d9d8-450f-87c2-e1f6669c41f8' | exclude results by providing the similarity ID of a result | String | No | N/A |
| include_queries | a227ec01-f97a-4084-91a4-47b350c1db54 | include only specified list of queries to the scan, cannot be provided with query exclusion flags | String | No | N/A |
| output_formats | 'json,sarif' | formats in which the results report will be exported | String | No | json |
| output_path | myResults/ | file path to store result in json format | String | No | "./" |
| payload_path | /tmp/mypayload.json | file path to store source internal representation in JSON format | String | No | N/A |
| queries | | path to directory with queries (default "./assets/queries") | String | No | ./assets/queries downloaded with the binaries |
| verbose | true | verbose scan | Boolean | No | false |
| type | Ansible,Dockerfile | case insensitive comma-separated list of platform types to scan (Ansible, AzureResourceManager, CloudFormation, Dockerfile, Kubernetes, OpenAPI, Terraform) | String | No | all types |
| bom | true | include bill of materials (BoM) in results.json output | Boolean | No | false |
| disable_full_descriptions | false | disable request for full descriptions and use default vulnerability descriptions | Boolean | false |
| disable_secrets | false | disable secrets detection | Boolean | false |
| secrets_regexes_path | ./mydir/secrets-config.json | path to custom secrets regex rules configuration file | String | No | N/A |
| libraries_path | ./myLibsDir | path to directory with Rego libraries | String | No | N/A |
| Variable | Example Value &nbsp; | Description &nbsp; | Type | Required | Default |
|-------------------------------------------|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|---------| -------- |--------------------------------------------------------|
| enable_comment | true | Enable pull request report comments | Boolean | No | false |
| comments_with_queries | true | Add queries in th pull request report comments (available when enable_comments = true) | Boolean | No | false |
| excluded_column_for_comments_with_queries | description_id,similarity_id,search_line,search_value | Excluded columns for the comment with queries, accepts a comma separated list | String | No | description_id,similarity_id,search_line,search_value |
| path | terraform/main.tf,Dockerfile | paths to a file or directories to scan, comma separated list | String | Yes | N/A |
| ignore_on_exit | results | defines which non-zero exit codes should be ignored (all, results, errors, none) | String | No | none |
| fail_on | high,medium | comma separated list of which severities returns exit code !=0 | String | No | high,medium,low,info |
| timeout | 75 | number of seconds the query has to execute before being canceled | String | No | 60 |
| profiling | CPU | turns on profiler that prints resource consumption in the logs during the execution (CPU, MEM) | String | No | N/A |
| config_path | ./kics.config | path to configuration file | String | No | N/A |
| platform_type | terraform,ansible | case insensitive list of platform types to scan | String | No | All platforms |
| exclude_paths | ./shouldNotScan/*,somefile.txt | exclude paths from scan, supports glob, comma separated list | String | No | N/A |
| exclude_queries | a227ec01-f97a-4084-91a4-47b350c1db54 | exclude queries by providing the query ID, comma separated list | String | No | N/A |
| exclude_categories | 'Observability,Networking and Firewall' | exclude categories by providing its name, comma separated list | String | No | N/A |
| exclude_results | 'd4a1fa80-d9d8-450f-87c2-e1f6669c41f8' | exclude results by providing the similarity ID of a result | String | No | N/A |
| include_queries | a227ec01-f97a-4084-91a4-47b350c1db54 | include only specified list of queries to the scan, cannot be provided with query exclusion flags | String | No | N/A |
| output_formats | 'json,sarif' | formats in which the results report will be exported | String | No | json |
| output_path | myResults/ | file path to store result in json format | String | No | "./" |
| payload_path | /tmp/mypayload.json | file path to store source internal representation in JSON format | String | No | N/A |
| queries | | path to directory with queries (default "./assets/queries") | String | No | ./assets/queries downloaded with the binaries |
| verbose | true | verbose scan | Boolean | No | false |
| type | Ansible,Dockerfile | case insensitive comma-separated list of platform types to scan (Ansible, AzureResourceManager, CloudFormation, Dockerfile, Kubernetes, OpenAPI, Terraform) | String | No | all types |
| bom | true | include bill of materials (BoM) in results.json output | Boolean | No | false |
| disable_full_descriptions | false | disable request for full descriptions and use default vulnerability descriptions | Boolean | false |
| disable_secrets | false | disable secrets detection | Boolean | false |
| secrets_regexes_path | ./mydir/secrets-config.json | path to custom secrets regex rules configuration file | String | No | N/A |
| libraries_path | ./myLibsDir | path to directory with Rego libraries | String | No | N/A |
## Simple usage example

View File

@ -10,6 +10,14 @@ inputs:
required: false
default: "false"
description: "Enable pull request report comments"
comments_with_queries:
required: false
default: "false"
description: "Add queries in th pull request report comments (available when enable_comments = true)"
excluded_column_for_comments_with_queries:
required: false
default: "description_id,similarity_id,search_line,search_value"
description: "Excluded columns for the comment with queries, accepts a comma separated list"
path:
description: "paths to a file or directories to scan, accepts a comma separated list"
required: true
@ -89,6 +97,8 @@ runs:
INPUT_TOKEN: ${{ inputs.token }}
INPUT_OUTPUT_PATH: ${{ inputs.output_path }}
INPUT_ENABLE_COMMENTS: ${{ inputs.enable_comments }}
INPUT_COMMENTS_WITH_QUERIES: ${{ inputs.comments_with_queries }}
INPUT_EXCLUDED_COLUMNS_FOR_COMMENTS_WITH_QUERIES: ${{ inputs.excluded_column_for_comments_with_queries }}
INPUT_OUTPUT_FORMATS: ${{ inputs.output_formats }}
WORKSPACE_PATH: $GITHUB_WORKSPACE
args:

View File

@ -11,7 +11,7 @@ const severityIcons = {
}
const emptyIcon = "https://user-images.githubusercontent.com/75368139/137874724-5118ebc4-9769-4eb2-923d-e4ca479f747f.png"
function createComment(results) {
function createComment(results, withQueries = false, excludedColumnsForCommentsWithQueries) {
let message = "![kics-logo](" + kicsLogo + ")\n";
message += `\n**KICS version: ${results['kics_version']}**\n`
@ -42,13 +42,96 @@ function createComment(results) {
message += "\n</td></tr>\n</table>\n\n";
if (withQueries === false) {
return message;
}
message += "### Queries Results\n"
message += "<table>\n";
message += "<tr></tr>\n";
message += "<tr><td>\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</td></tr>\n</table>\n\n";
return message;
}
async function postPRComment(results, repo, prNumber, octokit) {
const message = createComment(results);
function computeFlattenedQueries(results) {
let flattenedQueries = []
for (let index in results["queries"]) {
let value = results["queries"][index]
const { ['files']: files, ...valueWithoutFiles } = value
const { data: comments } = await octokit.rest.issues.listComments({
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,
});

View File

@ -48,6 +48,8 @@ async function main() {
// Get ENV variables
const githubToken = process.env.INPUT_TOKEN;
const enableComments = process.env.INPUT_ENABLE_COMMENTS;
const commentsWithQueries = process.env.INPUT_COMMENTS_WITH_QUERIES;
const excludedColumnsForCommentsWithQueries = process.env.INPUT_EXCLUDED_COLUMNS_FOR_COMMENTS_WITH_QUERIES.split(',');
const outputPath = processOutputPath(process.env.INPUT_OUTPUT_PATH);
const outputFormats = process.env.INPUT_OUTPUT_FORMATS;
const exitCode = process.env.KICS_EXIT_CODE
@ -70,7 +72,7 @@ async function main() {
const parsedResults = readJSON(outputPath.resultsJSONFile);
if (enableComments.toLocaleLowerCase() === "true") {
await commenter.postPRComment(parsedResults, repo, prNumber, octokit);
await commenter.postPRComment(parsedResults, repo, prNumber, octokit, commentsWithQueries.toLocaleLowerCase() === "true", excludedColumnsForCommentsWithQueries);
}
annotator.annotateChangesWithResults(parsedResults);