Skip to content

7.6 "safe credentials" too restrictive, preventing non-gradle-property externalization, and not safe #22618

@cloudshiftchris

Description

@cloudshiftchris

Expected Behavior

Gradle users should be able to provide "safe credentials" via methods aside from Gradle properties.

Current Behavior

With 7.6 "safe credentials" it appears that two concerns got mixed together:

  • prohibt storage of repository credentials in configuration cache;
  • externalize provision of credentials solely via Gradle properties.

Presently the externalization of credentials is overly restrictive and unnecessary. Users are already providing external credentials in many different ways. Solving for externalization is not necessary to satisfy the first point (just don't store the credentials in CC, where-ever they may have come from).

Context

Testing custom Gradle distribution against 7.6rc1, which includes a bundled Settings plugin that sets up private plugin & artifact repositories, including securely retrieving their credentials (via a ValueSource).

This fails on 7.6-rc-1:

- Task `:publish...` of type `org.gradle.api.publish.maven.tasks.PublishToMavenRepository`: Credential values found in configuration for: repository ****
  See https://docs.gradle.org/7.6-rc-1/userguide/configuration_cache.html#config_cache:requirements:safe_credentials

Unable to find a workaround as, to my knowledge, the requisite Gradle properties cannot be set programatically in a settings plugin. Given the nature of how credentials are currently securely retrieved (more info below), smuggling them in via Gradle properties increase the exposure of those credentials.

Ideally there would be a Credentials-provider-API to supply credentials and, separately, the CC would never store credentials.

This blocks migrating to 7.6-rc-1 (from 7.5.1).

Related: many examples, over many years, including many in Gradle docs (that have now been updated) talk about externalizing credentials, often showing this via properties, environment variables, etc. Those examples, and the many Gradle deployments based on them, will now fail the new "safe credentials" check (which is an exception, not having previously warned about these in prior Gradle releases).

Related: documentation implies that all repository credentials should use the new "safe credentials" approach. As implemented in 7.6-rc-1, Gradle only checks for publishing tasks. The logic for this should be at the repository/credential level, regardless of consumers of those repositories.

Steps to Reproduce

Any use of publishing repository credentials other than the new "safe credentials" approach reproduces the issue.

In this specific case, the credentials instance in use is:

internal abstract class RepositoryCredentials : PasswordCredentials {

    @get:Input
    abstract val usernameProp: Property<String>

    @get:Internal
    abstract val passwordProp: Property<String>

    @Input
    override fun getUsername(): String = usernameProp.get()

    override fun setUsername(name: String?) = usernameProp.set(name)

    @Internal
    override fun getPassword(): String = passwordProp.get()

    override fun setPassword(pwd: String?) = passwordProp.set(pwd)
}

This allows the password to be provided via a Provider (ValueSource in this case):

    private fun createRepoCredentials(codeArtifactTokenProvider: Provider<CodeArtifactTokenHolder>): PasswordCredentials {
        val credentials = objects.newInstance<RepositoryCredentials>()
        credentials.usernameProp.set("aws")
        credentials.passwordProp.set(codeArtifactTokenProvider.map { it.value })
        return credentials
    }

In the above code the secure password is not stored in the Credentials object (it's stateless, delegating the the properties).

Your Environment

Gradle 7.6-rc-1, Java 17, Mac OS 13

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions