diff --git a/github-actions/scan/README.adoc b/github-actions/scan/README.adoc index 635439bda..7dda30e0f 100644 --- a/github-actions/scan/README.adoc +++ b/github-actions/scan/README.adoc @@ -96,18 +96,22 @@ If no custom `sechub.json` is provided, it will be generated from the remaining === Outputs -The following table lists the output variables available after this SecHub GitHub Action has completed: +==== Output +Because of problems with GitHub action and outputs (see https://github.com/mercedes-benz/sechub/issues/3481 ) SecHub no longer supports outputs but provides environment variables instead. + +==== Environment variables for output +The following table lists the environment variables available after this SecHub GitHub Action has completed: [cols="20%,40%,40%"] |=== -| Output Name | Description | Expected Values - -| scan-trafficlight | The color of the traffic light reported by SecHub if the scan ran successfully, otherwise `FAILURE`. | One of `GREEN`, `YELLOW`, `RED`, or `FAILURE`. -| scan-findings-count | The total number of findings reported by SecHub. Returns 0 if the scan didn't complete. | 0 -| scan-findings-high | The number of high-level findings reported by SecHub. | 0 -| scan-findings-medium | The number of medium-level findings reported by SecHub. | 0 -| scan-findings-low | The number of low-level findings reported by SecHub. | 0 -| scan-readable-summary| A human-readable summary of the scan outcome, including the traffic light color, findings count, and their distribution. | For example, `SecHub scan could not be executed` if an error occurred. Otherwise, i.e. `SecHub reported traffic light color YELLOW with 15 findings, categorized as follows: MEDIUM (8), LOW (7)` +| Environment variable | Description | Expected Values + +| SECHUB_OUTPUT_SCAN_TRAFFICLIGHT | The color of the traffic light reported by SecHub if the scan ran successfully, otherwise `FAILURE`. | One of `GREEN`, `YELLOW`, `RED`, or `FAILURE`. +| SECHUB_OUTPUT_SCAN_FINDINGS_COUNT | The total number of findings reported by SecHub. Returns 0 if the scan didn't complete. | 0 +| SECHUB_OUTPUT_SCAN_FINDINGS_HIGH | The number of high-level findings reported by SecHub. | 0 +| SECHUB_OUTPUT_SCAN_FINDINGS_MEDIUM | The number of medium-level findings reported by SecHub. | 0 +| SECHUB_OUTPUT_SCAN_FINDINGS_LOW | The number of low-level findings reported by SecHub. | 0 +| SECHUB_OUTPUT_SCAN_READABLE_SUMMARY| A human-readable summary of the scan outcome, including the traffic light color, findings count, and their distribution. | For example, `SecHub scan could not be executed` if an error occurred. Otherwise, i.e. `SecHub reported traffic light color YELLOW with 15 findings, categorized as follows: MEDIUM (8), LOW (7)` |=== diff --git a/github-actions/scan/__test__/output-helper.test.ts b/github-actions/scan/__test__/output-helper.test.ts index 0fabd3d1f..22a84716a 100644 --- a/github-actions/scan/__test__/output-helper.test.ts +++ b/github-actions/scan/__test__/output-helper.test.ts @@ -1,46 +1,18 @@ // SPDX-License-Identifier: MIT import * as outputHelper from '../src/output-helper'; +import * as core from '@actions/core'; -import * as fs from 'fs'; -import * as path from 'path'; +jest.mock('@actions/core'); describe('storeOutput', () => { - const outputPath = path.join(__dirname, 'test_output.txt'); + const mockedCore = core as jest.Mocked; - beforeAll(() => { - process.env.GITHUB_OUTPUT = outputPath; - }); - - afterEach(() => { - if (fs.existsSync(outputPath)) { - fs.unlinkSync(outputPath); - } - }); - - it('should append a line with key=value to the file', () => { + it('test-key shall set SECHUB_OUTPUT_TEST_KEY', () => { /* execute */ - outputHelper.storeOutput('TEST_KEY', 'TEST_VALUE'); + outputHelper.storeOutput('test-key', 'test value1'); /* test */ - const content = fs.readFileSync(outputPath, 'utf8'); - expect(content).toBe('TEST_KEY=TEST_VALUE\n'); + expect(mockedCore.exportVariable).toBeCalledWith('SECHUB_OUTPUT_TEST_KEY', 'test value1'); }); - it('should append multiple lines correctly', () => { - /* execute */ - outputHelper.storeOutput('KEY1', 'VALUE1'); - outputHelper.storeOutput('KEY2', 'VALUE2'); - - /* test */ - const content = fs.readFileSync(outputPath, 'utf8'); - expect(content).toBe('KEY1=VALUE1\nKEY2=VALUE2\n'); - }); - - it('should throw an error if GITHUB_OUTPUT is not set', () => { - /* prepare */ - delete process.env.GITHUB_OUTPUT; - - /* execute + test */ - expect(() => outputHelper.storeOutput('KEY', 'VALUE')).toThrow('GITHUB_OUTPUT environment variable is not set'); - }); }); \ No newline at end of file diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js index aaf960bca..89e5803b7 100644 --- a/github-actions/scan/dist/index.js +++ b/github-actions/scan/dist/index.js @@ -28429,25 +28429,48 @@ function getFieldFromJson(field, jsonData) { return currentKey; } -;// CONCATENATED MODULE: ./src/github-output.ts -// SPDX-License-Identifier: MIT +;// CONCATENATED MODULE: ./src/output-helper.ts -const NEW_LINE_SEPARATOR = '\n'; /** - * Sets the value of an output variable for the GitHub Action. - * This method is a replacement of usage of core.setOutput(..) method. + * Sets the value of an output (environment ) variable for the GitHub Action. + * This method is a workaround because of problems with of core.setOutput(..) method. * There were problems with core.setOutput(...), see * - https://github.com/mercedes-benz/sechub/issues/3481#issuecomment-2539015176 and * - https://github.com/actions/toolkit/issues/1218 + * - https://github.com/actions/toolkit/issues/1906 + * + * As a workaround we provide instead of output + * special SecHub ouput environment variables with naming convention "SECHUB_OUTPUT_${fieldAdopted}" + * + * `fieldAdopted` is same as `field`, but uppercased and `-` will be replaced by `_` + * + * For example: `scan-readable-summary` will become `SECHUB_OUTPUT_SCAN_READABLE_SUMMARY` * + * If debugging is enabled in action the setting will be logged. */ function storeOutput(field, value) { - const filePath = process.env['GITHUB_OUTPUT'] || ''; - if (filePath) { - } - else { - core.setOutput(field, value); - } + // export the output to an "output" variable (this works) + const envVarName = `SECHUB_OUTPUT_${field.toUpperCase().replace(/-/g, '_')}`; + (0,core.exportVariable)(envVarName, value); + if (process.env.ACTIONS_RUNNER_DEBUG === 'true') { + // Print the environment variable for debugging + console.log(`Exported environment variable ${envVarName} with value: ${value}`); + } + // 1. This following out commented code was thought as a workaround + // for https://github.com/actions/toolkit/issues/1218 + // Because the GITHUB_OUTPUT file from a worfklow step (which worked) did not contain + // crypto.randomUUID() parts we tried to write the key/value file "normally" without + // the crypto parts, but It did not appear inside context output, means it didn't work + // (even when it the exact file structure as done by an echo ?!?!) + // But we keep it here for documentation: + // const outputFilePath = process.env['GITHUB_OUTPUT'] || ''; + // if (!outputFilePath) { + // throw new Error('GITHUB_OUTPUT environment variable is not set'); + // } + // const outputLine = `${field}=${value}\n`; + // fs.appendFileSync(outputFilePath, outputLine, { encoding: 'utf8' }); + // 2. Offical way by core API (does not work) + // setOutput(field,value); } ;// CONCATENATED MODULE: ./src/post-scan.ts @@ -28462,7 +28485,7 @@ function storeOutput(field, value) { -const post_scan_NEW_LINE_SEPARATOR = '\n'; +const NEW_LINE_SEPARATOR = '\n'; /** * Collect all necessary report data, downloads additional report formats (e.g. 'html') if necessary */ @@ -28536,7 +28559,7 @@ async function uploadArtifact(context, name, files) { if (core.isDebug()) { const filesInWorkspace = (0,external_child_process_.execFileSync)('ls', [rootDirectory], { encoding: 'utf-8' - }).split(post_scan_NEW_LINE_SEPARATOR); + }).split(NEW_LINE_SEPARATOR); for (const fileName of filesInWorkspace) { core.debug(fileName); } @@ -28559,7 +28582,7 @@ function resolveReportNameForScanJob(context) { const workspaceDir = sanitize(getWorkspaceDir()); const filesInWorkspace = (0,external_child_process_.execFileSync)('ls', [workspaceDir], { encoding: 'utf-8' - }).split(post_scan_NEW_LINE_SEPARATOR); + }).split(NEW_LINE_SEPARATOR); if (!context.jobUUID) { core.error('Illegal state: No job uuid resolved - not allowed at this point'); return ''; @@ -46215,7 +46238,7 @@ async function postScan(context) { main().catch(handleError); async function main() { - // Seperated launcher and main method. + // Separated launcher and main method. // Reason: launch mechanism would be loaded on imports // before we can handle mocking in integration tests! await launch(); diff --git a/github-actions/scan/src/output-helper.ts b/github-actions/scan/src/output-helper.ts index d3ef3dcc7..c26a1002a 100644 --- a/github-actions/scan/src/output-helper.ts +++ b/github-actions/scan/src/output-helper.ts @@ -1,23 +1,51 @@ // SPDX-License-Identifier: MIT - -import * as fs from 'fs'; +import { setOutput } from '@actions/core/lib/core'; +import { exportVariable } from '@actions/core/lib/core'; /** - * Sets the value of an output variable for the GitHub Action. - * This method is a replacement of usage of core.setOutput(..) method. + * Sets the value of an output (environment ) variable for the GitHub Action. + * This method is a workaround because of problems with of core.setOutput(..) method. * There were problems with core.setOutput(...), see * - https://github.com/mercedes-benz/sechub/issues/3481#issuecomment-2539015176 and * - https://github.com/actions/toolkit/issues/1218 + * - https://github.com/actions/toolkit/issues/1906 + * + * As a workaround we provide instead of output + * special SecHub ouput environment variables with naming convention "SECHUB_OUTPUT_${fieldAdopted}" + * + * `fieldAdopted` is same as `field`, but uppercased and `-` will be replaced by `_` + * + * For example: `scan-readable-summary` will become `SECHUB_OUTPUT_SCAN_READABLE_SUMMARY` * + * If debugging is enabled in action the setting will be logged. */ export function storeOutput(field: string, value: string) { - const outputFilePath = process.env['GITHUB_OUTPUT'] || ''; - - if (!outputFilePath) { - throw new Error('GITHUB_OUTPUT environment variable is not set'); + // export the output to an "output" variable (this works) + const envVarName = `SECHUB_OUTPUT_${field.toUpperCase().replace(/-/g, '_')}`; + exportVariable(envVarName, value); + if (process.env.ACTIONS_RUNNER_DEBUG === 'true') { + // Print the environment variable for debugging + console.log(`Exported environment variable ${envVarName} with value: ${value}`); } - const outputLine = `${field}=${value}\n`; + // 1. This following out commented code was thought as a workaround + // for https://github.com/actions/toolkit/issues/1218 + // Because the GITHUB_OUTPUT file from a worfklow step (which worked) did not contain + // crypto.randomUUID() parts we tried to write the key/value file "normally" without + // the crypto parts, but It did not appear inside context output, means it didn't work + // (even when it the exact file structure as done by an echo ?!?!) + // But we keep it here for documentation: + + // const outputFilePath = process.env['GITHUB_OUTPUT'] || ''; + // if (!outputFilePath) { + // throw new Error('GITHUB_OUTPUT environment variable is not set'); + // } + + // const outputLine = `${field}=${value}\n`; + // fs.appendFileSync(outputFilePath, outputLine, { encoding: 'utf8' }); + + + // 2. Offical way by core API (does not work) + // setOutput(field,value); - fs.appendFileSync(outputFilePath, outputLine, { encoding: 'utf8' }); }