diff --git a/github-actions/scan/README.adoc b/github-actions/scan/README.adoc
index 28f945113b..8d6c3e5de3 100644
--- a/github-actions/scan/README.adoc
+++ b/github-actions/scan/README.adoc
@@ -94,25 +94,29 @@ The following variables take priority over the configuration file:
If no custom `sechub.json` is provided, it will be generated from the remaining specified variables and used. However, if a custom `sechub.json` is provided, no separate configuration will be created, meaning the remaining set variables will essentially be ignored.
====
-=== Outputs
+=== Use SecHub results in GitHub workflows
-The following table lists the output variables available after this SecHub GitHub Action has completed:
+==== GitHub Output
+Because of problems with GitHub outputs (see https://github.com/mercedes-benz/sechub/issues/3481 ) SecHub no longer supports outputs but provides environment variables instead.
+
+==== Environment variables
+The following table lists the environment variables containing result data after this SecHub GitHub Action has completed:
[cols="20%,40%,40%"]
|===
-| Output Name | Description | Expected Values
+| Environment variable | 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)`
+| 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)`
|===
-You can access them after the action has run with `${{ steps.
.outputs. }}`
+You can access them after the action has run with `${{ env. }}`
=== Build
@@ -129,6 +133,16 @@ npm run build
This runs the ncc compiler and transpiles the files from the src folder into the `dist/` folder.
+=== Deployment
+A GitHub action needs a transpiled `index.js` to be used as an action from workflows.
+
+As long as we do not provide a new index.js the old action is still in usage, even when the source code has
+changed. If we do not build the file and commit and push it to git repository, the action will not
+be available!
+
+The complete deployment process is automated by `.github/workflows/release-github-action.yml` which will create a
+PR which will do all necessary steps.
+
=== Test
==== Unit tests
@@ -142,10 +156,19 @@ npm run test
==== Integration-Test
As a precondition to run the integration tests locally you have to
+execute `01-start.sh $secHubServerVersion $sechubServerPortNr $pdsVersion $pdsPortN`
+inside the integration test folder.
-- execute `__test__/01-start.sh $secHubServerVersion $sechubServerPortNr $pdsVersion $pdsPortNr`
+An example:
+
+[source,bash]
+----
+# Next lines will start a SecHub server of version 2.4.0 and a PDS with version 2.1.0
+cd ./github-actions/scan/__test__/integrationtest
+./01-start.sh 2.4.0 8443 2.1.0 8444
+----
-TIP: You can also start a SecHub server and a PDS (both in integration test mode) instead of using the `01-start` script.
+TIP: You can also start a SecHub server and a PDS from IDE (both in integration test mode) instead of using the `01-start` script.
After the script has been executed, you can execute integration tests multiple times via following command:
@@ -176,7 +199,9 @@ In this setup the tests can be executed from sidebar and from links created insi
[TIP]
====
-Unfortunately, the Jest UI integration works only for npm script "test". But to handle integration tests different (the tests shall only be executed when all is build and servers are started) they are not executed by "test" script.
+Unfortunately, the Jest UI integration works only for npm script "test".
+But to handle integration tests different (the tests shall only be executed
+when all is built and servers are started) they are not executed by "test" script.
If you want to **debug an integration test**, there is a temporary workaround necessary while you debug the test:
diff --git a/github-actions/scan/__test__/client-version-helper.test.ts b/github-actions/scan/__test__/client-version-helper.test.ts
index d8227497b2..72f9052e4f 100644
--- a/github-actions/scan/__test__/client-version-helper.test.ts
+++ b/github-actions/scan/__test__/client-version-helper.test.ts
@@ -3,6 +3,22 @@
import { getClientVersion } from '../src/client-version-helper';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
+import * as core from '@actions/core';
+
+jest.mock('@actions/core');
+
+const mockDebug = core.debug as jest.MockedFunction;
+
+const debugEnabled = false;
+
+beforeEach(() => {
+ mockDebug.mockImplementation((message: string | Error) => {
+ if (debugEnabled) {
+ console.log(`Debug: ${message}`);
+ }
+ });
+ mockDebug.mockClear();
+});
describe('getClientVersion', function () {
diff --git a/github-actions/scan/__test__/configuration-builder.test.ts b/github-actions/scan/__test__/configuration-builder.test.ts
index 2787db9307..1b8e238e5d 100644
--- a/github-actions/scan/__test__/configuration-builder.test.ts
+++ b/github-actions/scan/__test__/configuration-builder.test.ts
@@ -6,7 +6,12 @@ import { SecHubConfigurationModelBuilderData } from '../src/configuration-builde
jest.mock('@actions/core');
-function dumpModel(model: SecHubConfigurationModel){
+const debugEnabled = false;
+
+function logDebug(model: SecHubConfigurationModel){
+ if (! debugEnabled){
+ return;
+ }
const json = JSON.stringify(model, null, 2); // pretty printed output
console.log('json='+json);
@@ -34,7 +39,7 @@ describe('configuration-builder', function() {
const model= configBuilder.createSecHubConfigurationModel(builderData);
/* test */
- dumpModel(model);
+ logDebug(model);
expect(model.apiVersion).toEqual('1.0');
@@ -66,7 +71,7 @@ describe('configuration-builder', function() {
const model= configBuilder.createSecHubConfigurationModel(builderData);
/* test */
- dumpModel(model);
+ logDebug(model);
expect(model.apiVersion).toEqual('1.0');
@@ -101,7 +106,7 @@ describe('configuration-builder', function() {
const model= configBuilder.createSecHubConfigurationModel(builderData);
/* test */
- dumpModel(model);
+ logDebug(model);
expect(model.apiVersion).toEqual('1.0');
@@ -138,7 +143,7 @@ describe('configuration-builder', function() {
const model= configBuilder.createSecHubConfigurationModel(builderData);
/* test */
- dumpModel(model);
+ logDebug(model);
expect(model.apiVersion).toEqual('1.0');
@@ -172,7 +177,7 @@ describe('configuration-builder', function() {
const model= configBuilder.createSecHubConfigurationModel(builderData);
/* test */
- dumpModel(model);
+ logDebug(model);
expect(model.apiVersion).toEqual('1.0');
@@ -206,7 +211,7 @@ describe('configuration-builder', function() {
const model= configBuilder.createSecHubConfigurationModel(builderData);
/* test */
- dumpModel(model);
+ logDebug(model);
expect(model.apiVersion).toEqual('1.0');
@@ -241,7 +246,7 @@ describe('configuration-builder', function() {
const model= configBuilder.createSecHubConfigurationModel(builderData);
/* test */
- dumpModel(model);
+ logDebug(model);
expect(model.apiVersion).toEqual('1.0');
diff --git a/github-actions/scan/__test__/init-scan.test.ts b/github-actions/scan/__test__/init-scan.test.ts
index 94c3fa99f9..16737206ea 100644
--- a/github-actions/scan/__test__/init-scan.test.ts
+++ b/github-actions/scan/__test__/init-scan.test.ts
@@ -5,6 +5,22 @@ import {initReportFormats, initSecHubJson} from '../src/init-scan';
jest.mock('./../src/configuration-builder');
import {SecHubConfigurationModelBuilderData, createSecHubConfigJsonFile} from '../src/configuration-builder';
+import * as core from '@actions/core';
+
+jest.mock('@actions/core');
+
+const mockInfo = core.info as jest.MockedFunction;
+
+const debugEnabled = false;
+
+beforeEach(() => {
+ mockInfo.mockImplementation((message: string | Error) => {
+ if (debugEnabled) {
+ console.log(`Info: ${message}`);
+ }
+ });
+ mockInfo.mockClear();
+});
describe('initSecHubJson', function () {
it('throws error if configPath is set, but file does not exist', function () {
diff --git a/github-actions/scan/__test__/output-helper.test.ts b/github-actions/scan/__test__/output-helper.test.ts
new file mode 100644
index 0000000000..22a84716a0
--- /dev/null
+++ b/github-actions/scan/__test__/output-helper.test.ts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+import * as outputHelper from '../src/output-helper';
+import * as core from '@actions/core';
+
+jest.mock('@actions/core');
+
+describe('storeOutput', () => {
+ const mockedCore = core as jest.Mocked;
+
+ it('test-key shall set SECHUB_OUTPUT_TEST_KEY', () => {
+ /* execute */
+ outputHelper.storeOutput('test-key', 'test value1');
+
+ /* test */
+ expect(mockedCore.exportVariable).toBeCalledWith('SECHUB_OUTPUT_TEST_KEY', 'test value1');
+ });
+
+});
\ No newline at end of file
diff --git a/github-actions/scan/__test__/post-scan.test.ts b/github-actions/scan/__test__/post-scan.test.ts
index 8f1d49ce3e..ada369953b 100644
--- a/github-actions/scan/__test__/post-scan.test.ts
+++ b/github-actions/scan/__test__/post-scan.test.ts
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: MIT
import * as core from '@actions/core';
+import * as outputHelper from '../src/output-helper';
import { collectReportData, reportOutputs } from '../src/post-scan';
import { getReport } from '../src/sechub-cli';
import { LAUNCHER_CONTEXT_DEFAULTS } from '../src/launcher';
jest.mock('@actions/core');
+jest.mock('../src/output-helper');
const mockedCore = core as jest.Mocked;
+const mockedOutputHelper = outputHelper as jest.Mocked;
jest.mock('../src/sechub-cli');
const mockedGetReport = getReport as jest.MockedFunction;
@@ -20,7 +23,7 @@ describe('collectReportData', function () {
/* prepare */
const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS);
- testContext.reportFormats= [];
+ testContext.reportFormats = [];
/* execute */
collectReportData(testContext);
@@ -33,7 +36,7 @@ describe('collectReportData', function () {
it('format "json" - logs called 1 time , getReport never called', function () {
/* prepare */
const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS);
- testContext.reportFormats= ['json'];
+ testContext.reportFormats = ['json'];
/* execute */
collectReportData(testContext);
@@ -47,8 +50,8 @@ describe('collectReportData', function () {
/* prepare */
const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS);
- testContext.reportFormats= ['json','html'];
- testContext.jobUUID=1234; // necessary for download
+ testContext.reportFormats = ['json', 'html'];
+ testContext.jobUUID = 1234; // necessary for download
collectReportData(testContext);
@@ -61,8 +64,8 @@ describe('collectReportData', function () {
/* prepare */
const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS);
- testContext.reportFormats= ['json','html'];
- testContext.jobUUID=1234; // necessary for download
+ testContext.reportFormats = ['json', 'html'];
+ testContext.jobUUID = 1234; // necessary for download
/* execute */
collectReportData(testContext);
@@ -78,11 +81,11 @@ describe('collectReportData', function () {
/* prepare */
const testContext = Object.create(LAUNCHER_CONTEXT_DEFAULTS);
- testContext.reportFormats= ['json','html','xyz','bla'];
- testContext.jobUUID=1234; // necessary for download
-
+ testContext.reportFormats = ['json', 'html', 'xyz', 'bla'];
+ testContext.jobUUID = 1234; // necessary for download
+
fsMock.readFileSync = jest.fn(() => '{"test": "test"}'); // Mock an empty JSON report
- const sampleJson = {'test': 'test'};
+ const sampleJson = { 'test': 'test' };
/* execute */
collectReportData(testContext);
@@ -90,7 +93,7 @@ describe('collectReportData', function () {
/* test */
expect(mockedCore.info).toHaveBeenCalledTimes(4); // "json, html, xyz, bla" - 4 times logged (valid format check is not done here)
expect(mockedGetReport).toHaveBeenCalledTimes(3); // we fetch not json via getReport again (already done before), so only "html, xyz, bla" used
-
+
expect(testContext.secHubReportJsonObject).toEqual(sampleJson); // json object is available
});
@@ -136,13 +139,13 @@ describe('reportOutputs', function () {
/* test */
expect(mockedCore.debug).toHaveBeenCalledTimes(6);
- expect(mockedCore.setOutput).toHaveBeenCalledTimes(6);
- expect(mockedCore.setOutput).toBeCalledWith('scan-trafficlight', 'RED');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-count', '2');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-high', '1');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-medium', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-low', '1');
- expect(mockedCore.setOutput).toBeCalledWith('scan-readable-summary', 'SecHub reported traffic light color RED with 2 findings, categorized as follows: HIGH (1), LOW (1)');
+ expect(mockedOutputHelper.storeOutput).toHaveBeenCalledTimes(6);
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-trafficlight', 'RED');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-count', '2');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-high', '1');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-medium', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-low', '1');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-readable-summary', 'SecHub reported traffic light color RED with 2 findings, categorized as follows: HIGH (1), LOW (1)');
});
it('calls set github output with correct values when JSON report did not exist', function () {
@@ -152,13 +155,13 @@ describe('reportOutputs', function () {
/* test */
expect(mockedCore.debug).toHaveBeenCalledTimes(7);
expect(mockedCore.debug).toBeCalledWith('No findings reported to be categorized.');
- expect(mockedCore.setOutput).toHaveBeenCalledTimes(6);
- expect(mockedCore.setOutput).toBeCalledWith('scan-trafficlight', 'FAILURE');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-count', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-high', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-medium', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-low', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-readable-summary', 'SecHub scan could not be executed.');
+ expect(mockedOutputHelper.storeOutput).toHaveBeenCalledTimes(6);
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-trafficlight', 'FAILURE');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-count', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-high', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-medium', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-low', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-readable-summary', 'SecHub scan could not be executed.');
});
it('calls set github output with correct values when traffic light is green without findings.', function () {
@@ -180,13 +183,13 @@ describe('reportOutputs', function () {
/* test */
expect(mockedCore.debug).toHaveBeenCalledTimes(6);
- expect(mockedCore.setOutput).toHaveBeenCalledTimes(6);
- expect(mockedCore.setOutput).toBeCalledWith('scan-trafficlight', 'GREEN');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-count', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-high', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-medium', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-findings-low', '0');
- expect(mockedCore.setOutput).toBeCalledWith('scan-readable-summary', 'SecHub reported traffic light color GREEN without findings');
+ expect(mockedOutputHelper.storeOutput).toHaveBeenCalledTimes(6);
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-trafficlight', 'GREEN');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-count', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-high', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-medium', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-findings-low', '0');
+ expect(mockedOutputHelper.storeOutput).toBeCalledWith('scan-readable-summary', 'SecHub reported traffic light color GREEN without findings');
});
});
diff --git a/github-actions/scan/__test__/shell-arg-sanitizer.test.ts b/github-actions/scan/__test__/shell-arg-sanitizer.test.ts
index f03ed1a19d..bd4c5021f8 100644
--- a/github-actions/scan/__test__/shell-arg-sanitizer.test.ts
+++ b/github-actions/scan/__test__/shell-arg-sanitizer.test.ts
@@ -1,8 +1,27 @@
+/* eslint-disable indent */
// SPDX-License-Identifier: MIT
import * as shellArgSanitizer from '../src/shell-arg-sanitizer';
+import * as core from '@actions/core';
+
+jest.mock('@actions/core');
+
+const mockError = core.error as jest.MockedFunction;
+
+const debugEnabled = false;
+
+beforeEach(() => {
+ mockError.mockImplementation((message: string | Error) => {
+ if (debugEnabled) {
+ console.log(`Error: ${message}`);
+ }
+ });
+ mockError.mockClear();
+});
+
describe('sanitize', () => {
+
test.each([
['rm -rf /; echo hacked'], // Command chaining
['echo $(whoami)'], // Command substitution
@@ -69,7 +88,7 @@ describe('sanitize', () => {
(arg) => {
/* test */
expect(() => shellArgSanitizer.sanitize(arg)).not.toThrow();
- });
+ });
it('removes whitespaces', function () {
/* prepare */
diff --git a/github-actions/scan/dist/index.js b/github-actions/scan/dist/index.js
index da1b79d485..89e5803b74 100644
--- a/github-actions/scan/dist/index.js
+++ b/github-actions/scan/dist/index.js
@@ -28403,6 +28403,7 @@ function getReport(jobUUID, reportFormat, context) {
}
;// CONCATENATED MODULE: ./src/json-helper.ts
+// SPDX-License-Identifier: MIT
/**
* Reads the given field from JSON.
@@ -28428,6 +28429,50 @@ function getFieldFromJson(field, jsonData) {
return currentKey;
}
+;// CONCATENATED MODULE: ./src/output-helper.ts
+
+/**
+ * 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) {
+ // 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
// SPDX-License-Identifier: MIT
@@ -28439,6 +28484,7 @@ function getFieldFromJson(field, jsonData) {
+
const NEW_LINE_SEPARATOR = '\n';
/**
* Collect all necessary report data, downloads additional report formats (e.g. 'html') if necessary
@@ -28662,7 +28708,7 @@ function buildSummary(trafficLight, totalFindings, findings) {
function setOutput(field, value, dataFormat) {
value = value !== null && value !== void 0 ? value : (dataFormat === 'number' ? 0 : 'FAILURE');
core.debug(`Output ${field} set to ${value}`);
- core.setOutput(field, value.toString()); // Ensure value is converted to a string as GitHub Actions expects output variables to be strings.
+ storeOutput(field, value.toString()); // Ensure value is converted to a string as GitHub Actions expects output variables to be strings.
}
;// CONCATENATED MODULE: ./src/projectname-resolver.ts
@@ -28702,6 +28748,7 @@ function projectname_resolver_asJsonObject(text) {
// EXTERNAL MODULE: external "os"
var external_os_ = __nccwpck_require__(2037);
;// CONCATENATED MODULE: ./src/platform-helper.ts
+// SPDX-License-Identifier: MIT
function getPlatform() {
return external_os_.platform();
@@ -46017,6 +46064,7 @@ const { parseHTML: esm_parseHTML } = static_namespaceObject;
const { root: esm_root } = static_namespaceObject;
//# sourceMappingURL=index.js.map
;// CONCATENATED MODULE: ./src/client-version-helper.ts
+// SPDX-License-Identifier: MIT
@@ -46190,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/package.json b/github-actions/scan/package.json
index a2b1b52947..37db237428 100644
--- a/github-actions/scan/package.json
+++ b/github-actions/scan/package.json
@@ -5,6 +5,7 @@
"main": "dist/main.js",
"scripts": {
"build": "ncc build src/main.ts",
+ "deploy" : "./deploy.sh",
"cleanBuild": "ncc cache clean;ncc build src/main.ts",
"lint": "eslint src",
"prettier": "npx prettier --write src",
diff --git a/github-actions/scan/src/main.ts b/github-actions/scan/src/main.ts
index f4cb84aa3f..4cf6dbc799 100644
--- a/github-actions/scan/src/main.ts
+++ b/github-actions/scan/src/main.ts
@@ -6,7 +6,7 @@ import { handleError } from './action-helper';
main().catch(handleError);
async function main(): Promise {
- // 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
new file mode 100644
index 0000000000..c26a1002a8
--- /dev/null
+++ b/github-actions/scan/src/output-helper.ts
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: MIT
+import { setOutput } from '@actions/core/lib/core';
+import { exportVariable } from '@actions/core/lib/core';
+
+/**
+ * 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) {
+ // 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}`);
+ }
+
+ // 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);
+
+}
diff --git a/github-actions/scan/src/post-scan.ts b/github-actions/scan/src/post-scan.ts
index e7ffa5fca6..3442bf097c 100644
--- a/github-actions/scan/src/post-scan.ts
+++ b/github-actions/scan/src/post-scan.ts
@@ -8,8 +8,9 @@ import { LaunchContext } from './launcher';
import { logExitCode } from './exitcode';
import { getReport } from './sechub-cli';
import { getFieldFromJson } from './json-helper';
-import { execFileSync } from "child_process";
-import { sanitize } from "./shell-arg-sanitizer";
+import { execFileSync } from 'child_process';
+import { sanitize } from './shell-arg-sanitizer';
+import { storeOutput } from './output-helper';
const NEW_LINE_SEPARATOR = '\n';
@@ -280,5 +281,5 @@ function setOutput(field: string, value: any, dataFormat: string) {
value = value ?? (dataFormat === 'number' ? 0 : 'FAILURE');
core.debug(`Output ${field} set to ${value}`);
- core.setOutput(field, value.toString()); // Ensure value is converted to a string as GitHub Actions expects output variables to be strings.
+ storeOutput(field, value.toString()); // Ensure value is converted to a string as GitHub Actions expects output variables to be strings.
}
diff --git a/gradle/projects.gradle b/gradle/projects.gradle
index acadbd954c..2955e328fb 100644
--- a/gradle/projects.gradle
+++ b/gradle/projects.gradle
@@ -58,7 +58,10 @@ projectType = [
project(':sechub-wrapper-secretvalidation'),
/* archUnit */
- project(':sechub-archunit-test')
+ project(':sechub-archunit-test'),
+
+ /* developerTools */
+ project(':sechub-developertools') // to have DAUI available by build and a working fat jar provided by spring boot
],
/* adapter projects - have simple spring dependencies, but know only sechub-adapter as base */
diff --git a/release-pipeline.jenkins b/release-pipeline.jenkins
index 6f60cc88a8..0f214961ce 100644
--- a/release-pipeline.jenkins
+++ b/release-pipeline.jenkins
@@ -70,7 +70,7 @@ pipeline {
* Reason: because we do NOT want to have the integration tests executed, otherwise gradle will not execute them
* on integration phase again (because nothing has changed, so gradle will cache the results which are ignored ...
*/
- callGradleWrapper("ensureLocalhostCertificate build generateOpenapi buildDeveloperAdminUI -x :sechub-integrationtest:test -x :sechub-cli:build -Psechub.test.wiremock.https_port=${env.SECHUB_TEST_WIREMOCK_HTTPS_PORT} -Psechub.test.wiremock.http_port=${env.SECHUB_TEST_WIREMOCK_HTTP_PORT}")
+ callGradleWrapper("ensureLocalhostCertificate build generateOpenapi -x :sechub-integrationtest:test -x :sechub-cli:build -Psechub.test.wiremock.https_port=${env.SECHUB_TEST_WIREMOCK_HTTPS_PORT} -Psechub.test.wiremock.http_port=${env.SECHUB_TEST_WIREMOCK_HTTP_PORT}")
callGradleWrapper(":sechub-api-java:build :sechub-systemtest:build :sechub-pds-tools:buildPDSToolsCLI -Dsechub.build.stage=api-necessary")
}
}
diff --git a/sechub-developertools/README.adoc b/sechub-developertools/README.adoc
new file mode 100644
index 0000000000..e238bf67c2
--- /dev/null
+++ b/sechub-developertools/README.adoc
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: MIT
+:toc:
+
+== About
+`sechub-developertools` is a gradle subprojects
+only containing tools for SecHub development. It is not intended to be used in production.
+
+WARNING: No other gradle submodule shall have this project as a dependency!
+
+
+== Content
+
+=== DAUI
+The Developer Administration UI (DAUI) is a simple quick and dirty administration client which will reuse parts
+from `sechub-integration--test` (for example REST api access, URL building).
+
+Every single feature we implement, is available at this simple UI from the beginning.
+It is extreme simple to extend.
+
+[TIP]
+====
+Look into
+`/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/job/GetJobStatusAction.java`
+for an example how you can simply implement a feature.
+====
+
+===== Build
+Inside sechub root folder execute:
+
+[source, bash]
+----
+./gradlew :sechub-developertools:bootJar
+----
+
+This will build
+`/sechub-developertools/build/libs/sechub-developertools-0.0.0.jar`
+
+
+===== Start
+[source, bash]
+----
+export SECHUB_ADMIN_APITOKEN=int-test_superadmin-pwd
+export SECHUB_ADMIN_ENVIRONMENT=localhost
+export SECHUB_ADMIN_USERID=int-test_superadmin
+export SECHUB_ADMIN_SERVER=localhost
+export SECHUB_ADMIN_SERVER_PORT=8443
+
+java -jar ./sechub-developertools/build/libs/sechub-developertools-0.0.0.jar
+----
+
diff --git a/sechub-developertools/README.md b/sechub-developertools/README.md
deleted file mode 100644
index 8b14dd7e24..0000000000
--- a/sechub-developertools/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-
-What is "sechub-developertools" for?
-====================================
-
-A collection of some tooling around sechub which is only available for developers and not part of
-a deployment or a client given to users.
-
-__NEVER give those tools to admins or users!__
-
-## Content:
-### 1. Quick and dirty admin client
-One of the first things created here is a simple quick and dirty administration client which will reuse parts
-from integration test project - e.g. rest api access, url building etc. which is already done there. *So we do not reinvent the wheel...*
\ No newline at end of file
diff --git a/sechub-developertools/build.gradle b/sechub-developertools/build.gradle
index b7e3887037..4b132ec41d 100644
--- a/sechub-developertools/build.gradle
+++ b/sechub-developertools/build.gradle
@@ -7,7 +7,9 @@
*/
plugins {
id 'java-library'
+ id 'org.springframework.boot' apply true
}
+
dependencies {
implementation project(':sechub-testframework')
@@ -23,48 +25,9 @@ dependencies {
}
-task startIntegrationTestAdminUI(type: JavaExec){
-
- group 'sechub'
- description 'Starts developer admin ui ready to use with for a server started by gradle task '
-
- classpath = sourceSets.main.runtimeClasspath
-
- mainClass = 'com.mercedesbenz.sechub.developertools.admin.ui.DeveloperAdministrationUI'
-
- jvmArgs = ['-Dsechub.developertools.admin.integrationtestserver=true',
- '-Dsechub.developertools.admin.server=localhost',
- '-Dsechub.developertools.admin.serverport=8443',
- '-Dsechub.developertools.admin.userid=int-test_superadmin',
- '-Dsechub.developertools.admin.apitoken=int-test_superadmin-pwd']
-
-}
-
-task buildDeveloperAdminUI(type: Jar, dependsOn: build) {
- group 'sechub'
- description 'Builds the SecHub Developer Admin tool as standalone executable jar. Use launch-developer-admin-ui script to execute'
- archiveBaseName = 'sechub-developer-admin-ui'
- /* TODO: This is a 'dirty' fix for the standard archive entries limit of 64K. We should refactor this module to make it leaner */
- zip64 = true
-
- manifest {
- attributes 'Main-Class': 'com.mercedesbenz.sechub.developertools.admin.ui.DeveloperAdministrationUI'
- }
-
- from {
- configurations.runtimeClasspath.collect {
- it.isDirectory() ? it : zipTree(it)
- }
- }
- duplicatesStrategy = DuplicatesStrategy.INCLUDE
- with jar
-}
-
-
task importEclipseProjectsNeedingOpenApiFile(type: Exec){
workingDir "$rootDir"
commandLine './gradlew', ':sechub-systemtest:cleanEclipse',':sechub-systemtest:eclipse', ':sechub-web-server:cleanEclipse',':sechub-web-server:eclipse', ':sechub-api-java:cleanEclipse',':sechub-api-java:eclipse', ':sechub-pds-tools:cleanEclipse',':sechub-pds-tools:eclipse',':sechub-examples:example-sechub-api-java:cleanEclipse',':sechub-examples:example-sechub-api-java:eclipse','-Dsechub.build.stage=all'
-
}
/*
diff --git a/sechub-developertools/scripts/launch-developer-admin-ui b/sechub-developertools/scripts/launch-developer-admin-ui
index 8e7e6f49da..3e06b4a36d 100755
--- a/sechub-developertools/scripts/launch-developer-admin-ui
+++ b/sechub-developertools/scripts/launch-developer-admin-ui
@@ -1,17 +1,17 @@
#!/bin/bash
-# This the base template suitable for having a standalone running integrationtest admin ui.
-# Howto use when manually created:
-# - copy this script to a dedicated folder (X)
-# - define system properties and/or environment entries as necessary
-# - call ./gradlew buildDeveloperAdminUI
-# - copy build/libs/sechub-developer-admin-ui-0.0.0.jar to the folder (X)
-# - ensure script is executable and you have a java >=8 available on your system
-# - call the script and you are done
-#
-#
-
-DAUI_VERSION="0.0.0"
+# This the base template suitable for having a standalone running SecHub admin ui.
+# The sechub-developertools-x.y.z.jar can be downloaded
+# from the latest SecHub server release on github.com.
+# Alternatively the jar file can be created manually:
+# - call ./gradlew :sechub-developertools:bootJar
+# - the created file is: build/libs/sechub-developertools-0.0.0.jar
+#
+# Use:
+# - copy this script to a dedicated folder and make it executable: chmod a+x
+# - edit the copied script and define your system properties below
+# - copy sechub-developertools-x.y.z.jar to the folder
+# - call the script and the SecHub Developer Admin UI will open
export SECHUB_ADMIN_USERID=int-test_superadmin # your admin user id
export SECHUB_ADMIN_APITOKEN=int-test_superadmin-pwd
@@ -26,26 +26,17 @@ export SECHUB_ENABLE_INTEGRATION_TESTSERVER_MENU=true
export SECHUB_DISABLE_CONFIRMATIONS=true
export SECHUB_CHECK_STATUS_ON_STARTUP=false
-export SECHUB_ADMIN_ENVIRONMENT=localhost #Use : localhost, no color. Dedicated menu colors for: PROD, INT or TESTxyz
+export SECHUB_ADMIN_ENVIRONMENT="localhost" # Use : "localhost", no color. Dedicated menu colors for: "PROD", "INT" or "TESTxyz"
-export SECHUB_MASS_OPERATION_PARENTDIRECTORY=/home/$UID/.sechub/inttest/mass-operations #mass operation directory (containign csv files )
-export SECHUB_TARGETFOLDER_FOR_SECHUB_CLIENT_SCAN="/home/$USER/.sechub/test-targetfolder1"
+export SECHUB_MASS_OPERATION_PARENTDIRECTORY="$HOME/.sechub/inttest/mass-operations" # mass operation directory (containign csv files )
+export SECHUB_TARGETFOLDER_FOR_SECHUB_CLIENT_SCAN="$HOME/.sechub/test-targetfolder1"
-export SECHUB_PATH_TO_SECHUB_CLIENT_BINARY="/home/$USER/.local/bin/sechub"
+export SECHUB_PATH_TO_SECHUB_CLIENT_BINARY="/usr/local/bin/sechub"
export SECHUB_TRUSTALL_DENIED=false; # change this for other environments!
-# when next entry is set to true TRUSTALL is denied (currently only at go client)
echo "-------------------------------------------------------------"
-echo "Starting DAUI $DAUI_VERSION (Developer Admin UI)"
+echo "Starting SecHub Developer Admin UI"
echo "-------------------------------------------------------------"
echo "- SECHUB_TARGETFOLDER_FOR_SECHUB_CLIENT_SCAN:$SECHUB_TARGETFOLDER_FOR_SECHUB_CLIENT_SCAN"
echo "- SECHUB_PATH_TO_SECHUB_CLIENT_BINARY: $SECHUB_PATH_TO_SECHUB_CLIENT_BINARY"
-java -jar sechub-developer-admin-ui-$DAUI_VERSION.jar
-
-echo "Press any key to continue"
-while [ true ] ; do
-read -t 3 -n 1
-if [ $? = 0 ] ; then
-exit ;
-fi
-done
+java -jar sechub-developertools-*.jar
diff --git a/sechub-developertools/scripts/sdc.sh b/sechub-developertools/scripts/sdc.sh
index 003ca50a2d..f502bc9622 100755
--- a/sechub-developertools/scripts/sdc.sh
+++ b/sechub-developertools/scripts/sdc.sh
@@ -345,7 +345,7 @@ if [[ "$FULL_BUILD" = "YES" ]]; then
./gradlew spotlessCheck :sechub-cli:buildGo :sechub-cli:testGo
step "Build Server, DAUI and generate OpenAPI file"
- ./gradlew ensureLocalhostCertificate build generateOpenapi buildDeveloperAdminUI -x :sechub-cli:build
+ ./gradlew ensureLocalhostCertificate build generateOpenapi -x :sechub-cli:build
step "Generate and build Java projects related to SecHub Java API"
./gradlew :sechub-api-java:build :sechub-systemtest:build :sechub-pds-tools:buildPDSToolsCLI :sechub-web-server:build -Dsechub.build.stage=api-necessary
diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/DAUIApplication.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/DAUIApplication.java
new file mode 100644
index 0000000000..e402416979
--- /dev/null
+++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/DAUIApplication.java
@@ -0,0 +1,16 @@
+package com.mercedesbenz.sechub.developertools;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+
+@SpringBootApplication(exclude = RepositoryRestMvcAutoConfiguration.class) // we do not want to have automatic resources in HAL & co
+public class DAUIApplication {
+
+ public static void main(String[] args) {
+ SpringApplicationBuilder builder = new SpringApplicationBuilder(DAUIApplication.class);
+ builder.headless(false);
+
+ builder.run(args);
+ }
+}
diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/DAUICLIRunner.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/DAUICLIRunner.java
new file mode 100644
index 0000000000..faba0a26ac
--- /dev/null
+++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/DAUICLIRunner.java
@@ -0,0 +1,16 @@
+package com.mercedesbenz.sechub.developertools;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+import com.mercedesbenz.sechub.developertools.admin.ui.DeveloperAdministrationUI;
+
+@Component
+public class DAUICLIRunner implements CommandLineRunner {
+
+ @Override
+ public void run(String... args) throws Exception {
+ DeveloperAdministrationUI.main(args);
+ }
+
+}
diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java
index cdbefba643..e38c0d3530 100644
--- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java
+++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java
@@ -460,7 +460,7 @@ private void createIntegrationTestServerMenu() {
if (!ConfigurationSetup.isIntegrationTestServerMenuEnabled()) {
menu.setEnabled(false);
- menu.setToolTipText("Not enabled, use \"-D" + ConfigurationSetup.SECHUB_ENABLE_INTEGRATION_TESTSERVER_MENU.getSystemPropertyid()
+ menu.setToolTipText("Not enabled, use \"-D" + ConfigurationSetup.SECHUB_ENABLE_INTEGRATION_TESTSERVER_MENU.getSystemPropertyId()
+ "=true\" to enable it and run an integration test server!");
return;
}
diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/ConfigurationSetup.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/ConfigurationSetup.java
index b785a70f35..60644b8033 100644
--- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/ConfigurationSetup.java
+++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/ConfigurationSetup.java
@@ -15,88 +15,94 @@
*/
public enum ConfigurationSetup {
- SECHUB_ADMIN_USERID(false),
+ SECHUB_ADMIN_USERID(false, true),
- SECHUB_ADMIN_APITOKEN(false),
+ SECHUB_ADMIN_APITOKEN(false, true),
- SECHUB_ADMIN_SERVER("sechub.developertools.admin.server", false),
+ SECHUB_ADMIN_SERVER("sechub.developertools.admin.server", false, false),
- SECHUB_ADMIN_SERVER_PORT("sechub.developertools.admin.serverport", true),
+ SECHUB_ADMIN_SERVER_PORT("sechub.developertools.admin.serverport", true, false),
- SECHUB_ADMIN_SERVER_PROTOCOL("sechub.developertools.admin.serverprotocol", true),
+ SECHUB_ADMIN_SERVER_PROTOCOL("sechub.developertools.admin.serverprotocol", true, false),
- SECHUB_ENABLE_INTEGRATION_TESTSERVER_MENU("sechub.developertools.admin.integrationtestserver", true),
+ SECHUB_ENABLE_INTEGRATION_TESTSERVER_MENU("sechub.developertools.admin.integrationtestserver", true, false),
- SECHUB_DISABLE_CONFIRMATIONS("sechub.developertools.admin.disable.confim", true, "When set to true, no confirmation dialogs will appear"),
+ SECHUB_DISABLE_CONFIRMATIONS("sechub.developertools.admin.disable.confim", true, "When set to true, no confirmation dialogs will appear", false),
- SECHUB_CHECK_STATUS_ON_STARTUP("sechub.developertools.admin.statuscheck.onstartup", true),
+ SECHUB_CHECK_STATUS_ON_STARTUP("sechub.developertools.admin.statuscheck.onstartup", true, false),
/**
* Here you can set environment information. See description for details
*/
SECHUB_ADMIN_ENVIRONMENT("sechub.developertools.admin.environment", false,
- "Use 'PROD', 'INT' or anything containing 'TEST' for dedicated colors (red,yellow,cyan). All other variants are without special colors"),
+ "Use 'PROD', 'INT' or anything containing 'TEST' for dedicated colors (red,yellow,cyan). All other variants are without special colors", false),
- SECHUB_MASS_OPERATION_PARENTDIRECTORY("sechub.developertools.admin.massoperation.parentdirectory", true),
+ SECHUB_MASS_OPERATION_PARENTDIRECTORY("sechub.developertools.admin.massoperation.parentdirectory", true, false),
- PDS_SOLUTION_GENERATOR_SECHUB_CONFIGURATION_DIRECTORY("pds.solution.generator.config.sechub.parentdirectory", true),
+ PDS_SOLUTION_GENERATOR_SECHUB_CONFIGURATION_DIRECTORY("pds.solution.generator.config.sechub.parentdirectory", true, false),
/**
* Usage: for example -Dsechub.developertools.output.font.settings="courier 18"
*/
- SECHUB_OUTPUT_FONT_SETTINGS("sechub.developertools.output.font.settings", true),
+ SECHUB_OUTPUT_FONT_SETTINGS("sechub.developertools.output.font.settings", true, false),
- SECHUB_LOOK_AND_FEEL("sechub.developertools.lookandfeel.nimbus", true),
+ SECHUB_LOOK_AND_FEEL("sechub.developertools.lookandfeel.nimbus", true, false),
SECHUB_TARGETFOLDER_FOR_SECHUB_CLIENT_SCAN("sechub.developertools.admin.launch.scan.targetfolder", true,
- "Default path to parent folder of configuration file and sources to scan"),
+ "Default path to parent folder of configuration file and sources to scan", false),
/**
* When defined we use this path instead IDE relative one
*/
- SECHUB_PATH_TO_SECHUB_CLIENT_BINARY("sechub.developertools.admin.launch.clientbinary.path", true),
+ SECHUB_PATH_TO_SECHUB_CLIENT_BINARY("sechub.developertools.admin.launch.clientbinary.path", true, false),
- SECHUB_TRUSTALL_DENIED("sechub.developertools.trustall.denied", true);
+ SECHUB_TRUSTALL_DENIED("sechub.developertools.trustall.denied", true, false);
;
- private String systemPropertyid;
+ private String systemPropertyId;
private String environmentEntryId;
private boolean optional;
private String description;
+ private boolean sensitiveInformation;
- private ConfigurationSetup(boolean optional) {
- this(null, optional);
+ private ConfigurationSetup(boolean optional, boolean sensitiveInformation) {
+ this(null, optional, null, sensitiveInformation);
}
- private ConfigurationSetup(String systemPropertyid, boolean optional) {
- this(systemPropertyid, optional, null);
+ private ConfigurationSetup(String systemPropertyid, boolean optional, boolean sensitiveInformation) {
+ this(systemPropertyid, optional, null, sensitiveInformation);
}
- private ConfigurationSetup(String systemPropertyid, boolean optional, String description) {
+ private ConfigurationSetup(String systemPropertyid, boolean optional, String description, boolean sensitiveInformation) {
this.optional = optional;
- this.systemPropertyid = systemPropertyid;
+ this.systemPropertyId = systemPropertyid;
this.environmentEntryId = name();
this.description = description;
+ this.sensitiveInformation = sensitiveInformation;
+ }
+
+ public boolean isSensitiveInformation() {
+ return sensitiveInformation;
}
public String getEnvironmentEntryId() {
return environmentEntryId;
}
- public String getSystemPropertyid() {
- return systemPropertyid;
+ public String getSystemPropertyId() {
+ return systemPropertyId;
}
public static boolean isIntegrationTestServerMenuEnabled() {
- return Boolean.getBoolean(ConfigurationSetup.SECHUB_ENABLE_INTEGRATION_TESTSERVER_MENU.getSystemPropertyid());
+ return Boolean.getBoolean(ConfigurationSetup.SECHUB_ENABLE_INTEGRATION_TESTSERVER_MENU.getSystemPropertyId());
}
public static boolean isConfirmationDisabled() {
- return Boolean.getBoolean(ConfigurationSetup.SECHUB_DISABLE_CONFIRMATIONS.getSystemPropertyid());
+ return Boolean.getBoolean(ConfigurationSetup.SECHUB_DISABLE_CONFIRMATIONS.getSystemPropertyId());
}
public static boolean isCheckOnStartupEnabled() {
- return Boolean.getBoolean(ConfigurationSetup.SECHUB_CHECK_STATUS_ON_STARTUP.getSystemPropertyid());
+ return Boolean.getBoolean(ConfigurationSetup.SECHUB_CHECK_STATUS_ON_STARTUP.getSystemPropertyId());
}
public static String getOutputFontSettings(String defaultSetting) {
@@ -114,11 +120,11 @@ public static String getParentFolderPathForSecHubClientScanOrNull() {
* GTK
*/
public static boolean isNimbusLookAndFeelEnabled() {
- return Boolean.getBoolean(ConfigurationSetup.SECHUB_LOOK_AND_FEEL.getSystemPropertyid());
+ return Boolean.getBoolean(ConfigurationSetup.SECHUB_LOOK_AND_FEEL.getSystemPropertyId());
}
public static boolean isTrustAllDenied() {
- return Boolean.getBoolean(ConfigurationSetup.SECHUB_TRUSTALL_DENIED.getSystemPropertyid());
+ return Boolean.getBoolean(ConfigurationSetup.SECHUB_TRUSTALL_DENIED.getSystemPropertyId());
}
/**
@@ -161,8 +167,8 @@ public String getStringValue(String defaultValue, boolean failWhenNull) {
}
/* then try system property - if not already set */
if (value == null) {
- if (systemPropertyid != null) {
- value = System.getProperty(systemPropertyid, defaultValue);
+ if (systemPropertyId != null) {
+ value = System.getProperty(systemPropertyId, defaultValue);
}
}
/* then use default value - if not already set */
@@ -185,15 +191,56 @@ private void assertNotEmpty(String part, String missing) {
private static String description() {
StringBuilder sb = new StringBuilder();
- sb.append("Use following system properties:\n");
+ sb.append("\nMandatory settings:\n------------------------------\nAs environment variables):\n");
+ appendEnvironmentVariables(sb, false);
+ sb.append("Or by system properties:\n");
+ appendSystemProperties(sb, false);
+
+ sb.append("\nOptional settings:\n------------------------------\nAs environment variables):\n");
+ appendEnvironmentVariables(sb, true);
+ appendSystemProperties(sb, true);
+
+ return sb.toString();
+ }
+
+ private static void appendEnvironmentVariables(StringBuilder sb, boolean expectedToBeOptional) {
+ for (ConfigurationSetup setup : values()) {
+ if (expectedToBeOptional != setup.optional) {
+ continue;
+ }
+ if (setup.environmentEntryId == null) {
+ continue;
+ }
+ sb.append(" ");
+ sb.append(setup.environmentEntryId);
+ sb.append("=some-value");
+ if (setup.optional) {
+ sb.append(" (optional)");
+ }
+ if (setup.isSensitiveInformation()) {
+ sb.append(" (sensitive information)");
+ }
+ if (setup.description != null) {
+ sb.append(" [");
+ sb.append(setup.description);
+ sb.append("]");
+ }
+ sb.append("\n");
+ }
+ }
+
+ private static void appendSystemProperties(StringBuilder sb, boolean expectedToBeOptional) {
for (ConfigurationSetup setup : values()) {
- if (setup.systemPropertyid == null) {
+ if (setup.optional != expectedToBeOptional) {
+ continue;
+ }
+ if (setup.systemPropertyId == null || setup.isSensitiveInformation()) {
continue;
}
sb.append("-D");
- sb.append(setup.systemPropertyid);
+ sb.append(setup.systemPropertyId);
sb.append("=");
- String val = System.getProperty(setup.systemPropertyid);
+ String val = System.getProperty(setup.systemPropertyId);
if (val != null && !val.isEmpty()) {
val = "**** (already set)";
}
@@ -208,16 +255,6 @@ private static String description() {
}
sb.append("\n");
}
- sb.append("\nFor security reasons next parts must be set as environment variables (so not visible in process view):\n");
- for (ConfigurationSetup setup : values()) {
- if (setup.environmentEntryId == null) {
- continue;
- }
- sb.append(" ");
- sb.append(setup.environmentEntryId);
- sb.append("'\n");
- }
- return sb.toString();
}
}
diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CredentialUI.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CredentialUI.java
index c9ba22220e..5a34a0e6bc 100644
--- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CredentialUI.java
+++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CredentialUI.java
@@ -88,11 +88,11 @@ public CredentialUI(UIContext context) {
serverPortSpinner.setEnabled(false);
protocolField.setEnabled(false);
- serverField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_SERVER.getSystemPropertyid());
- useridField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_USERID.getSystemPropertyid());
- passwordField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_APITOKEN.getSystemPropertyid());
- serverPortSpinner.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_SERVER_PORT.getSystemPropertyid());
- protocolField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_SERVER_PROTOCOL.getSystemPropertyid());
+ serverField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_SERVER.getSystemPropertyId());
+ useridField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_USERID.getSystemPropertyId());
+ passwordField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_APITOKEN.getSystemPropertyId());
+ serverPortSpinner.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_SERVER_PORT.getSystemPropertyId());
+ protocolField.setToolTipText(ConfigurationSetup.SECHUB_ADMIN_SERVER_PROTOCOL.getSystemPropertyId());
useDifferentColorsForWellknownEnvironments();
diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/client/TriggerSecHubClientSynchronousScanAction.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/client/TriggerSecHubClientSynchronousScanAction.java
index b00b4b0cc5..03f0f9d548 100644
--- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/client/TriggerSecHubClientSynchronousScanAction.java
+++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/client/TriggerSecHubClientSynchronousScanAction.java
@@ -36,7 +36,7 @@ public void execute(ActionEvent event) throws Exception {
"Please enter target folder for sechub scan:\n\n"+
(optionalProject.isPresent() ? "": "WARN: You didn't define a project. So this folder must contain a sechub.json having projectId defined inside to work!)")+"\nServer, user and apitoken are used by DAUI setup!\n"+
"INFO: You can set a a default by system property:\n"+
- ConfigurationSetup.SECHUB_TARGETFOLDER_FOR_SECHUB_CLIENT_SCAN.getSystemPropertyid(), InputCacheIdentifier.CLIENT_SCAN_TARGETFOLDER
+ ConfigurationSetup.SECHUB_TARGETFOLDER_FOR_SECHUB_CLIENT_SCAN.getSystemPropertyId(), InputCacheIdentifier.CLIENT_SCAN_TARGETFOLDER
);
/* @formatter:on */
if (!optionalPath.isPresent()) {
diff --git a/sechub-developertools/src/main/resources/application.yaml b/sechub-developertools/src/main/resources/application.yaml
new file mode 100644
index 0000000000..4b4cc19c9c
--- /dev/null
+++ b/sechub-developertools/src/main/resources/application.yaml
@@ -0,0 +1,3 @@
+spring:
+ main:
+ web-application-type: none # we do not want to start tomcat by DAUI
\ No newline at end of file
diff --git a/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc b/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc
index c87c1a1889..8acdc852af 100644
--- a/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc
+++ b/sechub-doc/src/docs/asciidoc/sechub-developer-quickstart-guide.adoc
@@ -641,7 +641,7 @@ We explain the integration test setup based on the IntelliJ IDEA IDE.
First run the following commands to create the necessary certificates for the integration test servers:
----
-./gradlew ensureLocalhostCertificate build generateOpenapi buildDeveloperAdminUI -x :sechub-cli:build
+./gradlew ensureLocalhostCertificate build generateOpenapi -x :sechub-cli:build
----
----
./gradlew clean
diff --git a/sechub-openapi-java/src/main/resources/openapi.yaml b/sechub-openapi-java/src/main/resources/openapi.yaml
index 89428aa834..28369cef85 100644
--- a/sechub-openapi-java/src/main/resources/openapi.yaml
+++ b/sechub-openapi-java/src/main/resources/openapi.yaml
@@ -2019,13 +2019,17 @@ components:
title: SecHubJobInfoForUserListPage
type: object
properties:
- jobs:
+ content:
type: array
items:
$ref: '#/components/schemas/SecHubJobInfoForUser'
projectId:
type: string
-
+ page:
+ type: int
+ totalPages:
+ type: int
+
TemplateType:
title: TemplateType
type: string
diff --git a/sechub-web-ui/README.md b/sechub-web-ui/README.md
index 9d4872cecd..d5ee0f159b 100644
--- a/sechub-web-ui/README.md
+++ b/sechub-web-ui/README.md
@@ -40,6 +40,8 @@ To start the development server with hot-reload, run the following command. The
npm run dev
```
+> If you receive an empty page, do a reload (sometimes it needs a little bit of time until everything is setup correctly)
+
> Add NODE_OPTIONS='--no-warnings' to suppress the JSON import warnings that happen as part of the Vuetify import mapping. If you are on Node [v21.3.0](https://nodejs.org/en/blog/release/v21.3.0) or higher, you can change this to NODE_OPTIONS='--disable-warning=5401'. If you don't mind the warning, you can remove this from your package.json dev script.
#### Running in Development mode with sechub for testing
diff --git a/sechub-web-ui/package-lock.json b/sechub-web-ui/package-lock.json
index e9661aa883..5f7e2c0eb8 100644
--- a/sechub-web-ui/package-lock.json
+++ b/sechub-web-ui/package-lock.json
@@ -11,6 +11,7 @@
"@mdi/font": "7.4.47",
"@openapitools/openapi-generator-cli": "^2.15.3",
"core-js": "^3.37.1",
+ "pinia": "^2.3.0",
"roboto-fontface": "*",
"vue": "^3.4.31",
"vue-i18n": "^10.0.5",
@@ -5871,6 +5872,28 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pinia": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.0.tgz",
+ "integrity": "sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.3",
+ "vue-demi": "^0.14.10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.4.4",
+ "vue": "^2.7.0 || ^3.5.11"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/pkg-types": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.1.tgz",
@@ -7272,6 +7295,32 @@
}
}
},
+ "node_modules/vue-demi": {
+ "version": "0.14.10",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
+ "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vue-eslint-parser": {
"version": "9.4.3",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz",
diff --git a/sechub-web-ui/package.json b/sechub-web-ui/package.json
index d8ef8e8434..ffe48f1ef9 100644
--- a/sechub-web-ui/package.json
+++ b/sechub-web-ui/package.json
@@ -12,6 +12,7 @@
"@mdi/font": "7.4.47",
"@openapitools/openapi-generator-cli": "^2.15.3",
"core-js": "^3.37.1",
+ "pinia": "^2.3.0",
"roboto-fontface": "*",
"vue": "^3.4.31",
"vue-i18n": "^10.0.5",
diff --git a/sechub-web-ui/src/components.d.ts b/sechub-web-ui/src/components.d.ts
index a2f3fbe49f..0e51db0019 100644
--- a/sechub-web-ui/src/components.d.ts
+++ b/sechub-web-ui/src/components.d.ts
@@ -9,9 +9,10 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AppHeader: typeof import('./components/AppHeader.vue')['default']
- Projects: typeof import('./components/Projects.vue')['default']
+ Pagination: typeof import('./components/Pagination.vue')['default']
+ Project: typeof import('./components/Project.vue')['default']
+ ProjectsList: typeof import('./components/ProjectsList.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
- SecHubDefault: typeof import('./components/SecHubDefault.vue')['default']
}
}
diff --git a/sechub-web-ui/src/components/Pagination.vue b/sechub-web-ui/src/components/Pagination.vue
new file mode 100644
index 0000000000..62283dd3aa
--- /dev/null
+++ b/sechub-web-ui/src/components/Pagination.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sechub-web-ui/src/components/Project.vue b/sechub-web-ui/src/components/Project.vue
new file mode 100644
index 0000000000..51e3f93f96
--- /dev/null
+++ b/sechub-web-ui/src/components/Project.vue
@@ -0,0 +1,143 @@
+
+
+
+
+ {{ projectId }}
+
+
+
+
+
+ {{ $t('ERROR_FETCHING_DATA') }}
+ {{ $t('NO_JOBS_RUNNED') }}
+
+
+
+
+
+
+
+ {{ $t('HEADER_JOB_TABLE_CREATED') }} |
+ {{ $t('HEADER_JOB_TABLE_STATUS') }} |
+ {{ $t('HEADER_JOB_TABLE_RESULT') }} |
+ {{ $t('HEADER_JOB_TABLE_TRAFFIC_LIGHT') }} |
+ {{ $t('HEADER_JOB_TABLE_REPORT') }} |
+ {{ $t('JOB_TABLE_DOWNLOAD_JOBUUID') }} |
+
+
+
+
+ {{ formatDate(job.created) }} |
+ {{ job.executionState }} |
+ {{ job.executionResult }} |
+ |
+
+ {{ $t('JOB_TABLE_DOWNLOAD_REPORT') }}
+
+
+
+ |
+ {{ job.jobUUID }} |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sechub-web-ui/src/components/Projects.vue b/sechub-web-ui/src/components/ProjectsList.vue
similarity index 81%
rename from sechub-web-ui/src/components/Projects.vue
rename to sechub-web-ui/src/components/ProjectsList.vue
index 3fc9a1479f..58087600fa 100644
--- a/sechub-web-ui/src/components/Projects.vue
+++ b/sechub-web-ui/src/components/ProjectsList.vue
@@ -21,6 +21,7 @@
class="ma-5"
rounded="lg"
:value="project"
+ @click="openProjectPage(project)"
>
@@ -40,18 +41,24 @@
-
-
-
-
-
-
{{ $t('GREETING') }}
-
-
SecHub!
-
-
-
-
-
-
-
-
diff --git a/sechub-web-ui/src/i18n/locales/en.json b/sechub-web-ui/src/i18n/locales/en.json
index 7c924f137e..92b2528860 100644
--- a/sechub-web-ui/src/i18n/locales/en.json
+++ b/sechub-web-ui/src/i18n/locales/en.json
@@ -4,5 +4,13 @@
"OWNED": "owned",
"MEMBER": "member",
"NO_PROJECTS_ASSIGNED": "You are not assigned to any projects.",
- "ERROR_FETCHING_DATA": "Could not load data from Server."
+ "NO_JOBS_RUNNED": "No jobs were started for this project.",
+ "ERROR_FETCHING_DATA": "Could not load data from Server.",
+ "HEADER_JOB_TABLE_STATUS": "State",
+ "HEADER_JOB_TABLE_RESULT": "Result",
+ "HEADER_JOB_TABLE_CREATED": "Created",
+ "HEADER_JOB_TABLE_TRAFFIC_LIGHT": "Traffic Light",
+ "HEADER_JOB_TABLE_REPORT": "Report",
+ "JOB_TABLE_DOWNLOAD_REPORT": "Download",
+ "JOB_TABLE_DOWNLOAD_JOBUUID": "Job UUID"
}
\ No newline at end of file
diff --git a/sechub-web-ui/src/pages/[id].vue b/sechub-web-ui/src/pages/[id].vue
new file mode 100644
index 0000000000..9dfada12c0
--- /dev/null
+++ b/sechub-web-ui/src/pages/[id].vue
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/sechub-web-ui/src/pages/index.vue b/sechub-web-ui/src/pages/index.vue
index 38f800953b..4bab3539fa 100644
--- a/sechub-web-ui/src/pages/index.vue
+++ b/sechub-web-ui/src/pages/index.vue
@@ -1,8 +1,8 @@
-
+
diff --git a/sechub-web-ui/src/plugins/index.ts b/sechub-web-ui/src/plugins/index.ts
index 438ee69260..73adbace8f 100644
--- a/sechub-web-ui/src/plugins/index.ts
+++ b/sechub-web-ui/src/plugins/index.ts
@@ -9,6 +9,7 @@
import vuetify from './vuetify'
import router from '../router'
import i18n from '@/i18n'
+import { createPinia } from 'pinia'
// Types
import type { App } from 'vue'
@@ -18,4 +19,5 @@ export function registerPlugins (app: App) {
.use(vuetify)
.use(router)
.use(i18n)
+ .use(createPinia())
}
diff --git a/sechub-web-ui/src/services/defaultClient.ts b/sechub-web-ui/src/services/defaultClient.ts
index 1fe706c8e8..822b52a6ea 100644
--- a/sechub-web-ui/src/services/defaultClient.ts
+++ b/sechub-web-ui/src/services/defaultClient.ts
@@ -2,12 +2,13 @@
import configurationApi from './configurationService'
import projectApi from './productAdministrationService'
import systemApi from './systemApiService'
+import otherApi from './otherService'
const defaultClient = {
withProjectApi: projectApi,
withSystemApi: systemApi,
withConfigurationApi: configurationApi,
-
+ withOtherApi: otherApi,
}
export default defaultClient
diff --git a/sechub-web-ui/src/services/otherService.ts b/sechub-web-ui/src/services/otherService.ts
new file mode 100644
index 0000000000..31d1a7217f
--- /dev/null
+++ b/sechub-web-ui/src/services/otherService.ts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MIT
+import { OtherApi } from '@/generated-sources/openapi'
+import apiConfig from './configuration'
+
+const otherApi = new OtherApi(apiConfig)
+
+export default otherApi
diff --git a/sechub-web-ui/src/stores/projectStore.ts b/sechub-web-ui/src/stores/projectStore.ts
new file mode 100644
index 0000000000..1864aadb8c
--- /dev/null
+++ b/sechub-web-ui/src/stores/projectStore.ts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: MIT
+import { ProjectData } from '@/generated-sources/openapi'
+import { defineStore } from 'pinia'
+
+export const useProjectStore = defineStore('projectStore', {
+ state: () => ({
+ projects: [] as ProjectData[],
+ }),
+ actions: {
+ storeProjects (projects: ProjectData[]) {
+ this.projects = projects
+ },
+ },
+ getters: {
+ getProjectById: state => {
+ return (id: string) => state.projects.find(project => project.projectId === id) || {}
+ },
+ },
+})
diff --git a/sechub-web-ui/src/themes/darkTheme.ts b/sechub-web-ui/src/themes/darkTheme.ts
index dfae961671..75463638dc 100644
--- a/sechub-web-ui/src/themes/darkTheme.ts
+++ b/sechub-web-ui/src/themes/darkTheme.ts
@@ -6,5 +6,8 @@ export default {
background_default: '#0D0D0D',
background_paper: '#1A1A1A',
layer_01: '#262626',
+ warning: '#FACC00',
+ error: '#FF4A4A',
+ success: '#21A330',
},
}
diff --git a/sechub-web-ui/src/themes/lightTheme.ts b/sechub-web-ui/src/themes/lightTheme.ts
index 3aa4c4c988..66eaeb3b4a 100644
--- a/sechub-web-ui/src/themes/lightTheme.ts
+++ b/sechub-web-ui/src/themes/lightTheme.ts
@@ -6,5 +6,8 @@ export default {
background_default: '#F4F4F4',
background_paper: '#FFFFFF',
layer_01: '#F4F4F4',
+ warning: '#FACC00',
+ error: '#FF4A4A',
+ success: '#21A330',
},
}
diff --git a/sechub-web-ui/src/typed-router.d.ts b/sechub-web-ui/src/typed-router.d.ts
index 67341caac3..9cfb62a168 100644
--- a/sechub-web-ui/src/typed-router.d.ts
+++ b/sechub-web-ui/src/typed-router.d.ts
@@ -20,5 +20,6 @@ declare module 'vue-router/auto-routes' {
*/
export interface RouteNamedMap {
'/': RouteRecordInfo<'/', '/', Record, Record>,
+ '/[id]': RouteRecordInfo<'/[id]', '/:id', { id: ParamValue }, { id: ParamValue }>,
}
}
diff --git a/sechub-web-ui/src/utils/projectUtils.ts b/sechub-web-ui/src/utils/projectUtils.ts
new file mode 100644
index 0000000000..b4d073986c
--- /dev/null
+++ b/sechub-web-ui/src/utils/projectUtils.ts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+export function formatDate (dateString: string) {
+ const date = new Date(dateString)
+ const day = String(date.getDate()).padStart(2, '0')
+ const month = String(date.getMonth() + 1).padStart(2, '0')
+ const year = date.getFullYear()
+ const time = date.toTimeString().split(' ')[0]
+ return `${day}.${month}.${year} ${time}`
+}
+
+export function getTrafficLightClass (value: string) {
+ switch (value) {
+ case 'OFF':
+ return 'traffic-light-off'
+ case 'RED':
+ return 'traffic-light-red'
+ case 'GREEN':
+ return 'traffic-light-green'
+ case 'YELLOW':
+ return 'traffic-light-yellow'
+ default:
+ return 'traffic-light-none'
+ }
+}