gradle / gradle

Adaptable, fast automation for all
https://gradle.org
Apache License 2.0
16.94k stars 4.74k forks source link

Explicit repository credentials break with configuration caching #24040

Open ccjernigan opened 1 year ago

ccjernigan commented 1 year ago

Expected Behavior

Explicitly set credentials for a Maven repository are used.

Current Behavior

Build fails, asking for implicit properties to be configured. E.g.

* What went wrong:
Execution failed for task ':publish:publishDataPublicationToGitHubPackageRegistryRepository'.
> The following Gradle properties are missing for 'GitHubPackageRegistry' credentials:
    - GitHubPackageRegistryUsername
    - GitHubPackageRegistryPassword

Context

I have a simple Gradle project to publish dataset JAR files to GitHub Package Registry, as seen in the sample below. (The datasets are effectively a ZIP of a directory, so this is a reasonable way to get them uploaded to be consumed by another project behind authentication).

This fails in Gradle 8.0.1.

Steps to Reproduce

  1. Set up a script with the code below
  2. Generate a GitHub Personal Access token
    1. Generate a new Personal Access Token
    2. Put in a name for the token, such as package registry
    3. Check the box for write:packages only
    4. Click Generate Token
    5. Copy the token to be used in the next step
  3. Enable configuration caching org.gradle.unsafe.configuration-cache=true in gradle.properties
  4. Run the Gradle command, supplying the GitHub Package Registry details (URL, user, and token) and the package details (group, artifact id, version). This command would look something like: ./gradlew publishAllPublicationsToGitHubPackageRegistryRepository -PPUBLISHER_GITHUB_PACKAGE_REGISTRY_URL= -PPUBLISHER_GITHUB_PACKAGE_REGISTRY_USER= -PPUBLISHER_GITHUB_PACKAGE_REGISTRY_TOKEN= -PPUBLISHER_GROUP_ID= -PPUBLISHER_ARTIFACT_ID= -PPUBLISHER_VERSION=

In build.gradle.kts

plugins {
    id("maven-publish")
}

publishing {
    repositories {
        mavenLocal {
            name = "MavenLocal"
        }

        val githubPackageRegistryUrl = extra["PUBLISHER_GITHUB_PACKAGE_REGISTRY_URL"].toString()
        val githubPackageRegistryUsername = extra["PUBLISHER_GITHUB_PACKAGE_REGISTRY_USER"].toString()
        val githubPackageRegistryToken = extra["PUBLISHER_GITHUB_PACKAGE_REGISTRY_TOKEN"].toString()
        if (githubPackageRegistryUrl.isNotBlank() && githubPackageRegistryUsername.isNotBlank() && githubPackageRegistryToken.isNotBlank()) {
            maven(githubPackageRegistryUrl) {
                name = "GitHubPackageRegistry"
                credentials {
                    username = githubPackageRegistryUsername
                    password = githubPackageRegistryToken
                }
            }
        }
    }

    publications {
        create<MavenPublication>("data") {
            groupId = extra["PUBLISHER_GROUP_ID"].toString()
            artifactId = extra["PUBLISHER_ARTIFACT_ID"].toString()
            version = extra["PUBLISHER_VERSION"].toString()

            // Place a file with this name in the root directory
            artifact(File(rootDir, "to_publish.jar"))
        }
    }
}

Your Environment

Build scan URL:

ccjernigan commented 1 year ago

I previously flagged this as a regression, but I don't think that's true because I didn't have the configuration cache enabled when I was using Gradle 7.6. There were several moving parts to check when trying to get the reproduction steps narrowed down.

jbartok commented 1 year ago

Thank you for your interest in Gradle!

This issue needs a decision from the team responsible for that area. They have been informed, response time may vary.

abstratt commented 1 year ago

@ccjernigan Our documentation/implementation is at a messy state regarding this.

Up to 7.5, there was no support for Maven/Ivy publishing with the configuration cache. In 7.6.1/8.0, that support was implemented, but the choice then was not to persist credentials (at first we had an error message letting you know inlined/explicit credentials were not supported, but that was later reverted for being too harsh and still not fully effective).

For 8.1, we are considering supporting encryption of the configuration cache state files, and while doing so, changing the persistence of Maven/Ivy repos in the Maven/Ivy Publish plugin configurations so inlined/explicit credentials are preserved, but that is in the air now.

Meanwhile, just so you are unblocked, is there a technical reason why you could not externalize those credentials, as shown here?

ccjernigan commented 1 year ago

Thanks for the reply and the suggestions.

I have intentionally avoided implicit names (e.g. the implicit mySecureRepositoryUsername from the linked documentation). Because I'm part of multiple organizations that are using similar resources and I do work for these organizations on the same machine, I need to 1. be able to publish to both and 2. not mix the credentials between orgs when I set them in ~/.gradle/gradle.properties. If two projects define the same publishing repository, e.g. MavenCentral or GitHubPackageRegistry, then this type of collision would occur via implicit names.

I typically take my secrets and prefix them with the project or org name, e.g. MYPROJECT_MAVEN_PASSWORD or MYORG_MAVEN_PASSWORD which prevents this type of issue.

Thanks for considering this use case for the design of the configuration cache.

efemoney commented 1 year ago

Adding our own use case here.

We are creating a custom distribution that includes an init script to further simplify the setup for our engineers!

Today its cumbersome because to use our plugins & dependencies served from our internal artifactory, the exact same block of code needs to be specified in

To fix this, we are adding an init script that for each added repository (RepositoryHandler.configureEach) across these different points that match our internal artifactory URL, we automatically add the correct credentials

username = providers.gradleProperty(...).orElse(providers.environmentVariable(...))
password = providers.gradleProperty(...).orElse(providers.environmentVariable(...))

Now I didn't even get to test the init script because this is failing, with this issue, at publishing the custom distribution using the ivy-publish plugin šŸ˜…šŸ˜­

Based on the above it is clear that we will not know the names of these added repositories before hand and even if we do there is no way to influence the loaded gradle properties so that we could have repositoryNameUsername & repositoryNamePassword gradle properties.