Skip to content

Commit

Permalink
Add permission check, fix acceptance tests and UI typos
Browse files Browse the repository at this point in the history
  • Loading branch information
welandaz committed Sep 9, 2024
1 parent 3d80969 commit 12efce0
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 62 deletions.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ dependencies {
implementation("org.jenkins-ci.plugins.workflow:workflow-basic-steps")
implementation("org.jenkins-ci.plugins.workflow:workflow-durable-task-step")
implementation("org.jenkins-ci.plugins.workflow:workflow-step-api")
implementation("org.jenkins-ci.plugins:credentials")
implementation("org.jenkins-ci.plugins:plain-credentials")
implementation("io.jenkins.plugins:okhttp-api")

"optionalPluginImplementation"("org.jenkins-ci.main:maven-plugin:3.23") {
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
distributionSha256Sum=1541fa36599e12857140465f3c91a97409b4512501c26f9631fb113e392c5bd1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
161 changes: 106 additions & 55 deletions src/main/java/hudson/plugins/gradle/injection/InjectionConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,21 @@ public class InjectionConfig extends GlobalConfiguration {
private static final String GIT_PLUGIN_SHORT_NAME = "git";

private static final Set<String> LEGACY_GLOBAL_ENVIRONMENT_VARIABLES =
ImmutableSet.of(
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_INJECTION",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_URL",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_ALLOW_UNTRUSTED_SERVER",
"GRADLE_ENTERPRISE_ACCESS_KEY",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_PLUGIN_VERSION",
"JENKINSGRADLEPLUGIN_CCUD_PLUGIN_VERSION",
"JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_URL",
"JENKINSGRADLEPLUGIN_GRADLE_INJECTION_ENABLED_NODES",
"JENKINSGRADLEPLUGIN_GRADLE_INJECTION_DISABLED_NODES",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_EXTENSION_VERSION",
"JENKINSGRADLEPLUGIN_CCUD_EXTENSION_VERSION",
"JENKINSGRADLEPLUGIN_MAVEN_INJECTION_ENABLED_NODES",
"JENKINSGRADLEPLUGIN_MAVEN_INJECTION_DISABLED_NODES"
);
ImmutableSet.of(
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_INJECTION",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_URL",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_ALLOW_UNTRUSTED_SERVER",
"GRADLE_ENTERPRISE_ACCESS_KEY",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_PLUGIN_VERSION",
"JENKINSGRADLEPLUGIN_CCUD_PLUGIN_VERSION",
"JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_URL",
"JENKINSGRADLEPLUGIN_GRADLE_INJECTION_ENABLED_NODES",
"JENKINSGRADLEPLUGIN_GRADLE_INJECTION_DISABLED_NODES",
"JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_EXTENSION_VERSION",
"JENKINSGRADLEPLUGIN_CCUD_EXTENSION_VERSION",
"JENKINSGRADLEPLUGIN_MAVEN_INJECTION_ENABLED_NODES",
"JENKINSGRADLEPLUGIN_MAVEN_INJECTION_DISABLED_NODES"
);

private boolean enabled;

Expand Down Expand Up @@ -123,8 +123,8 @@ public UnsupportedMavenPluginWarningDetails getUnsupportedMavenPluginWarningDeta
VersionNumber mavenPluginVersion = InjectionUtil.mavenPluginVersionNumber().orElse(null);

return mavenPluginVersion == null || InjectionUtil.isSupportedMavenPluginVersion(mavenPluginVersion)
? null
: new UnsupportedMavenPluginWarningDetails(mavenPluginVersion);
? null
: new UnsupportedMavenPluginWarningDetails(mavenPluginVersion);
}

@Restricted(NoExternalUse.class)
Expand Down Expand Up @@ -232,7 +232,7 @@ public List<NodeLabelItem> getGradleInjectionEnabledNodes() {
@DataBoundSetter
public void setGradleInjectionEnabledNodes(List<NodeLabelItem> gradleInjectionEnabledNodes) {
this.gradleInjectionEnabledNodes =
gradleInjectionEnabledNodes == null ? null : ImmutableList.copyOf(gradleInjectionEnabledNodes);
gradleInjectionEnabledNodes == null ? null : ImmutableList.copyOf(gradleInjectionEnabledNodes);
}

@CheckForNull
Expand All @@ -243,7 +243,7 @@ public List<NodeLabelItem> getGradleInjectionDisabledNodes() {
@DataBoundSetter
public void setGradleInjectionDisabledNodes(List<NodeLabelItem> gradleInjectionDisabledNodes) {
this.gradleInjectionDisabledNodes =
gradleInjectionDisabledNodes == null ? null : ImmutableList.copyOf(gradleInjectionDisabledNodes);
gradleInjectionDisabledNodes == null ? null : ImmutableList.copyOf(gradleInjectionDisabledNodes);
}

public Boolean isGradleCaptureTaskInputFiles() {
Expand Down Expand Up @@ -321,7 +321,7 @@ public List<NodeLabelItem> getMavenInjectionEnabledNodes() {
@DataBoundSetter
public void setMavenInjectionEnabledNodes(List<NodeLabelItem> mavenInjectionEnabledNodes) {
this.mavenInjectionEnabledNodes =
mavenInjectionEnabledNodes == null ? null : ImmutableList.copyOf(mavenInjectionEnabledNodes);
mavenInjectionEnabledNodes == null ? null : ImmutableList.copyOf(mavenInjectionEnabledNodes);
}

@CheckForNull
Expand All @@ -332,7 +332,7 @@ public List<NodeLabelItem> getMavenInjectionDisabledNodes() {
@DataBoundSetter
public void setMavenInjectionDisabledNodes(List<NodeLabelItem> mavenInjectionDisabledNodes) {
this.mavenInjectionDisabledNodes =
mavenInjectionDisabledNodes == null ? null : ImmutableList.copyOf(mavenInjectionDisabledNodes);
mavenInjectionDisabledNodes == null ? null : ImmutableList.copyOf(mavenInjectionDisabledNodes);
}

public Boolean isMavenCaptureGoalInputFiles() {
Expand Down Expand Up @@ -403,30 +403,50 @@ private void clearRepeatableProperties() {
@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckServer(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating Server URL requires 'Administer' permission");
}

return checkRequiredUrl(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckGradlePluginVersion(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating Gradle Plugin version requires 'Administer' permission");
}

return checkVersion(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckCcudPluginVersion(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating CCUD Plugin version requires 'Administer' permission");
}

return checkVersion(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckGradlePluginRepositoryUrl(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating Gradle Plugin repository URL requires 'Administer' permission");
}

return checkUrl(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckAccessKeyCredentialId(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating access key credential ID requires 'Administer' permission");
}

String accessKeyId = Util.fixEmptyAndTrim(value);
if (accessKeyId == null) {
return FormValidation.ok();
Expand All @@ -441,13 +461,17 @@ public FormValidation doCheckAccessKeyCredentialId(@QueryParameter String value)
.orElse(null);

return DevelocityAccessCredentials.isValid(accessKeyFromCredentialId)
? FormValidation.ok()
: FormValidation.error(Messages.InjectionConfig_InvalidAccessKey());
? FormValidation.ok()
: FormValidation.error(Messages.InjectionConfig_InvalidAccessKey());
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckShortLivedTokenExpiry(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating short-lived token expiry requires 'Administer' permission");
}

String shortLivedTokenExpiry = Util.fixEmptyAndTrim(value);
if (shortLivedTokenExpiry == null) {
return FormValidation.ok();
Expand All @@ -466,72 +490,90 @@ public FormValidation doCheckShortLivedTokenExpiry(@QueryParameter String value)
@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckMavenExtensionCustomCoordinates(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating Maven Extension custom coordinates requires 'Administer' permission");
}

return validateMavenCoordinates(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckCcudExtensionCustomCoordinates(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating Maven Extension custom coordinates requires 'Administer' permission");
}

return validateMavenCoordinates(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckMavenExtensionRepositoryUrl(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating Maven Extension repository URL requires 'Administer' permission");
}

return checkUrl(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckMavenExtensionVersion(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating Maven Extension version requires 'Administer' permission");
}

return checkVersion(value);
}

@Restricted(NoExternalUse.class)
@POST
public FormValidation doCheckCcudExtensionVersion(@QueryParameter String value) {
if (checkAdministerPermission()) {
return FormValidation.error("Validating CCUD Extension version requires 'Administer' permission");
}

return checkVersion(value);
}

@SuppressWarnings("called by Jelly")
@POST
public ListBoxModel doFillGradlePluginRepositoryCredentialIdItems(@AncestorInPath Item project) {
return getAllCredentials(project);
return getAllCredentials(project);
}

@SuppressWarnings("called by Jelly")
@POST
public ListBoxModel doFillMavenExtensionRepositoryCredentialIdItems(@AncestorInPath Item project) {
return getAllCredentials(project);
return getAllCredentials(project);
}

@SuppressWarnings("called by Jelly")
@POST
public ListBoxModel doFillAccessKeyCredentialIdItems(@AncestorInPath Item project) {
return getAllCredentials(project);
return getAllCredentials(project);
}

private static ListBoxModel getAllCredentials(Item project) {
StandardListBoxModel listBoxModel = new StandardListBoxModel();

listBoxModel
.includeEmptyValue()
// Add project scoped credentials:
.includeMatchingAs(ACL.SYSTEM, project, StandardCredentials.class, Collections.emptyList(),
CredentialsMatchers.anyOf(
CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class),
CredentialsMatchers.instanceOf(StringCredentials.class)
));

Jenkins jenkins = Jenkins.getInstanceOrNull();
if (jenkins != null) {
// Add Jenkins system scoped credentials
listBoxModel.includeMatchingAs(ACL.SYSTEM, jenkins, StandardCredentials.class, Collections.emptyList(),
CredentialsMatchers.anyOf(
CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class),
CredentialsMatchers.instanceOf(StringCredentials.class)
)
);
if (jenkins != null && jenkins.hasPermission(Jenkins.ADMINISTER)) {
listBoxModel
.includeEmptyValue()
// Add project scoped credentials:
.includeMatchingAs(ACL.SYSTEM, project, StandardCredentials.class, Collections.emptyList(),
CredentialsMatchers.anyOf(
CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class),
CredentialsMatchers.instanceOf(StringCredentials.class)
))
.includeMatchingAs(ACL.SYSTEM, jenkins, StandardCredentials.class, Collections.emptyList(),
CredentialsMatchers.anyOf(
CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class),
CredentialsMatchers.instanceOf(StringCredentials.class)
)
);
}

return listBoxModel;
Expand All @@ -554,13 +596,13 @@ private static FormValidation checkUrl(String value, boolean required) {
String url = Util.fixEmptyAndTrim(value);
if (url == null) {
return required
? FormValidation.error(Messages.InjectionConfig_Required())
: FormValidation.ok();
? FormValidation.error(Messages.InjectionConfig_Required())
: FormValidation.ok();
}

return HttpUrlValidator.getInstance().isValid(url)
? FormValidation.ok()
: FormValidation.error(Messages.InjectionConfig_InvalidUrl());
? FormValidation.ok()
: FormValidation.error(Messages.InjectionConfig_InvalidUrl());
}

public static FormValidation checkRequiredVersion(String value) {
Expand All @@ -575,13 +617,13 @@ private static FormValidation checkVersion(String value, boolean required) {
String version = Util.fixEmptyAndTrim(value);
if (version == null) {
return required
? FormValidation.error(Messages.InjectionConfig_Required())
: FormValidation.ok();
? FormValidation.error(Messages.InjectionConfig_Required())
: FormValidation.ok();
}

return DevelocityVersionValidator.getInstance().isValid(version)
? FormValidation.ok()
: FormValidation.error(Messages.InjectionConfig_InvalidVersion());
? FormValidation.ok()
: FormValidation.error(Messages.InjectionConfig_InvalidVersion());
}

/**
Expand All @@ -605,6 +647,7 @@ protected Object readResolve() throws IOException {
SystemCredentialsProvider.getInstance().save();

setAccessKeyCredentialId(stringCredentials.getId());
accessKey = null;
}
if (gradlePluginRepositoryUsername != null && gradlePluginRepositoryPassword != null && gradlePluginRepositoryCredentialId == null) {
StandardUsernamePasswordCredentials standardUsernameCredentials = new UsernamePasswordCredentialsImpl(
Expand All @@ -619,16 +662,24 @@ protected Object readResolve() throws IOException {
SystemCredentialsProvider.getInstance().save();

setGradlePluginRepositoryCredentialId(standardUsernameCredentials.getId());
gradlePluginRepositoryUsername = null;
gradlePluginRepositoryPassword = null;
}
return this;
}

private static String migrateLegacyRepositoryFilters(String injectionVcsRepositoryPatterns) {
return Arrays.stream(injectionVcsRepositoryPatterns.split(","))
.map(Util::fixEmptyAndTrim)
.filter(Objects::nonNull)
.map(p -> VcsRepositoryFilter.INCLUSION_QUALIFIER + p)
.collect(Collectors.joining(VcsRepositoryFilter.SEPARATOR));
.map(Util::fixEmptyAndTrim)
.filter(Objects::nonNull)
.map(p -> VcsRepositoryFilter.INCLUSION_QUALIFIER + p)
.collect(Collectors.joining(VcsRepositoryFilter.SEPARATOR));
}

private static boolean checkAdministerPermission() {
Jenkins jenkins = Jenkins.getInstanceOrNull();

return jenkins == null || jenkins.hasPermission(Jenkins.ADMINISTER);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<f:entry field="enforceUrl">
<f:checkbox title="${%Enforce Develocity server url}"/>
</f:entry>
<f:entry title="Develocity Access Key Credential ID" field="accessKeyCredentialId">
<f:entry title="Develocity Access Key credential ID" field="accessKeyCredentialId">
<div class="alert alert-info" role="alert">
<l:icon class="icon-help icon-sm" alt="${%Access key format help}"/>
The access key must be in the <b><span>&lt;</span>server host name<span>&gt;</span>=<span>&lt;</span>access key<span>&gt;</span></b> format.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div>
The credentials containing Develocity access key.
The credentials containing the Develocity access key.
</div>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div>
The credentials containing username and password for a custom Gradle Plugin repository.
The credentials containing the username and password for a custom Gradle Plugin repository.
</div>
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div>
The credentials containing username and password for a custom Maven repository.
The credentials containing the username and password for a custom Maven repository.
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div>
The URL of the repository to use when resolving the Develocity and Common Custom User Data extensions.
Defaults to the Maven Central.
Defaults to Maven Central.
</div>

0 comments on commit 12efce0

Please sign in to comment.