Skip to content

Commit

Permalink
Added change requests #3028
Browse files Browse the repository at this point in the history
  • Loading branch information
lorriborri committed May 22, 2024
1 parent e4eeb37 commit 8468743
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.mercedesbenz.sechub.wrapper.prepare.modules.InputValidatorExitcode.*;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

Expand All @@ -19,9 +20,17 @@ public class AbstractInputValidator implements InputValidator {
private final Pattern LOCATION_PATTERN;
private final Pattern USERNAME_PATTERN;
private final Pattern PASSWORD_PATTERN;
private final List<String> forbiddenCharacters = Arrays.asList(">", "<", "!", "?", "*", "'", "\"", ";", "&", "|", "`", "$", "{", "}");
private final List<String> forbiddenCharacters = Collections
.unmodifiableList(Arrays.asList(">", "<", "!", "?", "*", "'", "\"", ";", "&", "|", "`", "$", "{", "}"));

public AbstractInputValidator(String type, Pattern locationPattern, Pattern usernamePattern, Pattern passwordPattern) {
assertPatternNotNull(locationPattern);
assertPatternNotNull(usernamePattern);
assertPatternNotNull(passwordPattern);
if (isTypeNullOrEmpty(type)) {
throw new IllegalArgumentException("Type must not be null or empty.");
}

this.TYPE = type;
this.LOCATION_PATTERN = locationPattern;
this.USERNAME_PATTERN = usernamePattern;
Expand All @@ -39,7 +48,7 @@ private void validateModule(PrepareWrapperContext context) throws PrepareWrapper
String type = secHubRemoteDataConfiguration.getType();

if (isTypeNullOrEmpty(type)) {
LOG.debug("Not type defined. Location is: {}", location);
LOG.debug("No type defined. Location is: {}", location);
validateLocation(location);
return;
} else if (isMatchingType(type)) {
Expand All @@ -52,9 +61,8 @@ private void validateModule(PrepareWrapperContext context) throws PrepareWrapper

private void validateCredentials(PrepareWrapperContext context) throws PrepareWrapperInputValidatorException {
SecHubRemoteDataConfiguration secHubRemoteDataConfiguration = context.getRemoteDataConfiguration();
if (secHubRemoteDataConfiguration.getCredentials().isEmpty()) {
return;
} else {

if (secHubRemoteDataConfiguration.getCredentials().isPresent()) {
SecHubRemoteCredentialConfiguration remoteCredentialConfiguration = secHubRemoteDataConfiguration.getCredentials().get();
if (remoteCredentialConfiguration.getUser().isPresent()) {
SecHubRemoteCredentialUserData user = remoteCredentialConfiguration.getUser().get();
Expand Down Expand Up @@ -116,4 +124,10 @@ private void validateLocationCharacters(String url) {
}
}
}

private void assertPatternNotNull(Pattern pattern) {
if (pattern == null) {
throw new IllegalArgumentException("Pattern must not be null.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.mercedesbenz.sechub.commons.pds.PDSDefaultParameterValueConstants;
import com.mercedesbenz.sechub.commons.pds.PDSProcessAdapterFactory;
import com.mercedesbenz.sechub.commons.pds.ProcessAdapter;

@Component
Expand All @@ -28,9 +26,6 @@ public abstract class WrapperTool {
@Value("${" + KEY_PDS_PREPARE_PROCESS_TIMEOUT_SECONDS + ":-1}")
private int pdsPrepareProcessTimeoutSeconds;

@Autowired
public PDSProcessAdapterFactory processAdapterFactory;

protected abstract void cleanUploadDirectory(String uploadDirectory) throws IOException;

protected void waitForProcessToFinish(ProcessAdapter process) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ public class GitInputValidator extends AbstractInputValidator {

private static final String TYPE = "git";
private static final String GIT_LOCATION_REGEX = "((git|ssh|http(s)?)|(git@[\\w\\.]+))(:(//)?)([\\w\\.@\\:/\\-~]+)(\\.git)(/)?$";
private static final Pattern GIT_LOCATION_PATTERN = Pattern.compile(GIT_LOCATION_REGEX);
private static final String GIT_USERNAME_REGEX = "^[a-zA-Z0-9-_\\d](?:[a-zA-Z0-9-_\\d]|(?=[a-zA-Z0-9-_\\d])){0,38}$";
private static final Pattern GIT_USERNAME_PATTERN = Pattern.compile(GIT_USERNAME_REGEX);
private static final String GIT_PASSWORD_REGEX = "^(gh[ps]_[a-zA-Z0-9]{36}|github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59})$";
private static final Pattern GIT_PASSWORD_PATTERN = Pattern.compile(GIT_PASSWORD_REGEX);

public GitInputValidator() {
super(TYPE, Pattern.compile(GIT_LOCATION_REGEX), Pattern.compile(GIT_USERNAME_REGEX), Pattern.compile(GIT_PASSWORD_REGEX));
super(TYPE, GIT_LOCATION_PATTERN, GIT_USERNAME_PATTERN, GIT_PASSWORD_PATTERN);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@Service
public class PrepareWrapperModuleGit implements PrepareWrapperModule {

Logger LOG = LoggerFactory.getLogger(PrepareWrapperModuleGit.class);
private static final Logger LOG = LoggerFactory.getLogger(PrepareWrapperModuleGit.class);

@Value("${" + KEY_PDS_PREPARE_AUTO_CLEANUP_GIT_FOLDER + ":true}")
private boolean pdsPrepareAutoCleanupGitFolder;
Expand Down Expand Up @@ -61,13 +61,14 @@ public boolean prepare(PrepareWrapperContext context) throws IOException {
prepareRemoteConfiguration(context, secHubRemoteDataConfiguration);

if (!isDownloadSuccessful(context)) {
LOG.error("Download of git repository was not successful.");
throw new IOException("Download of git repository was not successful.");
}
cleanup(context);
return true;
}

public boolean isDownloadSuccessful(PrepareWrapperContext context) {
protected boolean isDownloadSuccessful(PrepareWrapperContext context) {
// check if download folder contains git
Path path = Paths.get(context.getEnvironment().getPdsPrepareUploadFolderDirectory());
if (Files.isDirectory(path)) {
Expand All @@ -88,13 +89,12 @@ private void prepareRemoteConfiguration(PrepareWrapperContext context, SecHubRem
}

Optional<SecHubRemoteCredentialUserData> optUser = credentials.get().getUser();
if (optUser.isPresent()) {
SecHubRemoteCredentialUserData user = optUser.get();
clonePrivateRepository(context, user, location);
return;
if (optUser.isEmpty()) {
throw new IllegalStateException("Defined credentials have no credential user data for location: " + location);
}

throw new IllegalStateException("Defined credentials have no credential user data for location: " + location);
SecHubRemoteCredentialUserData user = optUser.get();
clonePrivateRepository(context, user, location);
}

private void clonePrivateRepository(PrepareWrapperContext context, SecHubRemoteCredentialUserData user, String location) throws IOException {
Expand All @@ -112,7 +112,7 @@ private void clonePrivateRepository(PrepareWrapperContext context, SecHubRemoteC

git.downloadRemoteData(gitContext);

SecHubMessage message = new SecHubMessage(SecHubMessageType.INFO, "Cloned private repository: " + location);
SecHubMessage message = new SecHubMessage(SecHubMessageType.INFO, "Cloned private image: " + location);
context.getUserMessages().add(message);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mercedesbenz.sechub.commons.pds.PDSProcessAdapterFactory;
import com.mercedesbenz.sechub.commons.pds.ProcessAdapter;
import com.mercedesbenz.sechub.wrapper.prepare.modules.WrapperTool;

Expand All @@ -22,6 +23,9 @@ public class WrapperGit extends WrapperTool {
@Autowired
JGitAdapter jGitAdapter;

@Autowired
PDSProcessAdapterFactory processAdapterFactory;

public void downloadRemoteData(GitContext gitContext) {
LOG.debug("Start cloning with JGit.");
jGitAdapter.clone(gitContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
@Service
public class PrepareWrapperModuleSkopeo implements PrepareWrapperModule {

Logger LOG = LoggerFactory.getLogger(PrepareWrapperModuleSkopeo.class);
private static final Logger LOG = LoggerFactory.getLogger(PrepareWrapperModuleSkopeo.class);

@Value("${" + KEY_PDS_PREPARE_MODULE_SKOPEO_ENABLED + ":true}")
private boolean pdsPrepareModuleSkopeoEnabled;
Expand Down Expand Up @@ -58,13 +58,14 @@ public boolean prepare(PrepareWrapperContext context) throws IOException {
prepareRemoteConfiguration(context, secHubRemoteDataConfiguration);

if (!isDownloadSuccessful(context)) {
LOG.error("Download of git repository was not successful.");
throw new IOException("Download of docker image was not successful.");
}
cleanup(context);
return true;
}

public boolean isDownloadSuccessful(PrepareWrapperContext context) {
protected boolean isDownloadSuccessful(PrepareWrapperContext context) {
// check if download folder contains a .tar archive
Path path = Paths.get(context.getEnvironment().getPdsPrepareUploadFolderDirectory());
if (Files.isDirectory(path)) {
Expand All @@ -75,7 +76,7 @@ public boolean isDownloadSuccessful(PrepareWrapperContext context) {
.toList(); // collect all matched to a List
return !result.isEmpty();
} catch (IOException e) {
throw new RuntimeException("Error while checking download of docker image", e);
return false;
}
}
return false;
Expand All @@ -95,13 +96,12 @@ private void prepareRemoteConfiguration(PrepareWrapperContext context, SecHubRem
}

Optional<SecHubRemoteCredentialUserData> optUser = credentials.get().getUser();
if (optUser.isPresent()) {
SecHubRemoteCredentialUserData user = optUser.get();
downloadPrivateImage(context, user, location);
return;
if (optUser.isEmpty()) {
throw new IllegalStateException("Defined credentials have no credential user data for location: " + location);
}

throw new IllegalStateException("Defined credentials have no credential user data for location: " + location);
SecHubRemoteCredentialUserData user = optUser.get();
downloadPrivateImage(context, user, location);
}

private void downloadPrivateImage(PrepareWrapperContext context, SecHubRemoteCredentialUserData user, String location) throws IOException {
Expand All @@ -119,7 +119,7 @@ private void downloadPrivateImage(PrepareWrapperContext context, SecHubRemoteCre

skopeo.download(skopeoContext);

SecHubMessage message = new SecHubMessage(SecHubMessageType.INFO, "Cloned private repository: " + location);
SecHubMessage message = new SecHubMessage(SecHubMessageType.INFO, "Download private image: " + location);
context.getUserMessages().add(message);
}

Expand All @@ -133,7 +133,7 @@ private void downloadPublicImage(PrepareWrapperContext context, String location)

skopeo.download(skopeoContext);

SecHubMessage message = new SecHubMessage(SecHubMessageType.INFO, "Cloned public repository: " + location);
SecHubMessage message = new SecHubMessage(SecHubMessageType.INFO, "Download public image: " + location);
context.getUserMessages().add(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ public class SkopeoInputValidator extends AbstractInputValidator {

public static final String TYPE = "docker";
private static final String SKOPEO_LOCATION_REGEX = "((docker://|https://)?([a-zA-Z0-9-_.].[a-zA-Z0-9-_.]/)?[a-zA-Z0-9-_.]+(:[a-zA-Z0-9-_.]+)?(/)?)+(@sha256:[a-f0-9]{64})?";
private static final Pattern SKOPEO_LOCATION_PATTERN = Pattern.compile(SKOPEO_LOCATION_REGEX);
private static final String SKOPEO_USERNAME_REGEX = "^[a-zA-Z0-9-_\\d](?:[a-zA-Z0-9-_\\d]|(?=[a-zA-Z0-9-_\\d])){0,38}$";
private static final Pattern SKOPEO_USERNAME_PATTERN = Pattern.compile(SKOPEO_USERNAME_REGEX);
private static final String SKOPEO_PASSWORD_REGEX = "^[a-zA-Z0-9-_\\d]{0,80}$";
private static final Pattern SKOPEO_PASSWORD_PATTERN = Pattern.compile(SKOPEO_PASSWORD_REGEX);

public SkopeoInputValidator() {
super(TYPE, Pattern.compile(SKOPEO_LOCATION_REGEX), Pattern.compile(SKOPEO_USERNAME_REGEX), Pattern.compile(SKOPEO_PASSWORD_REGEX));
super(TYPE, SKOPEO_LOCATION_PATTERN, SKOPEO_USERNAME_PATTERN, SKOPEO_PASSWORD_PATTERN);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.mercedesbenz.sechub.commons.core.security.CryptoAccess;
import com.mercedesbenz.sechub.commons.pds.PDSProcessAdapterFactory;
import com.mercedesbenz.sechub.commons.pds.ProcessAdapter;
import com.mercedesbenz.sechub.wrapper.prepare.modules.WrapperTool;

Expand All @@ -22,6 +24,9 @@ public class WrapperSkopeo extends WrapperTool {
@Value("${" + KEY_PDS_PREPARE_AUTHENTICATION_FILE_SKOPEO + ":authentication.json}")
String pdsPrepareAuthenticationFileSkopeo;

@Autowired
PDSProcessAdapterFactory processAdapterFactory;

public void download(SkopeoContext context) throws IOException {
if (!context.getCredentialMap().isEmpty()) {
login(context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ public class PrepareWrapperPreparationService {

public AdapterExecutionResult startPreparation() throws IOException {

boolean atLeastOneModuleExecuted = false;

LOG.debug("Start preparation");
PrepareWrapperContext context = factory.create(environment);
SecHubRemoteDataConfiguration remoteDataConfiguration = context.getRemoteDataConfiguration();
Expand All @@ -47,18 +45,14 @@ public AdapterExecutionResult startPreparation() throws IOException {

for (PrepareWrapperModule module : modules) {

context.getUserMessages().add(new SecHubMessage(SecHubMessageType.INFO, "Execute prepare module: " + module.getClass().getSimpleName()));
if (module.prepare(context)) {
atLeastOneModuleExecuted = true;
context.getUserMessages().add(new SecHubMessage(SecHubMessageType.INFO, "Executed prepare module: " + module.getClass().getSimpleName()));
PrepareResult result = new PrepareResult(PrepareStatus.OK);
return new AdapterExecutionResult(result.toString(), context.getUserMessages());
}
}

if (!atLeastOneModuleExecuted) {
return createAdapterExecutionResult(PrepareStatus.FAILED, SecHubMessageType.ERROR, "No module was able to prepare the defined remote data.");
}

PrepareResult result = new PrepareResult(PrepareStatus.OK);
return new AdapterExecutionResult(result.toString(), context.getUserMessages());
return createAdapterExecutionResult(PrepareStatus.FAILED, SecHubMessageType.ERROR, "No module was able to prepare the defined remote data.");
}

private AdapterExecutionResult createAdapterExecutionResult(PrepareStatus status, SecHubMessageType type, String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
@Component
public class PrepareWrapperRemoteConfigurationExtractor {

/**
* Extracts the remote data configuration from the SecHub configuration model.
* The method returns nul, if no remote configuration could be found. If more
* than one remote configuration is found, an exception is thrown.
*
* @param model sechub configuration model
* @return remote data configuration
*/
public SecHubRemoteDataConfiguration extract(SecHubConfigurationModel model) {
List<SecHubRemoteDataConfiguration> remoteDataConfigurationList = new ArrayList<>();
if (model == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ void prepare_successful_when_no_credentials_are_configured() throws IOException
verify(git).downloadRemoteData(any(GitContext.class));
}

@Test
void prepare_returns_false_when_modul_is_disabled() throws IOException {
/* prepare */
PrepareWrapperEnvironment environment = mock(PrepareWrapperEnvironment.class);
when(environment.getPdsPrepareUploadFolderDirectory()).thenReturn("temp");
PrepareWrapperContext context = new PrepareWrapperContext(createFromJSON("{}"), environment);

SecHubRemoteDataConfiguration remoteDataConfiguration = new SecHubRemoteDataConfiguration();
remoteDataConfiguration.setLocation("my-example-location");
remoteDataConfiguration.setType("docker");
context.setRemoteDataConfiguration(remoteDataConfiguration);

ReflectionTestUtils.setField(moduleToTest, "pdsPrepareModuleGitEnabled", false);

/* execute */
boolean result = moduleToTest.prepare(context);

/* test */
assertFalse(result);
}

@Test
void isDownloadSuccessful_returns_true_when_git_file_in_directory() throws IOException {
/* prepare */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,28 @@ void prepare_successful_when_no_credentials_are_configured() throws IOException
verify(skopeo).cleanUploadDirectory(tempDir.toString());
}

@Test
void prepare_returns_false_when_modul_is_disabled() throws IOException {
/* prepare */

PrepareWrapperEnvironment environment = mock(PrepareWrapperEnvironment.class);
when(environment.getPdsPrepareUploadFolderDirectory()).thenReturn("temp");
PrepareWrapperContext context = new PrepareWrapperContext(createFromJSON("{}"), environment);

SecHubRemoteDataConfiguration remoteDataConfiguration = new SecHubRemoteDataConfiguration();
remoteDataConfiguration.setLocation("my-example-location");
remoteDataConfiguration.setType("docker");
context.setRemoteDataConfiguration(remoteDataConfiguration);

ReflectionTestUtils.setField(moduleToTest, "pdsPrepareModuleSkopeoEnabled", false);

/* execute */
boolean result = moduleToTest.prepare(context);

/* test */
assertFalse(result);
}

@Test
void isDownloadSuccessful_returns_true_when_tar_file_in_directory() throws IOException {
/* prepare */
Expand Down

0 comments on commit 8468743

Please sign in to comment.