Skip to content

Commit

Permalink
[JENKINS-75073] Missing serverUrl in fillCredentialsIdItems cause som…
Browse files Browse the repository at this point in the history
…e credentials missing in the initial configuration

If the number of server instances is only one, when a new Jenkins project is created the server list combobox is not available. This causes, in the UI component that loads credentials, to pass the stapler parameter serverUrl as an empty string. In this scenario, serverUrl must be taken from the first of configured endpoints so that it can properly filter the list of credentials.
Move some unit test to JUnit5
  • Loading branch information
nfalco79 committed Jan 10, 2025
1 parent 43d58dd commit 9c6a177
Show file tree
Hide file tree
Showing 16 changed files with 636 additions and 600 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,9 @@ public BitbucketGitSCMBuilder(@NonNull BitbucketSCMSource scmSource, @NonNull SC
this.scmSource = scmSource;

String serverURL = scmSource.getServerUrl();
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(serverURL);
if (endpoint == null) {
endpoint = new BitbucketServerEndpoint(null, serverURL, false, null);
}
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
.findEndpoint(serverURL)
.orElse(new BitbucketServerEndpoint(null, serverURL, false, null));

String repositoryURL = endpoint.getRepositoryUrl(scmSource.getRepoOwner(), scmSource.getRepository());
if (BitbucketApiUtils.isCloud(endpoint.getServerUrl())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.interceptor.RequirePOST;

import static com.cloudbees.jenkins.plugins.bitbucket.impl.util.BitbucketApiUtils.getFromBitbucket;

Expand Down Expand Up @@ -288,9 +289,9 @@ public String getServerUrl() {
}

@DataBoundSetter
public void setServerUrl(String serverUrl) {
public void setServerUrl(@CheckForNull String serverUrl) {
serverUrl = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
if (!StringUtils.equals(this.serverUrl, serverUrl)) {
if (serverUrl != null && !StringUtils.equals(this.serverUrl, serverUrl)) {
this.serverUrl = serverUrl;
resetId();
}
Expand Down Expand Up @@ -384,14 +385,14 @@ public String getPattern() {
@DataBoundSetter
public void setBitbucketServerUrl(String url) {
url = BitbucketEndpointConfiguration.normalizeServerUrl(url);
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(url);
if (endpoint != null) {
// we have a match
setServerUrl(url);
return;
url = StringUtils.defaultIfBlank(url, BitbucketCloudEndpoint.SERVER_URL); // when BitbucketServerUrl was null means cloud was configured
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
.findEndpoint(url)
.orElse(null);
if (endpoint == null) {
LOGGER.log(Level.WARNING, "Call to legacy setBitbucketServerUrl({0}) method is configuring a url missing "
+ "from the global configuration.", url);
}
LOGGER.log(Level.WARNING, "Call to legacy setBitbucketServerUrl({0}) method is configuring a url missing "
+ "from the global configuration.", url);
setServerUrl(url);
}

Expand All @@ -400,7 +401,10 @@ public void setBitbucketServerUrl(String url) {
@RestrictedSince("2.2.0")
@CheckForNull
public String getBitbucketServerUrl() {
if (BitbucketEndpointConfiguration.get().findEndpoint(serverUrl) instanceof BitbucketCloudEndpoint) {
if (BitbucketEndpointConfiguration.get()
.findEndpoint(serverUrl)
.filter(BitbucketCloudEndpoint.class::isInstance)
.isPresent()) {
return null;
}
return serverUrl;
Expand Down Expand Up @@ -629,7 +633,7 @@ public String getIconClassName() {
@Override
public SCMNavigator newInstance(String name) {
BitbucketSCMNavigator instance = new BitbucketSCMNavigator(StringUtils.defaultString(name));
instance.setTraits((List) getTraitsDefaults());
instance.setTraits(getTraitsDefaults());
return instance;
}

Expand All @@ -647,16 +651,21 @@ public ListBoxModel doFillServerUrlItems(@AncestorInPath SCMSourceOwner context)
return BitbucketEndpointConfiguration.get().getEndpointItems();
}

@RequirePOST
@SuppressWarnings("unused") // used By stapler
public FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner context, @QueryParameter String serverUrl, @QueryParameter String value) {
return BitbucketCredentials.checkCredentialsId(context, value, serverUrl);
public static FormValidation doCheckCredentialsId(@AncestorInPath SCMSourceOwner context,
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL,
@QueryParameter String value) {
return BitbucketCredentials.checkCredentialsId(context, value, serverURL);
}

@RequirePOST
@SuppressWarnings("unused") // used By stapler
public static FormValidation doCheckMirrorId(@QueryParameter String value, @QueryParameter String serverUrl) {
public static FormValidation doCheckMirrorId(@QueryParameter String value,

Check warning

Code scanning / Jenkins Security Scan

Stapler: Missing permission check Warning

Potential missing permission check in DescriptorImpl#doCheckMirrorId
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
if (!value.isEmpty()) {
BitbucketServerWebhookImplementation webhookImplementation =
BitbucketServerEndpoint.findWebhookImplementation(serverUrl);
BitbucketServerEndpoint.findWebhookImplementation(serverURL);
if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) {
return FormValidation.error("Mirror can only be used with native webhooks");
}
Expand All @@ -666,13 +675,13 @@ public static FormValidation doCheckMirrorId(@QueryParameter String value, @Quer

@SuppressWarnings("unused") // used By stapler
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath SCMSourceOwner context,
@QueryParameter String serverUrl) {
return BitbucketCredentials.fillCredentialsIdItems(context, serverUrl);
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
return BitbucketCredentials.fillCredentialsIdItems(context, serverURL);
}

@SuppressWarnings("unused") // used By stapler
public ListBoxModel doFillMirrorIdItems(@AncestorInPath SCMSourceOwner context,
@QueryParameter String serverUrl,
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverUrl,
@QueryParameter String credentialsId,
@QueryParameter String repoOwner)
throws FormFillFailure {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,11 @@ public String getServerUrl() {

@DataBoundSetter
public void setServerUrl(@CheckForNull String serverUrl) {
this.serverUrl = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
String url = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
if (url == null) {
url = BitbucketEndpointConfiguration.get().getDefaultEndpoint().getServerUrl();
}
this.serverUrl = url;
}

@NonNull
Expand All @@ -401,7 +405,10 @@ public void setTraits(@CheckForNull List<SCMSourceTrait> traits) {
@DataBoundSetter
public void setBitbucketServerUrl(String url) {
url = BitbucketEndpointConfiguration.normalizeServerUrl(url);
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(url);
url = StringUtils.defaultIfBlank(url, BitbucketCloudEndpoint.SERVER_URL);
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
.findEndpoint(url)
.orElse(null);
if (endpoint != null) {
// we have a match
setServerUrl(endpoint.getServerUrl());
Expand All @@ -418,7 +425,10 @@ public void setBitbucketServerUrl(String url) {
@CheckForNull
public String getBitbucketServerUrl() {
String serverUrl = getServerUrl();
if (BitbucketEndpointConfiguration.get().findEndpoint(serverUrl) instanceof BitbucketCloudEndpoint) {
if (BitbucketEndpointConfiguration.get()
.findEndpoint(serverUrl)
.filter(BitbucketCloudEndpoint.class::isInstance)
.isPresent()) {
return null;
}
return serverUrl;
Expand Down Expand Up @@ -1336,8 +1346,8 @@ public String getDisplayName() {
@SuppressWarnings("unused") // used By stapler
public FormValidation doCheckCredentialsId(@CheckForNull @AncestorInPath SCMSourceOwner context,
@QueryParameter String value,
@QueryParameter String serverUrl) {
return BitbucketCredentials.checkCredentialsId(context, value, serverUrl);
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
return BitbucketCredentials.checkCredentialsId(context, value, serverURL);
}

@SuppressWarnings("unused") // used By stapler
Expand All @@ -1353,11 +1363,13 @@ public static FormValidation doCheckServerUrl(@AncestorInPath SCMSourceOwner con
return FormValidation.ok();
}

@RequirePOST
@SuppressWarnings("unused") // used By stapler
public static FormValidation doCheckMirrorId(@QueryParameter String value, @QueryParameter String serverUrl) {
public static FormValidation doCheckMirrorId(@QueryParameter String value,

Check warning

Code scanning / Jenkins Security Scan

Stapler: Missing permission check Warning

Potential missing permission check in DescriptorImpl#doCheckMirrorId
@QueryParameter(fixEmpty = true, value = "serverUrl") String serverURL) {
if (!value.isEmpty()) {
BitbucketServerWebhookImplementation webhookImplementation =
BitbucketServerEndpoint.findWebhookImplementation(serverUrl);
BitbucketServerEndpoint.findWebhookImplementation(serverURL);
if (webhookImplementation == BitbucketServerWebhookImplementation.PLUGIN) {
return FormValidation.error("Mirror can only be used with native webhooks");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
*/
package com.cloudbees.jenkins.plugins.bitbucket;

import com.cloudbees.jenkins.plugins.bitbucket.endpoints.BitbucketEndpointConfiguration;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import jenkins.scm.api.trait.SCMSourceBuilder;
Expand Down Expand Up @@ -74,7 +73,7 @@ public BitbucketSCMSourceBuilder(@CheckForNull String id, @NonNull String server
@NonNull String repoName, @CheckForNull String mirrorId) {
super(BitbucketSCMSource.class, repoName);
this.id = id;
this.serverUrl = BitbucketEndpointConfiguration.normalizeServerUrl(serverUrl);
this.serverUrl = serverUrl;
this.credentialsId = credentialsId;
this.mirrorId = mirrorId;
this.repoOwner = repoOwner;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ protected boolean isMatch(@Nullable String serverUrl) {
@Override
protected BitbucketApi create(@Nullable String serverUrl, @Nullable BitbucketAuthenticator authenticator,
@NonNull String owner, @CheckForNull String projectKey, @CheckForNull String repository) {
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(BitbucketCloudEndpoint.SERVER_URL);
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
.findEndpoint(BitbucketCloudEndpoint.SERVER_URL)
.orElse(null);
boolean enableCache = false;
int teamCacheDuration = 0;
int repositoriesCacheDuration = 0;
if (endpoint != null && endpoint instanceof BitbucketCloudEndpoint) {
enableCache = ((BitbucketCloudEndpoint) endpoint).isEnableCache();
teamCacheDuration = ((BitbucketCloudEndpoint) endpoint).getTeamCacheDuration();
repositoriesCacheDuration = ((BitbucketCloudEndpoint) endpoint).getRepositoriesCacheDuration();
if (endpoint instanceof BitbucketCloudEndpoint cloudEndpoint) {
enableCache = cloudEndpoint.isEnableCache();
teamCacheDuration = cloudEndpoint.getTeamCacheDuration();
repositoriesCacheDuration = cloudEndpoint.getRepositoriesCacheDuration();
}
return new BitbucketCloudApiClient(
enableCache, teamCacheDuration, repositoriesCacheDuration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,11 @@ public void setBitbucketJenkinsRootUrl(String bitbucketJenkinsRootUrl) {
*/
@NonNull
public String getEndpointJenkinsRootUrl() {
if (StringUtils.isBlank(bitbucketJenkinsRootUrl))
if (StringUtils.isBlank(bitbucketJenkinsRootUrl)) {
return ClassicDisplayURLProvider.get().getRoot();
else
} else {
return bitbucketJenkinsRootUrl;
}
}

/**
Expand All @@ -172,7 +173,9 @@ public static String getEndpointJenkinsRootUrl(String serverUrl) {
// Note: do not pre-initialize to the global value, so it can be
// reconfigured on the fly.

AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(serverUrl);
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get()
.findEndpoint(serverUrl)
.orElse(null);
if (endpoint != null) {
return endpoint.getEndpointJenkinsRootUrl();
}
Expand Down
Loading

0 comments on commit 9c6a177

Please sign in to comment.