Table of Contents
The signing plugin adds the ability to digitally sign built files and artifacts. These digital signatures can then be used to prove who built the artifact the signature is attached to as well as other information such as when the signature was generated.
The signing plugin currently only provides support for generating OpenPGP signatures (which is the signature format required for publication to the Maven Central Repository).
To use the Signing plugin, include the following in your build script:
In order to create OpenPGP signatures, you will need a key pair (instructions on creating a key pair using the GnuPG tools can be found in the GnuPG HOWTOs). You need to provide the signing plugin with your key information, which means three things:
The public key ID (The last 8 symbols of the keyId. You can use
gpg -K
to get it).The absolute path to the secret key ring file containing your private key. (Since gpg 2.1, you need to export the keys with command
gpg --keyring secring.gpg --export-secret-keys > ~/.gnupg/secring.gpg
).The passphrase used to protect your private key.
These items must be supplied as the values of properties signing.keyId
, signing.secretKeyRingFile
, and signing.password
respectively. Given the personal and private nature of these values, a good practice is to store them in the user gradle.properties
file (described in the section called “System properties”).
signing.keyId=24875D73 signing.password=secret signing.secretKeyRingFile=/Users/me/.gnupg/secring.gpg
If specifying this information (especially signing.password
) in the user gradle.properties
file is not feasible for your environment, you can source the information however you need to and set the project properties manually.
import org.gradle.plugins.signing.Sign gradle.taskGraph.whenReady { taskGraph -> if (taskGraph.allTasks.any { it instanceof Sign }) { // Use Java 6's console to read from the console (no good for // a CI environment) Console console = System.console() console.printf "\n\nWe have to sign some things in this build." + "\n\nPlease enter your signing details.\n\n" def id = console.readLine("PGP Key Id: ") def file = console.readLine("PGP Secret Key Ring File (absolute path): ") def password = console.readPassword("PGP Private Key Password: ") allprojects { ext."signing.keyId" = id } allprojects { ext."signing.secretKeyRingFile" = file } allprojects { ext."signing.password" = password } console.printf "\nThanks.\n\n" } }
Note that the presence of a null value for any these three properties will cause an exception.
OpenPGP supports subkeys, which are like the normal keys, except they’re bound to a master key pair. One feature of OpenPGP subkeys is that they can be revoked independently of the master keys which makes key management easier. A practical case study of how subkeys can be leveraged in software development can be read on the Debian wiki.
The signing plugin supports OpenPGP subkeys out of the box. Just specify a subkey ID as the value in the signing.keyId
property.
By default the signing plugin uses a Java-based implementation of PGP for signing. This implementation cannot use the gpg-agent program for managing private keys, though. If you want to use the gpg-agent, you can change the signatory implementation used by the signing plugin:
This tells the signing plugin to use the GnupgSignatory
instead of the default PgpSignatory
. The GnupgSignatory
relies on the gpg2 program to sign the artifacts. Of course, this requires that GnuPG is installed.
Without any further configuration the gpg2
(on Windows: gpg2.exe
) executable found on the PATH
will be used. The password is supplied by the gpg-agent
and the default key is used for signing.
The GnupgSignatory
supports a number of configuration options for controlling how gpg is invoked. These are typically set in gradle.properties:
Example: Configure the GnupgSignatory
gradle.properties
signing.gnupg.executable=gpg signing.gnupg.useLegacyGpg=true signing.gnupg.homeDir=gnupg-home signing.gnupg.optionsFile=gnupg-home/gpg.conf signing.gnupg.keyName=24875D73 signing.gnupg.passphrase=gradle
signing.gnupg.executable
The gpg executable that is invoked for signing. The default value of this property depends on
useLegacyGpg
. If that istrue
then the default value of executable is "gpg" otherwise it is "gpg2".signing.gnupg.useLegacyGpg
Must be
true
if GnuPG version 1 is used andfalse
otherwise. The default value of the property isfalse
.signing.gnupg.homeDir
Sets the home directory for GnuPG. If not given the default home directory of GnuPG is used.
signing.gnupg.optionsFile
Sets a custom options file for GnuPG. If not given GnuPG’s default configuration file is used.
signing.gnupg.keyName
The id of the key that should be used for signing. If not given then the default key configured in GnuPG will be used.
signing.gnupg.passphrase
The passphrase for unlocking the secret key. If not given then the gpg-agent program is used for getting the passphrase.
All configuration properties are optional.
As well as configuring how things are to be signed (i.e. the signatory configuration), you must also specify what is to be signed. The Signing plugin provides a DSL that allows you to specify the tasks and/or configurations that should be signed.
It is common to want to sign the artifacts of a configuration. For example, the Java plugin configures a jar to build and this jar artifact is added to the archives
configuration. Using the Signing DSL, you can specify that all of the artifacts of this configuration should be signed.
This will create a task (of type Sign
) in your project named “signArchives
”, that will build any archives
artifacts (if needed) and then generate signatures for them. The signature files will be placed alongside the artifacts being signed.
Example: Signing a configuration output
Output of gradle signArchives
> gradle signArchives > Task :compileJava > Task :processResources > Task :classes > Task :jar > Task :signArchives BUILD SUCCESSFUL in 0s 4 actionable tasks: 4 executed
In some cases the artifact that you need to sign may not be part of a configuration. In this case you can directly sign the task that produces the artifact to sign.
Example: Signing a task
build.gradle
task stuffZip (type: Zip) { baseName = "stuff" from "src/stuff" } signing { sign stuffZip }
This will create a task (of type Sign
) in your project named “signStuffZip
”, that will build the input task’s archive (if needed) and then sign it. The signature file will be placed alongside the artifact being signed.
Example: Signing a task output
Output of gradle signStuffZip
> gradle signStuffZip > Task :stuffZip > Task :signStuffZip BUILD SUCCESSFUL in 0s 2 actionable tasks: 2 executed
For a task to be “signable”, it must produce an archive of some type. Tasks that do this are the Tar
, Zip
, Jar
, War
and Ear
tasks.
A common usage pattern is to only sign build artifacts under certain conditions. For example, you may not wish to sign artifacts for non-release versions. To achieve this, you can specify that signing is only required under certain conditions.
Example: Conditional signing
build.gradle
version = '1.0-SNAPSHOT' ext.isReleaseVersion = !version.endsWith("SNAPSHOT") signing { required { isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives") } sign configurations.archives }
In this example, we only want to require signing if we are building a release version and we are going to publish it. Because we are inspecting the task graph to determine if we are going to be publishing, we must set the signing.required
property to a closure to defer the evaluation. See SigningExtension.setRequired(java.lang.Object)
for more information.
When specifying what is to be signed via the Signing DSL, the resultant signature artifacts are automatically added to the signatures
and archives
dependency configurations. This means that if you want to upload your signatures to your distribution repository along with the artifacts you simply execute the uploadArchives
task as normal.
Signing the generated POM file generated by the Maven Publishing plugin is currently not supported. Future versions of Gradle might add this functionality.
When deploying signatures for your artifacts to a Maven repository, you will also want to sign the published POM file. The signing plugin adds a signing.signPom()
(see: SigningExtension.signPom(org.gradle.api.artifacts.maven.MavenDeployment, groovy.lang.Closure)
) method that can be used in the beforeDeployment()
block in your upload task configuration.
Example: Signing a POM for deployment
build.gradle
uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } } } }
When signing is not required and the POM cannot be signed due to insufficient configuration (i.e. no credentials for signing) then the signPom()
method will silently do nothing.