Skip to content

Commit

Permalink
Switched from outputs to environment output #3481
Browse files Browse the repository at this point in the history
- directly writing to the file did not work
- directly using set-output command did not work
- using SECHUB_OUTPUT* environment values as alternative
- changed documentation
- wrote tests
  • Loading branch information
de-jcup committed Dec 16, 2024
1 parent 4ac750f commit 40acb9c
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 68 deletions.
22 changes: 13 additions & 9 deletions github-actions/scan/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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)`

|===

Expand Down
40 changes: 6 additions & 34 deletions github-actions/scan/__test__/output-helper.test.ts
Original file line number Diff line number Diff line change
@@ -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<typeof core>;

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');
});
});
53 changes: 38 additions & 15 deletions github-actions/scan/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
*/
Expand Down Expand Up @@ -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);
}
Expand All @@ -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 '';
Expand Down Expand Up @@ -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();
Expand Down
48 changes: 38 additions & 10 deletions github-actions/scan/src/output-helper.ts
Original file line number Diff line number Diff line change
@@ -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' });
}

0 comments on commit 40acb9c

Please sign in to comment.