diff --git a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectDetailInformationTest.java b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectDetailInformationTest.java index 200158329..09b897058 100644 --- a/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectDetailInformationTest.java +++ b/sechub-administration/src/test/java/com/mercedesbenz/sechub/domain/administration/project/ProjectDetailInformationTest.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.administration.project; import static org.assertj.core.api.Assertions.*; diff --git a/sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/util/SecHubStorageUtil.java b/sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/util/SecHubStorageUtil.java index c5b1b5940..6279b686c 100644 --- a/sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/util/SecHubStorageUtil.java +++ b/sechub-commons-core/src/main/java/com/mercedesbenz/sechub/commons/core/util/SecHubStorageUtil.java @@ -13,7 +13,7 @@ public class SecHubStorageUtil { public static String createStoragePathForProject(String projectId) { return "jobstorage/" + projectId; } - + public static String createAssetStoragePath() { return "assets"; } 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 9cbb9ee6c..5f8d34cc4 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,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.commons.model.template; /** 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 04ea28237..ee7e2ae6f 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 @@ -4,8 +4,10 @@ import java.util.ArrayList; import java.util.List; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; import com.mercedesbenz.sechub.commons.model.JSONable; +@JsonPropertyOrder({ "id", "type", "variables", "assets" }) public class TemplateDefinition implements JSONable { private static TemplateDefinition IMPORTER = new TemplateDefinition(); diff --git a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateIdenifierConstants.java b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateIdenifierConstants.java index 9a48c6120..56e15f48c 100644 --- a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateIdenifierConstants.java +++ b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateIdenifierConstants.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.commons.model.template; import com.mercedesbenz.sechub.commons.core.MustBeKeptStable; diff --git a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateType.java b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateType.java index 23599e5dd..c2460d27c 100644 --- a/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateType.java +++ b/sechub-commons-model/src/main/java/com/mercedesbenz/sechub/commons/model/template/TemplateType.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.commons.model.template; import static com.mercedesbenz.sechub.commons.model.template.TemplateIdenifierConstants.*; 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 f4b38b158..6bd36850b 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 @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.commons.model.template; import static org.assertj.core.api.Assertions.*; diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/DeveloperAdministration.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/DeveloperAdministration.java index ae47a8f73..5afb59515 100644 --- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/DeveloperAdministration.java +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/DeveloperAdministration.java @@ -26,6 +26,7 @@ import com.mercedesbenz.sechub.commons.pds.PDSDefaultParameterKeyConstants; import com.mercedesbenz.sechub.developertools.admin.ui.ConfigurationSetup; import com.mercedesbenz.sechub.developertools.admin.ui.UIContext; +import com.mercedesbenz.sechub.domain.scan.asset.AssetDetailData; import com.mercedesbenz.sechub.domain.scan.product.pds.PDSProductExecutorKeyConstants; import com.mercedesbenz.sechub.domain.scan.product.pds.SecHubProductExecutionPDSKeyProvider; import com.mercedesbenz.sechub.integrationtest.api.AsPDSUser; @@ -821,4 +822,40 @@ public void createOrUpdateTemplate(String templateId, TemplateDefinition templat asTestUser().createOrUpdateTemplate(templateId, templateDefinition); } + public void assignTemplateToProject(String templateId, String projectId) { + asTestUser().assignTemplateToProject(templateId, new FixedTestProject(projectId)); + } + + public void unassignTemplateFromProject(String templateId, String projectId) { + asTestUser().unassignTemplateFromProject(templateId, new FixedTestProject(projectId)); + } + + public List fetchAllTemplateIdentifiers() { + return asTestUser().fetchTemplateList(); + } + + public List fetchAllAssetIdentifiers() { + return asTestUser().fetchAllAssetIds(); + } + + public void uploadAssetFile(String assetId, File file) { + asTestUser().uploadAssetFile(assetId, file); + } + + public AssetDetailData fetchAssetDetails(String assetId) { + return asTestUser().fetchAssetDetails(assetId); + } + + public void deleteAsset(String assetId) { + asTestUser().deleteAsset(assetId); + } + + public void deleteAssetFile(String assetId, String fileName) { + asTestUser().deleteAssetFile(assetId, fileName); + } + + public File downloadAssetFile(String assetId, String fileName) { + return asTestUser().downloadAssetFile(assetId, fileName); + } + } diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java index 338d7d9fe..cdbefba64 100644 --- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/CommandUI.java @@ -20,6 +20,7 @@ import com.mercedesbenz.sechub.developertools.admin.ui.action.ActionSupport; import com.mercedesbenz.sechub.developertools.admin.ui.action.adapter.ShowProductExecutorTemplatesDialogAction; +import com.mercedesbenz.sechub.developertools.admin.ui.action.asset.ManageAssetsAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.client.TriggerSecHubClientSynchronousScanAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.config.ConfigureAutoCleanupAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.config.ConfigurePDSAutoCleanupAction; @@ -96,7 +97,10 @@ import com.mercedesbenz.sechub.developertools.admin.ui.action.scheduler.RefreshSchedulerStatusAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.status.CheckStatusAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.status.ListStatusEntriesAction; +import com.mercedesbenz.sechub.developertools.admin.ui.action.template.AssignTemplateToProjectAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.template.CreateOrUpdateTemplateAction; +import com.mercedesbenz.sechub.developertools.admin.ui.action.template.FetchAllTemplateIdentifiersAction; +import com.mercedesbenz.sechub.developertools.admin.ui.action.template.UnassignTemplateFromProjectAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.user.AcceptUserSignupAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.user.AnonymousRequestNewAPITokenUserAction; import com.mercedesbenz.sechub.developertools.admin.ui.action.user.AnonymousSigninNewUserAction; @@ -255,6 +259,12 @@ public void createConfigMenu() { JMenu templatesMenu = new JMenu("Templates"); menu.add(templatesMenu); add(templatesMenu, new CreateOrUpdateTemplateAction(context)); + add(templatesMenu, new FetchAllTemplateIdentifiersAction(context)); + + add(templatesMenu, new AssignTemplateToProjectAction(context)); + add(templatesMenu, new UnassignTemplateFromProjectAction(context)); + + menu.add(new ManageAssetsAction(context)); } diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/ManageAssetsDialogUI.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/ManageAssetsDialogUI.java new file mode 100644 index 000000000..335b80f5e --- /dev/null +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/ManageAssetsDialogUI.java @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.developertools.admin.ui; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.util.List; +import java.util.Optional; + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTextArea; +import javax.swing.JToolBar; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +import com.mercedesbenz.sechub.developertools.admin.ui.action.AbstractUIAction; +import com.mercedesbenz.sechub.developertools.admin.ui.cache.InputCacheIdentifier; +import com.mercedesbenz.sechub.domain.scan.asset.AssetDetailData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetFileInformation; + +public class ManageAssetsDialogUI { + + private JFrame frame; + private UIContext context; + private DefaultMutableTreeNode root; + private JTree tree; + private JTextArea textArea; + + public ManageAssetsDialogUI(UIContext context) { + this.context = context; + + frame = new JFrame(); + frame.setLayout(new BorderLayout()); + + createMenuBar(context); + + createToolBar(context); + + frame.setTitle("Manage assets"); + + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + frame.setSize(800, 600); + frame.setLocationRelativeTo(null); + + root = new DefaultMutableTreeNode(new AssetRootElement()); + DefaultTreeModel model = new DefaultTreeModel(root); + tree = new JTree(model); + + textArea = new JTextArea(); + JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(tree), new JScrollPane(textArea)); + frame.add(splitPane, BorderLayout.CENTER); + + tree.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + if (node == null) { + return; + } + + Object userObject = node.getUserObject(); + if (userObject instanceof AssetRootElement) { + refreshModel(); + return; + } + if (userObject instanceof AssetElement) { + node.removeAllChildren(); + + AssetElement element = (AssetElement) userObject; + String assetId = element.assetId; + AssetDetailData detailData = context.getAdministration().fetchAssetDetails(assetId); + textArea.setText(detailData.toFormattedJSON()); + int added = 0; + for (AssetFileInformation info : detailData.getFileInformation()) { + node.add(new DefaultMutableTreeNode(new AssetFileElement(assetId, info.getFileName(), info.getChecksum()))); + added++; + } + element.info = added + " files"; + } + tree.repaint(); + } + } + }); + } + + private void createToolBar(UIContext context) { + JToolBar toolbar = new JToolBar(); + toolbar.add(new RefresAction(context)); + toolbar.addSeparator(); + toolbar.add(new UploadAssetFileAction(context)); + toolbar.add(new DownloadAssetFileAction(context)); + toolbar.addSeparator(); + toolbar.add(new DeleteAction(context)); + + frame.add(toolbar, BorderLayout.NORTH); + } + + private void createMenuBar(UIContext context) { + JMenuBar menuBar = new JMenuBar(); + JMenu menu1 = new JMenu("Actions"); + menuBar.add(menu1); + menu1.add(new RefresAction(context)); + menu1.addSeparator(); + menu1.add(new UploadAssetFileAction(context)); + menu1.add(new DownloadAssetFileAction(context)); + menu1.addSeparator(); + menu1.add(new DeleteAction(context)); + + frame.setJMenuBar(menuBar); + } + + public static void main(String[] args) { + new ManageAssetsDialogUI(null).show(); + } + + public void show() { + frame.setVisible(true); + } + + private void refreshModel() { + root.removeAllChildren(); + List assetIdentifiers = context.getAdministration().fetchAllAssetIdentifiers(); + textArea.setText("Loaded asset identifiers:\n" + assetIdentifiers); + AssetRootElement rootElement = (AssetRootElement) root.getUserObject(); + rootElement.info = "Loaded: " + assetIdentifiers.size(); + + for (String assetId : assetIdentifiers) { + root.add(new DefaultMutableTreeNode(new AssetElement(assetId))); + } + tree.setModel(new DefaultTreeModel(root)); + } + + private class AssetRootElement { + private String info = "Double click to load"; + + @Override + public String toString() { + return "assets (" + info + ")"; + } + } + + private class AssetElement { + private String assetId; + private String info = "Double click to load"; + + private AssetElement(String assetId) { + this.assetId = assetId; + } + + @Override + public String toString() { + return assetId + "(" + info + ")"; + } + + } + + private class AssetFileElement { + + private String checksum; + private String fileName; + private String assetId; + + public AssetFileElement(String assetId, String fileName, String checksum) { + this.assetId = assetId; + this.fileName = fileName; + this.checksum = checksum; + } + + @Override + public String toString() { + return fileName + " (" + checksum + ")"; + } + + } + + private class RefresAction extends AbstractUIAction { + + public RefresAction(UIContext context) { + super("Refresh", context); + } + + private static final long serialVersionUID = 7392018849800602872L; + + @Override + protected void execute(ActionEvent e) throws Exception { + refreshModel(); + } + + } + + private class UploadAssetFileAction extends AbstractUIAction { + + public UploadAssetFileAction(UIContext context) { + super("Upload", context); + } + + private static final long serialVersionUID = 7392018849800602872L; + + @Override + protected void execute(ActionEvent e) throws Exception { + + Optional assetIdOpt = getUserInput("Select asset id", InputCacheIdentifier.ASSET_ID); + if (assetIdOpt.isEmpty()) { + return; + } + File file = getContext().getDialogUI().selectFile(null); + if (file == null) { + return; + } + String assetId = assetIdOpt.get(); + getContext().getAdministration().uploadAssetFile(assetId, file); + } + + } + + private class DownloadAssetFileAction extends AbstractUIAction { + + public DownloadAssetFileAction(UIContext context) { + super("Download", context); + } + + private static final long serialVersionUID = 7392018849800602872L; + + @Override + protected void execute(ActionEvent e) throws Exception { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + Object userObject = node.getUserObject(); + + if (userObject instanceof AssetFileElement) { + AssetFileElement assetElement = (AssetFileElement) userObject; + File file = getContext().getAdministration().downloadAssetFile(assetElement.assetId, assetElement.fileName); + textArea.setText("Downloaded to:\n" + file.getAbsolutePath()); + } + } + + } + + private class DeleteAction extends AbstractUIAction { + + public DeleteAction(UIContext context) { + super("Delete", context); + } + + private static final long serialVersionUID = 7392018849800602872L; + + @Override + protected void execute(ActionEvent e) throws Exception { + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); + Object userObject = node.getUserObject(); + if (userObject instanceof AssetElement) { + AssetElement assetElement = (AssetElement) userObject; + String assetId = assetElement.assetId; + if (!getContext().getDialogUI().confirm("Do you really want to delete complete asset:" + assetId)) { + return; + } + getContext().getAdministration().deleteAsset(assetId); + + } else if (userObject instanceof AssetFileElement) { + AssetFileElement assetElement = (AssetFileElement) userObject; + String assetId = assetElement.assetId; + String fileName = assetElement.fileName; + + if (!getContext().getDialogUI().confirm("Do you really want to delete file:" + fileName + " from asset:" + assetId)) { + return; + } + getContext().getAdministration().deleteAssetFile(assetId, fileName); + } + } + + } + +} diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/asset/ManageAssetsAction.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/asset/ManageAssetsAction.java new file mode 100644 index 000000000..0368e97e6 --- /dev/null +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/asset/ManageAssetsAction.java @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.developertools.admin.ui.action.asset; + +import java.awt.event.ActionEvent; + +import com.mercedesbenz.sechub.developertools.admin.ui.ManageAssetsDialogUI; +import com.mercedesbenz.sechub.developertools.admin.ui.UIContext; +import com.mercedesbenz.sechub.developertools.admin.ui.action.AbstractUIAction; + +public class ManageAssetsAction extends AbstractUIAction { + private static final long serialVersionUID = 1L; + + public ManageAssetsAction(UIContext context) { + super("Manage assets", context); + } + + @Override + public void execute(ActionEvent e) { + + ManageAssetsDialogUI ui = new ManageAssetsDialogUI(getContext()); + ui.show(); + + } + +} \ No newline at end of file diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/AssignTemplateToProjectAction.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/AssignTemplateToProjectAction.java new file mode 100644 index 000000000..10b63857a --- /dev/null +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/AssignTemplateToProjectAction.java @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.developertools.admin.ui.action.template; + +import java.awt.event.ActionEvent; +import java.util.Optional; + +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; +import com.mercedesbenz.sechub.developertools.admin.ui.UIContext; +import com.mercedesbenz.sechub.developertools.admin.ui.action.AbstractUIAction; +import com.mercedesbenz.sechub.developertools.admin.ui.cache.InputCacheIdentifier; + +public class AssignTemplateToProjectAction extends AbstractUIAction { + private static final long serialVersionUID = 1L; + + public AssignTemplateToProjectAction(UIContext context) { + super("Assign template to project", context); + } + + @Override + public void execute(ActionEvent e) { + Optional templateIdOpt = getUserInput("Please enter templateId", InputCacheIdentifier.TEMPLATE_ID); + if (!templateIdOpt.isPresent()) { + return; + } + String templateId = templateIdOpt.get(); + TemplateDefinition foundTemplate = getContext().getAdministration().fetchTemplateOrNull(templateId); + if (foundTemplate == null) { + error("The template " + templateId + " does not exist!"); + return; + } + Optional projectIdOpt = getUserInput("Please enter projectId", InputCacheIdentifier.PROJECT_ID); + if (!projectIdOpt.isPresent()) { + return; + } + String projectId = projectIdOpt.get(); + String projectInfo = getContext().getAdministration().fetchProjectInfo(projectId); + + if (projectInfo == null) { + error("The project " + projectId + " does not exist!"); + return; + } + + getContext().getAdministration().assignTemplateToProject(templateId, projectId); + + } + +} \ No newline at end of file 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 7a9ac33f6..acd995e26 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 @@ -5,6 +5,8 @@ import java.util.Optional; import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition.TemplateVariable; +import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition.TemplateVariableValidation; import com.mercedesbenz.sechub.commons.model.template.TemplateType; import com.mercedesbenz.sechub.developertools.admin.ui.UIContext; import com.mercedesbenz.sechub.developertools.admin.ui.action.AbstractUIAction; @@ -24,10 +26,13 @@ public void execute(ActionEvent e) { return; } + String dialogTitle = null; String templateId = templateIdOpt.get(); TemplateDefinition templateDefinition = getContext().getAdministration().fetchTemplateOrNull(templateId); if (templateDefinition == null) { - String title = "New template"; + /* we create an example here */ + + String title = "Create new template:" + templateId; String message = "Please enter template type"; Optional templateTypeOpt = getUserInputFromCombobox(title, TemplateType.WEBSCAN_LOGIN, message, TemplateType.values()); if (!templateTypeOpt.isPresent()) { @@ -36,9 +41,26 @@ public void execute(ActionEvent e) { templateDefinition = new TemplateDefinition(); templateDefinition.setId(templateId); templateDefinition.setType(templateTypeOpt.get()); + + templateDefinition.getAssets().add("example-asset-id"); + TemplateVariable exampleVariable = new TemplateVariable(); + exampleVariable.setName("example-variable"); + exampleVariable.setOptional(true); + TemplateVariableValidation validation = new TemplateVariableValidation(); + validation.setMinLength(2); + validation.setMaxLength(100); + validation.setRegularExpression("[0-9a-z].*"); + + exampleVariable.setValidation(validation); + templateDefinition.getVariables().add(exampleVariable); + + dialogTitle = "New Template:" + templateId + " (by example)"; + + } else { + dialogTitle = "Change existing template:" + templateId; } - Optional templateDefInputOpt = getUserInputFromTextArea("Template definition", templateDefinition.toFormattedJSON()); + Optional templateDefInputOpt = getUserInputFromTextArea(dialogTitle, templateDefinition.toFormattedJSON()); if (templateDefInputOpt.isEmpty()) { return; } diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/FetchAllTemplateIdentifiersAction.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/FetchAllTemplateIdentifiersAction.java new file mode 100644 index 000000000..763a9b163 --- /dev/null +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/FetchAllTemplateIdentifiersAction.java @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.developertools.admin.ui.action.template; + +import java.awt.event.ActionEvent; +import java.util.List; + +import com.mercedesbenz.sechub.developertools.admin.ui.UIContext; +import com.mercedesbenz.sechub.developertools.admin.ui.action.AbstractUIAction; + +public class FetchAllTemplateIdentifiersAction extends AbstractUIAction { + private static final long serialVersionUID = 1L; + + public FetchAllTemplateIdentifiersAction(UIContext context) { + super("Fetch all template identifiers", context); + } + + @Override + public void execute(ActionEvent e) { + List identifiers = getContext().getAdministration().fetchAllTemplateIdentifiers(); + output("Found template identiiers:\n" + identifiers.toString()); + } + +} \ No newline at end of file diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/UnassignTemplateFromProjectAction.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/UnassignTemplateFromProjectAction.java new file mode 100644 index 000000000..2ec9ef90c --- /dev/null +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/action/template/UnassignTemplateFromProjectAction.java @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.developertools.admin.ui.action.template; + +import java.awt.event.ActionEvent; +import java.util.Optional; + +import com.mercedesbenz.sechub.developertools.admin.ui.UIContext; +import com.mercedesbenz.sechub.developertools.admin.ui.action.AbstractUIAction; +import com.mercedesbenz.sechub.developertools.admin.ui.cache.InputCacheIdentifier; + +public class UnassignTemplateFromProjectAction extends AbstractUIAction { + private static final long serialVersionUID = 1L; + + public UnassignTemplateFromProjectAction(UIContext context) { + super("Unassign template from project", context); + } + + @Override + public void execute(ActionEvent e) { + Optional templateIdOpt = getUserInput("Please enter templateId", InputCacheIdentifier.TEMPLATE_ID); + if (!templateIdOpt.isPresent()) { + return; + } + String templateId = templateIdOpt.get(); + Optional projectIdOpt = getUserInput("Please enter projectId", InputCacheIdentifier.PROJECT_ID); + if (!projectIdOpt.isPresent()) { + return; + } + String projectId = projectIdOpt.get(); + + getContext().getAdministration().unassignTemplateFromProject(templateId, projectId); + + } + +} \ No newline at end of file diff --git a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/cache/InputCacheIdentifier.java b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/cache/InputCacheIdentifier.java index bd122c98a..931ff7b8d 100644 --- a/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/cache/InputCacheIdentifier.java +++ b/sechub-developertools/src/main/java/com/mercedesbenz/sechub/developertools/admin/ui/cache/InputCacheIdentifier.java @@ -52,4 +52,6 @@ public enum InputCacheIdentifier { TEMPLATE_ID, + ASSET_ID, + } \ No newline at end of file diff --git a/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects-events.puml b/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects-events.puml index 7c89fd10e..509fbc426 100644 --- a/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects-events.puml +++ b/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects-events.puml @@ -1,3 +1,4 @@ +' SPDX-License-Identifier: MIT @startuml 'Hide empty parts: diff --git a/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects.puml b/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects.puml index 9bb7547b3..c88bb9438 100644 --- a/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects.puml +++ b/sechub-doc/src/docs/asciidoc/diagrams/diagram_templates-mapping-to-projects.puml @@ -1,3 +1,4 @@ +' SPDX-License-Identifier: MIT @startuml 'Hide empty parts: 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 a1b1e5659..e735bd434 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 @@ -42,6 +42,7 @@ import com.mercedesbenz.sechub.commons.model.TrafficLight; import com.mercedesbenz.sechub.commons.model.template.TemplateDefinition; import com.mercedesbenz.sechub.domain.administration.project.ProjectDetailInformation; +import com.mercedesbenz.sechub.domain.scan.asset.AssetDetailData; import com.mercedesbenz.sechub.domain.scan.project.FalsePositiveProjectData; import com.mercedesbenz.sechub.integrationtest.JSONTestSupport; import com.mercedesbenz.sechub.integrationtest.internal.IntegrationTestContext; @@ -1488,6 +1489,13 @@ public AsUser uploadAssetFile(String assetId, File file) { return this; } + public AsUser uploadAssetFiles(String assetId, File... files) { + for (File file : files) { + uploadAssetFile(assetId, file); + } + return this; + } + public File downloadAssetFile(String assetId, String fileName) { String url = getUrlBuilder().buildAdminDownloadsAssetFile(assetId, fileName); /* @formatter:off */ @@ -1503,8 +1511,30 @@ public File downloadAssetFile(String assetId, String fileName) { }; RestTemplate template = getRestHelper().getTemplate(); File downloadedAssetFile = template.execute(url, HttpMethod.GET, requestCallback, responseExtractor); - + return downloadedAssetFile; } + public List fetchAllAssetIds() { + String url = getUrlBuilder().buildAdminFetchesAllAssetIds(); + String json = getRestHelper().getJSON(url); + return JSONConverter.get().fromJSONtoListOf(String.class, json); + } + + public AssetDetailData fetchAssetDetails(String assetId) { + String url = getUrlBuilder().buildAdminFetchesAssetDetails(assetId); + String json = getRestHelper().getJSON(url); + return JSONConverter.get().fromJSON(AssetDetailData.class, json); + } + + public void deleteAssetFile(String assetId, String fileName) { + String url = getUrlBuilder().buildAdminDeletesAssetFile(assetId, fileName); + getRestHelper().delete(url); + } + + public void deleteAsset(String assetId) { + String url = getUrlBuilder().buildAdminDeletesAsset(assetId); + getRestHelper().delete(url); + } + } diff --git a/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/AssetScenario1IntTest.java b/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/AssetScenario1IntTest.java index 1fc196861..4074635ec 100644 --- a/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/AssetScenario1IntTest.java +++ b/sechub-integrationtest/src/test/java/com/mercedesbenz/sechub/integrationtest/scenario1/AssetScenario1IntTest.java @@ -1,17 +1,22 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.integrationtest.scenario1; + import static com.mercedesbenz.sechub.integrationtest.api.TestAPI.*; import static com.mercedesbenz.sechub.integrationtest.api.TestAPI.as; import static org.assertj.core.api.Assertions.*; import java.io.File; +import java.util.List; +import java.util.UUID; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.Timeout; +import org.springframework.web.client.HttpClientErrorException.NotFound; -import com.mercedesbenz.sechub.commons.core.CommonConstants; +import com.mercedesbenz.sechub.domain.scan.asset.AssetDetailData; +import com.mercedesbenz.sechub.domain.scan.asset.AssetFileInformation; import com.mercedesbenz.sechub.integrationtest.api.IntegrationTestSetup; import com.mercedesbenz.sechub.integrationtest.api.TestAPI; import com.mercedesbenz.sechub.test.TestFileReader; @@ -30,22 +35,77 @@ public void before() { } @Test - public void asset_crud_test() { - File uploadedFile = new File("./src/test/resources/asset/asset1.txt"); - - as(SUPER_ADMIN).uploadAssetFile("my-asset-id", uploadedFile); - - File downloadedAssetFile = as(SUPER_ADMIN).downloadAssetFile("my-asset-id", uploadedFile.getName()); - - String output = TestFileReader.readTextFromFile(downloadedAssetFile); - assertThat(output).isEqualTo("I am textfile \"asset1.txt\""); - - - String checksum = TestAPI.createSHA256Of(uploadedFile); - File downloadedAssetFileChecksum = as(SUPER_ADMIN).downloadAssetFile("my-asset-id", uploadedFile.getName()+CommonConstants.DOT_CHECKSUM); - String checksumDownloadd = TestFileReader.readTextFromFile(downloadedAssetFileChecksum); - - assertThat(checksumDownloadd).isEqualTo(checksum); + public void asset_crud_operation_working_as_expected() { + /* ------- */ + /* prepare */ + /* ------- */ + File uploadedFile1 = new File("./src/test/resources/asset/examples-1/asset1.txt"); + File uploadedFile2 = new File("./src/test/resources/asset/examples-1/asset2.txt"); + + String assetId = "crud" + UUID.randomUUID().toString(); + + /* --------------- */ + /* execute + test */ + /* --------------- */ + as(SUPER_ADMIN).uploadAssetFiles(assetId, uploadedFile1, uploadedFile2); + + // fetch all asset ids + List allAssetIds = as(SUPER_ADMIN).fetchAllAssetIds(); + assertThat(allAssetIds).contains(assetId); + + /* download files */ + File downloadedAssetFile1 = as(SUPER_ADMIN).downloadAssetFile(assetId, uploadedFile1.getName()); + + String output = TestFileReader.readTextFromFile(downloadedAssetFile1); + assertThat(output).isEqualTo("I am text file \"asset1.txt\""); + + /* fetch asset details and check content is as expected */ + AssetDetailData detailData = as(SUPER_ADMIN).fetchAssetDetails(assetId); + assertThat(detailData.getAssetid()).isEqualTo(assetId); + + String checksum1 = TestAPI.createSHA256Of(uploadedFile1); + AssetFileInformation expectedInfo1 = new AssetFileInformation(); + expectedInfo1.setChecksum(checksum1); + expectedInfo1.setFileName("asset1.txt"); + + String checksum2 = TestAPI.createSHA256Of(uploadedFile2); + AssetFileInformation expectedInfo2 = new AssetFileInformation(); + expectedInfo2.setChecksum(checksum2); + expectedInfo2.setFileName("asset2.txt"); + + assertThat(detailData.getFileInformation()).contains(expectedInfo1, expectedInfo2).hasSize(2); + + /* delete single file from asset */ + as(SUPER_ADMIN).deleteAssetFile(assetId, "asset1.txt"); + + /* check asset still exists in list and details contain only asset2.txt */ + assertThat(as(SUPER_ADMIN).fetchAllAssetIds()).contains(assetId); + assertThat(as(SUPER_ADMIN).fetchAssetDetails(assetId).getFileInformation()).containsOnly(expectedInfo2); + + /* + * Upload asset 2 again, but with different content - we use other file from + * examples-2 instead of examples-1. Will override existing asset file. + */ + File uploadedFile2changed = new File("./src/test/resources/asset/examples-2/asset2.txt"); + String checksum2changed = TestAPI.createSHA256Of(uploadedFile2changed); + assertThat(checksum2changed).as("precondition-check that files are different").isNotEqualTo(checksum2); + + as(SUPER_ADMIN).uploadAssetFile(assetId, uploadedFile2changed); + + AssetFileInformation expectedInfo2Canged = new AssetFileInformation(); + expectedInfo2Canged.setChecksum(checksum2changed); + expectedInfo2Canged.setFileName("asset2.txt"); + + assertThat(as(SUPER_ADMIN).fetchAssetDetails(assetId).getFileInformation()).containsOnly(expectedInfo2Canged); + + output = TestFileReader.readTextFromFile(as(SUPER_ADMIN).downloadAssetFile(assetId, "asset2.txt")); + assertThat(output).isEqualTo("I am text file \"asset2.txt\" - but from folder example-2"); + + /* delete complete asset */ + as(SUPER_ADMIN).deleteAsset(assetId); + + assertThat(as(SUPER_ADMIN).fetchAllAssetIds()).doesNotContain(assetId); + assertThatThrownBy(() -> as(SUPER_ADMIN).fetchAssetDetails(assetId)).isInstanceOf(NotFound.class); } } diff --git a/sechub-integrationtest/src/test/resources/asset/asset1.txt b/sechub-integrationtest/src/test/resources/asset/examples-1/asset1.txt similarity index 100% rename from sechub-integrationtest/src/test/resources/asset/asset1.txt rename to sechub-integrationtest/src/test/resources/asset/examples-1/asset1.txt diff --git a/sechub-integrationtest/src/test/resources/asset/examples-1/asset2.txt b/sechub-integrationtest/src/test/resources/asset/examples-1/asset2.txt new file mode 100644 index 000000000..a47cb9bda --- /dev/null +++ b/sechub-integrationtest/src/test/resources/asset/examples-1/asset2.txt @@ -0,0 +1 @@ +I am text file "asset2.txt" \ No newline at end of file diff --git a/sechub-integrationtest/src/test/resources/asset/examples-2/asset2.txt b/sechub-integrationtest/src/test/resources/asset/examples-2/asset2.txt new file mode 100644 index 000000000..7ccc0dabc --- /dev/null +++ b/sechub-integrationtest/src/test/resources/asset/examples-2/asset2.txt @@ -0,0 +1 @@ +I am text file "asset2.txt" - but from folder example-2 \ No newline at end of file diff --git a/sechub-pds/src/main/java/com/mercedesbenz/sechub/pds/storage/PDSMultiStorageService.java b/sechub-pds/src/main/java/com/mercedesbenz/sechub/pds/storage/PDSMultiStorageService.java index faed5e1f3..efdbd681e 100644 --- a/sechub-pds/src/main/java/com/mercedesbenz/sechub/pds/storage/PDSMultiStorageService.java +++ b/sechub-pds/src/main/java/com/mercedesbenz/sechub/pds/storage/PDSMultiStorageService.java @@ -43,16 +43,16 @@ public PDSMultiStorageService(SharedVolumeSetup sharedVolumeSetup, S3Setup s3Set if (s3Setup.isAvailable()) { AwsS3JobStorageFactory awsJobFactory = new AwsS3JobStorageFactory(s3Setup); - + jobStorageFactory = awsJobFactory; assetStorageFactory = awsJobFactory; } else if (sharedVolumeSetup.isAvailable()) { SharedVolumeJobStorageFactory sharedVolumeStorageFactory = new SharedVolumeJobStorageFactory(sharedVolumeSetup); - + jobStorageFactory = sharedVolumeStorageFactory; - assetStorageFactory=sharedVolumeStorageFactory; - + assetStorageFactory = sharedVolumeStorageFactory; + } if (jobStorageFactory == null || assetStorageFactory == null) { @@ -75,8 +75,8 @@ public JobStorage createJobStorageForPath(String storagePath, UUID jobUUID) { } @Override - public AssetStorage createAssetStorage(String storagePath, String assetId) { - return assetStorageFactory.createAssetStorage(storagePath, assetId); + public AssetStorage createAssetStorage(String assetId) { + return assetStorageFactory.createAssetStorage(assetId); } } \ No newline at end of file diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetDetailData.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetDetailData.java new file mode 100644 index 000000000..59dcde86b --- /dev/null +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetDetailData.java @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.asset; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.mercedesbenz.sechub.commons.model.JSONable; + +@JsonIgnoreProperties(ignoreUnknown = true) // we do ignore to avoid problems from wrong configured values! +public class AssetDetailData implements JSONable { + + private String assetid; + + private List fileInformation = new ArrayList<>(); + + public void setAssetid(String assetid) { + this.assetid = assetid; + } + + public String getAssetid() { + return assetid; + } + + public List getFileInformation() { + return fileInformation; + } + + @Override + public Class getJSONTargetClass() { + return AssetDetailData.class; + } +} diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFile.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFile.java index 323202868..9d912b89e 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFile.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFile.java @@ -83,7 +83,7 @@ public byte[] getData() { /** * Asset id and file name or only strings. To avoid confusion in constructor * usage, this builder was introduced. - * + * * @author Albert Tregnaghi * */ diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileInformation.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileInformation.java new file mode 100644 index 000000000..d2968c291 --- /dev/null +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileInformation.java @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.asset; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) // we do ignore to avoid problems from wrong configured values! +public class AssetFileInformation { + + private String checksum; + + private String fileName; + + public String getChecksum() { + return checksum; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + @Override + public int hashCode() { + return Objects.hash(checksum, fileName); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AssetFileInformation other = (AssetFileInformation) obj; + return Objects.equals(checksum, other.checksum) && Objects.equals(fileName, other.fileName); + } + + @Override + public String toString() { + return "AssetFileInformation [" + (checksum != null ? "checksum=" + checksum + ", " : "") + (fileName != null ? "fileName=" + fileName : "") + "]"; + } + +} diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileRepository.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileRepository.java index 5fa84ab0e..553ce9c75 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileRepository.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileRepository.java @@ -1,11 +1,27 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan.asset; +import static com.mercedesbenz.sechub.domain.scan.asset.AssetFile.*; + +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import com.mercedesbenz.sechub.domain.scan.asset.AssetFile.AssetFileCompositeKey; public interface AssetFileRepository extends JpaRepository { + @Query(value = "SELECT DISTINCT " + COLUMN_ASSET_ID + " FROM " + TABLE_NAME, nativeQuery = true) + List fetchAllAssetIds(); + + @Query(value = "SELECT * from " + TABLE_NAME + " WHERE " + COLUMN_ASSET_ID + "=:assetId", nativeQuery = true) + List fetchAllAssetFilesWithAssetId(@Param("assetId") String assetId); + + @Modifying + @Query(value = "DELETE from " + TABLE_NAME + " WHERE " + COLUMN_ASSET_ID + "=:assetId", nativeQuery = true) + void deleteAssetFilesHavingAssetId(String assetId); } 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 b3742a656..d618ce2e3 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 @@ -4,6 +4,7 @@ import static com.mercedesbenz.sechub.commons.core.CommonConstants.*; import java.io.IOException; +import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -23,7 +24,11 @@ import com.mercedesbenz.sechub.sharedkernel.Step; import com.mercedesbenz.sechub.sharedkernel.logging.AuditLogService; import com.mercedesbenz.sechub.sharedkernel.logging.LogSanitizer; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminDeletesAssetCompletely; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminDeletesOneFileFromAsset; import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminDownloadsAssetFile; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminFetchesAssetDetails; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminFetchesAssetIds; import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminUploadsAssetFile; import jakarta.annotation.security.RolesAllowed; @@ -49,31 +54,63 @@ public class AssetRestController { @RequestMapping(path = "/asset/{assetId}/file", method = RequestMethod.POST) @ResponseStatus(HttpStatus.OK) /* @formatter:on */ - public void uploadAssetFile( - @PathVariable("assetId") String assetId, - @RequestPart(MULTIPART_FILE) MultipartFile file, + public void uploadAssetFile(@PathVariable("assetId") String assetId, @RequestPart(MULTIPART_FILE) MultipartFile file, @RequestParam(MULTIPART_CHECKSUM) String checkSum) { - auditLogService.log("starts upload of file:{} for asset: {}", logSanitizer.sanitize(file.getName(), 100),logSanitizer.sanitize(assetId, 40)); + auditLogService.log("starts upload of file:{} for asset: {}", logSanitizer.sanitize(file.getOriginalFilename(), 100), + logSanitizer.sanitize(assetId, 40)); assetService.uploadAssetFile(assetId, file, checkSum); } - + /* @formatter:off */ @UseCaseAdminDownloadsAssetFile(@Step(number = 1, next = 2, name = "REST API call to download a file for an asset", needsRestDoc = true)) @RequestMapping(path = "/asset/{assetId}/file/{fileName}", method = RequestMethod.GET, produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE, MediaType.ALL_VALUE}) @ResponseStatus(HttpStatus.OK) /* @formatter:on */ - public void downloadAssetFile ( - @PathVariable("assetId") String assetId, - @PathVariable("fileName") String fileName, - HttpServletResponse response - ) throws IOException { - - auditLogService.log("starts download of file:{} for asset: {}", logSanitizer.sanitize(fileName, 100),logSanitizer.sanitize(assetId, 40)); - + public void downloadAssetFile(@PathVariable("assetId") String assetId, @PathVariable("fileName") String fileName, HttpServletResponse response) + throws IOException { + + auditLogService.log("starts download of file:{} for asset: {}", logSanitizer.sanitize(fileName, 100), logSanitizer.sanitize(assetId, 40)); + assetService.downloadAssetFile(assetId, fileName, response.getOutputStream()); - + + } + + /* @formatter:off */ + @UseCaseAdminFetchesAssetIds(@Step(number = 1, next = 2, name = "REST API call to fetch all availbale asset ids", needsRestDoc = true)) + @RequestMapping(path = "/asset/ids", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseStatus(HttpStatus.OK) + /* @formatter:on */ + public List fetchAllAssetIds() { + return assetService.fetchAllAssetIds(); + } + + /* @formatter:off */ + @UseCaseAdminFetchesAssetDetails(@Step(number = 1, next = 2, name = "REST API call to fetch details about asset", needsRestDoc = true)) + @RequestMapping(path = "/asset/{assetId}/details", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE}) + @ResponseStatus(HttpStatus.OK) + /* @formatter:on */ + public AssetDetailData fetchAssetDetails(@PathVariable("assetId") String assetId) { + return assetService.fetchAssetDetails(assetId); + } + + /* @formatter:off */ + @UseCaseAdminDeletesOneFileFromAsset(@Step(number = 1, next = 2, name = "REST API call to delete an asset file", needsRestDoc = true)) + @RequestMapping(path = "/asset/{assetId}/file/{fileName}", method = RequestMethod.DELETE) + @ResponseStatus(HttpStatus.OK) + /* @formatter:on */ + public void deleteAssetFile(@PathVariable("assetId") String assetId, @PathVariable("fileName") String fileName) throws IOException { + assetService.deleteAssetFile(assetId, fileName); + } + + /* @formatter:off */ + @UseCaseAdminDeletesAssetCompletely(@Step(number = 1, next = 2, name = "REST API call to delete complete asset", needsRestDoc = true)) + @RequestMapping(path = "/asset/{assetId}", method = RequestMethod.DELETE) + @ResponseStatus(HttpStatus.OK) + /* @formatter:on */ + public void deleteAsset(@PathVariable("assetId") String assetId) throws IOException { + assetService.deleteAsset(assetId); } } 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 f31b6f8cb..c3a9eea47 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 @@ -6,12 +6,14 @@ import java.io.IOException; import java.io.InputStream; +import java.util.List; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import com.amazonaws.util.StringInputStream; @@ -23,6 +25,11 @@ import com.mercedesbenz.sechub.sharedkernel.error.BadRequestException; import com.mercedesbenz.sechub.sharedkernel.error.NotAcceptableException; import com.mercedesbenz.sechub.sharedkernel.error.NotFoundException; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminDeletesAssetCompletely; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminDeletesOneFileFromAsset; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminDownloadsAssetFile; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminFetchesAssetDetails; +import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminFetchesAssetIds; import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminUploadsAssetFile; import com.mercedesbenz.sechub.sharedkernel.validation.UserInputAssertion; import com.mercedesbenz.sechub.storage.core.AssetStorage; @@ -74,11 +81,11 @@ public void uploadAssetFile(String assetId, MultipartFile file, String checkSum) persistFileAndChecksumInDatabase(fileName, file, checkSum, assetId); storeUploadFileAndSha256Checksum(assetId, fileName, file, checkSum); - - LOG.info("Successfully uploaded asset file: {} for asset: {}", 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); + throw new SecHubRuntimeException("Was not able to upload file '" + fileName + "' for asset '" + assetId + "'", e); } } @@ -90,13 +97,13 @@ private void persistFileAndChecksumInDatabase(String fileName, MultipartFile fil AssetFile assetFile = new AssetFile(key); assetFile.setChecksum(checkSum); assetFile.setData(file.getBytes()); - + repository.save(assetFile); } private String assertAssetFile(MultipartFile file) { notNull(file, "file may not be null!"); - String fileName = file.getName(); + String fileName = file.getOriginalFilename(); inputAssertion.assertIsValidAssetFileName(fileName); @@ -114,7 +121,7 @@ private void handleChecksumValidation(String fileName, MultipartFile file, Strin assertCheckSumCorrect(checkSum, inputStream); } catch (IOException e) { - LOG.error("Was not able to validate uploaded file checksum for file: {} in asset: {}", fileName, assetid, e); + LOG.error("Was not able to validate uploaded file checksum for file '{}' in asset '{}'", fileName, assetid, e); throw new SecHubRuntimeException("Was not able to validate uploaded asset checksum"); } } @@ -146,8 +153,8 @@ private void store(String assetId, String fileName, MultipartFile file, String c assetStorage.store(createFileNameForChecksum(fileName), new StringInputStream(checkSum), checksumSizeInBytes); } 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); + 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 + "'"); } } @@ -155,20 +162,65 @@ private String createFileNameForChecksum(String fileName) { return fileName + DOT_CHECKSUM; } + @UseCaseAdminDownloadsAssetFile(@Step(number = 2, name = "Service downloads asset file from database")) public void downloadAssetFile(String assetId, String fileName, ServletOutputStream outputStream) throws IOException { inputAssertion.assertIsValidAssetId(assetId); inputAssertion.assertIsValidAssetFileName(fileName); - + notNull(outputStream, "output stream may not be null!"); - + 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!"); + throw new NotFoundException("For asset:" + assetId + " no file with name:" + fileName + " exists!"); } AssetFile assetFile = result.get(); outputStream.write(assetFile.getData()); - + + } + + @UseCaseAdminFetchesAssetIds(@Step(number = 2, name = "Service fetches all asset ids from database")) + public List fetchAllAssetIds() { + return repository.fetchAllAssetIds(); + } + + @UseCaseAdminFetchesAssetDetails(@Step(number = 2, name = "Service fetches asset details for given asset id")) + public AssetDetailData fetchAssetDetails(String assetId) { + inputAssertion.assertIsValidAssetId(assetId); + + List assetFiles = repository.fetchAllAssetFilesWithAssetId(assetId); + if (assetFiles.isEmpty()) { + throw new NotFoundException("No asset data available for asset id:" + assetId); + } + + AssetDetailData data = new AssetDetailData(); + data.setAssetid(assetId); + for (AssetFile assetFile : assetFiles) { + AssetFileInformation information = new AssetFileInformation(); + information.setFileName(assetFile.getKey().getFileName()); + information.setChecksum(assetFile.getChecksum()); + data.getFileInformation().add(information); + } + + return data; + } + + @UseCaseAdminDeletesOneFileFromAsset(@Step(number = 2, name = "Services deletes file from asset")) + public void deleteAssetFile(String assetId, String fileName) throws IOException { + inputAssertion.assertIsValidAssetId(assetId); + inputAssertion.assertIsValidAssetFileName(fileName); + + repository.deleteById(AssetFileCompositeKey.builder().assetId(assetId).fileName(fileName).build()); + storageService.createAssetStorage(assetId).delete(fileName); + } + + @UseCaseAdminDeletesAssetCompletely(@Step(number = 2, name = "Services deletes all asset parts")) + @Transactional + public void deleteAsset(String assetId) throws IOException { + inputAssertion.assertIsValidAssetId(assetId); + + repository.deleteAssetFilesHavingAssetId(assetId); + storageService.createAssetStorage(assetId).deleteAll(); } } diff --git a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolver.java b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolver.java index 3e322bfba..c19c76529 100644 --- a/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolver.java +++ b/sechub-scan/src/main/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolver.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan.template; import java.util.Collections; diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileInformationTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileInformationTest.java new file mode 100644 index 000000000..c603dbb9d --- /dev/null +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileInformationTest.java @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.asset; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +class AssetFileInformationTest { + + @ParameterizedTest + @ValueSource(strings = { "test1.txt", "filename", "" }) + @NullSource + void equals_returns_true_when_filename_and_checksum_are_same(String testText) { + /* prepare */ + String sameFileName = testText; + String sameChecksum = testText == null ? null : "checksum_dummy_" + testText; + + AssetFileInformation info1 = new AssetFileInformation(); + info1.setChecksum(sameChecksum); + info1.setFileName(sameFileName); + + AssetFileInformation info2 = new AssetFileInformation(); + info2.setChecksum(sameChecksum); + info2.setFileName(sameFileName); + + /* execute + test */ + assertThat(info1).isEqualTo(info2); + assertThat(info2).isEqualTo(info1); + } + + @Test + void equals_returns_false_when_filenames_are_NOT_same() { + /* prepare */ + String sameChecksum = "checksum_dummy"; + + AssetFileInformation info1 = new AssetFileInformation(); + info1.setChecksum(sameChecksum); + info1.setFileName("filename1"); + + AssetFileInformation info2 = new AssetFileInformation(); + info1.setChecksum(sameChecksum); + info2.setFileName("filename1"); + + /* execute + test */ + assertThat(info1).isNotEqualTo(info2); + assertThat(info2).isNotEqualTo(info1); + } + + @Test + void equals_returns_false_when_checksums_are_NOT_same() { + /* prepare */ + String sameFileName = "filename"; + + AssetFileInformation info1 = new AssetFileInformation(); + info1.setChecksum("checksum-1"); + info1.setFileName(sameFileName); + + AssetFileInformation info2 = new AssetFileInformation(); + info1.setChecksum("cecksum-2"); + info2.setFileName(sameFileName); + + /* execute + test */ + assertThat(info1).isNotEqualTo(info2); + assertThat(info2).isNotEqualTo(info1); + } + + @Test + void equals_returns_false_when_checksums_and_filename_are_NOT_same() { + /* prepare */ + + AssetFileInformation info1 = new AssetFileInformation(); + info1.setChecksum("checksum-1"); + info1.setFileName("file-1"); + + AssetFileInformation info2 = new AssetFileInformation(); + info1.setChecksum("cecksum-2"); + info2.setFileName("file-2"); + + /* execute + test */ + assertThat(info1).isNotEqualTo(info2); + assertThat(info2).isNotEqualTo(info1); + } + +} diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileRepositoryDBTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileRepositoryDBTest.java new file mode 100644 index 000000000..e0a83d5bb --- /dev/null +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetFileRepositoryDBTest.java @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.asset; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Iterator; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import com.mercedesbenz.sechub.domain.scan.asset.AssetFile.AssetFileCompositeKey; +import com.mercedesbenz.sechub.domain.scan.asset.AssetFileRepositoryDBTest.SimpleTestConfiguration; + +@RunWith(SpringRunner.class) +@DataJpaTest +@ContextConfiguration(classes = { AssetFile.class, AssetFileRepository.class, SimpleTestConfiguration.class }) +//@EnableAutoConfiguration +class AssetFileRepositoryDBTest { + @Autowired + private TestEntityManager entityManager; + + @Autowired + private AssetFileRepository repositoryToTest; + + @Test + void fetchAllAssetIds_no_assets_exist() throws Exception { + + /* execute */ + List result = repositoryToTest.fetchAllAssetIds(); + + /* test */ + assertThat(result).isEmpty(); + + } + + @Test + void fetchAllAssetIds() throws Exception { + + /* prepare */ + AssetFile file1 = new AssetFile(AssetFileCompositeKey.builder().assetId("asset1").fileName("file1").build()); + file1.setChecksum("pseudo-checksum"); + file1.setData("testdata1".getBytes()); + entityManager.persist(file1); + + AssetFile file2a = new AssetFile(AssetFileCompositeKey.builder().assetId("asset2").fileName("file2a").build()); + file2a.setChecksum("pseudo-checksum"); + file2a.setData("testdata2a".getBytes()); + entityManager.persist(file2a); + + AssetFile file2b = new AssetFile(AssetFileCompositeKey.builder().assetId("asset2").fileName("file2b").build()); + file2b.setChecksum("pseudo-checksum"); + file2b.setData("testdata2b".getBytes()); + entityManager.persist(file2b); + + /* execute */ + List result = repositoryToTest.fetchAllAssetIds(); + + /* test */ + assertThat(result).contains("asset1", "asset2").hasSize(2); + + } + + @Test + void fetchAllAssetFilesWithAssetId() throws Exception { + + /* prepare */ + AssetFile file1 = new AssetFile(AssetFileCompositeKey.builder().assetId("asset1").fileName("file1").build()); + file1.setChecksum("pseudo-checksum1"); + file1.setData("testdata1".getBytes()); + entityManager.persist(file1); + + AssetFile file2a = new AssetFile(AssetFileCompositeKey.builder().assetId("asset2").fileName("file2a").build()); + file2a.setChecksum("pseudo-checksum2a"); + file2a.setData("testdata2a".getBytes()); + entityManager.persist(file2a); + + AssetFile file2b = new AssetFile(AssetFileCompositeKey.builder().assetId("asset2").fileName("file2b").build()); + file2b.setChecksum("pseudo-checksum2b"); + file2b.setData("testdata2b".getBytes()); + entityManager.persist(file2b); + + /* execute */ + List result = repositoryToTest.fetchAllAssetFilesWithAssetId("asset2"); + + /* test */ + assertThat(result).hasSize(2); + Iterator iterator = result.iterator(); + AssetFile assetFile2a = iterator.next(); + AssetFile assetFile2b = iterator.next(); + + assertThat(assetFile2a.getChecksum()).isEqualTo(file2a.getChecksum()); + assertThat(assetFile2b.getChecksum()).isEqualTo(file2b.getChecksum()); + } + + @TestConfiguration + @EnableAutoConfiguration + public static class SimpleTestConfiguration { + + } +} 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 new file mode 100644 index 000000000..400874fc6 --- /dev/null +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/asset/AssetServiceTest.java @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.domain.scan.asset; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +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.StorageService; + +class AssetServiceTest { + + private StorageService storageService; + private AssetFileRepository repository; + private UserInputAssertion inputAssertion; + private CheckSumSupport checkSumSupport; + private AssetService serviceToTest; + + @BeforeEach + void beforeEach() { + + storageService = mock(StorageService.class); + repository = mock(AssetFileRepository.class); + + serviceToTest = new AssetService(repository, inputAssertion, checkSumSupport, storageService); + } + + @Test + void fetchAllAssetIds_returns_result_from_repo() { + /* prepare */ + when(repository.fetchAllAssetIds()).thenReturn(List.of("asset1","asset2")); + + /* execute */ + List result = serviceToTest.fetchAllAssetIds(); + + /* test */ + verify(repository).fetchAllAssetIds(); + assertThat(result).contains("asset1","asset2"); + } + + @Test + void fetchAssetDetails_returns_details_based_on_repo_info() { + /* prepare */ + String assetId = "test-asset-1"; + + AssetFile assetFile1 = createAssetFileMock("file1.txt", "checksum1"); + AssetFile assetFile2 = createAssetFileMock("file2.txt", "checksum2"); + + when(repository.fetchAllAssetFilesWithAssetId(assetId)).thenReturn(List.of(assetFile1, assetFile2)); + + /* execute */ + AssetDetailData result = serviceToTest.fetchAssetDetails(assetId); + + /* test */ + verify(repository).fetchAllAssetFilesWithAssetId(assetId); + assertThat(result.getAssetid()).isEqualTo(assetId); + + AssetFileInformation expectedInfo1 = new AssetFileInformation(); + expectedInfo1.setChecksum("checksum1"); + expectedInfo1.setFileName("file1.txt"); + + AssetFileInformation expectedInfo2 = new AssetFileInformation(); + expectedInfo2.setChecksum("checksum2"); + expectedInfo2.setFileName("file2.txt"); + + assertThat(result.getFileInformation()).contains(expectedInfo1, expectedInfo2); + } + + private AssetFile createAssetFileMock(String fileName, String checksum) { + AssetFileCompositeKey mockKey1 = mock(AssetFileCompositeKey.class); + when(mockKey1.getFileName()).thenReturn(fileName); + + AssetFile assetFile1 = mock(AssetFile.class); + when(assetFile1.getChecksum()).thenReturn(checksum); + when(assetFile1.getKey()).thenReturn(mockKey1); + return assetFile1; + } + +} 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 27ec6b64f..ce75f651e 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 @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan.template; import static org.assertj.core.api.Assertions.*; diff --git a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolverTest.java b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolverTest.java index 23c33283e..85e2a7fd2 100644 --- a/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolverTest.java +++ b/sechub-scan/src/test/java/com/mercedesbenz/sechub/domain/scan/template/TemplateTypeScanConfigIdResolverTest.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.domain.scan.template; import static org.assertj.core.api.Assertions.*; diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/storage/MultiStorageService.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/storage/MultiStorageService.java index 1ac76a06e..f3929b6ff 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/storage/MultiStorageService.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/storage/MultiStorageService.java @@ -8,7 +8,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import com.mercedesbenz.sechub.commons.core.util.SecHubStorageUtil; import com.mercedesbenz.sechub.storage.core.AssetStorage; import com.mercedesbenz.sechub.storage.core.AssetStorageFactory; import com.mercedesbenz.sechub.storage.core.JobStorage; @@ -64,8 +63,8 @@ public JobStorage createJobStorageForPath(String storagePath, UUID jobUUID) { } @Override - public AssetStorage createAssetStorage(String storagePath, String assetId) { - return assetStorageFactory.createAssetStorage(storagePath, assetId); + public AssetStorage createAssetStorage(String assetId) { + return assetStorageFactory.createAssetStorage(assetId); } } \ No newline at end of file diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java index a7dcf452c..e06cebed7 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/UseCaseIdentifier.java @@ -196,15 +196,17 @@ public enum UseCaseIdentifier { /* assets */ UC_ADMIN_UPLOADS_ASSET_FILE(87), - + UC_ADMIN_DOWNLOADS_ASSET_FILE(88), - UC_ADMIN_FETCHES_LISTS_OF_ASSET_FILENAMES(89), - - UC_ADMIN_DELETES_ONE_FILE_FROM_ASSET(90), - - UC_ADMIN_DELETES_ASSET_COMPLETELY(91), - + UC_ADMIN_FETCHES_ASSET_IDS(89), + + UC_ADMIN_FETCHES_ASSET_DETAILS(90), + + UC_ADMIN_DELETES_ONE_FILE_FROM_ASSET(91), + + UC_ADMIN_DELETES_ASSET_COMPLETELY(92), + ; /* +-----------------------------------------------------------------------+ */ /* +............................ Helpers ................................+ */ diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesAssetDetails.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesAssetDetails.java new file mode 100644 index 000000000..d48e2407a --- /dev/null +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesAssetDetails.java @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.sharedkernel.usecases.admin.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.mercedesbenz.sechub.sharedkernel.Step; +import com.mercedesbenz.sechub.sharedkernel.usecases.UseCaseDefinition; +import com.mercedesbenz.sechub.sharedkernel.usecases.UseCaseGroup; +import com.mercedesbenz.sechub.sharedkernel.usecases.UseCaseIdentifier; + +/* @formatter:off */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@UseCaseDefinition( + id=UseCaseIdentifier.UC_ADMIN_FETCHES_ASSET_DETAILS, + group=UseCaseGroup.CONFIGURATION, + apiName="adminFetchAssetDetails", + title="Admin fetches asset details", + description="An administrator fetches details about an asset. For example: the result will contain names but also checksum of files.") +public @interface UseCaseAdminFetchesAssetDetails { + + Step value(); +} +/* @formatter:on */ diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesFilenamesOfAsset.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesAssetIds.java similarity index 71% rename from sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesFilenamesOfAsset.java rename to sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesAssetIds.java index fd60780f4..0d9bece57 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesFilenamesOfAsset.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/usecases/admin/config/UseCaseAdminFetchesAssetIds.java @@ -15,12 +15,12 @@ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @UseCaseDefinition( - id=UseCaseIdentifier.UC_ADMIN_FETCHES_LISTS_OF_ASSET_FILENAMES, + id=UseCaseIdentifier.UC_ADMIN_FETCHES_ASSET_IDS, group=UseCaseGroup.CONFIGURATION, - apiName="adminFetchListOfAssetFilenames", - title="Admin fetches asset file names", - description="An administrator fetches all file names of an asset.") -public @interface UseCaseAdminFetchesFilenamesOfAsset { + apiName="adminFetchAssetIds", + title="Admin fetches asset ids", + description="An administrator fetches all available asset ids.") +public @interface UseCaseAdminFetchesAssetIds { Step value(); } diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/AssetFileNameValidationImpl.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/AssetFileNameValidationImpl.java index d8a0af346..1da559b4b 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/AssetFileNameValidationImpl.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/AssetFileNameValidationImpl.java @@ -21,10 +21,9 @@ protected void validate(ValidationContext context) { if (context.isInValid()) { return; } - validateNoUpperCaseCharacters(context); validateSameLengthWhenTrimmed(context); validateLength(context); - validateOnlyAlphabeticDigitOrAllowedParts(context, '-', '_'); + validateOnlyAlphabeticDigitOrAllowedParts(context, '.', '-', '_'); } @Override diff --git a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertion.java b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertion.java index 4e913448b..aa9d50df7 100644 --- a/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertion.java +++ b/sechub-shared-kernel/src/main/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertion.java @@ -143,7 +143,7 @@ public void assertIsValidAssetId(String assetId) { /** * Asserts this is an valid asset filename. If not, a * {@link NotAcceptableException} will be thrown - * + * * @param fileName */ public void assertIsValidAssetFileName(String fileName) { diff --git a/sechub-shared-kernel/src/test/java/com/mercedesbenz/sechub/sharedkernel/validation/AssetFileNameValidationImplTest.java b/sechub-shared-kernel/src/test/java/com/mercedesbenz/sechub/sharedkernel/validation/AssetFileNameValidationImplTest.java new file mode 100644 index 000000000..b72a4b939 --- /dev/null +++ b/sechub-shared-kernel/src/test/java/com/mercedesbenz/sechub/sharedkernel/validation/AssetFileNameValidationImplTest.java @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +package com.mercedesbenz.sechub.sharedkernel.validation; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class AssetFileNameValidationImplTest { + + private AssetFileNameValidationImpl validation; + + @BeforeEach + void beforeEach() { + validation = new AssetFileNameValidationImpl(); + } + + @ParameterizedTest + @ValueSource(strings = { "asset1.txt", "prod_local_config.txt" }) + void valid_filenames_accepted(String validFileName) { + + assertThat(validation.validate(validFileName).isValid()).isTrue(); + } + + @ParameterizedTest + @ValueSource(strings = { "$asset1.txt" }) + void invalid_filenames_not_accepted(String validFileName) { + + assertThat(validation.validate(validFileName).isValid()).isFalse(); + } + +} diff --git a/sechub-shared-kernel/src/test/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertionTest.java b/sechub-shared-kernel/src/test/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertionTest.java index 4377b72db..ca8033189 100644 --- a/sechub-shared-kernel/src/test/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertionTest.java +++ b/sechub-shared-kernel/src/test/java/com/mercedesbenz/sechub/sharedkernel/validation/UserInputAssertionTest.java @@ -66,18 +66,18 @@ void assetIdValidation_used_for_assert_assetId() { /* test */ verify(assetIdValidation).validate("x"); } - + @Test void assetFilenameValidation_used_for_assert_asseFilename() { - + /* prepare */ AssetFileNameValidation validation = mock(AssetFileNameValidation.class); when(validation.validate("x")).thenReturn(new ValidationResult()); assertToTest.assetFilenameValidation = validation; - + /* execute */ assertToTest.assertIsValidAssetFileName("x"); - + /* test */ verify(validation).validate("x"); } diff --git a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorage.java b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorage.java index ef4512fb6..dff9d8721 100644 --- a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorage.java +++ b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorage.java @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.storage.core; -public interface AssetStorage extends Storage{ - +public interface AssetStorage extends Storage { } diff --git a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorageFactory.java b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorageFactory.java index e4ca562eb..97bc0583d 100644 --- a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorageFactory.java +++ b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/AssetStorageFactory.java @@ -6,10 +6,10 @@ public interface AssetStorageFactory { /** * Creates a new asset storage for given asset id * - * @param storagePath storage path - * @param assetId asset identifier + * @param assetId asset identifier + * * @return asset storage, never null */ - public AssetStorage createAssetStorage(String storagePath, String assetId); + public AssetStorage createAssetStorage(String assetId); } 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 999e310dc..ebda37094 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 @@ -8,7 +8,7 @@ public interface Storage { /** - * Stores given stream for this asset + * Stores given stream a storage object * * @param name name for storage object * @param stream origin data stream @@ -16,7 +16,7 @@ public interface Storage { public void store(String name, InputStream stream) throws IOException; /** - * Stores given stream for this job + * Stores given stream a storage object * * @param name name for storage object * @param stream origin data stream @@ -33,6 +33,14 @@ public interface Storage { */ public InputStream fetch(String name) throws IOException; + /** + * Deletes object + * + * @param name name for storage object + * @throws IOException + */ + public void delete(String name) throws IOException; + /* * Deletes all content of this storage */ diff --git a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/StorageService.java b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/StorageService.java index 8d125ef45..3c41d1479 100644 --- a/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/StorageService.java +++ b/sechub-storage-core/src/main/java/com/mercedesbenz/sechub/storage/core/StorageService.java @@ -24,10 +24,10 @@ public interface StorageService { * Creates a new asset storage object. If you no longer need the asset storage * object, you have to close the storage object to save resources. * - * @param storagePath storage path for assets - * @param assetId asset identifier + * @param assetId asset identifier + * * @return asset storage object */ - public AssetStorage createAssetStorage(String storagePath, String assetId); + public AssetStorage createAssetStorage(String assetId); } \ No newline at end of file diff --git a/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AbstractAwsS3Storage.java b/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AbstractAwsS3Storage.java index 18c74d3c1..561e7fa78 100644 --- a/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AbstractAwsS3Storage.java +++ b/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AbstractAwsS3Storage.java @@ -148,6 +148,13 @@ public InputStream fetch(String name) throws IOException { } } + @Override + public void delete(String name) throws IOException { + assertNotClosed(); + + client.deleteObject(bucketName, getObjectName(name)); + } + @Override public void deleteAll() throws IOException { diff --git a/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3AssetStorage.java b/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3AssetStorage.java index 759e5de24..e22044b43 100644 --- a/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3AssetStorage.java +++ b/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3AssetStorage.java @@ -6,8 +6,8 @@ public class AwsS3AssetStorage extends AbstractAwsS3Storage implements AssetStorage { - public AwsS3AssetStorage(AmazonS3 client, String bucketName, String storagePath, String assetId) { - super(client, bucketName, storagePath, assetId); + public AwsS3AssetStorage(AmazonS3 client, String bucketName, String assetId) { + super(client, bucketName, "assets", assetId); } - + } diff --git a/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3JobStorageFactory.java b/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3JobStorageFactory.java index fd47047e5..b82d58dba 100644 --- a/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3JobStorageFactory.java +++ b/sechub-storage-s3-aws/src/main/java/com/mercedesbenz/sechub/storage/s3/AwsS3JobStorageFactory.java @@ -58,8 +58,8 @@ public JobStorage createJobStorage(String storagePath, UUID jobUUID) { } @Override - public AssetStorage createAssetStorage(String storagePath, String assetId) { - return new AwsS3AssetStorage(s3Client, bucketName, storagePath, assetId); + public AssetStorage createAssetStorage(String assetId) { + return new AwsS3AssetStorage(s3Client, bucketName, assetId); } } diff --git a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/AbstractSharedVolumeStorage.java b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/AbstractSharedVolumeStorage.java index 304a08c16..6b30cdcff 100644 --- a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/AbstractSharedVolumeStorage.java +++ b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/AbstractSharedVolumeStorage.java @@ -31,26 +31,27 @@ public abstract class AbstractSharedVolumeStorage implements Storage { /** * Creates a shared volume storage + * * @param rootLocation * @param rootStoragePath * @param additionalStoragePathParts */ - public AbstractSharedVolumeStorage(Path rootLocation, String rootStoragePath, Object ... additionalStoragePathParts) { + public AbstractSharedVolumeStorage(Path rootLocation, String rootStoragePath, Object... additionalStoragePathParts) { requireNonNull(rootLocation, "rootLocation may not be null"); requireNonNull(rootStoragePath, "storagePath may not be null"); this.volumePath = rootLocation.resolve(rootStoragePath); - if (additionalStoragePathParts!=null) { - for (Object additionalStoragePathPart: additionalStoragePathParts) { - if (additionalStoragePathPart==null) { + if (additionalStoragePathParts != null) { + for (Object additionalStoragePathPart : additionalStoragePathParts) { + if (additionalStoragePathPart == null) { LOG.warn("Additional part was null at position: "); continue; } - this.volumePath= volumePath.resolve(additionalStoragePathPart.toString()); + this.volumePath = volumePath.resolve(additionalStoragePathPart.toString()); } } - this.relativePath=volumePath.relativize(rootLocation); - + this.relativePath = volumePath.relativize(rootLocation).toAbsolutePath().normalize(); + LOG.debug("Created {} with releative path:{}, volumePath: {}", getClass().getSimpleName(), relativePath, volumePath); } @@ -94,19 +95,33 @@ public void store(String name, InputStream stream, long contentLength) throws IO throw new StorageException("Could not initialize storage directory at: " + volumePath, e); } - LOG.info("storing {} in path {}", name, relativePath); + LOG.trace("storing {} in path {}", name, relativePath); Path pathToFile = getPathToFile(name); try (InputStream inputStream = stream) { Files.copy(inputStream, pathToFile, StandardCopyOption.REPLACE_EXISTING); - LOG.debug("Stored: {} at {}", name, pathToFile); + LOG.info("Stored: {} at {}", name, pathToFile); } catch (Exception e) { throw new IOException("Was not able to store input stream into file: " + pathToFile, e); } } + @Override + public void delete(String name) throws IOException { + assertNotClosed(); + + Path path = getPathToFile(name); + if (!Files.exists(path)) { + LOG.debug("File '{}' did not exis in volumePatht: {}, skip deletion", name, volumePath); + return; + } + Files.delete(path); + LOG.info("Deleted: {} at {}", name, path); + + } + public void deleteAll() throws IOException { assertNotClosed(); @@ -117,7 +132,7 @@ public void deleteAll() throws IOException { } FileSystemUtils.deleteRecursively(volumePath); - LOG.info("deleted all inside {}", volumePath); + LOG.info("Deleted all inside {}", volumePath); } catch (Exception e) { throw new IOException("Was not able to delete all from: " + volumePath, e); @@ -168,7 +183,7 @@ private Path getPathToFile(String fileName) { private void assertNotClosed() { if (closed) { - throw new IllegalStateException(getClass().getSimpleName()+" already closed!"); + throw new IllegalStateException(getClass().getSimpleName() + " already closed!"); } } diff --git a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeAssetStorage.java b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeAssetStorage.java index 6e11810e4..abb44553e 100644 --- a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeAssetStorage.java +++ b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeAssetStorage.java @@ -9,9 +9,8 @@ public class SharedVolumeAssetStorage extends AbstractSharedVolumeStorage implements AssetStorage { - public SharedVolumeAssetStorage(Path rootLocation, String storagePath, String assetId) { - super(rootLocation,storagePath, assetId); - requireNonNull(assetId, "assetId may not be null"); + public SharedVolumeAssetStorage(Path rootLocation, String assetId) { + super(rootLocation, "assets", requireNonNull(assetId, "assetId may not be null")); } } diff --git a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorage.java b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorage.java index 442e51a79..6f20c1843 100644 --- a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorage.java +++ b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorage.java @@ -11,8 +11,7 @@ public class SharedVolumeJobStorage extends AbstractSharedVolumeStorage implements JobStorage { public SharedVolumeJobStorage(Path rootLocation, String storagePath, UUID jobUUID) { - super(rootLocation, storagePath, jobUUID); - requireNonNull(jobUUID, "jobUUID may not be null"); + super(rootLocation, storagePath, requireNonNull(jobUUID, "jobUUID may not be null")); } } diff --git a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorageFactory.java b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorageFactory.java index 59a26e305..110c3b715 100644 --- a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorageFactory.java +++ b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/SharedVolumeJobStorageFactory.java @@ -30,8 +30,8 @@ public JobStorage createJobStorage(String projectId, UUID jobUUID) { } @Override - public AssetStorage createAssetStorage(String storagePath, String assetId) { - return new SharedVolumeAssetStorage(sharedVolumeUploadDirectory, storagePath, assetId); + public AssetStorage createAssetStorage(String assetId) { + return new SharedVolumeAssetStorage(sharedVolumeUploadDirectory, assetId); } } diff --git a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/VolumePathBuilder.java b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/VolumePathBuilder.java index 63b769120..6f2005a51 100644 --- a/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/VolumePathBuilder.java +++ b/sechub-storage-sharedvolume-spring/src/main/java/com/mercedesbenz/sechub/storage/sharevolume/spring/VolumePathBuilder.java @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT package com.mercedesbenz.sechub.storage.sharevolume.spring; public interface VolumePathBuilder { diff --git a/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java b/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java index 77d01303d..c9ebdb340 100644 --- a/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java +++ b/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/SecHubTestURLBuilder.java @@ -20,6 +20,7 @@ public class SecHubTestURLBuilder extends AbstractTestURLBuilder { private static final String API_ADMIN_SCHEDULER = API_ADMIN + "/scheduler"; private static final String API_ADMIN_TEMPLATE = API_ADMIN + "/template"; + private static final String API_ADMIN_ASSET = API_ADMIN + "/asset"; private static final String API_ADMIN_SCAN = API_ADMIN + "/scan"; private static final String API_ADMIN_CONFIG = API_ADMIN + "/config"; private static final String API_ADMIN_CONFIG_MAPPING = API_ADMIN_CONFIG + "/mapping"; @@ -229,7 +230,7 @@ public String buildAdminChangesUserEmailAddress(String userId, String newEmailAd } /* +-----------------------------------------------------------------------+ */ - /* +............................ admin: templates and assets................+ */ + /* +............................ admin: templates .........................+ */ /* +-----------------------------------------------------------------------+ */ public String buildAdminAssignsTemplateToProjectUrl(String templateId, String projectId) { return buildUrl(API_ADMIN_PROJECT, projectId, "template", templateId); @@ -255,6 +256,33 @@ public String buildAdminFetchesTemplateList() { return buildUrl(API_ADMIN_TEMPLATE + "s"); } + /* +-----------------------------------------------------------------------+ */ + /* +............................ admin: assets ............................+ */ + /* +-----------------------------------------------------------------------+ */ + public String buildAdminUploadsAssetFile(String assetId) { + return buildUrl(API_ADMIN_ASSET, assetId, "file"); + } + + public String buildAdminDownloadsAssetFile(String assetId, String fileName) { + return buildUrl(API_ADMIN_ASSET, assetId, "file", fileName); + } + + public String buildAdminFetchesAllAssetIds() { + return buildUrl(API_ADMIN_ASSET, "ids"); + } + + public String buildAdminFetchesAssetDetails(String assetId) { + return buildUrl(API_ADMIN_ASSET, assetId, "details"); + } + + public String buildAdminDeletesAssetFile(String assetId, String fileName) { + return buildUrl(API_ADMIN_ASSET, assetId, "file", fileName); + } + + public String buildAdminDeletesAsset(String assetId) { + return buildUrl(API_ADMIN_ASSET, assetId); + } + /* +-----------------------------------------------------------------------+ */ /* +............................ admin/projects ...........................+ */ /* +-----------------------------------------------------------------------+ */ @@ -485,14 +513,6 @@ public String buildAdminFetchesEncryptionStatus() { return buildUrl(API_ADMIN, "encryption/status"); } - public String buildAdminUploadsAssetFile(String assetId) { - return buildUrl(API_ADMIN, "asset", assetId, "file"); - } - - public String buildAdminDownloadsAssetFile(String assetId, String fileName) { - return buildUrl(API_ADMIN, "asset", assetId, "file", fileName); - } - /* +-----------------------------------------------------------------------+ */ /* +............................ integration test special (anonymous) .....+ */ /* +-----------------------------------------------------------------------+ */ @@ -727,6 +747,4 @@ public String buildIntegrationTestFetchScanProjectConfigurations(String projectI return buildUrl(API_ANONYMOUS, "integrationtest/project-scanconfig/" + projectId); } - - } diff --git a/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/TestUtil.java b/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/TestUtil.java index c29eca564..9b552cdbb 100644 --- a/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/TestUtil.java +++ b/sechub-testframework/src/main/java/com/mercedesbenz/sechub/test/TestUtil.java @@ -198,10 +198,10 @@ public static Path createTempDirectoryInBuildFolder(String dirNectoryBaseName, F } return dirAsPath; } - + public static Path createTempFileInBuildSubFolder(String subFolderName, String explicitFileName, FileAttribute... attributes) throws IOException { Path parent = ensureBuildTmpDirAsFile(); - if (subFolderName!=null) { + if (subFolderName != null) { parent = parent.resolve(subFolderName); } Path filePath = parent.resolve(explicitFileName); @@ -214,13 +214,13 @@ public static Path createTempFileInBuildSubFolder(String subFolderName, String e throw new RuntimeException("Cannot delete former temp file", e); } } + Files.createDirectories(filePath.getParent()); Files.createFile(filePath, attributes); if (isDeletingTempFiles()) { filePath.toFile().deleteOnExit(); } return filePath; } - /** * Creates a temporary file inside gradle build folder at @@ -237,7 +237,7 @@ public static Path createTempFileInBuildSubFolder(String subFolderName, String e * @throws IOException */ public static Path createTempFileInBuildFolder(String explicitFileName, FileAttribute... attributes) throws IOException { - return createTempFileInBuildSubFolder(null, explicitFileName, attributes); + return createTempFileInBuildSubFolder(null, explicitFileName, attributes); } private static Path ensureBuildTmpDirAsFile() throws IOException {