Skip to content

Commit

Permalink
Merge pull request #46 from flowlogix/perms
Browse files Browse the repository at this point in the history
Breaking: Limit permissions (optionally) to collaborators when triggering builds
  • Loading branch information
bluesliverx committed Jul 18, 2022
2 parents af4a0ab + dd44add commit 2dcf62b
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 3 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ Commence the rebuilding

If no pattern is provided, `^REBUILD$` is used.

### Untrusted Builds
This plugin only triggers builds from trusted users.
This is an incompatible change since July 2022 releases of the plugin.
If you would like untrusted users to be able to trigger builds,
check the "Allow Untrusted Users" checkbox. Use this feature with caution because
it may open up security issues with your Jenkins infrastructure.

### GitHub organization folders

When using the GitHub organization folders approach to creating multibranch
Expand Down
Binary file modified docs/branch-property-strategy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.adobe.jenkins.github_pr_comment_build;

import com.cloudbees.plugins.credentials.common.StandardCredentials;
import hudson.model.Job;
import java.io.IOException;
import javax.annotation.Nonnull;
import jenkins.scm.api.SCMSource;
import org.jenkinsci.plugins.github_branch_source.Connector;
import org.jenkinsci.plugins.github_branch_source.GitHubSCMSource;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;

/**
* client utility methods
*/
public class GithubHelper {

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

private GithubHelper() {
// private
}

public static boolean isAuthorized(final Job<?, ?> job, final String author) {
try {
GHRepository ghRepository = getGHRepository(job);
boolean authorized = ghRepository.getCollaboratorNames().contains(author);
LOG.debug("User {} authorized: {}", author, authorized);
return authorized;
} catch (final IOException e) {
LOG.debug("Received an exception while trying to check if user {} is a collaborator for repo of job {}",
author, job.getFullName());
LOG.debug("isAuthorized() - Exception", e);
return false;
}
}

private static GHRepository getGHRepository(@Nonnull final Job<?, ?> job) throws IOException {
SCMSource scmSource = SCMSource.SourceByItem.findSource(job);
if (scmSource instanceof GitHubSCMSource) {
GitHubSCMSource gitHubSource = (GitHubSCMSource) scmSource;
StandardCredentials credentials = Connector.lookupScanCredentials(
job, gitHubSource.getApiUri(), gitHubSource.getCredentialsId());
GitHub github = Connector.connect(gitHubSource.getApiUri(), credentials);
return github.getRepository(gitHubSource.getRepoOwner() + "/" + gitHubSource.getRepository());
}
throw new IllegalArgumentException("Job's SCM is not GitHub.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ public void run() {
continue;
}
propFound = true;
String expectedCommentBody = ((TriggerPRCommentBranchProperty) prop).getCommentBody();
TriggerPRCommentBranchProperty branchProp = (TriggerPRCommentBranchProperty)prop;
String expectedCommentBody = branchProp.getCommentBody();
if (!branchProp.isAllowUntrusted() && !GithubHelper.isAuthorized(job, commentAuthor)) {
continue;
}
Pattern pattern = Pattern.compile(expectedCommentBody,
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
if (commentBody == null || pattern.matcher(commentBody).matches()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ protected void onEvent(GHEvent event, String payload) {
JSONObject pullRequest = json.getJSONObject("pull_request");
final String pullRequestUrl = pullRequest.getString("html_url");
Integer pullRequestId = pullRequest.getInt("number");
String author = json.getJSONObject("sender").getString("login");
LOGGER.fine(() -> String.format("PR Review Author: %s", author));

// Set some values used below
final Pattern pullRequestJobNamePattern = Pattern.compile("^PR-" + pullRequestId + "\\b.*$",
Expand Down Expand Up @@ -116,6 +118,10 @@ public void run() {
if (!(prop instanceof TriggerPRReviewBranchProperty)) {
continue;
}
TriggerPRReviewBranchProperty branchProp = (TriggerPRReviewBranchProperty)prop;
if (!branchProp.isAllowUntrusted() && !GithubHelper.isAuthorized(job, author)) {
continue;
}
propFound = true;
ParameterizedJobMixIn.scheduleBuild2(job, 0,
new CauseAction(new GitHubPullRequestReviewCause(pullRequestUrl)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.util.regex.Pattern;

import static com.google.common.collect.Sets.immutableEnumSet;
import static org.kohsuke.github.GHEvent.ISSUE_COMMENT;
import static org.kohsuke.github.GHEvent.PULL_REQUEST;

/**
Expand Down Expand Up @@ -80,6 +79,8 @@ protected void onEvent(GHEvent event, String payload) {
JSONObject pullRequest = json.getJSONObject("pull_request");
final String pullRequestUrl = pullRequest.getString("html_url");
Integer pullRequestId = pullRequest.getInt("number");
String author = json.getJSONObject("sender").getString("login");
LOGGER.fine(() -> String.format("PR Update Author: %s", author));

// Make sure the action is edited
String action = json.getString("action");
Expand Down Expand Up @@ -132,6 +133,10 @@ public void run() {
if (!(prop instanceof TriggerPRUpdateBranchProperty)) {
continue;
}
TriggerPRUpdateBranchProperty branchProp = (TriggerPRUpdateBranchProperty)prop;
if (!branchProp.isAllowUntrusted() && !GithubHelper.isAuthorized(job, author)) {
continue;
}
propFound = true;
ParameterizedJobMixIn.scheduleBuild2(job, 0,
new CauseAction(new GitHubPullRequestUpdateCause(pullRequestUrl)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import jenkins.branch.BranchPropertyDescriptor;
import jenkins.branch.JobDecorator;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

/**
* Allows a GitHub pull request comment to trigger an immediate build based on a comment string.
Expand All @@ -16,6 +17,7 @@ public class TriggerPRCommentBranchProperty extends BranchProperty {
* The comment body to trigger a new build on.
*/
private final String commentBody;
private boolean allowUntrusted;

/**
* Constructor.
Expand All @@ -37,6 +39,15 @@ public String getCommentBody() {
return commentBody;
}

public boolean isAllowUntrusted() {
return allowUntrusted;
}

@DataBoundSetter
public void setAllowUntrusted(boolean allowUntrusted) {
this.allowUntrusted = allowUntrusted;
}

@Override
public <P extends Job<P, B>, B extends Run<P, B>> JobDecorator<P, B> jobDecorator(Class<P> clazz) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,29 @@
import jenkins.branch.BranchPropertyDescriptor;
import jenkins.branch.JobDecorator;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

/**
* Allows a GitHub pull request update to trigger an immediate build.
*/
public class TriggerPRReviewBranchProperty extends BranchProperty {
private boolean allowUntrusted;

/**
* Constructor.
*/
@DataBoundConstructor
public TriggerPRReviewBranchProperty() { }

public boolean isAllowUntrusted() {
return allowUntrusted;
}

@DataBoundSetter
public void setAllowUntrusted(boolean allowUntrusted) {
this.allowUntrusted = allowUntrusted;
}

@Override
public <P extends Job<P, B>, B extends Run<P, B>> JobDecorator<P, B> jobDecorator(Class<P> clazz) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,29 @@
import jenkins.branch.BranchPropertyDescriptor;
import jenkins.branch.JobDecorator;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

/**
* Allows a GitHub pull request update to trigger an immediate build.
*/
public class TriggerPRUpdateBranchProperty extends BranchProperty {
private boolean allowUntrusted;

/**
* Constructor.
*/
@DataBoundConstructor
public TriggerPRUpdateBranchProperty() { }

public boolean isAllowUntrusted() {
return allowUntrusted;
}

@DataBoundSetter
public void setAllowUntrusted(boolean allowUntrusted) {
this.allowUntrusted = allowUntrusted;
}

@Override
public <P extends Job<P, B>, B extends Run<P, B>> JobDecorator<P, B> jobDecorator(Class<P> clazz) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@
<f:entry title="Comment Body" field="commentBody">
<f:textbox />
</f:entry>
</j:jelly>
<f:entry title="Allow untrusted users to trigger the build" field="allowUntrusted">
<f:checkbox default="false"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="Allow untrusted users to trigger the build" field="allowUntrusted">
<f:checkbox default="false"/>
</f:entry>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<f:entry title="Allow untrusted users to trigger the build" field="allowUntrusted">
<f:checkbox default="false"/>
</f:entry>
</j:jelly>

0 comments on commit 2dcf62b

Please sign in to comment.