com.salesforce.dockerfileimageupdate.process.ForkableRepoValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dockerfile-image-update Show documentation
Show all versions of dockerfile-image-update Show documentation
This tool provides a mechanism to make security updates to docker images at scale.
The tool searches github for declared docker images and sends pull requests to projects that are not using
the desired version of the requested docker image.
package com.salesforce.dockerfileimageupdate.process;
import com.salesforce.dockerfileimageupdate.model.FromInstruction;
import com.salesforce.dockerfileimageupdate.model.GitForkBranch;
import com.salesforce.dockerfileimageupdate.model.ImageKeyValuePair;
import com.salesforce.dockerfileimageupdate.model.ShouldForkResult;
import com.salesforce.dockerfileimageupdate.utils.DockerfileGitHubUtil;
import org.kohsuke.github.GHContent;
import org.kohsuke.github.GHRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import static com.salesforce.dockerfileimageupdate.model.ShouldForkResult.shouldForkResult;
import static com.salesforce.dockerfileimageupdate.model.ShouldForkResult.shouldNotForkResult;
public class ForkableRepoValidator {
private static final Logger log = LoggerFactory.getLogger(ForkableRepoValidator.class);
public static final String REPO_IS_FORK =
"it's a fork already. Sending a PR to a fork is unsupported at the moment.";
public static final String REPO_IS_ARCHIVED = "it's archived.";
public static final String REPO_IS_OWNED_BY_THIS_USER = "it is owned by this user.";
public static final String COULD_NOT_CHECK_THIS_USER =
"we could not determine fork status because we don't know the identity of the authenticated user.";
public static final String CONTENT_PATH_NOT_IN_DEFAULT_BRANCH_TEMPLATE =
"didn't find content path %s in default branch";
public static final String COULD_NOT_FIND_IMAGE_TO_UPDATE_TEMPLATE =
"didn't find the image '%s' which required an update in path %s";
private final DockerfileGitHubUtil dockerfileGitHubUtil;
public ForkableRepoValidator(DockerfileGitHubUtil dockerfileGitHubUtil) {
this.dockerfileGitHubUtil = dockerfileGitHubUtil;
}
/**
* Check various conditions required for a repo to qualify for updates
*
* @param parentRepo parent repo we're checking
* @param searchResultContent search result content we'll check against
* @param gitForkBranch forked git branch
* @return should we fork the parentRepo?
*/
public ShouldForkResult shouldFork(GHRepository parentRepo,
GHContent searchResultContent,
GitForkBranch gitForkBranch) {
return parentIsFork(parentRepo)
.and(parentIsArchived(parentRepo)
.and(thisUserIsNotOwner(parentRepo)
.and(contentHasChangesInDefaultBranch(parentRepo, searchResultContent, gitForkBranch))));
}
/**
* Check to see if the default branch of the parentRepo has the path we found in searchResultContent and
* whether that content has a qualifying base image update
* @param parentRepo parentRepo which we'd fork off of
* @param searchResultContent search result with path to check in parent repo's default branch (where we'd PR)
* @param gitForkBranch information about the imageName we'd like to update with the new tag.
* @return {@code ShouldForkResult } Object
*/
protected ShouldForkResult contentHasChangesInDefaultBranch(GHRepository parentRepo,
GHContent searchResultContent,
GitForkBranch gitForkBranch) {
try {
String searchContentPath = searchResultContent.getPath();
GHContent content =
dockerfileGitHubUtil.tryRetrievingContent(parentRepo,
searchContentPath, parentRepo.getDefaultBranch());
if (content == null) {
return shouldNotForkResult(
String.format(CONTENT_PATH_NOT_IN_DEFAULT_BRANCH_TEMPLATE, searchContentPath));
} else {
if (hasNoChanges(content, gitForkBranch)) {
return shouldNotForkResult(
String.format(COULD_NOT_FIND_IMAGE_TO_UPDATE_TEMPLATE,
gitForkBranch.getImageName(), searchContentPath));
}
}
} catch (InterruptedException e) {
log.warn("Couldn't get parent content to check for some reason for {}. Trying to proceed... exception: {}",
parentRepo.getFullName(), e.getMessage());
}
return shouldForkResult();
}
/**
* Check to see whether there are any changes in the specified content where the specified base image
* in gitForkBranch needs an update
*
* @param content content to check
* @param gitForkBranch information about the base image we'd like to update
* @return {@code Boolean} value signifying whether there are any changes content
*/
protected boolean hasNoChanges(GHContent content, GitForkBranch gitForkBranch) {
try (InputStream stream = content.read();
InputStreamReader streamR = new InputStreamReader(stream);
BufferedReader reader = new BufferedReader(streamR)) {
String line;
while ( (line = reader.readLine()) != null ) {
if (FromInstruction.isFromInstructionWithThisImageAndOlderTag(line,
gitForkBranch.getImageName(), gitForkBranch.getImageTag()) ||
ImageKeyValuePair.isImageKeyValuePairWithThisImageAndOlderTag(line,
gitForkBranch.getImageName(), gitForkBranch.getImageTag())) {
return false;
}
}
} catch (IOException exception) {
log.warn("Failed while checking if there are changes in {}. Skipping... exception: {}",
content.getPath(), exception.getMessage());
}
return true;
}
/**
* Attempts to check to see if this user is the owner of the repo (don't fork your own repo).
* If we can't tell because of a systemic error, don't attempt to fork (we could perhaps loosen this in the future).
* If this user is the owner of the repo, do not fork.
*
* @param parentRepo parent repo we're checking
* @return {@code ShouldForkResult} Object abstracting data if the user is owner of the repo
*/
protected ShouldForkResult thisUserIsNotOwner(GHRepository parentRepo) {
try {
if (dockerfileGitHubUtil.thisUserIsOwner(parentRepo)) {
return shouldNotForkResult(REPO_IS_OWNED_BY_THIS_USER);
}
} catch (IOException ioException) {
return shouldNotForkResult(COULD_NOT_CHECK_THIS_USER);
}
return shouldForkResult();
}
/**
* Check if parentRepo is a fork. Do not fork a fork (for now, at least).
*
* @param parentRepo parent repo we're checking
* @return {@code ShouldForkResult} Object abstracting data if parentRepo is a fork
*/
protected ShouldForkResult parentIsFork(GHRepository parentRepo) {
return parentRepo.isFork() ? shouldNotForkResult(REPO_IS_FORK) : shouldForkResult();
}
/**
* Check if parentRepo is archived. We won't be able to update it, so do not fork.
*
* @param parentRepo parent repo we're checking
* @return {@code ShouldForkResult} Object abstracting data if parentRepo is archived
*/
protected ShouldForkResult parentIsArchived(GHRepository parentRepo) {
return parentRepo.isArchived() ? shouldNotForkResult(REPO_IS_ARCHIVED) : shouldForkResult();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy