From 8eb0cd93b28f17dd78129c39c831d630392ccc64 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Tue, 19 Mar 2024 15:00:29 +0100 Subject: [PATCH] Configuration model now supports secret, license and codescan #2441 --- .../__test__/configuration-builder.test.ts | 252 +++++++++++++++++- .../scan/src/configuration-builder.ts | 72 +++-- .../scan/src/configuration-model.ts | 70 ++++- 3 files changed, 353 insertions(+), 41 deletions(-) diff --git a/github-actions/scan/__test__/configuration-builder.test.ts b/github-actions/scan/__test__/configuration-builder.test.ts index 4dc0ed80af..bd995677fb 100644 --- a/github-actions/scan/__test__/configuration-builder.test.ts +++ b/github-actions/scan/__test__/configuration-builder.test.ts @@ -1,37 +1,271 @@ // SPDX-License-Identifier: MIT import * as configBuilder from '../src/configuration-builder'; +import { SecHubConfigurationModel, ContentType, ScanType } from '../src/configuration-model'; import { SecHubConfigurationModelBuilderData } from '../src/configuration-builder'; + jest.mock('@actions/core'); + +function dumpModel(model: SecHubConfigurationModel){ + const json = JSON.stringify(model, null, 2); // pretty printed output + + console.log('json='+json); +} + describe('configuration-builder', function() { test('null parameters - a model is created with api version 1.0.0', function () { /* execute */ - const data = new SecHubConfigurationModelBuilderData(); - const model= configBuilder.createSecHubConfigurationModel(data); + const builderData = new SecHubConfigurationModelBuilderData(); + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + expect(model.apiVersion).toEqual('1.0'); + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + }); + + test('codescan generated per default - source,one folder defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1']; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); /* test */ + dumpModel(model); + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(1); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); + }); - test('codescan green', () => { + test('codescan generated per default - source, two folders defined', () => { /* prepare */ - const data = new SecHubConfigurationModelBuilderData(); - data.includeFolders= ['folder1']; + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + expect(firstSource?.excludes?.length).toEqual(0); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); + + }); + + test('codescan generated per default - source, two folders defined, one excluded', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.excludeFolders= ['folder3']; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeDefined(); + expect(model.data.binaries).toBeUndefined(); + + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + + expect(firstSource?.excludes?.length).toEqual(1); + expect(firstSource?.excludes?.[0]).toEqual('folder3'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); - const model= configBuilder.createSecHubConfigurationModel(data); + }); + + test('codescan generated per default - binaries, two folders defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.contentType=ContentType.BINARIES; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources).toBeUndefined(); + expect(model.data.binaries).toBeDefined(); + + expect(model.data.binaries?.length).toEqual(1); + + const firstBinary = model.data.binaries?.[0]; + expect(firstBinary?.fileSystem.folders?.length).toEqual(2); + expect(firstBinary?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstBinary?.fileSystem.folders?.[1]).toEqual('folder2'); + expect(firstBinary?.excludes?.length).toEqual(0); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeUndefined(); + expect(model.licenseScan).toBeUndefined(); + }); + + test('codescan and license scan - two folders defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.scanTypes=[ScanType.CODE_SCAN,ScanType.LICENSE_SCAN]; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources); + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.licenseScan).toBeDefined(); + expect(model.licenseScan?.use.length).toEqual(1); + expect(model.licenseScan?.use[0]).toEqual('reference-data-1'); // same data refererenced + + expect(model.secretScan).toBeUndefined(); + + }); + test('codescan and secret scan - two folders defined', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1','folder2']; + builderData.scanTypes=[ScanType.CODE_SCAN,ScanType.SECRET_SCAN]; + + /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); + + /* test */ + dumpModel(model); + + expect(model.apiVersion).toEqual('1.0'); + + expect(model.data.sources); + expect(model.data.sources?.length).toEqual(1); + + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(2); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.fileSystem.folders?.[1]).toEqual('folder2'); + + expect(model.codeScan).toBeDefined(); + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.codeScan?.use.length).toEqual(1); + expect(model.codeScan?.use[0]).toEqual('reference-data-1'); + + expect(model.secretScan).toBeDefined(); + expect(model.secretScan?.use.length).toEqual(1); + expect(model.secretScan?.use[0]).toEqual('reference-data-1'); // same data refererenced + + expect(model.licenseScan).toBeUndefined(); + + }); + test('secret scan standalone - source, one folder defined, one excluded', () => { + + /* prepare */ + const builderData = new SecHubConfigurationModelBuilderData(); + builderData.includeFolders= ['folder1']; + builderData.excludeFolders= ['folderX']; + builderData.scanTypes=[ScanType.SECRET_SCAN]; /* execute */ + const model= configBuilder.createSecHubConfigurationModel(builderData); /* test */ - const json = JSON.stringify(model); + dumpModel(model); - console.log('json='+json); expect(model.apiVersion).toEqual('1.0'); - expect(model.codeScan); + + expect(model.data.sources); + expect(model.data.sources?.length).toEqual(1); + const firstSource = model.data.sources?.[0]; + expect(firstSource?.fileSystem.folders?.length).toEqual(1); + expect(firstSource?.fileSystem.folders?.[0]).toEqual('folder1'); + expect(firstSource?.excludes?.length).toEqual(1); + expect(firstSource?.excludes?.[0]).toEqual('folderX'); + expect(model.codeScan).toBeUndefined(); + + expect(model.secretScan).toBeDefined(); + expect(model.secretScan?.use.length).toEqual(1); + expect(model.secretScan?.use[0]).toEqual('reference-data-1'); // same data refererenced + + expect(model.licenseScan).toBeUndefined(); + }); }); \ No newline at end of file diff --git a/github-actions/scan/src/configuration-builder.ts b/github-actions/scan/src/configuration-builder.ts index f2a2643405..aaff35da68 100644 --- a/github-actions/scan/src/configuration-builder.ts +++ b/github-actions/scan/src/configuration-builder.ts @@ -2,7 +2,8 @@ import * as core from '@actions/core'; import * as shell from 'shelljs'; -import { SecHubConfigurationModel } from './configuration-model'; +import { ScanType, ContentType, SecHubConfigurationModel } from './configuration-model'; +import * as cm from './configuration-model'; /** * Creates the sechub.json configuration file with the given user input values. @@ -10,8 +11,8 @@ import { SecHubConfigurationModel } from './configuration-model'; * @param includeFolders Which folders should be included * @param excludeFolders Which folders should be excluded */ -export function createSecHubConfigJsonFile(secHubJsonFilePath:string, data: SecHubConfigurationModelBuilderData) { - core.info('Config-Path was not found. Config will be created at '+ secHubJsonFilePath); +export function createSecHubConfigJsonFile(secHubJsonFilePath: string, data: SecHubConfigurationModelBuilderData) { + core.info('Config-Path was not found. Config will be created at ' + secHubJsonFilePath); const secHubJson = createSecHubConfigurationModel(data); const stringifiedSecHubJson = JSON.stringify(secHubJson); core.debug('SecHub-Config: ' + stringifiedSecHubJson); @@ -19,10 +20,13 @@ export function createSecHubConfigJsonFile(secHubJsonFilePath:string, data: SecH shell.ShellString(stringifiedSecHubJson).to(secHubJsonFilePath); } -export class SecHubConfigurationModelBuilderData{ +export class SecHubConfigurationModelBuilderData { includeFolders: string[] = []; excludeFolders: string[] = []; + + contentType: ContentType = ContentType.SOURCE; // per default source + scanTypes: ScanType[] = [ScanType.CODE_SCAN]; // per default only code scan } /** @@ -33,27 +37,51 @@ export class SecHubConfigurationModelBuilderData{ * * @returns model */ -export function createSecHubConfigurationModel(data: SecHubConfigurationModelBuilderData): SecHubConfigurationModel { - const model: SecHubConfigurationModel = { - 'apiVersion' : '1.0' - }; - - if (model.codeScan==null){ - model.codeScan={ - }; - } - if (data.includeFolders) { +export function createSecHubConfigurationModel(builderData: SecHubConfigurationModelBuilderData): SecHubConfigurationModel { + const model = new SecHubConfigurationModel(); - if (model.codeScan.fileSystem==null){ - model.codeScan.fileSystem={ - }; - } + const referenceName = 'reference-data-1'; - model.codeScan.fileSystem.folders = data.includeFolders; - } + createSourceOrBinaryDataReference(referenceName, builderData, model); - if (data.excludeFolders) { - model.codeScan.excludes = data.excludeFolders; + if (builderData.scanTypes?.indexOf(ScanType.CODE_SCAN) != -1) { + const codescan = new cm.CodeScan(); + codescan.use = [referenceName]; + model.codeScan = codescan; + } + if (builderData.scanTypes?.indexOf(ScanType.LICENSE_SCAN) != -1) { + const licenseScan = new cm.LicenseScan(); + licenseScan.use = [referenceName]; + model.licenseScan = licenseScan; } + if (builderData.scanTypes?.indexOf(ScanType.SECRET_SCAN) != -1) { + const secretScan = new cm.SecretScan(); + secretScan.use = [referenceName]; + model.secretScan = secretScan; + } + return model; } + +function createSourceOrBinaryDataReference(referenceName: string, builderData: SecHubConfigurationModelBuilderData, model: SecHubConfigurationModel) { + if (builderData.contentType == cm.ContentType.SOURCE) { + + const sourceData1 = new cm.SourceData(); + sourceData1.name = referenceName; + + sourceData1.fileSystem.folders = builderData.includeFolders; + sourceData1.excludes = builderData.excludeFolders; + + model.data.sources = [sourceData1]; + + } else if (builderData.contentType == cm.ContentType.BINARIES) { + const binaryData1 = new cm.BinaryData(); + binaryData1.name = referenceName; + + binaryData1.fileSystem.folders = builderData.includeFolders; + binaryData1.excludes = builderData.excludeFolders; + + model.data.binaries = [binaryData1]; + } +} + diff --git a/github-actions/scan/src/configuration-model.ts b/github-actions/scan/src/configuration-model.ts index 8e2d7cb619..d03985152f 100644 --- a/github-actions/scan/src/configuration-model.ts +++ b/github-actions/scan/src/configuration-model.ts @@ -1,18 +1,68 @@ // SPDX-License-Identifier: MIT +export enum ContentType{ + + SOURCE = 'source', + + BINARIES = 'binaries' +} + +export enum ScanType{ + + CODE_SCAN = 'code-scan', + + LICENSE_SCAN = 'license-scan', + + SECRET_SCAN = 'secret-scan', + +} + /** * SecHub configuration model */ -export type SecHubConfigurationModel = { - apiVersion: string; +export class SecHubConfigurationModel { + apiVersion='1.0'; + + data = new DataSection(); + codeScan?: CodeScan; -}; + secretScan?: SecretScan; + licenseScan?: LicenseScan; +} + +export class DataSection { + sources: SourceData[]|undefined; + binaries: BinaryData[]|undefined; +} + +export class SourceData { + name = ''; + fileSystem= new FileSystem(); + + excludes: string[]|undefined; + additionalFilenameExtensions: string[]|undefined; +} + +export class BinaryData { + name = ''; + fileSystem= new FileSystem(); + + excludes: string[]|undefined; + additionalFilenameExtensions: string[]|undefined; +} + +export class CodeScan { + use: string[] = []; +} + +export class SecretScan { + use: string[] = []; +} -type CodeScan = { - fileSystem?: FileSystem; - excludes?: string[]; -}; +export class LicenseScan { + use: string[] = []; +} -type FileSystem = { - folders?: string[]; -}; +export class FileSystem{ + folders?: string[] = []; +}