From 4b7af4c1dc78fff719e44cdac0768a0c73208757 Mon Sep 17 00:00:00 2001 From: Albert Tregnaghi Date: Thu, 14 Nov 2024 18:41:28 +0100 Subject: [PATCH] SecHub PDS communication parts for assets and templates #3523 - it is now ensured on every pds job call, that the assets in storage are same as in db. Same logic for admin create/update operation is used. - improved PDSWebScanJobScenario12IntTest which does now uses templates and assets. The test ensures that the PDS instance will receive the pds template meta data. - changed templateDefinition format. Assets now no longer an array but only one entry. Means we have 1:n relation here from asset to templates and no longer m:n. - added unit tests - introduced TemplateData resolver in commons-model which can be used from PDS and wrapper applications - introduced TemplateData inside SecHub convfiguration file - Template and Asset REST controller are now annotated with profile admin access --- .../sechub/adapter/pds/PDSAdapterV1.java | 23 +- .../adapter/AbstractAdapterConfigBuilder.java | 4 +- .../sechub/adapter/AdapterConfigBuilder.java | 4 +- .../adapter/AdapterConfigurationStrategy.java | 4 +- .../core/ConfigurationFailureException.java | 16 ++ .../model/login/WebLoginConfiguration.java | 11 + .../commons/model/template/TemplateData.java | 12 +- .../model/template/TemplateDataResolver.java | 42 ++++ .../model/template/TemplateDefinition.java | 125 +++++++++- .../template/TemplateDataResolverTest.java | 107 ++++++++ .../template/TemplateDefinitionTest.java | 11 +- .../template-definition-example1.json | 2 +- .../sechub/commons/pds/AbstractPDSKey.java | 2 +- .../commons/pds/PDSConfigDataKeyProvider.java | 8 +- .../pds/PDSDefaultParameterKeyConstants.java | 4 +- .../commons/pds/data/PDSTemplateMetaData.java | 114 +++++++++ .../pds/data/PDSTemplateMetaDataTest.java | 23 ++ .../CreateOrUpdateTemplateAction.java | 6 +- .../concept_templates_and_assets.adoc | 36 ++- .../pds-param-template-metadata-example1.json | 20 +- .../pds-param-template-metadata-syntax.json | 29 +-- .../snippet/template-definition-syntax.json | 20 +- .../TemplateRestControllerRestDocTest.java | 6 +- .../integrationtest-webscan.sh | 4 + .../sechub/integrationtest/api/AsUser.java | 5 +- .../resources/pds-config-integrationtest.json | 7 +- .../scenario1/TemplateScenario1IntTest.java | 18 +- .../PDSWebScanJobScenario12IntTest.java | 75 +++++- .../PDS_INTTEST_PRODUCT_WEBSCAN.zip | Bin 0 -> 214 bytes ...grationtest-webscanconfig-all-options.json | 12 +- .../CheckmarxExecutorConfigSuppport.java | 9 +- .../checkmarx/CheckmarxProductExecutor.java | 4 +- .../CheckmarxExecutorConfigSuppportTest.java | 21 +- .../pds/AbstractPDSProductExecutor.java | 3 +- .../pds/PDSAdapterConfigurationStrategy.java | 18 +- .../product/pds/PDSExecutorConfigSupport.java | 57 ++++- ...ecutorConfigSuppportServiceCollection.java | 7 + .../pds/PDSInfraScanProductExecutor.java | 3 +- .../pds/PDSTemplateMetaDataService.java | 116 +++++++++ .../pds/PDSWebScanProductExecutor.java | 3 +- .../RelevantScanTemplateDefinitionFilter.java | 75 ++++++ .../SecHubProductExecutionPDSKeyProvider.java | 2 +- .../pds/PDSExecutorConfigSupportTest.java | 140 +++++++++-- .../pds/PDSTemplateMetaDataServiceTest.java | 234 ++++++++++++++++++ ...evantScanTemplateDefinitionFilterTest.java | 96 +++++++ .../adapter/DefaultExecutorConfigSupport.java | 8 +- .../DefaultAdapterConfigurationStrategy.java | 3 +- .../domain/scan/ScanJobExecutionRunnable.java | 8 + .../domain/scan/ScanMessageHandler.java | 10 +- .../sechub/domain/scan/ScanService.java | 11 +- .../domain/scan/SecHubExecutionContext.java | 9 + .../scan/asset/AssetRestController.java | 3 + .../domain/scan/asset/AssetService.java | 116 ++++++--- .../ProductExecutorContextFactory.java | 4 +- .../scan/template/TemplateRestController.java | 3 + .../domain/scan/template/TemplateService.java | 31 ++- .../DefaultExecutorConfigSupportTest.java | 6 +- .../sechub/domain/scan/ScanServiceTest.java | 122 +++++---- .../domain/scan/asset/AssetServiceTest.java | 179 ++++++++++++++ .../product/ProductExecutorContextTest.java | 7 +- .../scan/template/TemplateServiceTest.java | 41 ++- .../server/SecHubServerPojoFactory.java | 6 + .../sechub/storage/core/Storage.java | 2 +- 63 files changed, 1823 insertions(+), 284 deletions(-) create mode 100644 sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/ConfigurationFailureException.java create mode 100644 sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolver.java create mode 100644 sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolverTest.java create mode 100644 sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaData.java create mode 100644 sechub-commons-pds/src/test/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaDataTest.java create mode 100644 sechub-integrationtest/src/test/resources/asset/scenario12/PDS_INTTEST_PRODUCT_WEBSCAN.zip create mode 100644 sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataService.java create mode 100644 sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilter.java create mode 100644 sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataServiceTest.java create mode 100644 sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilterTest.java diff --git a/sechub-adapter-pds/src/main/java/com/mercedesbenz/sechub/adapter/pds/PDSAdapterV1.java b/sechub-adapter-pds/src/main/java/com/mercedesbenz/sechub/adapter/pds/PDSAdapterV1.java index 1661e211ac..97d51ba16b 100644 --- a/sechub-adapter-pds/src/main/java/com/mercedesbenz/sechub/adapter/pds/PDSAdapterV1.java +++ b/sechub-adapter-pds/src/main/java/com/mercedesbenz/sechub/adapter/pds/PDSAdapterV1.java @@ -565,23 +565,28 @@ private String createJobDataJSON(PDSContext context) throws AdapterException { } private PDSJobData createJobData(PDSContext context) { - PDSAdapterConfig config = context.getConfig(); - PDSAdapterConfigData data = config.getPDSAdapterConfigData(); - assertConfigDataNotNull(data); - Map parameters = data.getJobParameters(); - + PDSAdapterConfig adapterConfig = context.getConfig(); + PDSAdapterConfigData adapterConfigData = adapterConfig.getPDSAdapterConfigData(); + assertConfigDataNotNull(adapterConfigData); + Map adapterConfigDataJobParameters = adapterConfigData.getJobParameters(); + + /* + * convert adapter configuration to PDS job data that shall be sent to PDS as + * key value parameters: + */ PDSJobData jobData = new PDSJobData(); - for (String key : parameters.keySet()) { + + for (String key : adapterConfigDataJobParameters.keySet()) { PDSJobParameterEntry parameter = new PDSJobParameterEntry(); parameter.key = key; - parameter.value = parameters.get(key); + parameter.value = adapterConfigDataJobParameters.get(key); jobData.parameters.add(parameter); } - UUID secHubJobUUID = data.getSecHubJobUUID(); + UUID secHubJobUUID = adapterConfigData.getSecHubJobUUID(); jobData.sechubJobUUID = secHubJobUUID.toString(); - jobData.productId = data.getPdsProductIdentifier(); + jobData.productId = adapterConfigData.getPdsProductIdentifier(); return jobData; } diff --git a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AbstractAdapterConfigBuilder.java b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AbstractAdapterConfigBuilder.java index 392669ca59..6a66e98300 100644 --- a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AbstractAdapterConfigBuilder.java +++ b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AbstractAdapterConfigBuilder.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import com.mercedesbenz.sechub.adapter.support.URIShrinkSupport; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; import com.mercedesbenz.sechub.commons.core.security.CryptoAccess; /** @@ -69,10 +70,11 @@ protected URIShrinkSupport createURIShrinkSupport() { * * @param strategy * @return builder (configured by strategy) + * @throws ConfigurationFailureException */ @Override @SuppressWarnings("unchecked") - public final B configure(AdapterConfigurationStrategy strategy) { + public final B configure(AdapterConfigurationStrategy strategy) throws ConfigurationFailureException { strategy.configure((B) this); return (B) this; } diff --git a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigBuilder.java b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigBuilder.java index 1d4ea473f9..fc450ce2dd 100644 --- a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigBuilder.java +++ b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigBuilder.java @@ -3,6 +3,8 @@ import static com.mercedesbenz.sechub.adapter.TimeConstants.*; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; + public interface AdapterConfigBuilder { public static final int DEFAULT_SCAN_RESULT_CHECK_IN_MILLISECONDS = TIME_1_MINUTE_IN_MILLISECONDS; @@ -30,7 +32,7 @@ public interface AdapterConfigBuilder { * @param strategy * @return builder (configured by strategy) */ - AdapterConfigBuilder configure(AdapterConfigurationStrategy strategy); + AdapterConfigBuilder configure(AdapterConfigurationStrategy strategy) throws ConfigurationFailureException; /** * Set result check interval in minutes. diff --git a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigurationStrategy.java b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigurationStrategy.java index b7976bcfae..8f30c4c0a7 100644 --- a/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigurationStrategy.java +++ b/sechub-adapter/src/main/java/com/mercedesbenz/sechub/adapter/AdapterConfigurationStrategy.java @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.adapter; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; + /** * A configuration strategy is used to configure a given config adapter builder * @@ -16,6 +18,6 @@ public interface AdapterConfigurationStrategy { * * @param configBuilder */ - void configure(B configBuilder); + void configure(B configBuilder) throws ConfigurationFailureException; } diff --git a/sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/ConfigurationFailureException.java b/sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/ConfigurationFailureException.java new file mode 100644 index 0000000000..1c1919643b --- /dev/null +++ b/sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/ConfigurationFailureException.java @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.commons.core; + +public class ConfigurationFailureException extends Exception { + + public ConfigurationFailureException(String message) { + super(message); + } + + public ConfigurationFailureException(String message, Throwable cause) { + super(message, cause); + } + + private static final long serialVersionUID = -384180667154600386L; + +} \ No newline at end of file diff --git a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/login/WebLoginConfiguration.java b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/login/WebLoginConfiguration.java index 3284dd9875..2809810f41 100644 --- a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/login/WebLoginConfiguration.java +++ b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/login/WebLoginConfiguration.java @@ -5,6 +5,7 @@ import java.util.Optional; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.mercedesbenz.sechub.commons.model.template.TemplateData; @JsonIgnoreProperties(ignoreUnknown = true) public class WebLoginConfiguration { @@ -19,6 +20,8 @@ public class WebLoginConfiguration { private WebLoginTOTPConfiguration totp; + private TemplateData templateData; + public URL getUrl() { return url; } @@ -43,4 +46,12 @@ public void setTotp(WebLoginTOTPConfiguration totp) { this.totp = totp; } + public TemplateData getTemplateData() { + return templateData; + } + + public void setTemplateData(TemplateData templateData) { + this.templateData = templateData; + } + } \ No newline at end of file diff --git a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateData.java b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateData.java index 5f8d34cc40..a0f2216ef4 100644 --- a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateData.java +++ b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateData.java @@ -1,12 +1,22 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.commons.model.template; +import java.util.LinkedHashMap; +import java.util.Map; + /** - * Template data for SecHub configuration model + * Template data for SecHub configuration model. Here users can define user + * specific template data - e.g. variables like "username", "password" * * @author Albert Tregnaghi * */ public class TemplateData { + private Map variables = new LinkedHashMap<>(); + + public Map getVariables() { + return variables; + } + } diff --git a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolver.java b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolver.java new file mode 100644 index 0000000000..7da6386f33 --- /dev/null +++ b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolver.java @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.commons.model.template; + +import java.util.Optional; + +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; +import com.mercedesbenz.sechub.commons.model.login.WebLoginConfiguration; + +public class TemplateDataResolver { + + public TemplateData resolveTemplateData(TemplateType type, SecHubConfigurationModel configuration) { + if (type == null) { + return null; + } + if (configuration == null) { + return null; + } + switch (type) { + case WEBSCAN_LOGIN: + return resolveWebScanLoginTemplateData(configuration); + default: + break; + } + return null; + } + + private TemplateData resolveWebScanLoginTemplateData(SecHubConfigurationModel configuration) { + Optional webScanOpt = configuration.getWebScan(); + if (webScanOpt.isEmpty()) { + return null; + } + SecHubWebScanConfiguration webScan = webScanOpt.get(); + Optional loginOpt = webScan.getLogin(); + if (loginOpt.isEmpty()) { + return null; + } + WebLoginConfiguration login = loginOpt.get(); + return login.getTemplateData(); + + } +} diff --git a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinition.java b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinition.java index ee7e2ae6fe..b8296dbb29 100644 --- a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinition.java +++ b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinition.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.mercedesbenz.sechub.commons.model.JSONable; @@ -14,16 +15,23 @@ public class TemplateDefinition implements JSONable { public static final String PROPERTY_TYPE = "type"; public static final String PROPERTY_ID = "id"; - public static final String PROPERTY_ASSETS = "assets"; + public static final String PROPERTY_ASSET_ID = "assetId"; public static final String PROPERTY_VARIABLES = "variables"; private TemplateType type; - private List assets = new ArrayList<>(); + private String assetId; private List variables = new ArrayList<>(); private String id; + public TemplateDefinition() { + } + + public static TemplateDefinitionBuilder builder() { + return new TemplateDefinitionBuilder(); + } + public static TemplateDefinition from(String json) { return IMPORTER.fromJSON(json); } @@ -36,8 +44,12 @@ public String getId() { return id; } - public List getAssets() { - return assets; + public void setAssetId(String assetId) { + this.assetId = assetId; + } + + public String getAssetId() { + return assetId; } public List getVariables() { @@ -52,6 +64,73 @@ public TemplateType getType() { return type; } + @Override + public Class getJSONTargetClass() { + return TemplateDefinition.class; + } + + @Override + public int hashCode() { + return Objects.hash(assetId, id, type, variables); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TemplateDefinition other = (TemplateDefinition) obj; + return Objects.equals(assetId, other.assetId) && Objects.equals(id, other.id) && type == other.type && Objects.equals(variables, other.variables); + } + + public static class TemplateDefinitionBuilder { + + private String assetId; + private String templateId; + private TemplateType templateType; + + private TemplateDefinitionBuilder() { + + } + + public TemplateDefinitionBuilder assetId(String assetId) { + this.assetId = assetId; + return this; + } + + public TemplateDefinitionBuilder templateId(String templateId) { + this.templateId = templateId; + return this; + } + + public TemplateDefinitionBuilder templateType(TemplateType templateType) { + this.templateType = templateType; + return this; + } + + public TemplateDefinition build() { + if (assetId == null) { + throw new IllegalStateException("assetId not defined"); + } + if (templateId == null) { + throw new IllegalStateException("templateId not defined"); + } + if (templateType == null) { + throw new IllegalStateException("templateType not defined"); + } + TemplateDefinition def = new TemplateDefinition(); + def.id = templateId; + def.type = templateType; + def.assetId = assetId; + + return def; + } + + } + public static class TemplateVariable { public static final String PROPERTY_NAME = "name"; public static final String PROPERTY_OPTIONAL = "optional"; @@ -85,6 +164,23 @@ public void setValidation(TemplateVariableValidation validation) { this.validation = validation; } + @Override + public int hashCode() { + return Objects.hash(name, optional, validation); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TemplateVariable other = (TemplateVariable) obj; + return Objects.equals(name, other.name) && optional == other.optional && Objects.equals(validation, other.validation); + } + } public static class TemplateVariableValidation { @@ -120,11 +216,24 @@ public String getRegularExpression() { public void setRegularExpression(String regularExpression) { this.regularExpression = regularExpression; } - } - @Override - public Class getJSONTargetClass() { - return TemplateDefinition.class; + @Override + public int hashCode() { + return Objects.hash(maxLength, minLength, regularExpression); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TemplateVariableValidation other = (TemplateVariableValidation) obj; + return Objects.equals(maxLength, other.maxLength) && Objects.equals(minLength, other.minLength) + && Objects.equals(regularExpression, other.regularExpression); + } } } diff --git a/sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolverTest.java b/sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolverTest.java new file mode 100644 index 0000000000..cbf6cf798d --- /dev/null +++ b/sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDataResolverTest.java @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.commons.model.template; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.NullSource; + +import com.mercedesbenz.sechub.commons.model.JSONConverter; +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; + +class TemplateDataResolverTest { + + TemplateDataResolver resolverToTest; + + @BeforeEach + void beforeEach() { + resolverToTest = new TemplateDataResolver(); + } + + @Test + void webscan_login_template_data_can_be_resolved_when_defined_in_model() { + + /* prepare */ + String json = """ + { + "webScan" : { + "login" : { + + "templateData" : { + "variables" : { + "username" : "the-user", + "password" : "the-password" + } + } + } + } + } + """; + SecHubConfigurationModel model = JSONConverter.get().fromJSON(SecHubConfigurationModel.class, json); + + /* execute */ + TemplateData result = resolverToTest.resolveTemplateData(TemplateType.WEBSCAN_LOGIN, model); + + /* test */ + assertThat(result).isNotNull(); + assertThat(result.getVariables()).containsEntry("username", "the-user").containsEntry("password", "the-password"); + } + + @Test + void webscan_login_template_data_cannot_be_resolved_when_not_defined_in_model() { + + /* prepare */ + String json = """ + { + "webScan" : { + + } + } + """; + SecHubConfigurationModel model = JSONConverter.get().fromJSON(SecHubConfigurationModel.class, json); + + /* execute */ + TemplateData result = resolverToTest.resolveTemplateData(TemplateType.WEBSCAN_LOGIN, model); + + /* test */ + assertThat(result).isNull(); + } + + @ParameterizedTest + @NullSource + @EnumSource(TemplateType.class) + void template_data_is_always_null_when_model_is_empty(TemplateType templateType) { + + /* prepare */ + String json = """ + { + } + """; + SecHubConfigurationModel model = JSONConverter.get().fromJSON(SecHubConfigurationModel.class, json); + + /* execute */ + TemplateData result = resolverToTest.resolveTemplateData(templateType, model); + + /* test */ + assertThat(result).isNull(); + } + + @ParameterizedTest + @NullSource + @EnumSource(TemplateType.class) + void template_data_is_always_null_when_model_is_null(TemplateType templateType) { + + /* prepare */ + SecHubConfigurationModel model = null; + + /* execute */ + TemplateData result = resolverToTest.resolveTemplateData(templateType, model); + + /* test */ + assertThat(result).isNull(); + } + +} diff --git a/sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinitionTest.java b/sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinitionTest.java index 6bd36850b2..073460e9e4 100644 --- a/sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinitionTest.java +++ b/sechub-commons-model/src/test/java/com/mercedesbenz/sechub/commons/model/template/TemplateDefinitionTest.java @@ -15,12 +15,9 @@ class TemplateDefinitionTest { public void json_to_from_works() throws Exception { /* prepare */ - TemplateDefinition definition = new TemplateDefinition(); - definition.setId("identifier"); - definition.getAssets().add("asset1"); - definition.getAssets().add("asset2"); - definition.setType(TemplateType.WEBSCAN_LOGIN); + TemplateDefinition definition = TemplateDefinition.builder().templateId("identifier").templateType(TemplateType.WEBSCAN_LOGIN).assetId("asset1") + .build(); TemplateVariable variable1 = new TemplateVariable(); variable1.setName("variable1"); @@ -40,7 +37,7 @@ public void json_to_from_works() throws Exception { TemplateDefinition deserialized = TemplateDefinition.from(json); assertThat(deserialized.getId()).isEqualTo("identifier"); assertThat(deserialized.getType()).isEqualTo(TemplateType.WEBSCAN_LOGIN); - assertThatList(deserialized.getAssets()).contains("asset1", "asset2"); + assertThat(deserialized.getAssetId()).isEqualTo("asset1"); assertThatList(deserialized.getVariables()).hasSize(1); TemplateVariable var1 = deserialized.getVariables().iterator().next(); @@ -67,7 +64,7 @@ public void example1_with_type_defined_by_id_and_not_enum_name_can_be_loaded() t /* test */ assertThat(deserialized.getId()).isEqualTo("identifier"); assertThat(deserialized.getType()).isEqualTo(TemplateType.WEBSCAN_LOGIN); - assertThatList(deserialized.getAssets()).contains("asset1", "asset2"); + assertThat(deserialized.getAssetId()).isEqualTo("asset0815"); assertThatList(deserialized.getVariables()).hasSize(1); TemplateVariable var1 = deserialized.getVariables().iterator().next(); diff --git a/sechub-commons-model/src/test/resources/template/template-definition-example1.json b/sechub-commons-model/src/test/resources/template/template-definition-example1.json index 22c7ef12a6..d07f391a88 100644 --- a/sechub-commons-model/src/test/resources/template/template-definition-example1.json +++ b/sechub-commons-model/src/test/resources/template/template-definition-example1.json @@ -1,6 +1,6 @@ { "type" : "webscan-login", - "assets" : [ "asset1", "asset2" ], + "assetId" : "asset0815", "variables" : [ { "name" : "variable1", "optional" : true, diff --git a/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/AbstractPDSKey.java b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/AbstractPDSKey.java index 8fbaa33bd7..417e1735a8 100644 --- a/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/AbstractPDSKey.java +++ b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/AbstractPDSKey.java @@ -61,7 +61,7 @@ public T markMandatory() { return (T) this; } - /* + /** * Mark this key as generated, means it will be automatically created and sent * on PDS calls */ diff --git a/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSConfigDataKeyProvider.java b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSConfigDataKeyProvider.java index acfbc84ac7..77d7e9fc3d 100644 --- a/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSConfigDataKeyProvider.java +++ b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSConfigDataKeyProvider.java @@ -188,7 +188,13 @@ public enum PDSConfigDataKeyProvider implements PDSKeyProvider */ PDS_MOCKING_DISABLED(new ExecutionPDSKey(PDSDefaultParameterKeyConstants.PARAM_KEY_PDS_MOCKING_DISABLED, "When 'true' any PDS adapter call will use real PDS adapter and not a mocked variant.").markForTestingOnly().markSendToPDS() - .markDefaultRecommended().withDefault(true)); + .markDefaultRecommended().withDefault(true)), + + PDS_CONFIG_TEMPLATE_META_DATA_LIST(new ExecutionPDSKey(PDSDefaultParameterKeyConstants.PARAM_KEY_PDS_CONFIG_TEMPLATE_META_DATA_LIST, """ + Contains a list of template meta data entries (json). + """).markGenerated()), + + ; private ExecutionPDSKey key; diff --git a/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSDefaultParameterKeyConstants.java b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSDefaultParameterKeyConstants.java index 310c9382d6..62981afb4e 100644 --- a/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSDefaultParameterKeyConstants.java +++ b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/PDSDefaultParameterKeyConstants.java @@ -6,7 +6,7 @@ /** * All default parameter keys supported by PDS. A PDS can support optional * parameters (via its configuration) but these ones are always supported and be - * available at runtime inside PDS scripts.
+ * available at runtime inside PDS.
*
* * Wrappers can use these constants as spring boot values. @@ -78,6 +78,8 @@ public class PDSDefaultParameterKeyConstants { public static final String PARAM_KEY_PDS_CONFIG_JOBSTORAGE_READ_RESILIENCE_RETRY_WAIT_SECONDS = "pds.config.jobstorage.read.resilience.retry.wait.seconds"; + public static final String PARAM_KEY_PDS_CONFIG_TEMPLATE_META_DATA_LIST = "pds.config.template.metadata.list"; + /* ---------------------- */ /* Integration tests only */ /* ---------------------- */ diff --git a/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaData.java b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaData.java new file mode 100644 index 0000000000..78acd6b804 --- /dev/null +++ b/sechub-commons-pds/src/main/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaData.java @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.commons.pds.data; + +import java.util.Objects; + +import com.mercedesbenz.sechub.commons.model.template.TemplateType; + +public class PDSTemplateMetaData { + + private String template; + private TemplateType type; + private PDSAssetData assetData; + + public PDSAssetData getAssetData() { + return assetData; + } + + public String getTemplate() { + return template; + } + + public TemplateType getType() { + return type; + } + + public void setType(TemplateType type) { + this.type = type; + } + + public void setTemplate(String templateId) { + this.template = templateId; + } + + public void setAssetData(PDSAssetData assetData) { + this.assetData = assetData; + } + + @Override + public int hashCode() { + return Objects.hash(assetData, template, type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PDSTemplateMetaData other = (PDSTemplateMetaData) obj; + return Objects.equals(assetData, other.assetData) && Objects.equals(template, other.template) && type == other.type; + } + + @Override + public String toString() { + return "PDSTemplateMetaData [" + (template != null ? "template=" + template + ", " : "") + (type != null ? "type=" + type + ", " : "") + + (assetData != null ? "assetData=" + assetData : "") + "]"; + } + + public static class PDSAssetData { + private String asset; + private String file; + private String checksum; + + public String getAsset() { + return asset; + } + + public void setAsset(String asset) { + this.asset = asset; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } + + @Override + public int hashCode() { + return Objects.hash(asset, checksum, file); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PDSAssetData other = (PDSAssetData) obj; + return Objects.equals(asset, other.asset) && Objects.equals(checksum, other.checksum) && Objects.equals(file, other.file); + } + + @Override + public String toString() { + return "PDSAssetData [" + (asset != null ? "asset=" + asset + ", " : "") + (file != null ? "file=" + file + ", " : "") + + (checksum != null ? "checksum=" + checksum : "") + "]"; + } + + } +} diff --git a/sechub-commons-pds/src/test/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaDataTest.java b/sechub-commons-pds/src/test/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaDataTest.java new file mode 100644 index 0000000000..ddf3aeae8a --- /dev/null +++ b/sechub-commons-pds/src/test/java/com/mercedesbenz/sechub/commons/pds/data/PDSTemplateMetaDataTest.java @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.commons.pds.data; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import com.mercedesbenz.sechub.commons.model.JSONConverter; +import com.mercedesbenz.sechub.test.TestFileReader; + +class PDSTemplateMetaDataTest { + + @ParameterizedTest + @ValueSource(strings = { "pds-param-template-metadata-example1.json", "pds-param-template-metadata-syntax.json" }) + void examples_in_doc_are_valid(String fileName) { + /* prepare */ + String json = TestFileReader.readTextFromFile("./../sechub-doc/src/docs/asciidoc/documents/shared/snippet/" + fileName); + + /* execute */ + JSONConverter.get().fromJSONtoListOf(PDSTemplateMetaData.class, json); + + } + +} diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/CreateOrUpdateTemplateAction.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/CreateOrUpdateTemplateAction.java index acd995e26b..3aa8002b15 100644 --- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/CreateOrUpdateTemplateAction.java +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/CreateOrUpdateTemplateAction.java @@ -38,11 +38,7 @@ public void execute(ActionEvent e) { if (!templateTypeOpt.isPresent()) { return; } - templateDefinition = new TemplateDefinition(); - templateDefinition.setId(templateId); - templateDefinition.setType(templateTypeOpt.get()); - - templateDefinition.getAssets().add("example-asset-id"); + templateDefinition = TemplateDefinition.builder().templateId(templateId).templateType(templateTypeOpt.get()).assetId("example-asset-id").build(); TemplateVariable exampleVariable = new TemplateVariable(); exampleVariable.setName("example-variable"); exampleVariable.setOptional(true); diff --git a/sechub-doc/src/docs/asciidoc/documents/shared/concepts/concept_templates_and_assets.adoc b/sechub-doc/src/docs/asciidoc/documents/shared/concepts/concept_templates_and_assets.adoc index 1585bcf19c..6251eb003c 100644 --- a/sechub-doc/src/docs/asciidoc/documents/shared/concepts/concept_templates_and_assets.adoc +++ b/sechub-doc/src/docs/asciidoc/documents/shared/concepts/concept_templates_and_assets.adoc @@ -55,20 +55,21 @@ A template is defined by following json syntax: ---- include::../snippet/template-definition-syntax.json[] ---- -<1> The type of the template. Must be set when a template is created. Will +<1> The template identifier +<2> The type of the template. Must be set when a template is created. Will be ignored on updates. Possible values are: `webscan-login` -<2> Array with asset identifiers assigned to the template -<3> Variable definitions as list of key and value pairs which can be mandatory or optional. +<3> Asset identifier for the template +<4> Variable definitions as list of key and value pairs which can be mandatory or optional. Via the type {sechub} server is able to check if the configuration is valid and give response to users when job starts. -<4> Name of the variable -<5> Describes if the variable is optional. + +<5> Name of the variable +<6> Describes if the variable is optional. + When `false` configuration must contain the variable inside template data. When `true` the configuration is valid without the variable. The default is `false`. -<6> Variable content validation definition ((optional) -<7> Minimum length (optional) -<8> Maximum length (optional) -<9> Regular expression (optional). If defined, the content must match the given regular expression +<7> Variable content validation definition ((optional) +<8> Minimum length (optional) +<9> Maximum length (optional) +<10> Regular expression (optional). If defined, the content must match the given regular expression to be valid. [CAUTION] @@ -180,16 +181,11 @@ structure looks like! Over REST API Administrators will be able to -- upload asset ZIP files by REST API and create checksum file + - `PUT /api/administration/asset/$assetId/file/$filename` -- download asset files by REST API + - `GET /api/administration/asset/$assetId/file/$filename` -- list (ZIP) file names + - `GET /api/administration/asset/$assetId/list` -- delete single asset file by REST API + - `DELETE /api/administration/asset/$assetId/file/$filename` -- delete all asset data by REST API + - `DELETE /api/administration/asset/$assetId` +- upload asset ZIP files by REST API and create checksum file +- download asset files by REST API +- list asset details (filenames and checksums) +- delete single asset file by REST API +- delete all asset data by REST API The REST API will always create an audit log entry @@ -242,7 +238,7 @@ further processed. ====== Template PDS parameter calculation If the job configuration has valid template data and the template is available in storage, {sechub} will calculate the -{pds} parameter : `pds.template.metadata` with JSON: +{pds} parameter : `pds.config.template.metadata.list` with JSON: [[sechub-concept-template-metadata-example]] .PDS parameter syntax for template meta data diff --git a/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-example1.json b/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-example1.json index 644ded1afa..28d91edf51 100644 --- a/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-example1.json +++ b/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-example1.json @@ -1,11 +1,9 @@ -{ - "templateMetaData" : [ { - "template" : "single-singon", - "type" : "webscan-login", - "assetData" : [ { - "asset" : "custom-webscan-setup", - "file" : "WEBSCAN_PRODUCT_ID.zip", - "checksum" : "434c6c6ec1b0ed9844149069d7d45ac18e72505b" - } ] - } ] -} \ No newline at end of file +[ { + "template" : "single-singon", + "type" : "webscan-login", + "assetData" : { + "asset" : "custom-webscan-setup", + "file" : "WEBSCAN_PRODUCT_ID.zip", + "checksum" : "434c6c6ec1b0ed9844149069d7d45ac18e72505b" + } +} ] \ No newline at end of file diff --git a/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-syntax.json b/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-syntax.json index 285fcffa03..b45a65ff72 100644 --- a/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-syntax.json +++ b/sechub-doc/src/docs/asciidoc/documents/shared/snippet/pds-param-template-metadata-syntax.json @@ -1,16 +1,13 @@ -{ - "templateMetaData" : [ //<1> - { - "template" : "$templateId", //<2> - "type": "$templateType", //<3> - - "assetData" : [ //<4> - { - "asset" : "$assetId", //<5> - "file" : "$fileName", //<6> - "checksum" : "$fileChecksum" //<7> - } - ] - }] - } -} \ No newline at end of file + [ //<1> + { + "template" : "templateId", //<2> + "type": "WEBSCAN_LOGIN", //<3> + + "assetData" : { //<4> + "asset" : "assetId", //<5> + "file" : "fileName", //<6> + "checksum" : "fileChecksum" //<7> + } + + } + ] diff --git a/sechub-doc/src/docs/asciidoc/documents/shared/snippet/template-definition-syntax.json b/sechub-doc/src/docs/asciidoc/documents/shared/snippet/template-definition-syntax.json index 5a3cc0f46b..b15de0e9fa 100644 --- a/sechub-doc/src/docs/asciidoc/documents/shared/snippet/template-definition-syntax.json +++ b/sechub-doc/src/docs/asciidoc/documents/shared/snippet/template-definition-syntax.json @@ -1,23 +1,23 @@ { "templateDefinition" : { - "id" : "$templateId", + "id" : "$templateId", //<1> - "type" : "$templateType", //<1> + "type" : "$templateType", //<2> - "assets" : ["$assetId1" , "$assetId2", /* .. ,*/ "$assetIdn"], //<2> + "assetId" : "$assetId", //<3> - "variables" : [ //<3> + "variables" : [ //<4> { - "name" : "$variableName", // <4> - "optional": false, // <5> + "name" : "$variableName", // <5> + "optional": false, // <6> - "validation" : { // <6> + "validation" : { // <7> - "minLength" : 1, // <7> - "maxLength" : 100, // <8> + "minLength" : 1, // <8> + "maxLength" : 100, // <9> - "regularExpression" : "$regularExpression" // <9> + "regularExpression" : "$regularExpression" // <10> } } ] diff --git a/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/TemplateRestControllerRestDocTest.java b/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/TemplateRestControllerRestDocTest.java index 94384c2aca..5750e8fe5f 100644 --- a/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/TemplateRestControllerRestDocTest.java +++ b/sechub-doc/src/test/java/com/mercedesbenz/sechub/restdoc/TemplateRestControllerRestDocTest.java @@ -90,7 +90,7 @@ public class TemplateRestControllerRestDocTest implements TestIsNecessaryForDocu public void before() { definition = new TemplateDefinition(); definition.setType(TemplateType.WEBSCAN_LOGIN); - definition.getAssets().add("asset-id1"); + definition.setAssetId("asset-id1"); usernameVariable = new TemplateVariable(); usernameVariable.setName("username"); @@ -138,7 +138,7 @@ public void restdoc_admin_creates_or_updates_template() throws Exception { requestFields( fieldWithPath(PROPERTY_TYPE).description("The template type. Must be be defined when a new template is created. An update will ignore changes of this property because the type is immutable! Currently supported types are: "+ TemplateType.values()), - fieldWithPath(PROPERTY_ASSETS).description("An array list containing ids of referenced assets"), + fieldWithPath(PROPERTY_ASSET_ID).description("The asset id used by the template"), fieldWithPath(PROPERTY_VARIABLES+"[]."+ TemplateVariable.PROPERTY_NAME).description("The variable name"), fieldWithPath(PROPERTY_VARIABLES+"[]."+ TemplateVariable.PROPERTY_OPTIONAL).optional().description("Defines if the variable is optional. The default is false"), fieldWithPath(PROPERTY_VARIABLES+"[]."+ TemplateVariable.PROPERTY_VALIDATION).optional().description("Defines a simple validation segment."), @@ -212,7 +212,7 @@ public void restdoc_admin_fetches_template() throws Exception { fieldWithPath(PROPERTY_TYPE).description("The template type. Currently supported types are: "+ TemplateType.values()), fieldWithPath(PROPERTY_ID).description("The (unique) template id"), - fieldWithPath(PROPERTY_ASSETS).description("An array list containing ids of referenced assets"), + fieldWithPath(PROPERTY_ASSET_ID).description("The asset id used by the template"), fieldWithPath(PROPERTY_VARIABLES+"[]."+ TemplateVariable.PROPERTY_NAME).description("The variable name"), fieldWithPath(PROPERTY_VARIABLES+"[]."+ TemplateVariable.PROPERTY_OPTIONAL).optional().description("Defines if the variable is optional. The default is false"), fieldWithPath(PROPERTY_VARIABLES+"[]."+ TemplateVariable.PROPERTY_VALIDATION).optional().description("Defines a simple validation segment."), diff --git a/sechub-integrationtest/pds/product-scripts/integrationtest-webscan.sh b/sechub-integrationtest/pds/product-scripts/integrationtest-webscan.sh index e049d6a539..7fd103086f 100755 --- a/sechub-integrationtest/pds/product-scripts/integrationtest-webscan.sh +++ b/sechub-integrationtest/pds/product-scripts/integrationtest-webscan.sh @@ -16,6 +16,10 @@ info:PDS_SCAN_CONFIGURATION=$PDS_SCAN_CONFIGURATION dumpPDSVariables + +# We added pds.config.templates.metadata.list as optional parameter here for testing +# So we can dump the variable here - used in scenario12 integration test +dumpVariable "PDS_CONFIG_TEMPLATE_METADATA_LIST" if [[ "$PDS_TEST_KEY_VARIANTNAME" = "a" ]]; then diff --git a/sechub-integrationtest/src/main/java/com/mercedesbenz/sechub/integrationtest/api/AsUser.java b/sechub-integrationtest/src/main/java/com/mercedesbenz/sechub/integrationtest/api/AsUser.java index e735bd4346..27e75b2338 100644 --- a/sechub-integrationtest/src/main/java/com/mercedesbenz/sechub/integrationtest/api/AsUser.java +++ b/sechub-integrationtest/src/main/java/com/mercedesbenz/sechub/integrationtest/api/AsUser.java @@ -1431,9 +1431,10 @@ public SecHubEncryptionStatus fetchEncryptionStatus() { return SecHubEncryptionStatus.fromString(json); } - public void createOrUpdateTemplate(String templateid, TemplateDefinition definition) { - String url = getUrlBuilder().buildAdminCreatesOrUpdatesTemplate(templateid); + public AsUser createOrUpdateTemplate(String templateId, TemplateDefinition definition) { + String url = getUrlBuilder().buildAdminCreatesOrUpdatesTemplate(templateId); getRestHelper().postJson(url, definition.toFormattedJSON()); + return this; } public TemplateDefinition fetchTemplateDefinitionOrNull(String templateId) { diff --git a/sechub-integrationtest/src/main/resources/pds-config-integrationtest.json b/sechub-integrationtest/src/main/resources/pds-config-integrationtest.json index 9b4651eaf0..79b6966008 100644 --- a/sechub-integrationtest/src/main/resources/pds-config-integrationtest.json +++ b/sechub-integrationtest/src/main/resources/pds-config-integrationtest.json @@ -5,7 +5,7 @@ "id" : "PDS_INTTEST_PRODUCT_CODESCAN", "path" : "./../sechub-integrationtest/pds/product-scripts/integrationtest-codescan.sh", "scanType" : "codeScan", - "envWhitelist" : [ "INTEGRATIONTEST_SCRIPT_ENV_ACCEPTED"], + "envWhitelist" : [ "INTEGRATIONTEST_SCRIPT_ENV_ACCEPTED" ], "description" : "This is only a fake code scan - used by integration tests. The code scan will just return data from uploaded zip file", "parameters" : { "mandatory" : [ { @@ -71,6 +71,9 @@ "optional" : [ { "key" : "pds.test.key.variantname", "description" : "a parameter from configuration - will be different in each integration test config from sechub integration test server" + }, { + "key" : "pds.config.template.metadata.list", + "description" : "normally this parameter is NOT sent to script, but for testing we add this parameter, so we can check by TestAPI..." } ] } }, { @@ -209,7 +212,7 @@ "path" : "./../sechub-integrationtest/pds/product-scripts/integrationtest-prepare.sh", "scanType" : "prepare", "description" : "This is a fake prepare scan - used by integration tests.", - "envWhitelist" : [ "PDS_STORAGE_*"], + "envWhitelist" : [ "PDS_STORAGE_*" ], "parameters" : { "optional" : [ { "key" : "pds.test.key.variantname", diff --git a/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/TemplateScenario1IntTest.java b/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/TemplateScenario1IntTest.java index c1b1c39fd8..5b50dbe352 100644 --- a/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/TemplateScenario1IntTest.java +++ b/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/TemplateScenario1IntTest.java @@ -44,10 +44,10 @@ public void before() { templateId = "template-1_" + System.nanoTime(); - createDefinition = new TemplateDefinition(); - createDefinition.setId(null); // the creation does not need an id. To test this we explicit set to null... - createDefinition.setType(TemplateType.WEBSCAN_LOGIN); - createDefinition.getAssets().add("asset1"); + String templateJson = TemplateDefinition.builder().templateId(templateId).templateType(TemplateType.WEBSCAN_LOGIN).assetId("asset1").build() + .toFormattedJSON(); + + createDefinition = TemplateDefinition.from(templateJson.replace(templateId, "does-not-matter-will-be-overriden")); usernameVariable = new TemplateVariable(); usernameVariable.setName("username"); @@ -58,11 +58,9 @@ public void before() { createDefinition.getVariables().add(usernameVariable); createDefinition.getVariables().add(passwordVariable); - definitionWithId = TemplateDefinition.from(createDefinition.toJSON()); - definitionWithId.setId(templateId); + definitionWithId = TemplateDefinition.from(templateJson); - updateDefinition = TemplateDefinition.from(createDefinition.toJSON()); - updateDefinition.setType(null); // the update does not need a type. To test this we explicit set to null.. + updateDefinition = TemplateDefinition.from(templateJson.replace(templateJson, "will-not-be-changed-by-update")); } @Test @@ -179,14 +177,14 @@ private void assertTemplateCanBeAssignedToProject() { private void assertTemplateCanBeUpdated() { /* prepare 2 - update */ - updateDefinition.getAssets().add("asset2"); + updateDefinition.setAssetId("asset2"); /* execute 2 - update */ as(SUPER_ADMIN).createOrUpdateTemplate(templateId, updateDefinition); /* test 2 - update works */ TemplateDefinition loadedTemplate = as(SUPER_ADMIN).fetchTemplateDefinitionOrNull(templateId); - assertThat(loadedTemplate.getAssets()).contains("asset1", "asset2"); + assertThat(loadedTemplate.getAssetId()).isEqualTo("asset2"); assertThat(loadedTemplate.getType()).isEqualTo(TemplateType.WEBSCAN_LOGIN); assertThat(loadedTemplate.getId()).isEqualTo(templateId); } diff --git a/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario12/PDSWebScanJobScenario12IntTest.java b/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario12/PDSWebScanJobScenario12IntTest.java index 67a8317c98..3a3504587b 100644 --- a/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario12/PDSWebScanJobScenario12IntTest.java +++ b/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario12/PDSWebScanJobScenario12IntTest.java @@ -2,12 +2,16 @@ package com.mercedesbenz.sechub.integrationtest.scenario12; import static com.mercedesbenz.sechub.integrationtest.api.TestAPI.*; +import static com.mercedesbenz.sechub.integrationtest.api.TestAPI.as; import static com.mercedesbenz.sechub.integrationtest.scenario12.Scenario12.*; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.*; +import java.io.File; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; @@ -15,7 +19,18 @@ import org.junit.Test; import org.junit.rules.Timeout; -import com.mercedesbenz.sechub.commons.model.*; +import com.mercedesbenz.sechub.commons.model.ClientCertificateConfiguration; +import com.mercedesbenz.sechub.commons.model.HTTPHeaderConfiguration; +import com.mercedesbenz.sechub.commons.model.JSONConverter; +import com.mercedesbenz.sechub.commons.model.SecHubMessageType; +import com.mercedesbenz.sechub.commons.model.SecHubScanConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanApiConfiguration; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanApiType; +import com.mercedesbenz.sechub.commons.model.SecHubWebScanConfiguration; +import com.mercedesbenz.sechub.commons.model.Severity; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition.TemplateVariable; +import com.mercedesbenz.sechub.commons.model.template.TemplateType; import com.mercedesbenz.sechub.integrationtest.api.IntegrationTestSetup; import com.mercedesbenz.sechub.integrationtest.api.TestProject; import com.mercedesbenz.sechub.integrationtest.internal.IntegrationTestFileSupport; @@ -35,18 +50,65 @@ public class PDSWebScanJobScenario12IntTest { @Rule public Timeout timeOut = Timeout.seconds(600); + /* @formatter:off + * + * This is test is a web scan integration test which + * tests multiple features. + * + * The test prepares + * - web scan in general with dedicated setup + * - uses a SecHub configuration with template data inside + * - creates an asset, creates a template which uses the asset, assigns template + * + * The tests checks following: + * + * - pds_web_scan_has_expected_info_finding_with_given_target_url_and_product2_level_information_and_sechub_web_config_parts + * - pds web scan has expected info finding, with + * - given target url + * - product level information + * - sechub web configuration parts + * + * - PDS parameter for template meta data configuration is correct and transmitted to PDS + * The parameter "pds.config.template.metadata.list" is normally not available inside + * the scripts, but for testing we added the parameter inside server configuration so it + * will be added to script level and can be checked by TestAPI + * + * @formatter:on + */ @Test - public void pds_web_scan_has_expected_info_finding_with_given_target_url_and_product2_level_information_and_sechub_web_config_parts() { + public void pds_web_scan_can_be_executed_and_works() throws Exception { /* @formatter:off */ /* prepare */ + String assetId="asset-s12-pds-inttest-webscan"; + File productZipFile = IntegrationTestFileSupport.getTestfileSupport().createFileFromResourcePath("/asset/scenario12/PDS_INTTEST_PRODUCT_WEBSCAN.zip"); + String configurationAsJson = IntegrationTestFileSupport.getTestfileSupport().loadTestFile("sechub-integrationtest-webscanconfig-all-options.json"); SecHubScanConfiguration configuration = SecHubScanConfiguration.createFromJSON(configurationAsJson); configuration.setProjectId("myTestProject"); TestProject project = PROJECT_1; String targetURL = configuration.getWebScan().get().getUrl().toString(); - as(SUPER_ADMIN).updateWhiteListForProject(project, Arrays.asList(targetURL)); + + TemplateVariable userNameVariable = new TemplateVariable(); + userNameVariable.setName("username"); + + TemplateVariable passwordVariable = new TemplateVariable(); + passwordVariable.setName("password"); + + TemplateDefinition templateDefinition = new TemplateDefinition(); + templateDefinition.setAssetId(assetId); + templateDefinition.setType(TemplateType.WEBSCAN_LOGIN); + templateDefinition.getVariables().add(userNameVariable); + templateDefinition.getVariables().add(passwordVariable); + + String templateId = "template-scenario12-1"; + as(SUPER_ADMIN). + updateWhiteListForProject(project, Arrays.asList(targetURL)). + uploadAssetFile(assetId, productZipFile). + createOrUpdateTemplate(templateId, templateDefinition). + assignTemplateToProject(templateId, project) + ; /* execute */ UUID jobUUID = as(USER_1).withSecHubClient().startAsynchronScanFor(project, configuration).getJobUUID(); @@ -119,6 +181,13 @@ public void pds_web_scan_has_expected_info_finding_with_given_target_url_and_pro hasMessage(SecHubMessageType.ERROR,"error from webscan by PDS for sechub job uuid: "+jobUUID). hasMessage(SecHubMessageType.INFO, "another-token.txtbearer-token.txtcertificate.p12openapi.json"); + UUID pdsJobUUID = waitForFirstPDSJobOfSecHubJobAndReturnPDSJobUUID(jobUUID); + Map variables = fetchPDSVariableTestOutputMap(pdsJobUUID); + + String expectedMetaDataListJson = """ + [{"template":"template-scenario12-1","type":"WEBSCAN_LOGIN","assetData":{"asset":"asset-s12-pds-inttest-webscan","file":"PDS_INTTEST_PRODUCT_WEBSCAN.zip","checksum":"ff06430bfc2d8c698ab8effa41b914525b8cca1c1eecefa76d248b25cc598fba"}}] + """.trim(); + assertThat(variables.get("PDS_CONFIG_TEMPLATE_METADATA_LIST")).isEqualTo(expectedMetaDataListJson); /* @formatter:on */ } diff --git a/sechub-integrationtest/src/test/resources/asset/scenario12/PDS_INTTEST_PRODUCT_WEBSCAN.zip b/sechub-integrationtest/src/test/resources/asset/scenario12/PDS_INTTEST_PRODUCT_WEBSCAN.zip new file mode 100644 index 0000000000000000000000000000000000000000..1c1ce661bfd44dd5645ed7c05d3810e8dc713dfb GIT binary patch literal 214 zcmWIWW@h1HW&nczw7kgA%j{FkfNT)v1>%y_;*zw?oK!=-l8TZ{g~VJ1B@`hgg|z%4 zh2rGYyu_l+d_yCJ%)FA+^rFO)%=|nBkji4N0B=SnduCi#r~oYi0fmMwjUXDubS?%3 kkQf6ag9HP^" ], - "excludes": [ "/public/media", "/contact.html", "/static", "<*>/admin/<*>" ], + "includes" : [ "/portal/admin", "/abc.html", "/hidden", "/customer/<*>" ], + "excludes" : [ "/public/media", "/contact.html", "/static", "<*>/admin/<*>" ], "maxScanDuration" : { "duration" : 35, "unit" : "minutes" @@ -39,7 +39,7 @@ "password" : "secret-password", "use" : [ "client-cert-api-file-reference" ] }, - "headers" : [{ + "headers" : [ { "name" : "Authorization", "use" : [ "header-file-ref-for-big-token" ] }, { @@ -50,9 +50,13 @@ }, { "name" : "Key", "use" : [ "another-header-file-ref-for-big-token" ] - }], + } ], "login" : { "url" : "https://demo.example.org/myapp/login", + "templateData" : { + "username" : "testuser", + "password" : "testpwd" + }, "basic" : { "realm" : "realm0", "user" : "user0", diff --git a/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppport.java b/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppport.java index 26cf7301f8..066af81fc3 100644 --- a/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppport.java +++ b/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppport.java @@ -9,6 +9,7 @@ import com.mercedesbenz.sechub.commons.core.environment.SystemEnvironmentVariableSupport; import com.mercedesbenz.sechub.commons.core.util.SimpleStringUtils; import com.mercedesbenz.sechub.commons.model.SecHubRuntimeException; +import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorContext; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfig; import com.mercedesbenz.sechub.sharedkernel.error.NotAcceptableException; import com.mercedesbenz.sechub.sharedkernel.mapping.MappingIdentifier; @@ -27,14 +28,14 @@ public class CheckmarxExecutorConfigSuppport extends DefaultExecutorConfigSuppor * @return support * @throws NotAcceptableException when configuration is not valid */ - public static CheckmarxExecutorConfigSuppport createSupportAndAssertConfigValid(ProductExecutorConfig config, + public static CheckmarxExecutorConfigSuppport createSupportAndAssertConfigValid(ProductExecutorContext context, SystemEnvironmentVariableSupport variableSupport) { - return new CheckmarxExecutorConfigSuppport(config, variableSupport, new CheckmarxProductExecutorMinimumConfigValidation()); + return new CheckmarxExecutorConfigSuppport(context, variableSupport, new CheckmarxProductExecutorMinimumConfigValidation()); } - private CheckmarxExecutorConfigSuppport(ProductExecutorConfig config, SystemEnvironmentVariableSupport variableSupport, + private CheckmarxExecutorConfigSuppport(ProductExecutorContext context, SystemEnvironmentVariableSupport variableSupport, Validation validation) { - super(config, variableSupport, validation); + super(context, variableSupport, validation); } public boolean isAlwaysFullScanEnabled() { diff --git a/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxProductExecutor.java b/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxProductExecutor.java index b17cc43bc0..d1c640f636 100644 --- a/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxProductExecutor.java +++ b/sechub-scan-product-checkmarx/src/main/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxProductExecutor.java @@ -109,8 +109,8 @@ protected List executeByAdapter(ProductExecutorData data) throws JobStorage storage = storageService.createJobStorageForProject(projectId, jobUUID); - CheckmarxExecutorConfigSuppport configSupport = CheckmarxExecutorConfigSuppport - .createSupportAndAssertConfigValid(data.getProductExecutorContext().getExecutorConfig(), systemEnvironmentVariableSupport); + CheckmarxExecutorConfigSuppport configSupport = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(data.getProductExecutorContext(), + systemEnvironmentVariableSupport); AdapterMetaDataCallback metaDataCallback = data.getProductExecutorContext().getCallback(); diff --git a/sechub-scan-product-checkmarx/src/test/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppportTest.java b/sechub-scan-product-checkmarx/src/test/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppportTest.java index 7fee8f00c9..01b4215396 100644 --- a/sechub-scan-product-checkmarx/src/test/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppportTest.java +++ b/sechub-scan-product-checkmarx/src/test/java/com/mercedesbenz/sechub/domain/scan/product/checkmarx/CheckmarxExecutorConfigSuppportTest.java @@ -12,6 +12,7 @@ import com.mercedesbenz.sechub.adapter.checkmarx.CheckmarxConstants; import com.mercedesbenz.sechub.commons.core.environment.SystemEnvironmentVariableSupport; +import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorContext; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfig; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetup; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetupJobParameter; @@ -23,12 +24,14 @@ public class CheckmarxExecutorConfigSuppportTest { private ProductExecutorConfigSetup setup; private List jobParameters; private SystemEnvironmentVariableSupport systemEnvironmentVariableSupport; + private ProductExecutorContext context; @Before public void before() throws Exception { - + context = mock(); systemEnvironmentVariableSupport = mock(SystemEnvironmentVariableSupport.class); config = mock(ProductExecutorConfig.class); + when(context.getExecutorConfig()).thenReturn(config); setup = mock(ProductExecutorConfigSetup.class); jobParameters = new ArrayList<>(); @@ -40,7 +43,7 @@ public void before() throws Exception { @Test public void client_secret_returns_default_when_not_configured() { /* prepare */ - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); assertEquals(CheckmarxConstants.DEFAULT_CLIENT_SECRET, supportToTest.getClientSecret()); } @@ -49,7 +52,7 @@ public void client_secret_returns_default_when_not_configured() { public void client_secret_returns_configured_value_when_parameter_available() { /* prepare */ jobParameters.add(new ProductExecutorConfigSetupJobParameter(CheckmarxExecutorConfigParameterKeys.CHECKMARX_CLIENT_SECRET, "new.secret")); - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); /* execute +test */ assertEquals("new.secret", supportToTest.getClientSecret()); @@ -59,7 +62,7 @@ public void client_secret_returns_configured_value_when_parameter_available() { public void client_secret_returns_an_empty_string_default_is_returned() { /* prepare */ jobParameters.add(new ProductExecutorConfigSetupJobParameter(CheckmarxExecutorConfigParameterKeys.CHECKMARX_CLIENT_SECRET, "")); - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); /* execute +test */ assertEquals(CheckmarxConstants.DEFAULT_CLIENT_SECRET, supportToTest.getClientSecret()); @@ -68,7 +71,7 @@ public void client_secret_returns_an_empty_string_default_is_returned() { @Test public void engine_configuration_name_returns_default_when_not_configured() { /* prepare */ - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); assertEquals(CheckmarxConstants.DEFAULT_CHECKMARX_ENGINECONFIGURATION_MULTILANGANGE_SCAN_NAME, supportToTest.getEngineConfigurationName()); } @@ -77,7 +80,7 @@ public void engine_configuration_name_returns_default_when_not_configured() { public void engine_configuration_name_returns_configured_value_when_parameter_available() { /* prepare */ jobParameters.add(new ProductExecutorConfigSetupJobParameter(CheckmarxExecutorConfigParameterKeys.CHECKMARX_ENGINE_CONFIGURATIONNAME, "test.engine")); - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); /* execute +test */ assertEquals("test.engine", supportToTest.getEngineConfigurationName()); @@ -87,7 +90,7 @@ public void engine_configuration_name_returns_configured_value_when_parameter_av public void engine_configuration_name_returns_an_empty_string_default_is_returned() { /* prepare */ jobParameters.add(new ProductExecutorConfigSetupJobParameter(CheckmarxExecutorConfigParameterKeys.CHECKMARX_ENGINE_CONFIGURATIONNAME, "")); - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); /* execute +test */ assertEquals(CheckmarxConstants.DEFAULT_CHECKMARX_ENGINECONFIGURATION_MULTILANGANGE_SCAN_NAME, supportToTest.getEngineConfigurationName()); @@ -97,7 +100,7 @@ public void engine_configuration_name_returns_an_empty_string_default_is_returne public void always_fullscan_enabled_true() { /* prepare */ jobParameters.add(new ProductExecutorConfigSetupJobParameter(CheckmarxExecutorConfigParameterKeys.CHECKMARX_FULLSCAN_ALWAYS, "true")); - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); /* test */ assertEquals(true, supportToTest.isAlwaysFullScanEnabled()); @@ -107,7 +110,7 @@ public void always_fullscan_enabled_true() { public void always_fullscan_enabled_false() { /* prepare */ jobParameters.add(new ProductExecutorConfigSetupJobParameter(CheckmarxExecutorConfigParameterKeys.CHECKMARX_FULLSCAN_ALWAYS, "false")); - supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(config, systemEnvironmentVariableSupport); + supportToTest = CheckmarxExecutorConfigSuppport.createSupportAndAssertConfigValid(context, systemEnvironmentVariableSupport); /* test */ assertEquals(false, supportToTest.isAlwaysFullScanEnabled()); diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/AbstractPDSProductExecutor.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/AbstractPDSProductExecutor.java index d12908f390..56041bb67a 100644 --- a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/AbstractPDSProductExecutor.java +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/AbstractPDSProductExecutor.java @@ -75,8 +75,7 @@ protected final List executeByAdapter(ProductExecutorData data) t LOG.debug("Trigger PDS adapter execution for scan type: {} by: {}", getScanType(), getClass().getSimpleName()); ProductExecutorContext executorContext = data.getProductExecutorContext(); - PDSExecutorConfigSupport configSupport = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(executorContext.getExecutorConfig(), - serviceCollection); + PDSExecutorConfigSupport configSupport = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(executorContext, serviceCollection); SecHubExecutionContext context = data.getSechubExecutionContext(); diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSAdapterConfigurationStrategy.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSAdapterConfigurationStrategy.java index 7693ce64bd..ed5dbf7d78 100644 --- a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSAdapterConfigurationStrategy.java +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSAdapterConfigurationStrategy.java @@ -13,6 +13,7 @@ import com.mercedesbenz.sechub.adapter.AdapterConfigurationStrategy; import com.mercedesbenz.sechub.adapter.pds.PDSAdapterConfigurator; import com.mercedesbenz.sechub.adapter.pds.PDSAdapterConfiguratorProvider; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; import com.mercedesbenz.sechub.commons.model.ScanType; import com.mercedesbenz.sechub.commons.model.SecHubRuntimeException; import com.mercedesbenz.sechub.domain.scan.DefaultAdapterConfigurationStrategy; @@ -136,7 +137,7 @@ private PDSAdapterConfigurationStrategy(PDSAdapterConfigurationStrategyConfig co } @Override - public void configure(B configBuilder) { + public void configure(B configBuilder) throws ConfigurationFailureException { PDSAdapterConfigurator pdsConfigurator = null; if (configBuilder instanceof PDSAdapterConfiguratorProvider) { PDSAdapterConfiguratorProvider provider = (PDSAdapterConfiguratorProvider) configBuilder; @@ -153,13 +154,11 @@ public void configure( handlePdsParts(pdsConfigurator); } - private void handlePdsParts(PDSAdapterConfigurator pdsConfigurable) { + private void handlePdsParts(PDSAdapterConfigurator pdsConfigurable) throws ConfigurationFailureException { PDSExecutorConfigSupport configSupport = strategyConfig.configSupport; SecHubExecutionContext context = strategyConfig.productExecutorData.getSechubExecutionContext(); - Map jobParametersToSend = configSupport.createJobParametersToSendToPDS(context.getConfiguration()); - pdsConfigurable.setJobParameters(jobParametersToSend); pdsConfigurable.setReusingSecHubStorage(configSupport.isReusingSecHubStorage()); pdsConfigurable.setScanType(strategyConfig.scanType); pdsConfigurable.setPdsProductIdentifier(configSupport.getPDSProductIdentifier()); @@ -170,7 +169,6 @@ private void handlePdsParts(PDSAdapterConfigurator pdsConfigurable) { pdsConfigurable.setBinaryTarFileInputStreamOrNull(strategyConfig.binariesTarFileInputStreamOrNull); pdsConfigurable.setSourceCodeZipFileRequired(strategyConfig.contentProvider.isSourceRequired()); pdsConfigurable.setBinaryTarFileRequired(strategyConfig.contentProvider.isBinaryRequired()); - pdsConfigurable.setResilienceMaxRetries(configSupport.getPDSAdapterResilienceMaxRetries()); pdsConfigurable.setResilienceTimeToWaitBeforeRetryInMilliseconds(configSupport.getPDSAdapterResilienceRetryWaitInMilliseconds()); @@ -179,6 +177,14 @@ private void handlePdsParts(PDSAdapterConfigurator pdsConfigurable) { handleBinariesChecksum(pdsConfigurable); handleBinariesFileSize(pdsConfigurable); + + handleJobParameters(pdsConfigurable, configSupport, context); + } + + private void handleJobParameters(PDSAdapterConfigurator pdsConfigurable, PDSExecutorConfigSupport configSupport, SecHubExecutionContext context) + throws ConfigurationFailureException { + Map jobParametersToSend = configSupport.createJobParametersToSendToPDS(context); + pdsConfigurable.setJobParameters(jobParametersToSend); } private void handleSourceCodeChecksum(PDSAdapterConfigurator pdsConfigurable) { @@ -237,7 +243,7 @@ private void handleBinariesFileSize(PDSAdapterConfigurator pdsConfigurable) { } } - private void handleCommonParts(B configBuilder) { + private void handleCommonParts(B configBuilder) throws ConfigurationFailureException { /* standard configuration */ /* @formatter:off */ diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupport.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupport.java index a6dc958cc0..d119bbd8e4 100644 --- a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupport.java +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupport.java @@ -14,19 +14,27 @@ import org.slf4j.LoggerFactory; import com.mercedesbenz.sechub.adapter.DefaultExecutorConfigSupport; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; import com.mercedesbenz.sechub.commons.core.environment.SystemEnvironmentVariableSupport; import com.mercedesbenz.sechub.commons.core.util.SecHubStorageUtil; import com.mercedesbenz.sechub.commons.core.util.SimpleStringUtils; +import com.mercedesbenz.sechub.commons.model.JSONConverter; +import com.mercedesbenz.sechub.commons.model.ScanType; import com.mercedesbenz.sechub.commons.model.SecHubDataConfigurationType; import com.mercedesbenz.sechub.commons.model.SecHubDataConfigurationTypeListParser; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; import com.mercedesbenz.sechub.commons.pds.PDSConfigDataKeyProvider; import com.mercedesbenz.sechub.commons.pds.PDSDefaultParameterKeyConstants; import com.mercedesbenz.sechub.commons.pds.PDSKey; import com.mercedesbenz.sechub.commons.pds.PDSKeyProvider; +import com.mercedesbenz.sechub.commons.pds.data.PDSTemplateMetaData; import com.mercedesbenz.sechub.domain.scan.NetworkTargetProductServerDataProvider; import com.mercedesbenz.sechub.domain.scan.NetworkTargetType; +import com.mercedesbenz.sechub.domain.scan.SecHubExecutionContext; import com.mercedesbenz.sechub.domain.scan.config.ScanMapping; +import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorContext; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfig; +import com.mercedesbenz.sechub.sharedkernel.ProductIdentifier; import com.mercedesbenz.sechub.sharedkernel.configuration.SecHubConfiguration; import com.mercedesbenz.sechub.sharedkernel.error.NotAcceptableException; import com.mercedesbenz.sechub.sharedkernel.validation.Validation; @@ -42,6 +50,8 @@ public class PDSExecutorConfigSupport extends DefaultExecutorConfigSupport imple private PDSExecutorConfigSuppportServiceCollection serviceCollection; private SecHubDataConfigurationTypeListParser parser = new SecHubDataConfigurationTypeListParser(); + PDSTemplateMetaDataService templateMetaDataTransformer = new PDSTemplateMetaDataService(); + static { List> allParameterProviders = new ArrayList<>(); allParameterProviders.addAll(Arrays.asList(SecHubProductExecutionPDSKeyProvider.values())); @@ -64,29 +74,63 @@ public static List> getUnmodifiableListOfParame * @return support * @throws NotAcceptableException when configuration is not valid */ - public static PDSExecutorConfigSupport createSupportAndAssertConfigValid(ProductExecutorConfig config, + public static PDSExecutorConfigSupport createSupportAndAssertConfigValid(ProductExecutorContext context, PDSExecutorConfigSuppportServiceCollection serviceCollection) { - return new PDSExecutorConfigSupport(config, serviceCollection, new PDSProductExecutorMinimumConfigValidation()); + PDSExecutorConfigSupport result = new PDSExecutorConfigSupport(context, serviceCollection, new PDSProductExecutorMinimumConfigValidation()); + return result; } - private PDSExecutorConfigSupport(ProductExecutorConfig config, PDSExecutorConfigSuppportServiceCollection serviceCollection, + private PDSExecutorConfigSupport(ProductExecutorContext context, PDSExecutorConfigSuppportServiceCollection serviceCollection, Validation validation) { - super(config, serviceCollection.getSystemEnvironmentVariableSupport(), validation); + super(context, serviceCollection.getSystemEnvironmentVariableSupport(), validation); this.serviceCollection = serviceCollection; } - public Map createJobParametersToSendToPDS(SecHubConfiguration secHubConfiguration) { + public Map createJobParametersToSendToPDS(SecHubExecutionContext context) throws ConfigurationFailureException { + if (context == null) { + throw new IllegalArgumentException("context may not be null!"); + } + SecHubConfiguration configuration = context.getConfiguration(); + if (configuration == null) { + throw new IllegalStateException("configuration may not be null inside context at this moment!"); + } + ProductIdentifier productIdentifier = config.getProductIdentifier(); + if (productIdentifier == null) { + throw new IllegalStateException("productIdentifier may not be null inside config at this moment!"); + } + ScanType scanType = productIdentifier.getType(); + if (scanType == null) { + throw new IllegalStateException("scanType may not be null inside productIdentifier:" + productIdentifier); + } Map parametersToSend = createParametersToSendByProviders(keyProvidersForSendingParametersToPDS); handleEnvironmentVariablesInJobParameters(parametersToSend); /* handle remaining parts without environment variable conversion */ - handleSecHubStorageIfNecessary(secHubConfiguration, parametersToSend); + handleSecHubStorageIfNecessary(configuration, parametersToSend); addMappingsAsJobParameter(parametersToSend); + addPdsTemplateMetaDataList(scanType, context, parametersToSend); return parametersToSend; } + private void addPdsTemplateMetaDataList(ScanType scanType, SecHubExecutionContext context, Map parametersToSend) + throws ConfigurationFailureException { + List templateDefinitions = context.getTemplateDefinitions(); + if (templateDefinitions == null) { + throw new IllegalStateException("template definitions may not be null inside context at this moment!"); + } + PDSTemplateMetaDataService templateMetaDataService = serviceCollection.getTemplateMetaDataService(); + + List pdsTemplateMetaDataList = templateMetaDataService.createTemplateMetaData(templateDefinitions, getPDSProductIdentifier(), + scanType, context.getConfiguration()); + + templateMetaDataService.ensureTemplateAssetFilesAreAvailableInStorage(pdsTemplateMetaDataList); + + String pdsTemplateMetaDataListAsJson = JSONConverter.get().toJSON(pdsTemplateMetaDataList, false); + parametersToSend.put(PDSDefaultParameterKeyConstants.PARAM_KEY_PDS_CONFIG_TEMPLATE_META_DATA_LIST, pdsTemplateMetaDataListAsJson); + } + private void handleSecHubStorageIfNecessary(SecHubConfiguration secHubConfiguration, Map parametersToSend) { if (isReusingSecHubStorage()) { String projectId = secHubConfiguration.getProjectId(); @@ -310,4 +354,5 @@ public boolean isGivenStorageSupportedByPDSProduct(PDSStorageContentProvider con public String getDataTypesSupportedByPDSAsString() { return getParameter(PDSConfigDataKeyProvider.PDS_CONFIG_SUPPORTED_DATATYPES); } + } diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSuppportServiceCollection.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSuppportServiceCollection.java index 5bd6854a7b..b36d5113a8 100644 --- a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSuppportServiceCollection.java +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSuppportServiceCollection.java @@ -16,6 +16,9 @@ public class PDSExecutorConfigSuppportServiceCollection { @Autowired ScanMappingRepository scanMappingRepository; + @Autowired + PDSTemplateMetaDataService templateMetaDataService; + public SystemEnvironmentVariableSupport getSystemEnvironmentVariableSupport() { return systemEnvironment; } @@ -23,4 +26,8 @@ public SystemEnvironmentVariableSupport getSystemEnvironmentVariableSupport() { public ScanMappingRepository getScanMappingRepository() { return scanMappingRepository; } + + public PDSTemplateMetaDataService getTemplateMetaDataService() { + return templateMetaDataService; + } } diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSInfraScanProductExecutor.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSInfraScanProductExecutor.java index cb1192bd72..a20c32b386 100644 --- a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSInfraScanProductExecutor.java +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSInfraScanProductExecutor.java @@ -112,8 +112,7 @@ protected void customize(ProductExecutorData data) { data.setNetworkLocationProvider(new InfraScanNetworkLocationProvider(secHubConfiguration)); ProductExecutorContext executorContext = data.getProductExecutorContext(); - PDSExecutorConfigSupport configSupport = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(executorContext.getExecutorConfig(), - serviceCollection); + PDSExecutorConfigSupport configSupport = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(executorContext, serviceCollection); data.setNetworkTargetDataProvider(configSupport); } diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataService.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataService.java new file mode 100644 index 0000000000..d2c38946f1 --- /dev/null +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataService.java @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.product.pds; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; +import com.mercedesbenz.sechub.commons.model.ScanType; +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; +import com.mercedesbenz.sechub.commons.pds.data.PDSTemplateMetaData; +import com.mercedesbenz.sechub.commons.pds.data.PDSTemplateMetaData.PDSAssetData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetDetailData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetFileData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetService; +import com.mercedesbenz.sechub.sharedkernel.error.NotFoundException; + +@Service +public class PDSTemplateMetaDataService { + + private static final Logger LOG = LoggerFactory.getLogger(PDSTemplateMetaDataService.class); + + @Autowired + AssetService assetService; + + @Autowired + RelevantScanTemplateDefinitionFilter filter; + + public List createTemplateMetaData(List templateDefinitions, String pdsProductId, ScanType scanType, + SecHubConfigurationModel configuration) throws ConfigurationFailureException { + + List result = new ArrayList<>(); + + List filteredDefinitions = filter.filter(templateDefinitions, scanType, configuration); + if (filteredDefinitions.isEmpty()) { + LOG.debug("Given {} template definitions, after filtering: {}", templateDefinitions.size(), filteredDefinitions.size()); + } + + resolveAssetFileDataAndAddToResult(result, pdsProductId, filteredDefinitions); + + return result; + } + + /** + * Ensures that asset files in given PDS template meta data is available in + * storage. + * + * @param metaDataList list containing template meta data + * @throws ConfigurationFailureException + */ + public void ensureTemplateAssetFilesAreAvailableInStorage(List metaDataList) throws ConfigurationFailureException { + for (PDSTemplateMetaData metaData : metaDataList) { + + PDSAssetData assetData = metaData.getAssetData(); + + String assetId = assetData.getAsset(); + String fileName = assetData.getFile(); + + assetService.ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(fileName, assetId); + + } + } + + private void resolveAssetFileDataAndAddToResult(List result, String pdsProductId, List filteredDefinitions) + throws ConfigurationFailureException { + if (filteredDefinitions.isEmpty()) { + return; + } + + String filename = pdsProductId + ".zip"; + + for (TemplateDefinition definition : filteredDefinitions) { + String assetId = definition.getAssetId(); + AssetDetailData details = null; + try { + details = assetService.fetchAssetDetails(assetId); + } catch (NotFoundException e) { + /* asset does not exist */ + throw new ConfigurationFailureException("The asset " + assetId + " does not exist! Cannot transform", e); + } + + List files = details.getFiles(); + boolean fileForTemplateFound = false; + + for (AssetFileData fileData : files) { + if (!filename.equals(fileData.getFileName())) { + continue; + } + /* found */ + PDSAssetData assetData = new PDSAssetData(); + assetData.setAsset(assetId); + assetData.setFile(fileData.getFileName()); + assetData.setChecksum(fileData.getChecksum()); + + PDSTemplateMetaData metaData = new PDSTemplateMetaData(); + metaData.setTemplate(definition.getId()); + metaData.setType(definition.getType()); + metaData.setAssetData(assetData); + + result.add(metaData); + + fileForTemplateFound = true; + break; + } + + if (!fileForTemplateFound) { + throw new ConfigurationFailureException("The asset " + assetId + " does not contain file '" + filename + "'"); + } + } + } +} diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSWebScanProductExecutor.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSWebScanProductExecutor.java index b11947eac7..4e4478da99 100644 --- a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSWebScanProductExecutor.java +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSWebScanProductExecutor.java @@ -110,8 +110,7 @@ protected void customize(ProductExecutorData data) { data.setNetworkLocationProvider(new WebScanNetworkLocationProvider(secHubConfiguration)); ProductExecutorContext executorContext = data.getProductExecutorContext(); - PDSExecutorConfigSupport configSupport = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(executorContext.getExecutorConfig(), - serviceCollection); + PDSExecutorConfigSupport configSupport = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(executorContext, serviceCollection); data.setNetworkTargetDataProvider(configSupport); diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilter.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilter.java new file mode 100644 index 0000000000..724f720403 --- /dev/null +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilter.java @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.product.pds; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.mercedesbenz.sechub.commons.model.ScanType; +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; +import com.mercedesbenz.sechub.commons.model.template.TemplateData; +import com.mercedesbenz.sechub.commons.model.template.TemplateDataResolver; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; +import com.mercedesbenz.sechub.commons.model.template.TemplateType; + +@Component +/** + * Filters template definitions which are relevant for a scan + * + * @author Albert Tregnaghi + * + */ +public class RelevantScanTemplateDefinitionFilter { + + @Autowired + TemplateDataResolver templateDataResolver; + + /** + * Filters template definitions for only relevant definitions for given scan + * type and configuration. If the configuration does not contain a templateData + * definition, the list will always be empty. If configuration contains template + * data, but the scan type does not need/use them the result will also be empty + * + * @param templateDefinitions all given definitions + * @param scanType scan type for which relevant definitions shall be + * filtered + * @param configuration SecHub configuration which contains template data + * (or not) + * @return list of relevant template definitions for the scan, never + * null + */ + public List filter(List templateDefinitions, ScanType scanType, SecHubConfigurationModel configuration) { + List result = new ArrayList<>(); + + for (TemplateDefinition definition : templateDefinitions) { + + addDefinitionToResultIfNecessary(definition, scanType, configuration, result); + } + return result; + } + + private void addDefinitionToResultIfNecessary(TemplateDefinition definition, ScanType scanType, SecHubConfigurationModel configuration, + List result) { + if (scanType == null) { + return; + } + switch (scanType) { + case WEB_SCAN: + /* for web scan we accept WEBSCAN_LOGIN templates */ + if (TemplateType.WEBSCAN_LOGIN.equals(definition.getType())) { + TemplateData templateData = templateDataResolver.resolveTemplateData(TemplateType.WEBSCAN_LOGIN, configuration); + if (templateData != null) { + /* data available, so add to result */ + result.add(definition); + } + } + break; + default: + break; + } + + } + +} diff --git a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/SecHubProductExecutionPDSKeyProvider.java b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/SecHubProductExecutionPDSKeyProvider.java index 395e7fd580..2120e1a489 100644 --- a/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/SecHubProductExecutionPDSKeyProvider.java +++ b/sechub-scan-product-pds/src/main/java/com/mercedesbenz/sechub/domain/scan/product/pds/SecHubProductExecutionPDSKeyProvider.java @@ -8,7 +8,7 @@ import com.mercedesbenz.sechub.domain.scan.NetworkTargetType; /** - * These providers/keys are used by sechub PDS product executors at runtime + * These providers/keys are used by SecHub PDS product executors at runtime * while communicating with PDS servers. * * @author Albert Tregnaghi diff --git a/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupportTest.java b/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupportTest.java index 32049385b1..99aa876939 100644 --- a/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupportTest.java +++ b/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSExecutorConfigSupportTest.java @@ -1,10 +1,13 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan.product.pds; +import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -24,16 +27,25 @@ import com.mercedesbenz.sechub.commons.mapping.MappingData; import com.mercedesbenz.sechub.commons.mapping.MappingEntry; import com.mercedesbenz.sechub.commons.model.JSONConverter; +import com.mercedesbenz.sechub.commons.model.ScanType; import com.mercedesbenz.sechub.commons.model.SecHubDataConfigurationType; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; import com.mercedesbenz.sechub.commons.pds.PDSConfigDataKeyProvider; +import com.mercedesbenz.sechub.commons.pds.PDSDefaultParameterKeyConstants; +import com.mercedesbenz.sechub.commons.pds.data.PDSTemplateMetaData; +import com.mercedesbenz.sechub.commons.pds.data.PDSTemplateMetaData.PDSAssetData; import com.mercedesbenz.sechub.domain.scan.NetworkTargetType; +import com.mercedesbenz.sechub.domain.scan.SecHubExecutionContext; import com.mercedesbenz.sechub.domain.scan.config.ScanMapping; import com.mercedesbenz.sechub.domain.scan.config.ScanMappingRepository; +import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorContext; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfig; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetup; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetupCredentials; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetupJobParameter; +import com.mercedesbenz.sechub.sharedkernel.ProductIdentifier; import com.mercedesbenz.sechub.sharedkernel.configuration.SecHubConfiguration; +import com.mercedesbenz.sechub.test.TestCanaryException; public class PDSExecutorConfigSupportTest { @@ -59,11 +71,27 @@ public class PDSExecutorConfigSupportTest { private List jobParameters; private ScanMappingRepository repository; private SystemEnvironmentVariableSupport systemEnvironmentVariableSupport; + private ProductExecutorContext context; + private SecHubExecutionContext sechubExecutionContext; + private SecHubConfiguration sechubConfiguration; + private PDSTemplateMetaDataService templateMetaDataService; @BeforeEach public void before() throws Exception { - config = mock(ProductExecutorConfig.class); - executorConfigSetup = mock(ProductExecutorConfigSetup.class); + sechubConfiguration = mock(); + sechubExecutionContext = mock(); + config = mock(); + context = mock(); + executorConfigSetup = mock(); + serviceCollection = mock(); + repository = mock(); + templateMetaDataService = mock(); + + when(sechubExecutionContext.getTemplateDefinitions()).thenReturn(Collections.emptyList()); + when(sechubExecutionContext.getConfiguration()).thenReturn(sechubConfiguration); + + when(config.getProductIdentifier()).thenReturn(ProductIdentifier.UNKNOWN);// the scan type unknown is used, because not really relevant + when(context.getExecutorConfig()).thenReturn(config); jobParameters = new ArrayList<>(); jobParameters.add(new ProductExecutorConfigSetupJobParameter(PDSConfigDataKeyProvider.PDS_CONFIG_PRODUCTIDENTIFIER.getKey().getId(), @@ -82,16 +110,14 @@ public void before() throws Exception { when(executorConfigSetup.getJobParameters()).thenReturn(jobParameters); - serviceCollection = mock(PDSExecutorConfigSuppportServiceCollection.class); - Answer defaultAnswerWithNoConversion = createAnswerWhichReturnsAlwaysJustTheOriginValue(); systemEnvironmentVariableSupport = mock(SystemEnvironmentVariableSupport.class, defaultAnswerWithNoConversion); - repository = mock(ScanMappingRepository.class); - when(serviceCollection.getScanMappingRepository()).thenReturn(repository); when(serviceCollection.getSystemEnvironmentVariableSupport()).thenReturn(systemEnvironmentVariableSupport); - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + when(serviceCollection.getTemplateMetaDataService()).thenReturn(templateMetaDataService); + + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); } @EnumSource(SecHubDataConfigurationType.class) @@ -107,7 +133,7 @@ void isGivenStorageSupportedByPDSProduct_binary_and_source_required_from_model_a .add(new ProductExecutorConfigSetupJobParameter(PDSConfigDataKeyProvider.PDS_CONFIG_SUPPORTED_DATATYPES.getKey().getId(), type.toString())); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -143,7 +169,7 @@ void isGivenStorageSupportedByPDSProduct_no_binary_in_model_required_but_product SecHubDataConfigurationType.BINARY.toString())); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -164,7 +190,7 @@ void isGivenStorageSupportedByPDSProduct_only_source_in_model_required_but_produ jobParameters.add(new ProductExecutorConfigSetupJobParameter(PDSConfigDataKeyProvider.PDS_CONFIG_SUPPORTED_DATATYPES.getKey().getId(), typesAsString)); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -185,7 +211,7 @@ void isGivenStorageSupportedByPDSProduct_only_binary_in_model_required_but_produ jobParameters.add(new ProductExecutorConfigSetupJobParameter(PDSConfigDataKeyProvider.PDS_CONFIG_SUPPORTED_DATATYPES.getKey().getId(), typesAsString)); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -206,7 +232,7 @@ void isGivenStorageSupportedByPDSProduct_no_source_in_model_required_but_product SecHubDataConfigurationType.SOURCE.toString())); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -227,7 +253,7 @@ void isGivenStorageSupportedByPDSProduct_no_source_or_binary_in_model_required_b SecHubDataConfigurationType.NONE.toString())); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -249,7 +275,7 @@ void isGivenStorageSupportedByPDSProduct_no_source_or_binary_in_model_required_b .add(new ProductExecutorConfigSetupJobParameter(PDSConfigDataKeyProvider.PDS_CONFIG_SUPPORTED_DATATYPES.getKey().getId(), type.toString())); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -272,7 +298,7 @@ void isGivenStorageSupportedByPDSProduct_no_source_or_binary_in_model_but_wrong_ jobParameters.add(new ProductExecutorConfigSetupJobParameter(PDSConfigDataKeyProvider.PDS_CONFIG_SUPPORTED_DATATYPES.getKey().getId(), typesAsString)); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); /* execute */ boolean result = supportToTest.isGivenStorageSupportedByPDSProduct(contentProvider); @@ -297,7 +323,25 @@ void isTargetTypeForbidden_returns_false_for_target_type_requested_is_intranet_w } @Test - void createJobParametersToSendToPDS_environmentVariablesEntriesAreReplacedWithTheirContent() { + void createJobParametersToSendToPDS_null_list_of_template_meta_data_throws_illegal_argument_exception() { + assertThatThrownBy(() -> supportToTest.createJobParametersToSendToPDS(null)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void createJobParametersToSendToPDS_empty_template_list_is_accepted() throws Exception { + /* prepare */ + when(sechubExecutionContext.getTemplateDefinitions()).thenReturn(Collections.emptyList()); + + /* execute */ + Map result = supportToTest.createJobParametersToSendToPDS(sechubExecutionContext); + + /* test */ + String data = result.get(PDSDefaultParameterKeyConstants.PARAM_KEY_PDS_CONFIG_TEMPLATE_META_DATA_LIST); + assertThat(data).isEqualTo("[]"); + } + + @Test + void createJobParametersToSendToPDS_environmentVariablesEntriesAreReplacedWithTheirContent() throws Exception { /* prepare */ String parameterKey1 = "test.key1"; String parameterKey2 = "test.key2"; @@ -308,15 +352,13 @@ void createJobParametersToSendToPDS_environmentVariablesEntriesAreReplacedWithTh jobParameters.add(new ProductExecutorConfigSetupJobParameter(parameterKey3, "just-a-key-not-converted")); // create support again (necessary to have new job parameters included) - supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(config, serviceCollection); + supportToTest = PDSExecutorConfigSupport.createSupportAndAssertConfigValid(context, serviceCollection); when(systemEnvironmentVariableSupport.getValueOrVariableContent("env:A_TESTVARIABLE")).thenReturn("resolved-value"); when(systemEnvironmentVariableSupport.getValueOrVariableContent("env:A_NOT_EXISTING_VARIABLE")).thenReturn(null); - SecHubConfiguration sechubConfiguration = mock(SecHubConfiguration.class); - /* execute */ - Map parameterMap = supportToTest.createJobParametersToSendToPDS(sechubConfiguration); + Map parameterMap = supportToTest.createJobParametersToSendToPDS(sechubExecutionContext); /* test */ assertEquals("resolved-value", parameterMap.get(parameterKey1)); @@ -326,15 +368,13 @@ void createJobParametersToSendToPDS_environmentVariablesEntriesAreReplacedWithTh } @Test - void createJobParametersToSendToPDS_mapping_is_resolved() { + void createJobParametersToSendToPDS_mapping_is_resolved() throws Exception { /* prepare */ mockSecHubMappingInDatabase(); mockSecHubMappingId2InDatabase(); - SecHubConfiguration sechubConfiguration = new SecHubConfiguration(); - /* execute */ - Map parameters = supportToTest.createJobParametersToSendToPDS(sechubConfiguration); + Map parameters = supportToTest.createJobParametersToSendToPDS(sechubExecutionContext); /* test 1 */ String p1 = parameters.get(SECHUB_MAPPING_ID_1); @@ -385,6 +425,58 @@ void createJobParametersToSendToPDS_mapping_is_resolved() { verify(systemEnvironmentVariableSupport, times(1)).getValueOrVariableContent(any()); } + @Test + void createJobParametersToSendToPDS_pds_template_meta_data_is_created_by_result_from_template_metadata_service() throws Exception { + /* prepare */ + List templateDefinitions = mock(); + when(sechubExecutionContext.getTemplateDefinitions()).thenReturn(templateDefinitions); + + List templateMetaDataServiceResult = createTemplateMetaDataServiceExampleResult(); + + when(templateMetaDataService.createTemplateMetaData(eq(templateDefinitions), anyString(), any(ScanType.class), eq(sechubConfiguration))) + .thenReturn(templateMetaDataServiceResult); + /* execute */ + Map parameterMap = supportToTest.createJobParametersToSendToPDS(sechubExecutionContext); + + /* test */ + String expectedJson = JSONConverter.get().toJSON(templateMetaDataServiceResult, false); + String jsonFromConfigSupport = parameterMap.get(PDSDefaultParameterKeyConstants.PARAM_KEY_PDS_CONFIG_TEMPLATE_META_DATA_LIST); + + assertThat(jsonFromConfigSupport).isNotNull().isEqualTo(expectedJson).hasSizeGreaterThan(10); + + } + + @Test + void createJobParametersToSendToPDS_templateDataService_is_called_twice_in_correct_order_and_arguments() throws Exception { + /* prepare */ + List templateDefinitions = mock(); + when(sechubExecutionContext.getTemplateDefinitions()).thenReturn(templateDefinitions); + + List templateMetaDataServiceResult = createTemplateMetaDataServiceExampleResult(); + + when(templateMetaDataService.createTemplateMetaData(eq(templateDefinitions), anyString(), any(ScanType.class), eq(sechubConfiguration))) + .thenReturn(templateMetaDataServiceResult); + // next line does ensure that it is called with the former result. It also + // breaks further processing + doThrow(new TestCanaryException()).when(templateMetaDataService).ensureTemplateAssetFilesAreAvailableInStorage(templateMetaDataServiceResult); + + /* execute + test */ + assertThatThrownBy(() -> supportToTest.createJobParametersToSendToPDS(sechubExecutionContext)).isInstanceOf(TestCanaryException.class); + + } + + private List createTemplateMetaDataServiceExampleResult() { + List templateMetaDataServiceResult = new ArrayList<>(); + PDSTemplateMetaData pdsTemplateMetaData1 = new PDSTemplateMetaData(); + PDSAssetData assetData1 = new PDSAssetData(); + assetData1.setAsset("asset-id-1"); + assetData1.setChecksum("checksum1"); + assetData1.setFile("file1"); + pdsTemplateMetaData1.setAssetData(assetData1); + templateMetaDataServiceResult.add(pdsTemplateMetaData1); + return templateMetaDataServiceResult; + } + private void mockSecHubMappingId2InDatabase() { String mappingId = SECHUB_MAPPING_ID_2; diff --git a/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataServiceTest.java b/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataServiceTest.java new file mode 100644 index 0000000000..cc7c62ab91 --- /dev/null +++ b/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/PDSTemplateMetaDataServiceTest.java @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.product.pds; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; +import com.mercedesbenz.sechub.commons.model.ScanType; +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition.TemplateVariable; +import com.mercedesbenz.sechub.commons.model.template.TemplateType; +import com.mercedesbenz.sechub.commons.pds.data.PDSTemplateMetaData; +import com.mercedesbenz.sechub.commons.pds.data.PDSTemplateMetaData.PDSAssetData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetDetailData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetFileData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetService; +import com.mercedesbenz.sechub.sharedkernel.error.NotFoundException; + +class PDSTemplateMetaDataServiceTest { + private PDSTemplateMetaDataService serviceToTest; + private AssetService assetService; + private RelevantScanTemplateDefinitionFilter filter; + + @BeforeEach + void beforeEach() { + + filter = mock(); + assetService = mock(); + + serviceToTest = new PDSTemplateMetaDataService(); + serviceToTest.filter = filter; + serviceToTest.assetService = assetService; + } + + @Test + void createTemplateMetaData_returns_pds_template_meta_data_when_asset_is_available() throws Exception { + + /* prepare */ + ScanType exampleScanType = ScanType.WEB_SCAN; + TemplateType exampleTemplateType = TemplateType.WEBSCAN_LOGIN; + String exampleTemplateId1 = "template_id_1"; + String exampleChecksum1 = "checksum1"; + String exampleAssetId1 = "asset1"; + + SecHubConfigurationModel configuration = mock(); + + // prepare template data + List givenDefinitions = mock(); + List filteredDefinitions = new ArrayList<>(); + TemplateVariable variable1 = new TemplateVariable(); + variable1.setName("var1"); + + TemplateDefinition templateDefinition1 = new TemplateDefinition(); + templateDefinition1.setAssetId(exampleAssetId1); + templateDefinition1.setId(exampleTemplateId1); + templateDefinition1.setType(exampleTemplateType); + + templateDefinition1.getVariables().add(variable1); + filteredDefinitions.add(templateDefinition1); + + when(filter.filter(givenDefinitions, exampleScanType, configuration)).thenReturn(filteredDefinitions); + + // prepare asset data + AssetFileData assetFile1a = new AssetFileData(); + assetFile1a.setChecksum("other"); + assetFile1a.setFileName("other_product_id.zip"); + AssetDetailData assetDetailData1 = mock(); + + AssetFileData assetFile1b = new AssetFileData(); + assetFile1b.setChecksum(exampleChecksum1); + assetFile1b.setFileName("test_product_id.zip"); + + List assetfiles = new ArrayList<>(); + assetfiles.add(assetFile1a); + assetfiles.add(assetFile1b); + + when(assetDetailData1.getFiles()).thenReturn(assetfiles); + when(assetService.fetchAssetDetails(exampleAssetId1)).thenReturn(assetDetailData1); + + /* execute */ + List result = serviceToTest.createTemplateMetaData(givenDefinitions, "test_product_id", exampleScanType, configuration); + + /* test */ + PDSTemplateMetaData expectedTemplateMetaData1 = new PDSTemplateMetaData(); + expectedTemplateMetaData1.setTemplate(exampleTemplateId1); + expectedTemplateMetaData1.setType(exampleTemplateType); + + PDSAssetData assetData1 = new PDSAssetData(); + assetData1.setAsset(exampleAssetId1); + assetData1.setChecksum(exampleChecksum1); + assetData1.setFile("test_product_id.zip"); + + expectedTemplateMetaData1.setAssetData(assetData1); + + assertThat(result).isNotNull().contains(expectedTemplateMetaData1).hasSize(1); + } + + @Test + void createTemplateMetaData_returns_empty_pds_template_meta_data_when_definition_list_is_empty() throws Exception { + + /* prepare */ + ScanType exampleScanType = ScanType.WEB_SCAN; + + SecHubConfigurationModel configuration = mock(); + + // prepare template data + List givenDefinitions = mock(); + List filteredDefinitions = new ArrayList<>(); + + when(filter.filter(givenDefinitions, exampleScanType, configuration)).thenReturn(filteredDefinitions); + + /* execute */ + List result = serviceToTest.createTemplateMetaData(givenDefinitions, "test_product_id", exampleScanType, configuration); + + /* test */ + assertThat(result).isNotNull().isEmpty(); + } + + @Test + void createTemplateMetaData_throws_exception_when_asset_not_found() throws Exception { + + /* prepare */ + ScanType exampleScanType = ScanType.WEB_SCAN; + TemplateType exampleTemplateType = TemplateType.WEBSCAN_LOGIN; + String exampleTemplateId1 = "template_id_1"; + String exampleAssetId1 = "asset1"; + + SecHubConfigurationModel configuration = mock(); + + // prepare template data + List givenDefinitions = mock(); + List filteredDefinitions = new ArrayList<>(); + TemplateVariable variable1 = new TemplateVariable(); + variable1.setName("var1"); + + TemplateDefinition templateDefinition1 = new TemplateDefinition(); + templateDefinition1.setAssetId(exampleAssetId1); + templateDefinition1.setId(exampleTemplateId1); + templateDefinition1.setType(exampleTemplateType); + + templateDefinition1.getVariables().add(variable1); + filteredDefinitions.add(templateDefinition1); + + when(filter.filter(givenDefinitions, exampleScanType, configuration)).thenReturn(filteredDefinitions); + + when(assetService.fetchAssetDetails(exampleAssetId1)).thenThrow(NotFoundException.class); + + /* execute + test */ + assertThatThrownBy(() -> serviceToTest.createTemplateMetaData(givenDefinitions, "test_product_id", exampleScanType, configuration)) + .isInstanceOf(ConfigurationFailureException.class).hasMessageContaining(exampleAssetId1 + " does not exist"); + } + + @Test + void createTemplateMetaData_throws_exception_when_asset_product_file_not_found() throws Exception { + + /* prepare */ + ScanType exampleScanType = ScanType.WEB_SCAN; + TemplateType exampleTemplateType = TemplateType.WEBSCAN_LOGIN; + String exampleTemplateId1 = "template_id_1"; + String exampleAssetId1 = "asset1"; + + SecHubConfigurationModel configuration = mock(); + + // prepare template data + List givenDefinitions = mock(); + List filteredDefinitions = new ArrayList<>(); + TemplateVariable variable1 = new TemplateVariable(); + variable1.setName("var1"); + + TemplateDefinition templateDefinition1 = new TemplateDefinition(); + templateDefinition1.setAssetId(exampleAssetId1); + templateDefinition1.setId(exampleTemplateId1); + templateDefinition1.setType(exampleTemplateType); + + templateDefinition1.getVariables().add(variable1); + filteredDefinitions.add(templateDefinition1); + + when(filter.filter(givenDefinitions, exampleScanType, configuration)).thenReturn(filteredDefinitions); + // prepare asset data + AssetFileData assetFile1a = new AssetFileData(); + assetFile1a.setChecksum("other"); + assetFile1a.setFileName("other_product_id.zip"); + AssetDetailData assetDetailData1 = mock(); + + List assetfiles = new ArrayList<>(); + assetfiles.add(assetFile1a); + + when(assetDetailData1.getFiles()).thenReturn(assetfiles); + when(assetService.fetchAssetDetails(exampleAssetId1)).thenReturn(assetDetailData1); + + /* execute + test */ + assertThatThrownBy(() -> serviceToTest.createTemplateMetaData(givenDefinitions, "test_product_id", exampleScanType, configuration)) + .isInstanceOf(ConfigurationFailureException.class).hasMessageContaining("does not contain file 'test_product_id.zip'"); + ; + } + + @Test + void ensureTemplateAssetFilesAreAvailableInStorage_calls_asste_service_for_each_metadata_assetfile() throws Exception { + + /* prepare */ + PDSAssetData assetData1 = new PDSAssetData(); + assetData1.setAsset("asset1"); + assetData1.setFile("file1.txt"); + + PDSTemplateMetaData templateMetaData1 = new PDSTemplateMetaData(); + templateMetaData1.setAssetData(assetData1); + + PDSAssetData assetData2 = new PDSAssetData(); + assetData2.setAsset("asset2"); + assetData2.setFile("file2.txt"); + + PDSTemplateMetaData templateMetaData2 = new PDSTemplateMetaData(); + templateMetaData2.setAssetData(assetData2); + + List metaDataList = new ArrayList<>(); + metaDataList.add(templateMetaData1); + metaDataList.add(templateMetaData2); + + /* execute */ + serviceToTest.ensureTemplateAssetFilesAreAvailableInStorage(metaDataList); + + /* test */ + verify(assetService).ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase("file1.txt", "asset1"); + verify(assetService).ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase("file2.txt", "asset2"); + } + +} diff --git a/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilterTest.java b/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilterTest.java new file mode 100644 index 0000000000..365d9ab202 --- /dev/null +++ b/sechub-scan-product-pds/src/test/java/com/mercedesbenz/sechub/domain/scan/product/pds/RelevantScanTemplateDefinitionFilterTest.java @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.product.pds; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; +import org.junit.jupiter.params.provider.NullSource; + +import com.mercedesbenz.sechub.commons.model.ScanType; +import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModel; +import com.mercedesbenz.sechub.commons.model.template.TemplateData; +import com.mercedesbenz.sechub.commons.model.template.TemplateDataResolver; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; +import com.mercedesbenz.sechub.commons.model.template.TemplateType; + +class RelevantScanTemplateDefinitionFilterTest { + private RelevantScanTemplateDefinitionFilter filterToTest; + private SecHubConfigurationModel configuration; + private TemplateDataResolver templateDataResolver; + private TemplateDefinition defininition1WebScanLogin; + private TemplateDefinition defininition2NoTemplateType; + private List templateDefinitions; + + @BeforeEach + void beforeEach() { + templateDataResolver = mock(); + configuration = mock(); + + filterToTest = new RelevantScanTemplateDefinitionFilter(); + filterToTest.templateDataResolver = templateDataResolver; + + defininition1WebScanLogin = new TemplateDefinition(); + defininition1WebScanLogin.setType(TemplateType.WEBSCAN_LOGIN); + + defininition2NoTemplateType = new TemplateDefinition(); + defininition2NoTemplateType.setType(null); + + templateDefinitions = new ArrayList<>(2); + templateDefinitions.add(defininition1WebScanLogin); + templateDefinitions.add(defininition2NoTemplateType); + + } + + @Test + void webscan_login_definition_inside_result_when_resolver_finds_template_data_and_scan_type_is_web_scan() { + /* prepare */ + TemplateData templateData = mock(); + + when(templateDataResolver.resolveTemplateData(TemplateType.WEBSCAN_LOGIN, configuration)).thenReturn(templateData); + + /* execute */ + List result = filterToTest.filter(templateDefinitions, ScanType.WEB_SCAN, configuration); + + /* test */ + assertThat(result).contains(defininition1WebScanLogin).doesNotContain(defininition2NoTemplateType).hasSize(1); + } + + @ParameterizedTest + @EnumSource(value = ScanType.class, mode = Mode.EXCLUDE, names = "WEB_SCAN") + @NullSource + void webscan_login_definition_not_inside_result_when_resolver_finds_template_data_but_scan_type_is_not_web_scan(ScanType scanType) { + /* prepare */ + TemplateData templateData = mock(); + + when(templateDataResolver.resolveTemplateData(TemplateType.WEBSCAN_LOGIN, configuration)).thenReturn(templateData); + + /* execute */ + List result = filterToTest.filter(templateDefinitions, scanType, configuration); + + /* test */ + assertThat(result).isEmpty(); + } + + @ParameterizedTest + @EnumSource(value = ScanType.class) + @NullSource + void no_login_definition_inside_result_when_resolver_does_not_find_template_data(ScanType scanType) { + /* prepare */ + when(templateDataResolver.resolveTemplateData(TemplateType.WEBSCAN_LOGIN, configuration)).thenReturn(null); + + /* execute */ + List result = filterToTest.filter(templateDefinitions, scanType, configuration); + + /* test */ + assertThat(result).isEmpty(); + } + +} diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupport.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupport.java index 63abcbeae6..ec6eac4871 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupport.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupport.java @@ -14,6 +14,7 @@ import com.mercedesbenz.sechub.commons.mapping.NamePatternIdProvider; import com.mercedesbenz.sechub.commons.mapping.NamePatternIdProviderFactory; import com.mercedesbenz.sechub.commons.model.SecHubRuntimeException; +import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorContext; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfig; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetupCredentials; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetupJobParameter; @@ -41,12 +42,13 @@ public class DefaultExecutorConfigSupport { NamePatternIdProviderFactory providerFactory; - public DefaultExecutorConfigSupport(ProductExecutorConfig config, SystemEnvironmentVariableSupport variableSupport, + public DefaultExecutorConfigSupport(ProductExecutorContext context, SystemEnvironmentVariableSupport variableSupport, Validation validation) { - notNull(config, "config may not be null!"); + notNull(context, "context may not be null!"); + notNull(context.getExecutorConfig(), "executor config may not be null!"); notNull(variableSupport, "variableSupport may not be null!"); - this.config = config; + this.config = context.getExecutorConfig(); this.variableSupport = variableSupport; providerFactory = new NamePatternIdProviderFactory(); diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/DefaultAdapterConfigurationStrategy.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/DefaultAdapterConfigurationStrategy.java index 128cd891bf..3f97199e3f 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/DefaultAdapterConfigurationStrategy.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/DefaultAdapterConfigurationStrategy.java @@ -5,6 +5,7 @@ import com.mercedesbenz.sechub.adapter.AdapterConfigBuilder; import com.mercedesbenz.sechub.adapter.AdapterConfigurationStrategy; import com.mercedesbenz.sechub.adapter.DefaultExecutorConfigSupport; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; import com.mercedesbenz.sechub.commons.model.ScanType; import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorData; @@ -46,7 +47,7 @@ public DefaultAdapterConfigurationStrategy(ProductExecutorData data, DefaultExec } @Override - public void configure(B configBuilder) { + public void configure(B configBuilder) throws ConfigurationFailureException { /* @formatter:off */ SecHubExecutionContext context = data.getSechubExecutionContext(); String projectId = context.getConfiguration().getProjectId(); diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanJobExecutionRunnable.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanJobExecutionRunnable.java index c102279096..8595244d30 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanJobExecutionRunnable.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanJobExecutionRunnable.java @@ -14,6 +14,7 @@ import com.mercedesbenz.sechub.domain.scan.product.WebScanProductExecutionService; import com.mercedesbenz.sechub.sharedkernel.LogConstants; import com.mercedesbenz.sechub.sharedkernel.Step; +import com.mercedesbenz.sechub.sharedkernel.usecases.job.UseCaseSchedulerStartsJob; import com.mercedesbenz.sechub.sharedkernel.usecases.other.UseCaseSystemSuspendsJobsWhenSigTermReceived; /** @@ -36,6 +37,13 @@ public ScanJobRunnableData getRunnableData() { } @Override + @UseCaseSchedulerStartsJob(@Step(number = 3, name = "Runnable calls execution services", + + description = """ + The job execution runnable creates the execution context and calls dedicated execution services + (preparation, analytics, product execution, storage and reporting) synchronously for the job. + It is also responsible for cancelation and supsension of jobs. + """)) public void run() { /* runs in own thread so we set job uuid to MDC here ! */ try { diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanMessageHandler.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanMessageHandler.java index 121c1daf53..9454f811e8 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanMessageHandler.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanMessageHandler.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan; -import java.util.List; +import java.util.Set; import java.util.UUID; import org.slf4j.Logger; @@ -138,7 +138,7 @@ private DomainMessageSynchronousResult handleAssignTemplateToProjectRequest(Doma try { templateService.assignTemplateToProject(templateId, projectId); - List templateIds = templateService.fetchAssignedTemplateIdsForProject(projectId); + Set templateIds = templateService.fetchAssignedTemplateIdsForProject(projectId); return templateAssignmentDone(projectId, templateIds); } catch (Exception e) { return templateAssignmentFailed(e); @@ -154,7 +154,7 @@ private DomainMessageSynchronousResult handleUnassignTemplateFromProjectRequest( try { templateService.unassignTemplateFromProject(templateId, projectId); - List templateIds = templateService.fetchAssignedTemplateIdsForProject(projectId); + Set templateIds = templateService.fetchAssignedTemplateIdsForProject(projectId); return templateUnassignmentDone(projectId, templateIds); } catch (Exception e) { return templateUnassignmentFailed(e); @@ -190,7 +190,7 @@ private DomainMessageSynchronousResult purgeDone(UUID jobUUID) { } @IsSendingSyncMessageAnswer(value = MessageID.RESULT_ASSIGN_TEMPLATE_TO_PROJECT, answeringTo = MessageID.REQUEST_ASSIGN_TEMPLATE_TO_PROJECT, branchName = "success") - private DomainMessageSynchronousResult templateAssignmentDone(String projectId, List assignedTemplates) { + private DomainMessageSynchronousResult templateAssignmentDone(String projectId, Set assignedTemplates) { DomainMessageSynchronousResult result = new DomainMessageSynchronousResult(MessageID.RESULT_ASSIGN_TEMPLATE_TO_PROJECT); SecHubProjectTemplates templates = new SecHubProjectTemplates(); templates.setProjectId(projectId); @@ -207,7 +207,7 @@ private DomainMessageSynchronousResult templateAssignmentFailed(Exception failur } @IsSendingSyncMessageAnswer(value = MessageID.RESULT_UNASSIGN_TEMPLATE_FROM_PROJECT, answeringTo = MessageID.REQUEST_UNASSIGN_TEMPLATE_FROM_PROJECT, branchName = "success") - private DomainMessageSynchronousResult templateUnassignmentDone(String projectId, List assignedTemplates) { + private DomainMessageSynchronousResult templateUnassignmentDone(String projectId, Set assignedTemplates) { DomainMessageSynchronousResult result = new DomainMessageSynchronousResult(MessageID.RESULT_UNASSIGN_TEMPLATE_FROM_PROJECT); SecHubProjectTemplates templates = new SecHubProjectTemplates(); templates.setProjectId(projectId); diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanService.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanService.java index 6ad21e23b4..98f2563fef 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanService.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/ScanService.java @@ -26,6 +26,7 @@ import com.mercedesbenz.sechub.domain.scan.report.CreateScanReportService; import com.mercedesbenz.sechub.domain.scan.report.ScanReport; import com.mercedesbenz.sechub.domain.scan.report.ScanReportException; +import com.mercedesbenz.sechub.domain.scan.template.TemplateService; import com.mercedesbenz.sechub.sharedkernel.MustBeDocumented; import com.mercedesbenz.sechub.sharedkernel.ProgressStateFetcher; import com.mercedesbenz.sechub.sharedkernel.Step; @@ -80,6 +81,9 @@ public class ScanService implements SynchronMessageHandler { @Autowired ScanProgressStateFetcherFactory monitorFactory; + @Autowired + TemplateService templateService; + @MustBeDocumented("Define delay in milliseconds, for before next job cancellation check will be executed.") @Value("${sechub.config.check.canceljob.delay:" + DEFAULT_CHECK_CANCELJOB_DELAY_MILLIS + "}") private int millisecondsToWaitBeforeCancelCheck = DEFAULT_CHECK_CANCELJOB_DELAY_MILLIS; @@ -195,7 +199,7 @@ private void cleanupStorage(SecHubExecutionContext context) { } - private SecHubExecutionContext createExecutionContext(DomainMessage message) throws JSONConverterException { + SecHubExecutionContext createExecutionContext(DomainMessage message) throws JSONConverterException { UUID executionUUID = message.get(SECHUB_EXECUTION_UUID); UUID sechubJobUUID = message.get(SECHUB_JOB_UUID); @@ -206,7 +210,6 @@ private SecHubExecutionContext createExecutionContext(DomainMessage message) thr throw new IllegalStateException("SecHubConfiguration not found in message - so cannot execute!"); } SecHubExecutionContext executionContext = new SecHubExecutionContext(sechubJobUUID, configuration, executedBy, executionUUID); - buildOptions(executionContext); return executionContext; @@ -224,6 +227,10 @@ private void buildOptions(SecHubExecutionContext executionContext) { ScanProjectMockDataConfiguration mockDataConfig = ScanProjectMockDataConfiguration.fromString(data); executionContext.putData(ScanKey.PROJECT_MOCKDATA_CONFIGURATION, mockDataConfig); } + + /* append template definitions */ + executionContext.getTemplateDefinitions().addAll(templateService.fetchAllTemplateDefinitionsForProject(projectId)); + } @Override diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/SecHubExecutionContext.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/SecHubExecutionContext.java index 43f2b7621c..f93e6969d2 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/SecHubExecutionContext.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/SecHubExecutionContext.java @@ -2,13 +2,16 @@ package com.mercedesbenz.sechub.domain.scan; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; import com.mercedesbenz.sechub.domain.scan.product.ProductExecutor; import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorData; import com.mercedesbenz.sechub.sharedkernel.TypedKey; @@ -50,6 +53,8 @@ public class SecHubExecutionContext { private boolean suspended; + private List templateDefinitions = new ArrayList<>(); + public SecHubExecutionContext(UUID sechubJobUUID, SecHubConfiguration configuration, String executedBy, UUID executionUUID) { this(sechubJobUUID, configuration, executedBy, executionUUID, null); } @@ -191,4 +196,8 @@ public boolean isSuspended() { return suspended; } + public List getTemplateDefinitions() { + return templateDefinitions; + } + } diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetRestController.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetRestController.java index d618ce2e3c..370799d02c 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetRestController.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetRestController.java @@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; @@ -20,6 +21,7 @@ import org.springframework.web.multipart.MultipartFile; import com.mercedesbenz.sechub.sharedkernel.APIConstants; +import com.mercedesbenz.sechub.sharedkernel.Profiles; import com.mercedesbenz.sechub.sharedkernel.RoleConstants; import com.mercedesbenz.sechub.sharedkernel.Step; import com.mercedesbenz.sechub.sharedkernel.logging.AuditLogService; @@ -38,6 +40,7 @@ @EnableAutoConfiguration @RequestMapping(APIConstants.API_ADMINISTRATION) @RolesAllowed({ RoleConstants.ROLE_SUPERADMIN }) +@Profile(Profiles.ADMIN_ACCESS) public class AssetRestController { @Autowired diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetService.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetService.java index ed460f2eaf..87ae96193c 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetService.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetService.java @@ -4,10 +4,12 @@ import static com.mercedesbenz.sechub.commons.core.CommonConstants.*; import static com.mercedesbenz.sechub.sharedkernel.util.Assert.*; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Optional; +import java.util.Scanner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,10 +19,10 @@ import org.springframework.web.multipart.MultipartFile; import com.amazonaws.util.StringInputStream; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; import com.mercedesbenz.sechub.commons.core.security.CheckSumSupport; import com.mercedesbenz.sechub.commons.model.SecHubRuntimeException; import com.mercedesbenz.sechub.domain.scan.asset.AssetFile.AssetFileCompositeKey; -import com.mercedesbenz.sechub.sharedkernel.RoleConstants; import com.mercedesbenz.sechub.sharedkernel.Step; import com.mercedesbenz.sechub.sharedkernel.error.BadRequestException; import com.mercedesbenz.sechub.sharedkernel.error.NotAcceptableException; @@ -35,11 +37,9 @@ import com.mercedesbenz.sechub.storage.core.AssetStorage; import com.mercedesbenz.sechub.storage.core.StorageService; -import jakarta.annotation.security.RolesAllowed; import jakarta.servlet.ServletOutputStream; @Service -@RolesAllowed(RoleConstants.ROLE_SUPERADMIN) public class AssetService { private static final Logger LOG = LoggerFactory.getLogger(AssetService.class); @@ -67,36 +67,90 @@ public class AssetService { /* @formatter:on */ @UseCaseAdminUploadsAssetFile(@Step(number = 2, name = "Service tries to upload file for asset", description = "Uploaded file will be stored in database and in storage")) - public void uploadAssetFile(String assetId, MultipartFile file, String checkSum) { + public void uploadAssetFile(String assetId, MultipartFile multipartFile, String checkSum) { inputAssertion.assertIsValidAssetId(assetId); inputAssertion.assertIsValidSha256Checksum(checkSum); - String fileName = assertAssetFile(file); + String fileName = assertAssetFile(multipartFile); - handleChecksumValidation(fileName, file, checkSum, assetId); + handleChecksumValidation(fileName, multipartFile, checkSum, assetId); try { /* now store */ - persistFileAndChecksumInDatabase(fileName, file, checkSum, assetId); + byte[] bytes = multipartFile.getBytes(); + persistFileAndChecksumInDatabase(fileName, bytes, checkSum, assetId); - storeUploadFileAndSha256Checksum(assetId, fileName, file, checkSum); + ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(fileName, assetId); LOG.info("Successfully uploaded file '{}' for asset '{}'", fileName, assetId); } catch (IOException e) { throw new SecHubRuntimeException("Was not able to upload file '" + fileName + "' for asset '" + assetId + "'", e); + } catch (ConfigurationFailureException e) { + throw new IllegalStateException("A configuration failure should not happen at this point!", e); } } - private void persistFileAndChecksumInDatabase(String fileName, MultipartFile file, String checkSum, String assetId) throws IOException { + /** + * Ensures file for asset exists in database and and also in storage (with same + * checksum). If the file is not inside database a {@link NotFoundException} + * will be thrown. If the file is not available in storage, or the checksum in + * storage is different than the checksum from database, the file will stored + * again in storage (with data from database) + * + * @param fileName file name + * @param assetId asset identifier + * @throws ConfigurationFailureException if there are configuration problems + * @throws NotFoundException when the asset or the file is not found + * in database + * + */ + public void ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(String fileName, String assetId) throws ConfigurationFailureException { + + try (AssetStorage assetStorage = storageService.createAssetStorage(assetId)) { + AssetFile assetFile = assertAssetFileFromDatabase(assetId, fileName); + String checksumFromDatabase = assetFile.getChecksum(); + + if (assetStorage.isExisting(fileName)) { + String checksumFileName = fileName + DOT_CHECKSUM; + if (assetStorage.isExisting(checksumFileName)) { + + String checksumFromStorage = null; + try (InputStream inputStream = assetStorage.fetch(checksumFileName); Scanner scanner = new Scanner(inputStream)) { + checksumFromStorage = scanner.hasNext() ? scanner.next() : ""; + } + if (checksumFromStorage.equals(checksumFromDatabase)) { + LOG.debug("Checksum for file '{}' in asset '{}' is '{}' in database and storage. Can be kept, no recration necessary", fileName, + assetId, checksumFromStorage, checksumFromDatabase); + return; + } + LOG.warn( + "Checksum for file '{}' in asset '{}' was '{}' instead of expected value from database '{}'. Will recreated file and checksum in storage.", + fileName, assetId, checksumFromStorage, checksumFromDatabase); + } else { + LOG.warn("Asset storage for file '{}' in asset '{}' did exist, but checksum did not exist. Will recreated file and checksum in storage.", + fileName, assetId); + } + } else { + LOG.info("Asset storage for file '{}' in asset '{}' does not exist and must be created.", fileName, assetId); + } + storeStream(fileName, checksumFromDatabase, assetStorage, assetFile.getData().length, new ByteArrayInputStream(assetFile.getData())); + + } catch (NotFoundException | IOException e) { + throw new ConfigurationFailureException("Was not able to ensure file " + fileName + " in asset " + assetId, e); + } + + } + + private void persistFileAndChecksumInDatabase(String fileName, byte[] bytes, String checkSum, String assetId) throws IOException { /* delete if exists */ AssetFileCompositeKey key = AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build(); repository.deleteById(key); AssetFile assetFile = new AssetFile(key); assetFile.setChecksum(checkSum); - assetFile.setData(file.getBytes()); + assetFile.setData(bytes); repository.save(assetFile); } @@ -133,29 +187,11 @@ private void assertCheckSumCorrect(String checkSum, InputStream inputStream) { } } - private void storeUploadFileAndSha256Checksum(String assetId, String fileName, MultipartFile file, String checkSum) { - AssetStorage assetStorage = storageService.createAssetStorage(assetId); - try { - store(assetId, fileName, file, checkSum, assetStorage); - } finally { - assetStorage.close(); - } - } - - private void store(String assetId, String fileName, MultipartFile file, String checkSum, AssetStorage assetStorage) { - - try (InputStream inputStream = file.getInputStream()) { - - long fileSize = file.getSize(); - assetStorage.store(fileName, inputStream, fileSize); - - long checksumSizeInBytes = checkSum.getBytes().length; - assetStorage.store(createFileNameForChecksum(fileName), new StringInputStream(checkSum), checksumSizeInBytes); + private void storeStream(String fileName, String checkSum, AssetStorage assetStorage, long fileSize, InputStream inputStream) throws IOException { + assetStorage.store(fileName, inputStream, fileSize); - } catch (IOException e) { - LOG.error("Was not able to store file '{}' for asset '{}' !", fileName, assetId, e); - throw new SecHubRuntimeException("Was not able to upload file '" + fileName + " for asset '" + assetId + "'"); - } + long checksumSizeInBytes = checkSum.getBytes().length; + assetStorage.store(createFileNameForChecksum(fileName), new StringInputStream(checkSum), checksumSizeInBytes); } private String createFileNameForChecksum(String fileName) { @@ -169,14 +205,19 @@ public void downloadAssetFile(String assetId, String fileName, ServletOutputStre notNull(outputStream, "output stream may not be null!"); + AssetFile assetFile = assertAssetFileFromDatabase(assetId, fileName); + outputStream.write(assetFile.getData()); + + } + + private AssetFile assertAssetFileFromDatabase(String assetId, String fileName) { AssetFileCompositeKey key = AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build(); Optional result = repository.findById(key); if (result.isEmpty()) { throw new NotFoundException("For asset:" + assetId + " no file with name:" + fileName + " exists!"); } AssetFile assetFile = result.get(); - outputStream.write(assetFile.getData()); - + return assetFile; } @UseCaseAdminFetchesAssetIds(@Step(number = 2, name = "Service fetches all asset ids from database")) @@ -184,6 +225,13 @@ public List fetchAllAssetIds() { return repository.fetchAllAssetIds(); } + /** + * Fetches asset details (from database) + * + * @param assetId asset identifier + * @return detail data + * @throws NotFoundException when no asset exists for given identifier + */ @UseCaseAdminFetchesAssetDetails(@Step(number = 2, name = "Service fetches asset details for given asset id")) public AssetDetailData fetchAssetDetails(String assetId) { inputAssertion.assertIsValidAssetId(assetId); diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextFactory.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextFactory.java index 2ff0b373ad..76e0f72049 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextFactory.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextFactory.java @@ -15,12 +15,12 @@ public class ProductExecutorContextFactory { @Autowired ProductResultTransactionService transactionService; - public ProductExecutorContext create(List formerResults, SecHubExecutionContext executionContext, ProductExecutor productExecutor, + public ProductExecutorContext create(List formerResults, SecHubExecutionContext sechubExecutionContext, ProductExecutor productExecutor, ProductExecutorConfig config) { ProductExecutorContext productExecutorContext = new ProductExecutorContext(config, formerResults); - ProductExecutorCallbackImpl callback = new ProductExecutorCallbackImpl(executionContext, productExecutorContext, transactionService); + ProductExecutorCallbackImpl callback = new ProductExecutorCallbackImpl(sechubExecutionContext, productExecutorContext, transactionService); productExecutorContext.callback = callback; productExecutorContext.useFirstFormerResult(); diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateRestController.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateRestController.java index 7e123d8235..54f4b3edff 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateRestController.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateRestController.java @@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Profile; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -15,6 +16,7 @@ import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; import com.mercedesbenz.sechub.sharedkernel.APIConstants; +import com.mercedesbenz.sechub.sharedkernel.Profiles; import com.mercedesbenz.sechub.sharedkernel.RoleConstants; import com.mercedesbenz.sechub.sharedkernel.Step; import com.mercedesbenz.sechub.sharedkernel.logging.AuditLogService; @@ -30,6 +32,7 @@ @EnableAutoConfiguration @RequestMapping(APIConstants.API_ADMINISTRATION) @RolesAllowed({ RoleConstants.ROLE_SUPERADMIN }) +@Profile(Profiles.ADMIN_ACCESS) public class TemplateRestController { @Autowired diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateService.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateService.java index 9c4bd51a11..48e57fc8f5 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateService.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateService.java @@ -2,6 +2,7 @@ package com.mercedesbenz.sechub.domain.scan.template; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -17,7 +18,6 @@ import com.mercedesbenz.sechub.domain.scan.project.ScanProjectConfig; import com.mercedesbenz.sechub.domain.scan.project.ScanProjectConfigID; import com.mercedesbenz.sechub.domain.scan.project.ScanProjectConfigService; -import com.mercedesbenz.sechub.sharedkernel.RoleConstants; import com.mercedesbenz.sechub.sharedkernel.Step; import com.mercedesbenz.sechub.sharedkernel.error.NotFoundException; import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminAssignsTemplateToProject; @@ -28,10 +28,7 @@ import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminUnassignsTemplateFromProject; import com.mercedesbenz.sechub.sharedkernel.validation.UserInputAssertion; -import jakarta.annotation.security.RolesAllowed; - @Service -@RolesAllowed(RoleConstants.ROLE_SUPERADMIN) public class TemplateService { private static final Logger LOG = LoggerFactory.getLogger(TemplateService.class); @@ -177,8 +174,14 @@ public void unassignTemplateFromProject(String templateId, String projectId) { LOG.info("unassigned template '{}' from project '{}'", templateId, projectId); } - public List fetchAssignedTemplateIdsForProject(String projectId) { - List result = new ArrayList<>(); + /** + * Fetches all template identifiers for given project + * + * @param projectId project identifier + * @return set with identifiers, never null + */ + public Set fetchAssignedTemplateIdsForProject(String projectId) { + Set result = new LinkedHashSet<>(); for (TemplateType type : TemplateType.values()) { ScanProjectConfigID configId = resolver.resolve(type); ScanProjectConfig config = configService.get(projectId, configId, false); @@ -191,4 +194,20 @@ public List fetchAssignedTemplateIdsForProject(String projectId) { return result; } + /** + * Fetches all template definitions for given project + * + * @param projectId project identifier + * @return list of template definitions, never null + */ + public List fetchAllTemplateDefinitionsForProject(String projectId) { + List result = new ArrayList<>(); + Set templateIds = fetchAssignedTemplateIdsForProject(projectId); + for (String templateId : templateIds) { + TemplateDefinition templateDefinition = fetchTemplateDefinition(templateId); + result.add(templateDefinition); + } + return result; + } + } diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupportTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupportTest.java index 793506b90b..36227db6b2 100644 --- a/sechub-scan/src/test/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupportTest.java +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/adapter/DefaultExecutorConfigSupportTest.java @@ -11,6 +11,7 @@ import org.junit.Test; import com.mercedesbenz.sechub.commons.core.environment.SystemEnvironmentVariableSupport; +import com.mercedesbenz.sechub.domain.scan.product.ProductExecutorContext; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfig; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetup; import com.mercedesbenz.sechub.domain.scan.product.config.ProductExecutorConfigSetupCredentials; @@ -23,10 +24,13 @@ public class DefaultExecutorConfigSupportTest { private ProductExecutorConfigSetupCredentials credentialsInConfigSetup; private SystemEnvironmentVariableSupport environmentVariableSupport; private List jobParameters; + private ProductExecutorContext context; @Before public void before() throws Exception { config = mock(ProductExecutorConfig.class); + context = mock(); + when(context.getExecutorConfig()).thenReturn(config); setup = mock(ProductExecutorConfigSetup.class); jobParameters = new ArrayList<>(); @@ -44,7 +48,7 @@ public void before() throws Exception { when(setup.getJobParameters()).thenReturn(jobParameters); environmentVariableSupport = mock(SystemEnvironmentVariableSupport.class); - supportToTest = new DefaultExecutorConfigSupport(config, environmentVariableSupport, null); + supportToTest = new DefaultExecutorConfigSupport(context, environmentVariableSupport, null); } @Test diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/ScanServiceTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/ScanServiceTest.java index 4d95118bd9..49fbf41d06 100644 --- a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/ScanServiceTest.java +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/ScanServiceTest.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -9,13 +9,14 @@ import java.util.List; import java.util.UUID; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.core.task.TaskExecutor; import com.mercedesbenz.sechub.commons.model.JSONConverterException; import com.mercedesbenz.sechub.commons.model.TrafficLight; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; import com.mercedesbenz.sechub.domain.scan.log.ProjectScanLogService; import com.mercedesbenz.sechub.domain.scan.product.AnalyticsProductExecutionService; import com.mercedesbenz.sechub.domain.scan.product.CodeScanProductExecutionService; @@ -31,6 +32,7 @@ import com.mercedesbenz.sechub.domain.scan.project.ScanProjectMockDataConfiguration; import com.mercedesbenz.sechub.domain.scan.report.CreateScanReportService; import com.mercedesbenz.sechub.domain.scan.report.ScanReport; +import com.mercedesbenz.sechub.domain.scan.template.TemplateService; import com.mercedesbenz.sechub.sharedkernel.ProgressState; import com.mercedesbenz.sechub.sharedkernel.ProgressStateFetcher; import com.mercedesbenz.sechub.sharedkernel.configuration.SecHubConfiguration; @@ -71,41 +73,41 @@ public class ScanServiceTest { private PrepareProductExecutionService prepareProductExecutionService; private SecretScanProductExecutionService secretScanProductExecutionService; private ProgressState progressState; + private TemplateService templateService; private static final SecHubConfiguration SECHUB_CONFIG = new SecHubConfiguration(); - @Before - public void before() throws Exception { - storageService = mock(SecHubStorageService.class); - jobStorage = mock(JobStorage.class); - scanProjectConfigService = mock(ScanProjectConfigService.class); - scanJobListener = mock(ScanJobListener.class); - stateFetcherFactory = mock(ScanProgressStateFetcherFactory.class); - ProgressStateFetcher progressStateFetcher = mock(ProgressStateFetcher.class); - progressState = mock(ProgressState.class); + @BeforeEach + void before() throws Exception { + storageService = mock(); + jobStorage = mock(); + scanProjectConfigService = mock(); + scanJobListener = mock(); + stateFetcherFactory = mock(); + ProgressStateFetcher progressStateFetcher = mock(); + progressState = mock(); + templateService = mock(); when(storageService.createJobStorageForProject(any(), any())).thenReturn(jobStorage); when(stateFetcherFactory.createProgressStateFetcher(any())).thenReturn(progressStateFetcher); when(progressStateFetcher.fetchProgressState()).thenReturn(progressState); - webScanProductExecutionService = mock(WebScanProductExecutionService.class); - codeScanProductExecutionService = mock(CodeScanProductExecutionService.class); - infrastructureScanProductExecutionService = mock(InfrastructureScanProductExecutionService.class); - licenseScanProductExecutionService = mock(LicenseScanProductExecutionService.class); - analyticsProductExecutionService = mock(AnalyticsProductExecutionService.class); - prepareProductExecutionService = mock(PrepareProductExecutionService.class); - secretScanProductExecutionService = mock(SecretScanProductExecutionService.class); + webScanProductExecutionService = mock(); + codeScanProductExecutionService = mock(); + infrastructureScanProductExecutionService = mock(); + licenseScanProductExecutionService = mock(); + analyticsProductExecutionService = mock(); + prepareProductExecutionService = mock(); + secretScanProductExecutionService = mock(); + scanLogService = mock(); + reportService = mock(); + report = mock(); + productExecutionServiceContainer = mock(); - scanLogService = mock(ProjectScanLogService.class); - - reportService = mock(CreateScanReportService.class); - report = mock(ScanReport.class); when(report.getTrafficLightAsString()).thenReturn(TRAFFIC_LIGHT); when(reportService.createReport(any())).thenReturn(report); serviceToTest = new ScanService(); - productExecutionServiceContainer = mock(ProductExecutionServiceContainer.class); - serviceToTest.productExecutionServiceContainer = productExecutionServiceContainer; when(productExecutionServiceContainer.getWebScanProductExecutionService()).thenReturn(webScanProductExecutionService); when(productExecutionServiceContainer.getInfraScanProductExecutionService()).thenReturn(infrastructureScanProductExecutionService); @@ -121,20 +123,22 @@ public void before() throws Exception { serviceToTest.scanProjectConfigService = scanProjectConfigService; serviceToTest.scanJobListener = scanJobListener; serviceToTest.monitorFactory = stateFetcherFactory; + serviceToTest.productExecutionServiceContainer = productExecutionServiceContainer; + serviceToTest.templateService = templateService; } @Test - public void when_no_exception_is_thrown_result_has_not_failed() throws Exception { + void when_no_exception_is_thrown_result_has_not_failed() throws Exception { /* execute */ DomainMessageSynchronousResult result = serviceToTest.receiveSynchronMessage(prepareValidRequest()); /* test */ - assertFalse(result.hasFailed()); + assertThat(result.hasFailed()).isFalse(); } @Test - public void scanservice_does_execute_webscan_execution_service() throws Exception { + void scanservice_does_execute_webscan_execution_service() throws Exception { /* execute */ serviceToTest.receiveSynchronMessage(prepareValidRequest()); @@ -144,7 +148,7 @@ public void scanservice_does_execute_webscan_execution_service() throws Exceptio } @Test - public void scanservice_does_execute_infrascan_execution_service() throws Exception { + void scanservice_does_execute_infrascan_execution_service() throws Exception { /* execute */ serviceToTest.receiveSynchronMessage(prepareValidRequest()); @@ -154,7 +158,7 @@ public void scanservice_does_execute_infrascan_execution_service() throws Except } @Test - public void scanservice_does_execute_codescan_execution_service() throws Exception { + void scanservice_does_execute_codescan_execution_service() throws Exception { /* execute */ serviceToTest.receiveSynchronMessage(prepareValidRequest()); @@ -164,7 +168,7 @@ public void scanservice_does_execute_codescan_execution_service() throws Excepti } @Test - public void scanservice_does_execute_prepare_execution_service() throws Exception { + void scanservice_does_execute_prepare_execution_service() throws Exception { /* execute */ serviceToTest.receiveSynchronMessage(prepareValidRequest()); @@ -174,14 +178,14 @@ public void scanservice_does_execute_prepare_execution_service() throws Exceptio } @Test - public void scanservice_does_cleanup_storage_of_job__when_not_failed() throws Exception { + void scanservice_does_cleanup_storage_of_job__when_not_failed() throws Exception { /* execute */ DomainMessageSynchronousResult result = serviceToTest.receiveSynchronMessage(prepareValidRequest()); /* test */ verify(jobStorage).deleteAll(); - assertFalse(result.hasFailed()); + assertThat(result.hasFailed()).isFalse(); } /** @@ -194,7 +198,7 @@ public void scanservice_does_cleanup_storage_of_job__when_not_failed() throws Ex * @throws Exception */ @Test - public void scanservice_does_cleanup_storage_of_job__when_HAS_failed() throws Exception { + void scanservice_does_cleanup_storage_of_job__when_HAS_failed() throws Exception { /* prepare */ DomainMessage request = prepareValidRequest(); @@ -205,13 +209,13 @@ public void scanservice_does_cleanup_storage_of_job__when_HAS_failed() throws Ex DomainMessageSynchronousResult result = serviceToTest.receiveSynchronMessage(request); /* test */ - assertTrue(result.hasFailed()); + assertThat(result.hasFailed()).isTrue(); verify(jobStorage/* when retry implemented:,never() */).deleteAll(); } @Test - public void scanservice_does_execute_report_service() throws Exception { + void scanservice_does_execute_report_service() throws Exception { /* execute */ serviceToTest.receiveSynchronMessage(prepareValidRequest()); @@ -221,17 +225,17 @@ public void scanservice_does_execute_report_service() throws Exception { } @Test - public void scanservice_set_result_traficlight_as_from_report() throws Exception { + void scanservice_set_result_traficlight_as_from_report() throws Exception { /* execute */ DomainMessageSynchronousResult result = serviceToTest.receiveSynchronMessage(prepareValidRequest()); /* test */ - assertEquals(TRAFFIC_LIGHT, result.get(MessageDataKeys.REPORT_TRAFFIC_LIGHT)); + assertThat(result.get(MessageDataKeys.REPORT_TRAFFIC_LIGHT)).isEqualTo(TRAFFIC_LIGHT); } @Test - public void scanservice_does_NOT_execute_reportservice_when_webscan_throws_sechubexception() throws Exception { + void scanservice_does_NOT_execute_reportservice_when_webscan_throws_sechubexception() throws Exception { /* prepare */ DomainMessage request = prepareValidRequest(); @@ -242,7 +246,7 @@ public void scanservice_does_NOT_execute_reportservice_when_webscan_throws_sechu DomainMessageSynchronousResult result = serviceToTest.receiveSynchronMessage(request); /* test */ - assertTrue(result.hasFailed()); + assertThat(result.hasFailed()).isTrue(); verify(webScanProductExecutionService).executeProductsAndStoreResults(any()); verify(reportService, never()).createReport(any()); @@ -250,7 +254,7 @@ public void scanservice_does_NOT_execute_reportservice_when_webscan_throws_sechu } @Test - public void event_handling_works_as_expected_and_SCAN_DONE_is_returned_as_resulting_message_id() { + void event_handling_works_as_expected_and_SCAN_DONE_is_returned_as_resulting_message_id() { /* prepare */ DomainMessage request = prepareValidRequest(); @@ -258,11 +262,11 @@ public void event_handling_works_as_expected_and_SCAN_DONE_is_returned_as_result DomainMessageSynchronousResult result = simulateEventSend(request, serviceToTest); /* test */ - assertEquals(MessageID.SCAN_DONE, result.getMessageId()); + assertThat(result.getMessageId()).isEqualTo(MessageID.SCAN_DONE); } @Test - public void event_handling_FAILED_when_configuration_is_not_set() { + void event_handling_FAILED_when_configuration_is_not_set() { /* prepare */ DomainMessage request = prepareValidRequest(); request.set(MessageDataKeys.SECHUB_UNENCRYPTED_CONFIG, null); @@ -271,11 +275,11 @@ public void event_handling_FAILED_when_configuration_is_not_set() { DomainMessageSynchronousResult result = simulateEventSend(request, serviceToTest); /* test */ - assertEquals(MessageID.SCAN_FAILED, result.getMessageId()); + assertThat(result.getMessageId()).isEqualTo(MessageID.SCAN_FAILED); } @Test - public void event_handling_FAILED_when_configuration_is_set_but_contains_no_projectId() { + void event_handling_FAILED_when_configuration_is_set_but_contains_no_projectId() { /* prepare */ SecHubConfiguration configNoProjectId = prepareValidConfiguration(); configNoProjectId.setProjectId(null); @@ -285,11 +289,11 @@ public void event_handling_FAILED_when_configuration_is_set_but_contains_no_proj DomainMessageSynchronousResult result = simulateEventSend(request, serviceToTest); /* test */ - assertEquals(MessageID.SCAN_FAILED, result.getMessageId()); + assertThat(result.getMessageId()).isEqualTo(MessageID.SCAN_FAILED); } @Test - public void scan_service_fetches_configuration_without_accesscheck() throws Exception { + void scan_service_fetches_configuration_without_accesscheck() throws Exception { /* prepare */ SecHubConfiguration configNoProjectId = prepareValidConfiguration(); DomainMessage request = prepareRequest(configNoProjectId); @@ -302,7 +306,7 @@ public void scan_service_fetches_configuration_without_accesscheck() throws Exce } @Test - public void scan_service_fetches_mock_configuration_and_puts_mock_project_configuration_complete_in_execution_context() throws Exception { + void scan_service_fetches_mock_configuration_and_puts_mock_project_configuration_complete_in_execution_context() throws Exception { /* prepare */ SecHubConfiguration configNoProjectId = prepareValidConfiguration(); DomainMessage request = prepareRequest(configNoProjectId); @@ -322,7 +326,27 @@ public void scan_service_fetches_mock_configuration_and_puts_mock_project_config ArgumentCaptor contextCaptor = ArgumentCaptor.forClass(SecHubExecutionContext.class); verify(codeScanProductExecutionService).executeProductsAndStoreResults(contextCaptor.capture()); SecHubExecutionContext context = contextCaptor.getValue(); - assertEquals(projectMockDataConfig, context.getData(ScanKey.PROJECT_MOCKDATA_CONFIGURATION)); + assertThat(context.getData(ScanKey.PROJECT_MOCKDATA_CONFIGURATION)).isEqualTo(projectMockDataConfig); + } + + @Test + void created_sechub_execution_context_for_scan_has_template_ids_for_project_inside() { + /* prepare */ + DomainMessage message = mock(); + SecHubConfiguration sechubConfiguration = mock(); + when(sechubConfiguration.getProjectId()).thenReturn("project1"); + when(message.get(MessageDataKeys.SECHUB_UNENCRYPTED_CONFIG)).thenReturn(sechubConfiguration); + + List definitionList = new ArrayList<>(); + TemplateDefinition definition1 = mock(); + definitionList.add(definition1); + when(templateService.fetchAllTemplateDefinitionsForProject("project1")).thenReturn(definitionList); + + /* execute */ + SecHubExecutionContext result = serviceToTest.createExecutionContext(message); + + /* test */ + assertThat(result.getTemplateDefinitions()).contains(definition1).hasSize(1); } private DomainMessage prepareValidRequest() { diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetServiceTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetServiceTest.java index 46b99ab8e6..95a1483efe 100644 --- a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetServiceTest.java +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetServiceTest.java @@ -4,14 +4,20 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import com.mercedesbenz.sechub.commons.core.ConfigurationFailureException; import com.mercedesbenz.sechub.commons.core.security.CheckSumSupport; import com.mercedesbenz.sechub.domain.scan.asset.AssetFile.AssetFileCompositeKey; import com.mercedesbenz.sechub.sharedkernel.validation.UserInputAssertion; +import com.mercedesbenz.sechub.storage.core.AssetStorage; import com.mercedesbenz.sechub.storage.core.StorageService; class AssetServiceTest { @@ -73,6 +79,179 @@ void fetchAssetDetails_returns_details_based_on_repo_info() { assertThat(result.getFiles()).contains(expectedInfo1, expectedInfo2); } + @Test + void ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase_throws_config_failure_when_not_in_database() throws Exception { + /* prepare */ + String assetId = "asset1"; + String fileName = "file1.zip"; + AssetFileCompositeKey key = AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build(); + + when(repository.findById(key)).thenReturn(Optional.empty()); + + /* execute + test */ + assertThatThrownBy(() -> serviceToTest.ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(fileName, assetId)) + .isInstanceOf(ConfigurationFailureException.class); + + } + + @Test + void ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase_not_in_storage_creates_it() throws Exception { + /* prepare */ + String assetId = "asset1"; + String fileName = "file1.zip"; + String content = "testbytes"; + long contentSize = content.length(); + String checksum = "checksum"; + long checksumSize = checksum.length(); + byte[] bytes = content.getBytes(); + AssetFileCompositeKey key = AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build(); + + AssetFile assetFile = mock(); + when(assetFile.getChecksum()).thenReturn(checksum); + when(assetFile.getData()).thenReturn(bytes); + when(assetFile.getKey()).thenReturn(key); + + when(repository.findById(key)).thenReturn(Optional.of(assetFile)); + AssetStorage assetStorage = mock(); + when(storageService.createAssetStorage(assetId)).thenReturn(assetStorage); + + when(assetStorage.isExisting(fileName)).thenReturn(false); + + /* execute */ + serviceToTest.ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(fileName, assetId); + + /* test */ + verify(storageService).createAssetStorage(assetId); + verify(assetStorage).isExisting(fileName); + + ArgumentCaptor streamCaptor = ArgumentCaptor.captor(); + verify(assetStorage).store(eq(fileName), streamCaptor.capture(), eq(contentSize)); + assertThat(streamCaptor.getValue()).hasBinaryContent(bytes); + + ArgumentCaptor streamCaptor2 = ArgumentCaptor.captor(); + verify(assetStorage).store(eq(fileName + ".checksum"), streamCaptor2.capture(), eq(checksumSize)); + assertThat(streamCaptor2.getValue()).hasContent(checksum); + + } + + @Test + void ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase_file_in_storage_but_no_checksum_fie_creates_it() throws Exception { + /* prepare */ + String assetId = "asset1"; + String fileName = "file1.zip"; + String content = "testbytes"; + long contentSize = content.length(); + String checksum = "checksum"; + long checksumSize = checksum.length(); + byte[] bytes = content.getBytes(); + AssetFileCompositeKey key = AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build(); + + AssetFile assetFile = mock(); + when(assetFile.getChecksum()).thenReturn(checksum); + when(assetFile.getData()).thenReturn(bytes); + when(assetFile.getKey()).thenReturn(key); + + when(repository.findById(key)).thenReturn(Optional.of(assetFile)); + AssetStorage assetStorage = mock(); + when(storageService.createAssetStorage(assetId)).thenReturn(assetStorage); + + when(assetStorage.isExisting(fileName)).thenReturn(true); + when(assetStorage.isExisting(fileName + ".checksum")).thenReturn(false); + + /* execute */ + serviceToTest.ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(fileName, assetId); + + /* test */ + verify(storageService).createAssetStorage(assetId); + verify(assetStorage).isExisting(fileName); + + ArgumentCaptor streamCaptor = ArgumentCaptor.captor(); + verify(assetStorage).store(eq(fileName), streamCaptor.capture(), eq(contentSize)); + assertThat(streamCaptor.getValue()).hasBinaryContent(bytes); + + ArgumentCaptor streamCaptor2 = ArgumentCaptor.captor(); + verify(assetStorage).store(eq(fileName + ".checksum"), streamCaptor2.capture(), eq(checksumSize)); + assertThat(streamCaptor2.getValue()).hasContent(checksum); + + } + + @Test + void ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase_in_storage_but_checksum_difers_recreates_it() throws Exception { + /* prepare */ + String assetId = "asset1"; + String fileName = "file1.zip"; + String content = "testbytes"; + long contentSize = content.length(); + String checksum = "checksum"; + long checksumSize = checksum.length(); + byte[] bytes = content.getBytes(); + AssetFileCompositeKey key = AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build(); + + AssetFile assetFile = mock(); + when(assetFile.getChecksum()).thenReturn(checksum); + when(assetFile.getData()).thenReturn(bytes); + when(assetFile.getKey()).thenReturn(key); + + when(repository.findById(key)).thenReturn(Optional.of(assetFile)); + AssetStorage assetStorage = mock(); + when(storageService.createAssetStorage(assetId)).thenReturn(assetStorage); + + when(assetStorage.isExisting(fileName)).thenReturn(true); + when(assetStorage.isExisting(fileName + ".checksum")).thenReturn(true); + when(assetStorage.fetch(fileName + ".checksum")).thenReturn(mock()); + + /* execute */ + serviceToTest.ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(fileName, assetId); + + /* test */ + verify(storageService).createAssetStorage(assetId); + verify(assetStorage).isExisting(fileName); + + ArgumentCaptor streamCaptor = ArgumentCaptor.captor(); + verify(assetStorage).store(eq(fileName), streamCaptor.capture(), eq(contentSize)); + assertThat(streamCaptor.getValue()).hasBinaryContent(bytes); + + ArgumentCaptor streamCaptor2 = ArgumentCaptor.captor(); + verify(assetStorage).store(eq(fileName + ".checksum"), streamCaptor2.capture(), eq(checksumSize)); + assertThat(streamCaptor2.getValue()).hasContent(checksum); + + } + + @Test + void ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase_in_storage_and_checksum_same_no_recreation() throws Exception { + /* prepare */ + String assetId = "asset1"; + String fileName = "file1.zip"; + String content = "testbytes"; + String checksum = "checksum"; + byte[] bytes = content.getBytes(); + AssetFileCompositeKey key = AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build(); + + AssetFile assetFile = mock(); + when(assetFile.getChecksum()).thenReturn(checksum); + when(assetFile.getData()).thenReturn(bytes); + when(assetFile.getKey()).thenReturn(key); + + when(repository.findById(key)).thenReturn(Optional.of(assetFile)); + AssetStorage assetStorage = mock(); + when(storageService.createAssetStorage(assetId)).thenReturn(assetStorage); + + when(assetStorage.isExisting(fileName)).thenReturn(true); + when(assetStorage.isExisting(fileName + ".checksum")).thenReturn(true); + when(assetStorage.fetch(fileName + ".checksum")).thenReturn(new ByteArrayInputStream(checksum.getBytes())); + + /* execute */ + serviceToTest.ensureAssetFileInStorageAvailableAndHasSameChecksumAsInDatabase(fileName, assetId); + + /* test */ + verify(storageService).createAssetStorage(assetId); + verify(assetStorage).isExisting(fileName); + verify(assetStorage).isExisting(fileName + ".checksum"); + + verify(assetStorage, never()).store(anyString(), any(InputStream.class), anyLong()); + + } + private AssetFile createAssetFileMock(String fileName, String checksum) { AssetFileCompositeKey mockKey1 = mock(AssetFileCompositeKey.class); when(mockKey1.getFileName()).thenReturn(fileName); diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextTest.java index 98c03a9ce4..da5faf3b83 100644 --- a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextTest.java +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/product/ProductExecutorContextTest.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan.product; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; import java.util.ArrayList; @@ -22,7 +22,8 @@ public class ProductExecutorContextTest { @Before public void before() { - formerResults = new ArrayList(); + formerResults = new ArrayList<>(); + callback = mock(ProductExecutorCallback.class); config = mock(ProductExecutorConfig.class); when(callback.getMetaDataConverter()).thenReturn(converter); @@ -69,7 +70,7 @@ public void formerResults_1_result_with_metadata__results_in_metadata_from_callb /* test */ verify(callback).getMetaDataOrNull(); - assertEquals(result, metaData); + assertThat(result).isEqualTo(metaData); } @Test diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateServiceTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateServiceTest.java index ce75f651e7..ed1610d7b1 100644 --- a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateServiceTest.java +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateServiceTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import java.util.List; import java.util.Optional; import java.util.Set; @@ -14,6 +15,8 @@ import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition.TemplateVariable; import com.mercedesbenz.sechub.commons.model.template.TemplateType; +import com.mercedesbenz.sechub.domain.scan.project.ScanProjectConfig; +import com.mercedesbenz.sechub.domain.scan.project.ScanProjectConfigID; import com.mercedesbenz.sechub.domain.scan.project.ScanProjectConfigService; import com.mercedesbenz.sechub.sharedkernel.validation.UserInputAssertion; @@ -97,7 +100,7 @@ void update_createOrUpdateTemplate_stores_existing_template_with_new_template_de TemplateDefinition existingTemplateDefinition = new TemplateDefinition(); existingTemplateDefinition.setId(templateId); existingTemplateDefinition.setType(TemplateType.WEBSCAN_LOGIN); - existingTemplateDefinition.getAssets().add("asset1"); + existingTemplateDefinition.setAssetId("asset1"); existingTemplateDefinition.getVariables().add(variable1); Template existingTemplate = new Template(templateId); @@ -166,4 +169,40 @@ void fetch_returns_definition_from_repo() { assertThat(result.toFormattedJSON()).isEqualTo(def.toFormattedJSON()); } + @Test + void fetchAssignedTemplateIdsForProject() { + /* prepare */ + when(resolver.resolve(TemplateType.WEBSCAN_LOGIN)).thenReturn(ScanProjectConfigID.TEMPLATE_WEBSCAN_LOGIN); + ScanProjectConfig config = mock(); + when(configService.get("project1",ScanProjectConfigID.TEMPLATE_WEBSCAN_LOGIN, false)).thenReturn(config); + when(config.getData()).thenReturn("template-id-1"); + + /* execute */ + Set result = serviceToTest.fetchAssignedTemplateIdsForProject("project1"); + assertThat(result).contains("template-id-1").hasSize(1); + } + + @Test + void fetch_template_definitions_for_project() { + /* prepare */ + + when(resolver.resolve(TemplateType.WEBSCAN_LOGIN)).thenReturn(ScanProjectConfigID.TEMPLATE_WEBSCAN_LOGIN); + ScanProjectConfig config = mock(); + when(configService.get("project1",ScanProjectConfigID.TEMPLATE_WEBSCAN_LOGIN, false)).thenReturn(config); + when(config.getData()).thenReturn("template1"); + + Template template1Entity = mock(); + TemplateDefinition t1 = TemplateDefinition.builder().assetId("asset1").templateId("template1").templateType(TemplateType.WEBSCAN_LOGIN).build(); + when(template1Entity.getDefinition()).thenReturn(t1.toFormattedJSON()); + + when(repository.findById("template1")).thenReturn(Optional.of(template1Entity)); + + /* execute */ + List templateDefinitions = serviceToTest.fetchAllTemplateDefinitionsForProject("project1"); + + /* test */ + assertThat(templateDefinitions).contains(t1); + + } + } diff --git a/sechub-server/src/main/java/com/mercedesbenz/sechub/server/SecHubServerPojoFactory.java b/sechub-server/src/main/java/com/mercedesbenz/sechub/server/SecHubServerPojoFactory.java index f2fe11be02..61a3f5cfc7 100644 --- a/sechub-server/src/main/java/com/mercedesbenz/sechub/server/SecHubServerPojoFactory.java +++ b/sechub-server/src/main/java/com/mercedesbenz/sechub/server/SecHubServerPojoFactory.java @@ -12,6 +12,7 @@ import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModelSupport; import com.mercedesbenz.sechub.commons.model.SecHubConfigurationModelValidator; import com.mercedesbenz.sechub.commons.model.TrafficLightSupport; +import com.mercedesbenz.sechub.commons.model.template.TemplateDataResolver; /** * This factory creates some "plain old java" objects and inject them into @@ -58,4 +59,9 @@ SecHubConfigurationModelSupport createSecHubConfigurationModelSupport() { SecHubConfigurationModelValidator createSecHubConfigurationValidator() { return new SecHubConfigurationModelValidator(); } + + @Bean + TemplateDataResolver createTemplateDataResolver() { + return new TemplateDataResolver(); + } } diff --git a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/Storage.java b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/Storage.java index ebda370946..78c040abd7 100644 --- a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/Storage.java +++ b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/Storage.java @@ -5,7 +5,7 @@ import java.io.InputStream; import java.util.Set; -public interface Storage { +public interface Storage extends AutoCloseable { /** * Stores given stream a storage object