Skip to content

Commit 4600d2f

Browse files
feat: add output_name input to map KICS --output-name CLI option (#154)
* feat: add output_name input to map KICS --output-name CLI option * feat: pass output_name safely, document it and cover it with tests - Pass --output-name as a single argument so a name with spaces is not split. - Drop a trailing .json from the name, KICS appends the extension itself. - Resolve the entrypoint.sh conflict with the path flags now kept in "$@". - Remove the output_name entry from args, nothing reads positional arguments. - Document output_name in the README. - Cover the flag, the report lookup and the cleanup with tests. --------- Co-authored-by: Artur Ribeiro <153724638+cx-artur-ribeiro@users.noreply.github.com>
1 parent f9c9b7a commit 4600d2f

6 files changed

Lines changed: 49 additions & 6 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ Ensure that you're using the <a href="https://github.com/Checkmarx/kics-github-a
193193
| 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 |
194194
| output_formats | 'json,sarif' | formats in which the results report will be exported | String | No | json |
195195
| output_path | myResults/ | file path to store result in json format | String | No | "./" |
196+
| output_name | my-results | name of the results report files, without extension (KICS adds .json, .sarif); defaults to results | String | No | results |
196197
| payload_path | /tmp/mypayload.json | file path to store source internal representation in JSON format | String | No | N/A |
197198
| queries | | path to directory with queries (default "./assets/queries") | String | No | ./assets/queries downloaded with the binaries |
198199
| verbose | true | verbose scan | Boolean | No | false |

‎action.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ inputs:
7171
output_path:
7272
description: "directory to store results report"
7373
required: false
74+
output_name:
75+
description: "name for output results file"
76+
required: false
7477
payload_path:
7578
description: "file path to store source internal representation in JSON format"
7679
required: false
@@ -113,6 +116,7 @@ runs:
113116
env:
114117
INPUT_TOKEN: ${{ inputs.token }}
115118
INPUT_OUTPUT_PATH: ${{ inputs.output_path }}
119+
INPUT_OUTPUT_NAME: ${{ inputs.output_name }}
116120
INPUT_ENABLE_ANNOTATIONS: ${{ inputs.enable_annotations }}
117121
INPUT_ENABLE_COMMENTS: ${{ inputs.enable_comments }}
118122
INPUT_ENABLE_JOBS_SUMMARY: ${{ inputs.enable_jobs_summary }}

‎entrypoint.sh‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ fi
6666
# Check for Output Path #
6767
############################
6868

69-
CP_PATH="./results.json"
69+
# KICS appends the extension itself, so a trailing .json would only confuse the file lookup
70+
INPUT_OUTPUT_NAME="${INPUT_OUTPUT_NAME%.json}"
71+
[[ ! -z "$INPUT_OUTPUT_NAME" ]] && set -- "$@" --output-name "$INPUT_OUTPUT_NAME"
72+
73+
CP_PATH="./${INPUT_OUTPUT_NAME:-results}.json"
7074
if [ ! -z "$INPUT_OUTPUT_PATH" ]; then
7175
set -- "$@" -o "$INPUT_OUTPUT_PATH"
7276
CP_PATH=$INPUT_OUTPUT_PATH

‎src/main.js‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,18 @@ async function cleanupOutput(resultsJSONFile, outputFormats) {
2222
}
2323
}
2424

25-
function processOutputPath(output) {
25+
function processOutputPath(output, outputName) {
26+
const resultsFilename = outputName || "results";
2627
if (output === '') {
2728
return {
2829
path: "./",
29-
resultsJSONFile: "./results.json"
30+
resultsJSONFile: `./${resultsFilename}.json`
3031
}
3132
}
3233

3334
return {
3435
path: output,
35-
resultsJSONFile: filepath.join(output, "/results.json")
36+
resultsJSONFile: filepath.join(output, `/${resultsFilename}.json`)
3637
}
3738
}
3839

@@ -56,7 +57,7 @@ async function main() {
5657
let enableJobsSummary = process.env.INPUT_ENABLE_JOBS_SUMMARY;
5758
const commentsWithQueries = process.env.INPUT_COMMENTS_WITH_QUERIES;
5859
const excludedColumnsForCommentsWithQueries = process.env.INPUT_EXCLUDED_COLUMNS_FOR_COMMENTS_WITH_QUERIES.split(',');
59-
const outputPath = processOutputPath(process.env.INPUT_OUTPUT_PATH);
60+
const outputPath = processOutputPath(process.env.INPUT_OUTPUT_PATH, process.env.INPUT_OUTPUT_NAME);
6061
const outputFormats = process.env.INPUT_OUTPUT_FORMATS;
6162
const exitCode = process.env.KICS_EXIT_CODE
6263

‎test/e2e/entrypoint.test.js‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ test('inputs mapped to KICS flags', async (t) => {
6464
['exclude_categories', 'Observability,Backup', '--exclude-categories'],
6565
['platform_type', 'Terraform,Dockerfile', '--type'],
6666
['type', 'Ansible,Dockerfile', '--type'],
67+
['output_name', 'my-results', '--output-name'],
6768
['fail_on', 'high,medium', '--fail-on'],
6869
['timeout', '60', '--timeout'],
6970
['profiling', 'CPU', '--profiling'],
@@ -93,6 +94,7 @@ test('inputs mapped to KICS flags', async (t) => {
9394
['secrets_regexes_path', 'my dir/secret regexes.json', '-r'],
9495
['queries', 'my queries,team queries', '-q'],
9596
['output_path', 'my out', '-o'],
97+
['output_name', 'my results', '--output-name'],
9698
]
9799
for (const [input, value, flag] of withSpaces) {
98100
await t.test(`${input} keeps a value containing spaces as one argument`, async (t) => {
@@ -101,6 +103,15 @@ test('inputs mapped to KICS flags', async (t) => {
101103
})
102104
}
103105

106+
await t.test('output_name is given to KICS without the .json extension it appends itself', async (t) => {
107+
const run = await runEntrypoint(t, { inputs: { output_name: 'my-results.json' } })
108+
assert.equal(flagValue(run.args, '--output-name'), 'my-results')
109+
})
110+
111+
await t.test('output_name left unset -> no --output-name', async (t) => {
112+
assert.ok(!(await runEntrypoint(t)).args.includes('--output-name'))
113+
})
114+
104115
const switches = [
105116
['exclude_gitignore', '--exclude-gitignore'],
106117
['disable_secrets', '--disable-secrets'],
@@ -248,6 +259,23 @@ test('whole action: entrypoint, KICS, JavaScript stage and GitHub', async (t) =>
248259
assert.match(run.summary, /\| TOTAL \| 4 \|/, run.stdout + run.stderr)
249260
})
250261

262+
for (const name of ['my-results', 'my results', 'my-results.json']) {
263+
await t.test(`reports named "${name}" through output_name are picked up`, async (t) => {
264+
const run = await runEntrypoint(t, { runMain: true, results: kicsResults(), inputs: { output_name: name, enable_jobs_summary: 'true' } })
265+
assert.match(run.summary, /\| TOTAL \| 4 \|/, run.stdout + run.stderr)
266+
})
267+
}
268+
269+
await t.test('reports named through output_name are picked up from output_path', async (t) => {
270+
const run = await runEntrypoint(t, { runMain: true, results: kicsResults(), inputs: { output_name: 'my-results', output_path: 'reports', enable_jobs_summary: 'true' } })
271+
assert.match(run.summary, /\| TOTAL \| 4 \|/, run.stdout + run.stderr)
272+
})
273+
274+
await t.test('the workspace is left without the named report nobody asked for', async (t) => {
275+
const run = await runEntrypoint(t, { runMain: true, results: kicsResults(), inputs: { output_name: 'my-results', output_formats: 'sarif' } })
276+
assert.equal(fs.existsSync(path.join(run.workspace, 'my-results.json')), false)
277+
})
278+
251279
await t.test('results.json is left readable for the next workflow steps', async (t) => {
252280
const run = await runEntrypoint(t, { results: kicsResults() })
253281
const mode = fs.statSync(path.join(run.workspace, 'results.json')).mode

‎test/helpers/run-entrypoint.js‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,18 @@ function sandboxedEntrypoint(sandbox) {
2828
const FAKE_KICS = `#!/bin/bash
2929
printf '%s\\n' "$@" > "$SANDBOX/kics-args.txt"
3030
out=./
31+
name=""
3132
while [ $# -gt 0 ]; do
3233
if [ "$1" = "-o" ]; then out="$2"; fi
34+
if [ "$1" = "--output-name" ]; then name="$2"; fi
3335
shift
3436
done
37+
# like KICS: the name comes from --output-name (or the config file), and a trailing .json is not doubled
38+
name="\${name:-\${FAKE_KICS_NAME:-results}}"
39+
name="\${name%.json}"
3540
if [ -n "$FAKE_KICS_RESULTS" ]; then
3641
mkdir -p "$out"
37-
file="$out/\${FAKE_KICS_NAME:-results}.json"
42+
file="$out/$name.json"
3843
cp "$FAKE_KICS_RESULTS" "$file"
3944
chmod 755 "$file" # KICS v2.1.20 writes its reports world-readable
4045
fi

0 commit comments

Comments
 (0)