diff --git a/acceptance-tests/src/main/java/hudson/plugin/gradle/BuildScansInjectionSettings.java b/acceptance-tests/src/main/java/hudson/plugin/gradle/BuildScansInjectionSettings.java index e551226b..d2db4426 100644 --- a/acceptance-tests/src/main/java/hudson/plugin/gradle/BuildScansInjectionSettings.java +++ b/acceptance-tests/src/main/java/hudson/plugin/gradle/BuildScansInjectionSettings.java @@ -18,6 +18,7 @@ public class BuildScansInjectionSettings extends JenkinsConfig { private static final String GE_PLUGIN_VERSION_FIELD = "gradlePluginVersion"; private static final String GIT_REPOSITORY_FILTERS_FIELD = "vcsRepositoryFilter"; private static final String GE_ACCESS_KEY_FIELD = "accessKey"; + private static final String GE_GRADLE_PLUGIN_REPOSITORY_PASSWORD_FIELD = "gradlePluginRepositoryPassword"; public BuildScansInjectionSettings(Jenkins jenkins) { super(jenkins); @@ -55,6 +56,10 @@ public void setGradleEnterpriseAccessKey(String accessKey) { setBuildScansInjectionFormValue(GE_ACCESS_KEY_FIELD, accessKey); } + public void setGradleEnterpriseGradlePluginRepoPassword(String password) { + setBuildScansInjectionFormValue(GE_GRADLE_PLUGIN_REPOSITORY_PASSWORD_FIELD, password); + } + public void setGradleEnterprisePluginVersion(String version) { setBuildScansInjectionFormValue(GE_PLUGIN_VERSION_FIELD, version); } diff --git a/acceptance-tests/src/test/java/hudson/plugins/gradle/AbstractAcceptanceTest.java b/acceptance-tests/src/test/java/hudson/plugins/gradle/AbstractAcceptanceTest.java index e966f24f..719888f7 100644 --- a/acceptance-tests/src/test/java/hudson/plugins/gradle/AbstractAcceptanceTest.java +++ b/acceptance-tests/src/test/java/hudson/plugins/gradle/AbstractAcceptanceTest.java @@ -114,6 +114,12 @@ protected final void enableBuildScansForMaven() { }); } + protected final void setGradlePluginRepositoryPassword(String password) { + updateBuildScansInjectionSettings(settings -> { + settings.setGradleEnterpriseGradlePluginRepoPassword(password); + }); + } + private void updateBuildScansInjectionSettings(Consumer spec) { BuildScansInjectionSettings settings = new BuildScansInjectionSettings(jenkins); settings.configure(); diff --git a/acceptance-tests/src/test/java/hudson/plugins/gradle/GradleInjectionTest.java b/acceptance-tests/src/test/java/hudson/plugins/gradle/GradleInjectionTest.java index 69a30780..e03aa6e5 100644 --- a/acceptance-tests/src/test/java/hudson/plugins/gradle/GradleInjectionTest.java +++ b/acceptance-tests/src/test/java/hudson/plugins/gradle/GradleInjectionTest.java @@ -158,6 +158,29 @@ public void accessKeyIsMasked() { build.action(EnvInjectAction.class).shouldContain("GRADLE_ENTERPRISE_ACCESS_KEY", "[*******]"); } + @Test + @WithPlugins("envinject") + public void gradlePluginRepoPasswordIsMasked() { + // given + setGradlePluginRepositoryPassword("foo"); + + FreeStyleJob job = jenkins.jobs.create(FreeStyleJob.class); + job.copyDir(resource("/simple_gradle_project")); + GradleStep gradle = job.addBuildStep(GradleStep.class); + gradle.setVersion(GRADLE_VERSION); + gradle.setSwitches("--no-daemon"); + gradle.setTasks("helloWorld"); + job.save(); + + // when + Build build = job.startBuild(); + + // then + build.shouldSucceed(); + assertBuildScanPublished(build); + build.action(EnvInjectAction.class).shouldContain("JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD", "[*******]"); + } + @Test public void logsErrorIfBuildScanUploadFailed() { // given diff --git a/build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts b/build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts index 7246e6a9..a9d70df3 100644 --- a/build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts +++ b/build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts @@ -2,7 +2,7 @@ import org.gradle.api.internal.artifacts.transform.UnzipTransform import org.gradle.internal.os.OperatingSystem // Latest version: https://chromedriver.storage.googleapis.com/LATEST_RELEASE -val chromeDriverVersion = "116.0.5845.96" +val chromeDriverVersion = "117.0.5938.88" val ciTeamCityBuild: Boolean by (gradle as ExtensionAware).extra val os: OperatingSystem = OperatingSystem.current() diff --git a/src/main/java/hudson/plugins/gradle/injection/BuildScanEnvironmentContributor.java b/src/main/java/hudson/plugins/gradle/injection/BuildScanEnvironmentContributor.java index e773d40d..537a560e 100644 --- a/src/main/java/hudson/plugins/gradle/injection/BuildScanEnvironmentContributor.java +++ b/src/main/java/hudson/plugins/gradle/injection/BuildScanEnvironmentContributor.java @@ -12,30 +12,28 @@ import hudson.util.Secret; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static hudson.plugins.gradle.injection.GradleInjectionAware.JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD; @Extension public class BuildScanEnvironmentContributor extends EnvironmentContributor { @Override public void buildEnvironmentFor(@Nonnull Run run, @Nonnull EnvVars envs, @Nonnull TaskListener listener) { - Secret secret = InjectionConfig.get().getAccessKey(); - if (secret == null || alreadyExecuted(run)) { - return; - } - - String accessKey = secret.getPlainText(); - if (!GradleEnterpriseAccessKeyValidator.getInstance().isValid(accessKey)) { - GradleEnterpriseLogger logger = new GradleEnterpriseLogger(listener); - logger.error("Gradle Enterprise access key format is not valid"); - run.addAction(GradleEnterpriseParametersAction.empty()); + Secret secretKey = InjectionConfig.get().getAccessKey(); + Secret secretPassword = InjectionConfig.get().getGradlePluginRepositoryPassword(); + if ((secretKey == null && secretPassword == null) || alreadyExecuted(run)) { return; } - run.addAction(GradleEnterpriseParametersAction.of(accessKey)); + run.addAction(GradleEnterpriseParametersAction.of(new GradleEnterpriseLogger(listener), secretKey, secretPassword)); } private static boolean alreadyExecuted(@Nonnull Run run) { @@ -45,7 +43,7 @@ private static boolean alreadyExecuted(@Nonnull Run run) { public static class GradleEnterpriseParametersAction extends ParametersAction { private static final String GRADLE_ENTERPRISE_ACCESS_KEY = "GRADLE_ENTERPRISE_ACCESS_KEY"; - private static final Set ADDITIONAL_SAFE_PARAMETERS = Collections.singleton(GRADLE_ENTERPRISE_ACCESS_KEY); + private static final String GRADLE_ENTERPRISE_REPO_PASSWORD = JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD; private static final GradleEnterpriseParametersAction EMPTY = new GradleEnterpriseParametersAction(); @@ -61,10 +59,24 @@ static GradleEnterpriseParametersAction empty() { return EMPTY; } - static GradleEnterpriseParametersAction of(String accessKey) { + static GradleEnterpriseParametersAction of(GradleEnterpriseLogger logger, @Nullable Secret accessKey, @Nullable Secret repoPassword) { + List values = new ArrayList<>(); + if (accessKey != null) { + if (!GradleEnterpriseAccessKeyValidator.getInstance().isValid(accessKey.getPlainText())) { + logger.error("Gradle Enterprise access key format is not valid"); + } else { + values.add(new PasswordParameterValue(GRADLE_ENTERPRISE_ACCESS_KEY, accessKey.getPlainText())); + } + } + if (repoPassword != null) { + values.add(new PasswordParameterValue(GRADLE_ENTERPRISE_REPO_PASSWORD, repoPassword.getPlainText())); + } + if (values.isEmpty()) { + return GradleEnterpriseParametersAction.empty(); + } return new GradleEnterpriseParametersAction( - Collections.singletonList(new PasswordParameterValue(GRADLE_ENTERPRISE_ACCESS_KEY, accessKey, null)), - ADDITIONAL_SAFE_PARAMETERS + values, + Stream.of(GRADLE_ENTERPRISE_ACCESS_KEY, GRADLE_ENTERPRISE_REPO_PASSWORD).collect(Collectors.toSet()) ); } } diff --git a/src/main/java/hudson/plugins/gradle/injection/GradleBuildScanInjection.java b/src/main/java/hudson/plugins/gradle/injection/GradleBuildScanInjection.java index 011c8ba3..9779fcf2 100644 --- a/src/main/java/hudson/plugins/gradle/injection/GradleBuildScanInjection.java +++ b/src/main/java/hudson/plugins/gradle/injection/GradleBuildScanInjection.java @@ -122,6 +122,13 @@ private void injectEnvironmentVariables(InjectionConfig config, Node node) { if (pluginRepositoryUrl != null && InjectionUtil.isValid(InjectionConfig.checkUrl(pluginRepositoryUrl))) { EnvUtil.setEnvVar(node, JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_URL, pluginRepositoryUrl); } + + if (config.getGradlePluginRepositoryUsername() != null) { + EnvUtil.setEnvVar(node, JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_USERNAME, config.getGradlePluginRepositoryUsername()); + } else { + EnvUtil.removeEnvVar(node, JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_USERNAME); + } + String ccudPluginVersion = config.getCcudPluginVersion(); if (ccudPluginVersion != null && InjectionUtil.isValid(InjectionConfig.checkVersion(ccudPluginVersion))) { EnvUtil.setEnvVar(node, JENKINSGRADLEPLUGIN_CCUD_PLUGIN_VERSION, ccudPluginVersion); diff --git a/src/main/java/hudson/plugins/gradle/injection/GradleInjectionAware.java b/src/main/java/hudson/plugins/gradle/injection/GradleInjectionAware.java index 91f43292..1c2da34f 100644 --- a/src/main/java/hudson/plugins/gradle/injection/GradleInjectionAware.java +++ b/src/main/java/hudson/plugins/gradle/injection/GradleInjectionAware.java @@ -18,6 +18,8 @@ public interface GradleInjectionAware { String JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_ENFORCE_URL = "JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_ENFORCE_URL"; String JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_ALLOW_UNTRUSTED_SERVER = "JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_ALLOW_UNTRUSTED_SERVER"; String JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_URL = "JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_URL"; + String JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_USERNAME = "JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_USERNAME"; + String JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD = "JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD"; String JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_PLUGIN_VERSION = "JENKINSGRADLEPLUGIN_GRADLE_ENTERPRISE_PLUGIN_VERSION"; String JENKINSGRADLEPLUGIN_CCUD_PLUGIN_VERSION = "JENKINSGRADLEPLUGIN_CCUD_PLUGIN_VERSION"; diff --git a/src/main/java/hudson/plugins/gradle/injection/InjectionConfig.java b/src/main/java/hudson/plugins/gradle/injection/InjectionConfig.java index 347d5454..268b1e2c 100644 --- a/src/main/java/hudson/plugins/gradle/injection/InjectionConfig.java +++ b/src/main/java/hudson/plugins/gradle/injection/InjectionConfig.java @@ -58,6 +58,8 @@ public class InjectionConfig extends GlobalConfiguration { private String gradlePluginVersion; private String ccudPluginVersion; private String gradlePluginRepositoryUrl; + private String gradlePluginRepositoryUsername; + private Secret gradlePluginRepositoryPassword; private ImmutableList gradleInjectionEnabledNodes; private ImmutableList gradleInjectionDisabledNodes; @@ -148,6 +150,30 @@ public void setAccessKey(Secret accessKey) { } } + @CheckForNull + public String getGradlePluginRepositoryUsername() { + return gradlePluginRepositoryUsername; + } + + @DataBoundSetter + public void setGradlePluginRepositoryUsername(String gradlePluginRepositoryUsername) { + this.gradlePluginRepositoryUsername = Util.fixEmptyAndTrim(gradlePluginRepositoryUsername); + } + + @CheckForNull + public Secret getGradlePluginRepositoryPassword() { + return gradlePluginRepositoryPassword; + } + + @DataBoundSetter + public void setGradlePluginRepositoryPassword(Secret gradlePluginRepositoryPassword) { + if (Util.fixEmptyAndTrim(gradlePluginRepositoryPassword.getPlainText()) == null) { + this.gradlePluginRepositoryPassword = null; + } else { + this.gradlePluginRepositoryPassword = gradlePluginRepositoryPassword; + } + } + @CheckForNull public String getGradlePluginVersion() { return gradlePluginVersion; diff --git a/src/main/resources/hudson/plugins/gradle/injection/InjectionConfig/config.jelly b/src/main/resources/hudson/plugins/gradle/injection/InjectionConfig/config.jelly index 2f6715c3..92707207 100644 --- a/src/main/resources/hudson/plugins/gradle/injection/InjectionConfig/config.jelly +++ b/src/main/resources/hudson/plugins/gradle/injection/InjectionConfig/config.jelly @@ -72,6 +72,12 @@ + + + + + + diff --git a/src/main/resources/hudson/plugins/gradle/injection/init-script.gradle b/src/main/resources/hudson/plugins/gradle/injection/init-script.gradle index 49ab1a58..6d1ffd12 100644 --- a/src/main/resources/hudson/plugins/gradle/injection/init-script.gradle +++ b/src/main/resources/hudson/plugins/gradle/injection/init-script.gradle @@ -23,6 +23,8 @@ initscript { def pluginRepositoryUrl = getInputParam('jenkinsGradlePlugin.gradle.plugin-repository.url') def gePluginVersion = getInputParam('jenkinsGradlePlugin.gradle-enterprise.plugin.version') def ccudPluginVersion = getInputParam('jenkinsGradlePlugin.ccud.plugin.version') + def gradlePluginRepoUsername = getInputParam('jenkinsGradlePlugin.gradle.plugin-repository.username') + def gradlePluginRepoPassword = getInputParam('jenkinsGradlePlugin.gradle.plugin-repository.password') def atLeastGradle5 = GradleVersion.current() >= GradleVersion.version('5.0') def atLeastGradle4 = GradleVersion.current() >= GradleVersion.version('4.0') @@ -30,9 +32,19 @@ initscript { if (gePluginVersion || ccudPluginVersion && atLeastGradle4) { pluginRepositoryUrl = pluginRepositoryUrl ?: 'https://plugins.gradle.org/m2' logger.quiet("Gradle Enterprise plugins resolution: $pluginRepositoryUrl") - repositories { - maven { url pluginRepositoryUrl } + maven { + url pluginRepositoryUrl + if (gradlePluginRepoUsername && gradlePluginRepoPassword) { + credentials { + username(gradlePluginRepoUsername) + password(gradlePluginRepoPassword) + } + authentication { + basic(BasicAuthentication) + } + } + } } } diff --git a/src/test/groovy/hudson/plugins/gradle/injection/BuildScanEnvironmentContributorTest.groovy b/src/test/groovy/hudson/plugins/gradle/injection/BuildScanEnvironmentContributorTest.groovy index ac7915f9..5f636e65 100644 --- a/src/test/groovy/hudson/plugins/gradle/injection/BuildScanEnvironmentContributorTest.groovy +++ b/src/test/groovy/hudson/plugins/gradle/injection/BuildScanEnvironmentContributorTest.groovy @@ -1,7 +1,7 @@ package hudson.plugins.gradle.injection import hudson.EnvVars -import hudson.model.PasswordParameterValue +import hudson.model.ParameterValue import hudson.model.Run import hudson.model.TaskListener import hudson.plugins.gradle.BaseJenkinsIntegrationTest @@ -29,6 +29,19 @@ class BuildScanEnvironmentContributorTest extends BaseJenkinsIntegrationTest { 0 * run.addAction(_) } + def 'does nothing if no password'() { + given: + def config = InjectionConfig.get() + config.setGradlePluginRepositoryPassword(Secret.fromString("")) + config.save() + + when: + buildScanEnvironmentContributor.buildEnvironmentFor(run, new EnvVars(), TaskListener.NULL) + + then: + 0 * run.addAction(_) + } + def 'adds empty action if access key is invalid'() { given: def config = InjectionConfig.get() @@ -44,6 +57,24 @@ class BuildScanEnvironmentContributorTest extends BaseJenkinsIntegrationTest { } } + def 'adds action if access key is invalid but password is there'() { + given: + def config = InjectionConfig.get() + config.setAccessKey(Secret.fromString("secret")) + config.setGradlePluginRepositoryPassword(Secret.fromString("foo")) + config.save() + + when: + buildScanEnvironmentContributor.buildEnvironmentFor(run, new EnvVars(), TaskListener.NULL) + + then: + 1 * run.addAction { GradleEnterpriseParametersAction action -> + def parameters = action.getAllParameters() + parameters.size() == 1 + paramEquals(parameters.first(), 'JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD', 'foo') + } + } + def 'adds an action with the access key'() { given: def accessKey = "server=secret" @@ -58,7 +89,48 @@ class BuildScanEnvironmentContributorTest extends BaseJenkinsIntegrationTest { 1 * run.addAction { GradleEnterpriseParametersAction action -> def parameters = action.getAllParameters() parameters.size() == 1 - parameters.first() == new PasswordParameterValue('GRADLE_ENTERPRISE_ACCESS_KEY', accessKey, null) + paramEquals(parameters.first(), 'GRADLE_ENTERPRISE_ACCESS_KEY', accessKey) + } + } + + def 'adds an action with the password'() { + given: + def config = InjectionConfig.get() + config.setGradlePluginRepositoryPassword(Secret.fromString("foo")) + config.save() + + when: + buildScanEnvironmentContributor.buildEnvironmentFor(run, new EnvVars(), TaskListener.NULL) + + then: + 1 * run.addAction { GradleEnterpriseParametersAction action -> + def parameters = action.getAllParameters() + parameters.size() == 1 + paramEquals(parameters.first(), 'JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD', 'foo') + } + } + + def 'adds an action with access key and password'() { + given: + def config = InjectionConfig.get() + config.setAccessKey(Secret.fromString("server=secret")) + config.setGradlePluginRepositoryPassword(Secret.fromString("foo")) + config.save() + + when: + buildScanEnvironmentContributor.buildEnvironmentFor(run, new EnvVars(), TaskListener.NULL) + + then: + 1 * run.addAction { GradleEnterpriseParametersAction action -> + def parameters = action.getAllParameters() + parameters.size() == 2 + paramEquals(parameters[0], 'GRADLE_ENTERPRISE_ACCESS_KEY', 'server=secret') + paramEquals(parameters[1], 'JENKINSGRADLEPLUGIN_GRADLE_PLUGIN_REPOSITORY_PASSWORD', 'foo') } } + + private boolean paramEquals(ParameterValue param, String name, String value) { + param.name == name && param.value?.plainText == value + } + }