This message was deleted.
# community-support
s
This message was deleted.
c
meh. no workaround. safe credentials is poorly designed in it’s current state. it takes perfectly good use cases (such as yours) and forces a very-opinionated mechanism to specify credentials. And then - it doesn’t even secure the credentials, they end up in the configuration cache. Oh, and the allegedly “safe” portion only applies on the publish tasks, not on the repositories themselves.
v
They don't make it into configuration cache, do they? That's why you cannot set credentials directly like in the above example with configuration cache.
c
yep. all the Gradle properties do. If you hexdump the file in .gradle/configuration-cache you’ll see them there.
v
Hm, from https://docs.gradle.org/7.6/userguide/configuration_cache.html#config_cache:requirements:safe_credentials
For security reasons, the configuration cache does not store credentials declared inline.
I thought it wouldn't, but I guess that only refers to having hard-coded values inline and it is landing in CC as it is stored in a Gradle property. 😞
c
It doesn’t store the creds on the repo, but they can only come from properties that are stored. Flawed design.
v
Even if you use the built-in naming-convention based approach? o_O I thought those will then be excluded. 🤦
c
Nope. That ticket shows them, using Gradle’s safe credential sample.
🤦
v
😞
g
Could it be worked around by using custom
ValueSource
via
(this as AuthenticationSupportedInternal).configuredCredentials.set(valueSource)
?
c
for the original report above of duplicating creds - the workaround would be to do nothing. For the issue of insecure creds - that’s where I started that prompted the ticket, a ValueSource that resolved the credentials programatically (temp credentials from API call) and set them as you noted. Even in that case, as Gradle has no concept of a “secret”, the output from the ValueSource is, by definition, stored in CC to be checked against in separate runs (had to hack up an equals() method on a holder class to not compare the expected-to-change temp credentials that shouldn’t invalidate CC).
Ticket has a bunch of thoughts on adding first-class “secret” support.
Writing up a note to Gradle security team on CC storing properties, which will be surprising for many (they were previously transient and are likely used in a wide range of ways to pass sensitive info).
g
😞
c
Repro showing that environment variables, Gradle properties, ValueSource objects end up stored in CC (whether they are used for sensitive data or not, as Gradle has no distinction).
Copy code
plugins {
    `java-library`
    `maven-publish`
}

version = "1.0.2"
group = "com.example"

/*

# clearout CC, run build to populate CC
rm -rf .gradle/configuration-cache; ENV_SECRET=ANOTHER-SECRET ./gradlew  publish -PfooBar=BAZ_SECRET -PmySecureRepositoryUsername=secret-user -PmySecureRepositoryPassword=secret-password --info --configuration-cache

# dump out all files in CC
find .gradle/configuration-cache

# hexdump the build fingerprint (path will vary)
hexdump -C .gradle/configuration-cache/aqvxhqqm6jsa3zloo4iteoqug/buildfingerprint.bin

For this example, there are five secrets:

1) Environment variable ENV_SECRET (value: ANOTHER-SECRET);
2) Gradle property fooBar (value: BAZ_SECRET);
3) Gradle property mySecretRepositoryUsername (from "safe" credentials) (value: secret-user)
4) Gradle property mySecretRepositoryPassword (from "safe" credentials) (value: secret-password)
5) ValueSource output (value: VALUESOURCE_SECRET)

Each of the above secrets is present, in clear text, in the stored configuration cache.

 */
publishing {
    publications {
        create<MavenPublication>("library") {
            from(components.getByName("java"))
        }
    }
    repositories {
        maven {
            name = "mySecureRepository"
            credentials(PasswordCredentials::class)
            url = uri("<https://foo.com>")
        }
    }
}

val fooTask = tasks.register("foo") {
    inputs.property("envVar", providers.environmentVariable("ENV_SECRET"))
    inputs.property("gradleProp", providers.gradleProperty("fooBar"))
    inputs.property("valueSource", providers.of(MyValueSource::class, {}))
    doFirst {
        println(inputs.properties["envVar"])
        println(inputs.properties["gradleProp"])
        println(inputs.properties["valueSource"])
    }
}

tasks.named("publish") {
    dependsOn(fooTask)
}

abstract class MyValueSource : ValueSource<String,ValueSourceParameters.None> {
    override fun obtain(): String? {
        // in real code this would be externally-resolved via API call, keystore, etc
        return "VALUESOURCE_SECRET"
    }
}
1