Skip to content

Commit

Permalink
[FIXED JENKINS-36240] Full implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
stephenc committed Jul 17, 2017
1 parent c10b23b commit 3299bf5
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 8 deletions.
Expand Up @@ -357,15 +357,11 @@ public String getPermission() {
* {@inheritDoc}
*/
@Override
protected boolean checkTrusted(@NonNull GitHubSCMSourceRequest request, @NonNull PullRequestSCMHead head) {
protected boolean checkTrusted(@NonNull GitHubSCMSourceRequest request, @NonNull PullRequestSCMHead head)
throws IOException, InterruptedException {
if (!head.getOrigin().equals(SCMHeadOrigin.DEFAULT)) {
try {
// TODO get the repository from getTrusted which currently doesn't provide it to the request.
GHPermissionType permission = request.getRepository().getPermission(head.getSourceOwner());
return permission.ordinal() <= this.permission.ordinal();
} catch (IOException e) {
// ignore
}
GHPermissionType permission = request.getPermissions(head.getSourceOwner());
return permission.ordinal() <= this.permission.ordinal();
}
return false;
}
Expand Down
@@ -0,0 +1,45 @@
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package org.jenkinsci.plugins.github_branch_source;

import java.io.IOException;
import org.kohsuke.github.GHPermissionType;

/**
* A deferred source of permission information about a repository.
*
* @since TODO
*/
public abstract class GitHubPermissionsSource {
/**
* Fetches the permissions of the supplied username.
*
* @param username the username.
* @return the permissions.
* @throws IOException if there was an IO error.
* @throws InterruptedException if interrupted.
*/
public abstract GHPermissionType fetch(String username) throws IOException, InterruptedException;
}
Expand Up @@ -29,6 +29,7 @@
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardCredentials;
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
import com.google.common.base.Function;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
Expand Down Expand Up @@ -111,6 +112,7 @@
import org.kohsuke.github.GHIssueState;
import org.kohsuke.github.GHMyself;
import org.kohsuke.github.GHOrganization;
import org.kohsuke.github.GHPermissionType;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHRef;
import org.kohsuke.github.GHRepository;
Expand Down Expand Up @@ -853,6 +855,12 @@ protected final void retrieve(@CheckForNull SCMSourceCriteria criteria,
// TODO request.setTags(repo.getTags);
}
request.setCollaboratorNames(new LazyContributorNames(request, listener, github, ghRepository, credentials));
request.setPermissionsSource(new GitHubPermissionsSource() {
@Override
public GHPermissionType fetch(String username) throws IOException, InterruptedException {
return ghRepository.getPermission(username);
}
});

if (request.isFetchBranches() && !request.isComplete()) {
listener.getLogger().format("%n Checking branches...%n");
Expand Down Expand Up @@ -1184,6 +1192,7 @@ public SCMRevision getTrustedRevision(SCMRevision revision, final TaskListener l
} else {
request.setCollaboratorNames(new DeferredContributorNames(request, listener));
}
request.setPermissionsSource(new DeferredPermissionsSource(listener));
if (request.isTrusted(head)) {
return revision;
}
Expand Down Expand Up @@ -1928,4 +1937,38 @@ protected Set<String> create() {
}
}
}

private class DeferredPermissionsSource extends GitHubPermissionsSource implements Closeable {

private final TaskListener listener;
private GitHub github;
private GHRepository repo;

public DeferredPermissionsSource(TaskListener listener) {
this.listener = listener;
}

@Override
public GHPermissionType fetch(String username) throws IOException, InterruptedException {
if (repo == null) {
listener.getLogger().format("Connecting to %s to check permissions of obtain list of %s for %s/%s%n",
apiUri == null ? GITHUB_URL : apiUri, username, repoOwner, repository);
StandardCredentials credentials = Connector.lookupScanCredentials(
(Item) getOwner(), apiUri, credentialsId
);
github = Connector.connect(apiUri, credentials);
repo = github.getRepository(repository);
}
return repo.getPermission(username);
}

@Override
public void close() throws IOException {
if (github != null) {
Connector.release(github);
github = null;
repo = null;
}
}
}
}
Expand Up @@ -23,6 +23,7 @@
*/
package org.jenkinsci.plugins.github_branch_source;

import com.google.common.base.Function;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Util;
Expand All @@ -42,6 +43,7 @@
import jenkins.scm.api.mixin.TagSCMHead;
import jenkins.scm.api.trait.SCMSourceRequest;
import org.kohsuke.github.GHBranch;
import org.kohsuke.github.GHPermissionType;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
Expand Down Expand Up @@ -119,6 +121,16 @@ public class GitHubSCMSourceRequest extends SCMSourceRequest {
*/
@CheckForNull
private GHRepository repository;
/**
* The resolved permissions keyed by user.
*/
@NonNull
private final Map<String, GHPermissionType> permissions = new HashMap<>();
/**
* A deferred lookup of the permissions.
*/
@CheckForNull
private GitHubPermissionsSource permissionsSource;

/**
* Constructor.
Expand Down Expand Up @@ -412,6 +424,52 @@ public void close() throws IOException {
if (branches instanceof Closeable) {
((Closeable) branches).close();
}
if (permissionsSource instanceof Closeable) {
((Closeable) permissionsSource).close();
}
super.close();
}

/**
* Returns the permissions of the supplied user.
*
* @param username the user.
* @return the permissions of the supplied user.
*/
public synchronized GHPermissionType getPermissions(String username) throws IOException, InterruptedException {
if (permissions.containsKey(username)) {
return permissions.get(username);
}
if (permissionsSource != null) {
GHPermissionType result = permissionsSource.fetch(username);
permissions.put(username, result);
return result;
}
if (repository != null && username.equalsIgnoreCase(repository.getOwnerName())) {
return GHPermissionType.ADMIN;
}
if (collaboratorNames != null && collaboratorNames.contains(username)) {
return GHPermissionType.WRITE;
}
return GHPermissionType.NONE;
}

/**
* Returns the permission source.
*
* @return the permission source.
*/
@CheckForNull
public GitHubPermissionsSource getPermissionsSource() {
return permissionsSource;
}

/**
* Sets the permission source.
*
* @param permissionsSource the permission source.
*/
public void setPermissionsSource(@CheckForNull GitHubPermissionsSource permissionsSource) {
this.permissionsSource = permissionsSource;
}
}

0 comments on commit 3299bf5

Please sign in to comment.