Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDS prepare upload remote data to shared storage #3131

Merged
merged 29 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c98952d
Added upload classes and archive support for prepare #3026
lorriborri May 14, 2024
6e5f747
moved git download into folder #3026
lorriborri May 15, 2024
8b6c45a
Added checksum for upload files
lorriborri May 16, 2024
74f6c0c
Added test for UploadService #3026
lorriborri May 21, 2024
00a4ff3
Added unit tests for upload #3026
lorriborri May 22, 2024
e8ea8e6
Refactored PDSStorageConstants #3026
lorriborri May 24, 2024
4d2082f
Merge branch 'develop' into feature-3026-pds-prepare-upload-service
lorriborri May 24, 2024
43a6c11
Added change requests #3026
lorriborri May 24, 2024
d2b7d1c
Added change requests #3026
lorriborri May 27, 2024
e1eb1e2
Moved LogSanitizer in pds-commons-core #3026
lorriborri May 27, 2024
75ac56e
Added UploadException and LogSanitazier #3026
lorriborri May 28, 2024
55187d0
Added UsageException for wrong configurations and download fails #3026
lorriborri May 28, 2024
51e2555
Initial integration test #3026
lorriborri May 29, 2024
26da4f6
Added PDS_SORAGE environment variables to be adde to the envrionment …
lorriborri May 29, 2024
6054e12
Added integrationtest #3026
lorriborri May 31, 2024
129e07c
Added change requests #3026
lorriborri May 31, 2024
86034e2
Merge branch 'develop' into feature-3026-pds-prepare-upload-service
lorriborri May 31, 2024
c0d27f6
Removed unnecessary ENV #3026
lorriborri May 31, 2024
8561617
Refactoring + changes #3026
de-jcup Jun 3, 2024
ba0f3ab
Reduced log output and speed up integration tests #3197, #3198
de-jcup Jun 7, 2024
2dd0cb7
Fixed storage problem and enhanced integration tests #3026
de-jcup Jun 7, 2024
083b221
Refactoring and bugfixes #3026
de-jcup Jun 10, 2024
6b535c4
Skopeo call changes #3026
de-jcup Jun 10, 2024
63ce627
Changed directory cleanup from process to plain java #3026
de-jcup Jun 10, 2024
30e7e64
Changed git prepare module cleanup behavior and documentatino #3026
de-jcup Jun 11, 2024
a4ac055
Merge branch 'develop' into feature-3026-pds-prepare-upload-service
de-jcup Jun 11, 2024
87d2b9c
Review changes #3026
de-jcup Jun 12, 2024
2e87924
Merge branch 'develop' into feature-3026-pds-prepare-upload-service
de-jcup Jun 13, 2024
a1b1809
Review changes #3026
de-jcup Jun 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.mercedesbenz.sechub.commons.archive;
de-jcup marked this conversation as resolved.
Show resolved Hide resolved

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

public class DirectoryAndFileSupport {

/**
* Cleans all unwanted content recursively starting with parent folder. Each
* file or directory which is accepted by the given filter will be deleted.
*
* @param parentDirectory the directory to start from
* @param filterAcceptingFilesToDelete filter which accepts only files to delete
* @throws IOException
*/
public void cleanDirectories(File parentDirectory, FileFilter filterAcceptingFilesToDelete) throws IOException {
if (parentDirectory == null) {
throw new IllegalArgumentException("Parent folder may not be null!");
}
cleanDirectoriesRecursive(parentDirectory, filterAcceptingFilesToDelete);
}

private void cleanDirectoriesRecursive(File parentDirectory, FileFilter filter) throws IOException {
File[] files = parentDirectory.listFiles();

for (File file : files) {
handleFileOrDirectoryRecursive(filter, file);
}

}

private void handleFileOrDirectoryRecursive(FileFilter filter, File file) throws IOException {
if (file.isDirectory()) {
if (filter.accept(file)) {
/* delete the sub directory recursive */
FileUtils.forceDelete(file);
} else {
/* not accepted to delete, but inspect children */
cleanDirectoriesRecursive(file, filter);
}
} else {
/* not directory */
if (filter.accept(file)) {
FileUtils.forceDelete(file);
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package com.mercedesbenz.sechub.commons.archive;

import static org.junit.jupiter.api.Assertions.*;

import java.io.File;
import java.io.IOException;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import com.mercedesbenz.sechub.test.TestFileWriter;
import com.mercedesbenz.sechub.test.TestUtil;

class DirectoryAndFileSupportTest {

private DirectoryAndFileSupport supportToTest;

private TestFileWriter testFileWriter = new TestFileWriter();
private File gitFolder;
private File gitIgnoreInGitFolder;
private File gitAttributesInGitFolder;
private File testDataInGit;
private File subFolder1;
private File testDataInSubFolder1;
private File gitAttributesInSubFolder1;
private File gitIgnoreInSubFolder1;
private File git2InsideSubFolder1;
private File testDataInGit2;
private File subFolder2InSubFolder1;
private File testDataInSubFolder2;
private File parentFolder;

@BeforeEach
void beforeEach() {
supportToTest = new DirectoryAndFileSupport();
}

@Test
void testfile_structure_removing_git_folder_git_attributes_and_git_ignore_files_recursive() throws Exception {
/* prepare */
initTestFileStructure();

/* execute */
supportToTest.cleanDirectories(parentFolder, (file) -> {
if (file.isDirectory()) {
return file.getName().equals(".git");
}
return file.getName().equals(".gitattributes") || file.getName().equals(".gitignore");
});

/* test */
assertFalse(gitIgnoreInGitFolder.exists());
assertFalse(gitAttributesInGitFolder.exists());
assertFalse(testDataInGit.exists());
assertTrue(testDataInSubFolder1.exists());
assertFalse(gitAttributesInSubFolder1.exists());
assertFalse(gitIgnoreInSubFolder1.exists());
assertFalse(gitFolder.exists());
assertFalse(git2InsideSubFolder1.exists());
assertFalse(testDataInGit2.exists());
assertTrue(testDataInSubFolder2.exists());

}

@Test
void testfile_structure_removing_git_attributes_and_git_ignore_files_recursive() throws Exception {
/* prepare */
initTestFileStructure();

/* execute */
supportToTest.cleanDirectories(parentFolder, (file) -> {
if (file.isFile()) {
return file.getName().equals(".gitattributes") || file.getName().equals(".gitignore");
}
return false;
});

/* test */
assertFalse(gitIgnoreInGitFolder.exists());
assertFalse(gitAttributesInGitFolder.exists());
assertTrue(testDataInGit.exists());
assertTrue(testDataInSubFolder1.exists());
assertFalse(gitAttributesInSubFolder1.exists());
assertFalse(gitIgnoreInSubFolder1.exists());
assertTrue(gitFolder.exists());
assertTrue(git2InsideSubFolder1.exists());
assertTrue(testDataInGit2.exists());
assertTrue(testDataInSubFolder2.exists());

}

@Test
void testfile_structure_removing_git_folder_only_recursive() throws Exception {
/* prepare */
initTestFileStructure();

/* execute */
supportToTest.cleanDirectories(parentFolder, (file) -> {
if (file.isDirectory()) {
return file.getName().equals(".git");
}
return false;
});

/* test */
assertFalse(gitIgnoreInGitFolder.exists());
assertFalse(gitAttributesInGitFolder.exists());
assertFalse(testDataInGit.exists());
assertTrue(testDataInSubFolder1.exists());
assertTrue(gitAttributesInSubFolder1.exists());
assertTrue(gitIgnoreInSubFolder1.exists());
assertFalse(gitFolder.exists());
assertFalse(git2InsideSubFolder1.exists());
assertFalse(testDataInGit2.exists());
assertTrue(testDataInSubFolder2.exists());

}

@Test
void testfile_structure_nothing_removed_because_all_not_accepted_recursive() throws Exception {
/* prepare */
initTestFileStructure();

/* execute */
supportToTest.cleanDirectories(parentFolder, (file) -> {
return false;
});

assertAllTestFileStructureFiles(true);

}

@Test
void testfile_structure_all_removed_because_all_accepted_recursive() throws Exception {
/* prepare */
initTestFileStructure();

/* execute */
supportToTest.cleanDirectories(parentFolder, (file) -> {
return true;
});

assertAllTestFileStructureFiles(false);

}

/**
* Creates following file structure:
*
* <pre>
* /.git/.gitignore
* /.git/.gitattributes
* /.git/testdata-inside-git-folder.txt
* /subfolder1/testdata.txt
* /subfolder1/.gitattributes
* /subfolder1/.gitignore
* /subfolder1/.git/testdata-git2.txt
* /subfolder1/subfolder2/testdata-in-subfolder2
* </pre>
*
* @throws IOException
*/
void initTestFileStructure() throws IOException {
parentFolder = TestUtil.createTempDirectoryInBuildFolder("directory-and-file-support").toFile();

gitFolder = new File(parentFolder, ".git");
gitIgnoreInGitFolder = new File(gitFolder, ".gitignore");
gitAttributesInGitFolder = new File(gitFolder, ".gitattributes");
testDataInGit = new File(gitFolder, "testdata-inside-git-folder.txt");

testFileWriter.write(gitIgnoreInGitFolder, "testdata-gitignore-in-gitfolder");
testFileWriter.write(gitAttributesInGitFolder, "testdata-gitattributes-in-gitfolder");
testFileWriter.write(testDataInGit, "testdata-in-git-folder");

subFolder1 = new File(parentFolder, "subfolder1");

testDataInSubFolder1 = new File(subFolder1, "testdata.txt");
gitAttributesInSubFolder1 = new File(subFolder1, ".gitattributes");
gitIgnoreInSubFolder1 = new File(subFolder1, ".gitignore");

testFileWriter.write(testDataInSubFolder1, "testdata-subfolder1");
testFileWriter.write(gitAttributesInSubFolder1, "testdata-gitattributes-in-gitfolder");
testFileWriter.write(gitIgnoreInSubFolder1, "testdata-in-git-folder");

git2InsideSubFolder1 = new File(subFolder1, ".git");
testDataInGit2 = new File(git2InsideSubFolder1, "testdata-git2.txt");
testFileWriter.write(testDataInGit2, "testdata-in-git-folder2");

subFolder2InSubFolder1 = new File(subFolder1, "subfolder2");
testDataInSubFolder2 = new File(subFolder2InSubFolder1, "testdata-in-subfolder2");
testFileWriter.write(testDataInSubFolder2, "testdata-in-subfolder2");

/* check precondition */
assertAllTestFileStructureFiles(true);

}

private void assertAllTestFileStructureFiles(boolean mustExist) {
assertEquals(mustExist, gitFolder.exists());
assertEquals(mustExist, gitIgnoreInGitFolder.exists());
assertEquals(mustExist, gitAttributesInGitFolder.exists());
assertEquals(mustExist, testDataInGit.exists());
assertEquals(mustExist, testDataInSubFolder1.exists());
assertEquals(mustExist, gitAttributesInSubFolder1.exists());
assertEquals(mustExist, gitIgnoreInSubFolder1.exists());
assertEquals(mustExist, git2InsideSubFolder1.exists());
assertEquals(mustExist, testDataInGit2.exists());
assertEquals(mustExist, testDataInSubFolder2.exists());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.commons.pds;

import java.util.List;

public class DefaultProcessBuilderFactory implements ProcessBuilderFactory {

public ProcessBuilder createForCommands(String... commands) {
return new ProcessBuilder(commands);
}

@Override
public ProcessBuilder createForCommandList(List<String> commands) {
return new ProcessBuilder(commands);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.commons.pds;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

/**
Expand All @@ -15,11 +19,11 @@ public ProcessAdapter(Process process) {
this.process = process;
}

public boolean waitFor(long minutesToWaitForResult, TimeUnit timeUnit) throws InterruptedException {
public boolean waitFor(long timeOut, TimeUnit timeUnit) throws InterruptedException {
if (process == null) {
return false;
}
return process.waitFor(minutesToWaitForResult, timeUnit);
return process.waitFor(timeOut, timeUnit);
}

public boolean isAlive() {
Expand All @@ -43,8 +47,55 @@ public int exitValue() {
return process.exitValue();
}

public Process getProcess() {
return process;
/**
* Sends given characters as user input to process -uses UTF-8 as charset.
*
* Attention: You are NOT allowed to redirect the input stream of the process
* builder when you use this method - Otherwise it will not work!
*
* <h3>Correct example</h3>
*
* <pre>
* ProcessBuilder pb = new ProcessBuilder("bash", "script-with-userinput.sh");
* pb.redirectOutput(Redirect.INHERIT);
* pb.redirectError(Redirect.INHERIT);
* </pre>
*
* <h3>Wrong examples</h3> Example W1
*
* <pre>
* ProcessBuilder pb = new ProcessBuilder("bash", "script-with-userinput.sh");
* pb.inheritIO(); // does also redirect input -> will not work...
* </pre>
*
* Example W2
*
* <pre>
* ProcessBuilder pb = new ProcessBuilder("bash", "script-with-userinput.sh");
* pb.redirectOutput(Redirect.INHERIT);
* pb.redirectError(Redirect.INHERIT);
* pb.redirectInput(Redirect.INHERIT); // redirect input -> will not work...
* </pre>
*
*
*
*/
public void enterInput(char[] unsealedPassword) throws IOException {
if (process == null) {
return;
}
/*
* Don't be confused: in javadoc of this method we forbid the redirect of INPUT
* stream when using enterInput and here we use the output stream of the
* process... It is correct, because the output stream is connected to the input
* stream of the process - see see javadoc of getOutputStream() for more
* details.
*/
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream(), StandardCharsets.UTF_8))) {
bw.write(unsealedPassword);
bw.flush();
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.commons.pds;

import java.util.List;

/**
* An abstraction for creating process builders. Via this class we can mock
* process building in tests very easy with Mockito.
*
* @author Albert Tregnaghi
*
*/
public interface ProcessBuilderFactory {

public ProcessBuilder createForCommands(String... commands);

public ProcessBuilder createForCommandList(List<String> commands);
}
Loading
Loading