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

[JENKINS-66661] Fix fallback behavior of Fork PR trust criteria #711

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -1021,7 +1021,7 @@
request.setPermissionsSource(new GitHubPermissionsSource() {
@Override
public GHPermissionType fetch(String username) throws IOException, InterruptedException {
return ghRepository.getPermission(username);
return getPermissions(ghRepository, username, listener);
}
});

Expand Down Expand Up @@ -1242,35 +1242,44 @@
}
}

if (request.process(
new PullRequestSCMHead(pr, branchName, strategy == ChangeRequestCheckoutStrategy.MERGE),
null,
new SCMSourceRequest.ProbeLambda<PullRequestSCMHead, Void>() {
@NonNull
@Override
public SCMSourceCriteria.Probe create(
@NonNull PullRequestSCMHead head, @Nullable Void revisionInfo)
throws IOException, InterruptedException {
boolean trusted = request.isTrusted(head);
if (!trusted) {
listener.getLogger().format(" (not from a trusted source)%n");
try {
if (request.process(
new PullRequestSCMHead(pr, branchName, strategy == ChangeRequestCheckoutStrategy.MERGE),
null,
new SCMSourceRequest.ProbeLambda<PullRequestSCMHead, Void>() {
@NonNull
@Override
public SCMSourceCriteria.Probe create(
@NonNull PullRequestSCMHead head, @Nullable Void revisionInfo)
throws IOException, InterruptedException {
boolean trusted = request.isTrusted(head);
if (!trusted) {
listener.getLogger().format(" (not from a trusted source)%n");
}
return new GitHubSCMProbe(
apiUri, credentials, ghRepository, trusted ? head : head.getTarget(), null);
}
return new GitHubSCMProbe(
apiUri, credentials, ghRepository, trusted ? head : head.getTarget(), null);
}
},
new SCMSourceRequest.LazyRevisionLambda<PullRequestSCMHead, SCMRevision, Void>() {
@NonNull
@Override
public SCMRevision create(@NonNull PullRequestSCMHead head, @Nullable Void ignored)
throws IOException, InterruptedException {
},
new SCMSourceRequest.LazyRevisionLambda<PullRequestSCMHead, SCMRevision, Void>() {
@NonNull
@Override
public SCMRevision create(@NonNull PullRequestSCMHead head, @Nullable Void ignored)
throws IOException, InterruptedException {

return createPullRequestSCMRevision(pr, head, listener, ghRepository);
}
},
new MergabilityWitness(pr, strategy, listener),
new CriteriaWitness(listener))) {
listener.getLogger().format("%n Pull request %d processed (query completed)%n", number);
return createPullRequestSCMRevision(pr, head, listener, ghRepository);
}
},
new MergabilityWitness(pr, strategy, listener),
new CriteriaWitness(listener))) {
listener.getLogger().format("%n Pull request %d processed (query completed)%n", number);
}
} catch (WrappedException e) {
try {
e.unwrap();

Check warning on line 1278 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 1278 is not covered by tests
} catch (Exception ue) {
LOGGER.log(Level.FINE, "Failed to process pull request", ue);
}

Check warning on line 1281 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 1281 is not covered by tests
listener.getLogger().format("%n Failed to process pull request %d, skipping%n%n", number);
}
}
}
Expand Down Expand Up @@ -1567,26 +1576,52 @@
@NonNull GHRepository ghRepository)
throws IOException {
if (credentials == null && (apiUri == null || GITHUB_URL.equals(apiUri))) {
// anonymous access to GitHub will never get list of collaborators and will
// burn an API call, so no point in even trying
listener.getLogger().println("Anonymous cannot query list of collaborators, assuming none");
return collaboratorNames = Collections.emptySet();
listener.getLogger().println(" Anonymous cannot query list of collaborators");
throw new IOException("Anonymous cannot query list of collaborators");

Check warning on line 1580 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 1579-1580 are not covered by tests
} else {
try {
return collaboratorNames = new HashSet<>(ghRepository.getCollaboratorNames());
} catch (FileNotFoundException e) {
// not permitted
listener.getLogger().println("Not permitted to query list of collaborators, assuming none");
return collaboratorNames = Collections.emptySet();
// listener.getLogger().println(" Not permitted to query list of collaborators");
listener.getLogger().format(" Not permitted to query list of collaborators: %s", e.getMessage());
throw e;
} catch (HttpException e) {
if (e.getResponseCode() == HttpServletResponse.SC_UNAUTHORIZED
|| e.getResponseCode() == HttpServletResponse.SC_FORBIDDEN

Check warning on line 1590 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 1590 is only partially covered, one branch is missing
|| e.getResponseCode() == HttpServletResponse.SC_NOT_FOUND) {
listener.getLogger().println("Not permitted to query list of collaborators, assuming none");
return collaboratorNames = Collections.emptySet();
// listener.getLogger().println(" Not permitted to query list of
// collaborators");
listener.getLogger()
.format(" Not permitted to query list of collaborators: %s", e.getMessage());
} else {
throw e;
// listener.getLogger().println(" Failed to query list of collaborators");
listener.getLogger().format(" Failed to query list of collaborators: %s", e.getMessage());

Check warning on line 1598 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 1598 is not covered by tests
}
throw e;
}
}
}

private GHPermissionType getPermissions(
@NonNull GHRepository repo, @NonNull String username, @NonNull TaskListener listener) throws IOException {

try {
return repo.getPermission(username);
} catch (FileNotFoundException e) {
// listener.getLogger().println(" Not permitted to query list of permissions");
listener.getLogger().format(" Not permitted to query list of permissions: %s", e.getMessage());
throw new WrappedException(e);
} catch (HttpException e) {
if (e.getResponseCode() == HttpServletResponse.SC_UNAUTHORIZED
|| e.getResponseCode() == HttpServletResponse.SC_FORBIDDEN

Check warning on line 1616 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 1616 is only partially covered, one branch is missing
|| e.getResponseCode() == HttpServletResponse.SC_NOT_FOUND) {

Check warning on line 1617 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 1617 is not covered by tests
// listener.getLogger().println(" Not permitted to query list of permissions");
listener.getLogger().format(" Not permitted to query list of permissions: %s", e.getMessage());
} else {
// listener.getLogger().println(" Failed to query list of permissions");
listener.getLogger().format(" Failed to query list of permissions: %s", e.getMessage());

Check warning on line 1622 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 1622 is not covered by tests
}
throw new WrappedException(e);
}
}

Expand Down Expand Up @@ -1866,9 +1901,8 @@
try {
wrapped.unwrap();
} catch (HttpException e) {
listener.getLogger()
.format("It seems %s is unreachable, assuming no trusted collaborators%n", apiUri);
collaboratorNames = Collections.singleton(repoOwner);
listener.getLogger().format("Cannot retrieve trusted revision: %s%n");
throw e;

Check warning on line 1905 in src/main/java/org/jenkinsci/plugins/github_branch_source/GitHubSCMSource.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 1904-1905 are not covered by tests
}
}
PullRequestSCMRevision rev = (PullRequestSCMRevision) revision;
Expand Down Expand Up @@ -2928,7 +2962,7 @@
String fullName = repoOwner + "/" + repository;
repo = github.getRepository(fullName);
}
return repo.getPermission(username);
return getPermissions(repo, username, listener);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;

import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.common.SingleRootFileSource;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
import com.github.tomakehurst.wiremock.extension.requestfilter.RequestFilterAction;
import com.github.tomakehurst.wiremock.extension.requestfilter.StubRequestFilter;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.Response;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
Expand Down Expand Up @@ -38,30 +41,47 @@ public abstract class AbstractGitHubWireMockTest {
@Rule
public WireMockRule githubApi = factory.getRule(WireMockConfiguration.options()
.dynamicPort()
.needClientAuth(true)
.usingFilesUnderClasspath("api")
.extensions(new ResponseTransformer() {
@Override
public Response transform(Request request, Response response, FileSource files, Parameters parameters) {
if ("application/json"
.equals(response.getHeaders().getContentTypeHeader().mimeTypePart())) {
return Response.Builder.like(response)
.but()
.body(response.getBodyAsString()
.replace(
"https://api.github.com/", "http://localhost:" + githubApi.port() + "/")
.replace(
"https://raw.githubusercontent.com/",
"http://localhost:" + githubRaw.port() + "/"))
.build();
}
return response;
}
.extensions(
new ResponseTransformer() {
@Override
public Response transform(
Request request, Response response, FileSource files, Parameters parameters) {
if ("application/json"
.equals(response.getHeaders()
.getContentTypeHeader()
.mimeTypePart())) {
return Response.Builder.like(response)
.but()
.body(response.getBodyAsString()
.replace(
"https://api.github.com/",
"http://localhost:" + githubApi.port() + "/")
.replace(
"https://raw.githubusercontent.com/",
"http://localhost:" + githubRaw.port() + "/"))
.build();
}
return response;
}

@Override
public String getName() {
return "url-rewrite";
}
}));
@Override
public String getName() {
return "url-rewrite";
}
},
new StubRequestFilter() {
@Override
public RequestFilterAction filter(Request request) {
return RequestFilterAction.continueWith(request);
}

@Override
public String getName() {
return "test-auth";
}
}));

@Before
public void prepareMockGitHub() {
Expand Down Expand Up @@ -89,4 +109,8 @@ void prepareMockGitHubFileMappings() {
new SingleRootFileSource("src/test/resources/raw/mappings"),
new SingleRootFileSource("src/test/resources/raw/__files"));
}

StandardUsernameCredentials getCredentials() {
return null;
}
}
Loading
Loading