Gradle signArchives unable to read Secret Key
Asked Answered
B

2

16

I am trying to publish my Java Library to Maven Central. A part of this involves using the signing gradle plugin to sign the artifacts. I need to sign it without using the keyring file as document here as I cant provide my CI secure access to the key ring file.

However when I do this my build fails with:

FAILURE: Build failed with an exception.

* What went wrong:
Could not evaluate onlyIf predicate for task ':signArchives'.
> Could not read PGP secret key

What am I doing wrong? I presume it is related to my GPG_SIGNING_KEY. I used the full private key from the response of gpg --list-secret-keys --keyid-format LONG. Is this not correct?


My build.gradle

apply plugin: 'java'
apply plugin: 'signing'
apply plugin: 'maven'
apply from: 'publish.gradle'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3'
    testCompile 'junit:junit:4.11'
}

task Wrapper(type: Wrapper) {
    gradleVersion = '5.6.2'
}

My publish.gradle

apply plugin: 'maven'
apply plugin: 'signing'

def isReleaseBuild() {
    return !VERSION.contains("SNAPSHOT")
}

def getReleaseRepositoryUrl() {
    return 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
}

def getSnapshotRepositoryUrl() {
    return 'https://oss.sonatype.org/content/repositories/snapshots/'
}

afterEvaluate { project ->
    uploadArchives {
        repositories {
            mavenDeployer {
                beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

                repository(url: getReleaseRepositoryUrl()) {
                    def ossrhUsername = OSSRH_USERNAME
                    def ossrhPassword = OSSRH_PASSWORD

                    authentication(userName: ossrhUsername, password: ossrhPassword)
                }

                snapshotRepository(url: getSnapshotRepositoryUrl()) {
                    def ossrhUsername = OSSRH_USERNAME
                    def ossrhPassword = OSSRH_PASSWORD

                    authentication(userName: ossrhUsername, password: ossrhPassword)
                }

                pom.groupId = GROUP_ID
                pom.artifactId = ARTIFACT_ID
                pom.version = VERSION

                pom.project {
                    name ARTIFACT_ID
                    packaging PROJECT_PACKAGING
                    description PROJECT_DESCRIPTION
                    url PROJECT_URL

                    scm {
                        url SCM_URL
                        connection SCM_CONNECTION
                    }

                    licenses {
                        license {
                            name LICENSE_NAME
                            url LICENSE_URL
                        }
                    }

                    organization {
                        name = ORGANIZATION_NAME
                        url = ORGANIZATION_URL
                    }

                    developers {
                        developer {
                            id DEVELOPER_ID
                            name DEVELOPER_NAME
                            email DEVELOPER_EMAIL
                        }
                    }
                }
            }
        }

        signing {
            required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }

            def signingKey = GPG_SIGNING_KEY
            def signingPassword = GPG_SIGNING_PASSWORD

            useInMemoryPgpKeys(signingKey, signingPassword)

            sign configurations.archives
        }

        task javadocJar(type: Jar) {
            classifier = 'javadoc'
            from javadoc
        }

        task sourcesJar(type: Jar) {
            classifier = 'sources'
            from sourceSets.main.allSource
        }

        artifacts {
            archives javadocJar, sourcesJar
        }
    }
}

And with gradle.properties

RELEASE_REPOSITORY_URL='https://oss.sonatype.org/service/local/staging/deploy/maven2/'
SNAPSHOT_REPOSITORY_URL='https://oss.sonatype.org/content/repositories/snapshots/'
GPG_SIGNING_KEY=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
GPG_SIGNING_PASSWORD=the password used to encrypt the key
OSSRH_USERNAME=my ossrh username
OSSRH_PASSWORD=my ossrh password

VERSION=1.0.0
GROUP_ID=com.example
ARTIFACT_ID=project-name

PROJECT_PACKAGING=...
PROJECT_DESCRIPTION=...
PROJECT_URL=...

SCM_URL=...
SCM_CONNECTION=...

LICENSE_NAME=Apache License, Version 2.0
LICENSE_URL=...

ORGANIZATION_NAME=...
ORGANIZATION_URL=...

DEVELOPER_ID=...
DEVELOPER_NAME=...
DEVELOPER_EMAIL=...
Baccy answered 13/9, 2019 at 9:53 Comment(0)
R
25

As you suspected, it’s the format of the secret PGP key that is wrong here. The useInMemoryPgpKeys method expects an “ascii-armored in-memory PGP secret key”. gpg --list-secret-keys is only meant for human consumption and doesn’t even show the ‘content’ of the secret key.

You can get the key in the correct format using gpg --armor --export-secret-keys [email protected] instead. Use your own key ID (as returned by gpg --list-secret-keys) or email address instead of [email protected].

To make use of the exported key in the gradle.properties file, you need to escape the newline characters. For example, you could append a new, working line for your GPG_SIGNING_KEY property like so:

gpg --armor --export-secret-keys [email protected] \
    | awk 'NR == 1 { print "GPG_SIGNING_KEY=" } 1' ORS='\\n' \
    >> gradle.properties

(See this answer for an explanation of the main awk magic that is used here.)

With your gradle.properties file updated as described (and using your build scripts), I could successfully sign my dummy JAR files with ./gradlew signArchives.

Rosariarosario answered 18/9, 2019 at 20:43 Comment(3)
So when I run the command above in my gradle.properties I get something along the lines of: GPG_SIGNING_KEY=\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\nxxx\nyyy\n-----END PGP PRIVATE KEY BLOCK-----\n Is that correct?Baccy
It works great. I also saw that if you replace ORS='\\n' by ORS='\\n\\\n' the key is inserted as a multiline property (that seems more tidy to me). However, you should remove the final '\n\' manually from the file for it to work properly with other settings if you do it this way.Flight
@Chiriki bless youDeathbed
F
4

To remove unnecessary characters you can use:

gpg --export-secret-keys <public key 8digits> | base64
Fryd answered 19/4, 2023 at 15:7 Comment(1)
Thank you for this, I wasted 6 hours using the wrong secret keyLetishaletitia

© 2022 - 2024 — McMap. All rights reserved.