Skip to content

Commit ad02c30

Browse files
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.
1 parent 27f471d commit ad02c30

5 files changed

Lines changed: 40 additions & 3 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: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ runs:
140140
- ${{ inputs.exclude_gitignore}}
141141
- ${{ inputs.output_formats }}
142142
- ${{ inputs.output_path }}
143-
- ${{ inputs.output_name }}
144143
- ${{ inputs.payload_path }}
145144
- ${{ inputs.queries }}
146145
- ${{ inputs.verbose }}

‎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

‎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)