// Copyright (C) 2024 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[signing_plugin]]
= The Signing Plugin

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 https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP[OpenPGP signatures] (which is the signature format http://central.sonatype.org/pages/requirements.html#sign-files-with-gpgpgp[required for publication to the Maven Central Repository]).

[[sec:signing_usage]]
== Usage

To use the Signing Plugin, include the following in your build script:

.Using the Signing Plugin
====
include::sample[dir="snippets/signing/maven-publish/kotlin",files="build.gradle.kts[tags=use-plugin]"]
include::sample[dir="snippets/signing/maven-publish/groovy",files="build.gradle[tags=use-plugin]"]
====

[[sec:signatory_credentials]]
== Signatory credentials

In order to create OpenPGP signatures, you will need a key pair (instructions on creating a key pair using the https://www.gnupg.org/[GnuPG tools] can be found in the https://www.gnupg.org/documentation/howtos.html[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 the `signing.keyId`, `signing.secretKeyRingFile`, and `signing.password` properties, respectively.

NOTE: Given the personal and private nature of these values, a good practice is to store them in the `gradle.properties` file in the user's Gradle home directory (described in <<build_environment.adoc#sec:gradle_system_properties,System properties>>) instead of in the project directory itself.

[source,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 supply the information via the command line:
----
> gradle sign -Psigning.secretKeyRingFile=/Users/me/.gnupg/secring.gpg -Psigning.password=secret -Psigning.keyId=24875D73
----

[[sec:in-memory-keys]]
=== Using in-memory ascii-armored keys

In some setups it is easier to use environment variables to pass the secret key and password used for signing.
For instance, when using a CI server to sign artifacts, securely providing the keyring file is often troublesome.
On the other hand, most CI servers provide means to securely store environment variables and provide them to builds.
Using the following setup, you can pass the secret key (in ascii-armored format) and the password using the `ORG_GRADLE_PROJECT_signingKey` and `ORG_GRADLE_PROJECT_signingPassword` environment variables, respectively:

====
include::sample[dir="snippets/signing/in-memory/kotlin",files="build.gradle.kts[tags=signing]"]
include::sample[dir="snippets/signing/in-memory/groovy",files="build.gradle[tags=signing]"]
====

=== Using in-memory ascii-armored OpenPGP subkeys

To prevent sharing of the master key and to keep it secure it is also possible to use in-memory ascii-armored subkeys.
The main difference between using in-memory ascii-armored keys and subkeys is that it is necessary to specify key identifier as well.
Using the following setup, you can pass the key identifier, secret key (in ascii-armored format) and the password using the `ORG_GRADLE_PROJECT_signingKeyId`, `ORG_GRADLE_PROJECT_signingKey` and `ORG_GRADLE_PROJECT_signingPassword`
environment variables respectively:

====
include::sample[dir="snippets/signing/in-memory-subkey/kotlin",files="build.gradle.kts[tags=signing]"]
include::sample[dir="snippets/signing/in-memory-subkey/groovy",files="build.gradle[tags=signing]"]
====

[[sec:subkeys]]
=== Using OpenPGP subkeys

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 https://wiki.debian.org/Subkeys[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.

[[sec:using_gpg_agent]]
== Using gpg-agent

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:

.Sign with GnuPG
====
include::sample[dir="snippets/signing/gnupg-signatory/kotlin",files="build.gradle.kts[tags=configure-signatory]"]
include::sample[dir="snippets/signing/gnupg-signatory/groovy",files="build.gradle[tags=configure-signatory]"]
====

This tells the Signing Plugin to use the `GnupgSignatory` instead of the default link:{javadocPath}/org/gradle/plugins/signing/signatory/pgp/PgpSignatory.html[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 `gpg` (on Windows: `gpg.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.


[[sec:sec:gnupg_signatory_configuration]]
=== Gnupg signatory configuration

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

[source.multi-language-sample,properties]
.gradle.properties
----
include::{snippetsPath}/signing/gnupg-signatory/groovy/gradle.properties[tag=user-properties]
----

`signing.gnupg.executable`::
The gpg executable that is invoked for signing. The default value of this property depends on `useLegacyGpg`. If that is `true` then the default value of executable is "gpg" otherwise it is "gpg2".
`signing.gnupg.useLegacyGpg`::
Must be `true` if GnuPG version 1 is used and `false` otherwise. The default value of the property is `false`.
`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.

[[sec:specifying_what_to_sign]]
== Specifying what to sign

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.

[[sec:signing_publications]]
=== Signing Publications

When publishing artifacts, you often want to sign them so the consumer of your artifacts can verify their signature. For example, the <<java_plugin.adoc#java_plugin,Java plugin>> defines a component that you can use to define a publication to a Maven (or Ivy) repository using the <<publishing_maven.adoc#publishing_maven, Maven Publish Plugin>> (or the <<publishing_ivy.adoc#publishing_ivy, Ivy Publish Plugin>>, respectively). Using the Signing DSL, you can specify that all of the artifacts of this publication should be signed.

.Signing a publication
====
include::sample[dir="snippets/signing/maven-publish/kotlin",files="build.gradle.kts[tags=sign-publication]"]
include::sample[dir="snippets/signing/maven-publish/groovy",files="build.gradle[tags=sign-publication]"]
====

This will create a task (of type link:{groovyDslPath}/org.gradle.plugins.signing.Sign.html[Sign]) in your project named `signMavenJavaPublication` that will build all artifacts that are part of the publication (if needed) and then generate signatures for them. The signature files will be placed alongside the artifacts being signed.

=== Example: Signing a publication output

.Output of **`gradle signMavenJavaPublication`**
----
> gradle signMavenJavaPublication
include::{snippetsPath}/signing/maven-publish/tests/signingPluginSignPublication.out[]
----

In addition, the above DSL allows to `sign` multiple comma-separated publications. Alternatively, you may specify `publishing.publications` to sign all publications, or use `publishing.publications.matching { … }` to sign all publications that match the specified predicate.

[[sec:signing_configurations]]
=== Signing Configurations

It is common to want to sign the artifacts of a configuration. For example, the <<java_plugin.adoc#java_plugin,Java plugin>> configures a jar to build and this jar artifact is added to the `runtimeElements` configuration. Using the Signing DSL, you can specify that all of the artifacts of this configuration should be signed.

.Signing a configuration
====
include::sample[dir="snippets/signing/configurations/kotlin",files="build.gradle.kts[tags=sign-runtime-elements]"]
include::sample[dir="snippets/signing/configurations/groovy",files="build.gradle[tags=sign-runtime-elements]"]
====

This will create a task (of type link:{groovyDslPath}/org.gradle.plugins.signing.Sign.html[Sign]) in your project named `signRuntimeElements`, that will build any `runtimeElements` 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 signRuntimeElements`**
----
> gradle signRuntimeElements
include::{snippetsPath}/signing/configurations/tests/signingRuntimeElementsOutput.out[]
----

[[sec:signing_tasks]]
=== Signing Task Output

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.

.Signing a task output
====
include::sample[dir="snippets/signing/tasks/kotlin",files="build.gradle.kts[tags=sign-task]"]
include::sample[dir="snippets/signing/tasks/groovy",files="build.gradle[tags=sign-task]"]
====

This will create a task (of type link:{groovyDslPath}/org.gradle.plugins.signing.Sign.html[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
include::{snippetsPath}/signing/tasks/tests/signingTaskOutput.out[]
----

For a task to be _signable_, it must produce an archive of some type, i.e. it must extend link:{groovyDslPath}/org.gradle.api.tasks.bundling.AbstractArchiveTask.html[AbstractArchiveTask].
Tasks that do this are the link:{groovyDslPath}/org.gradle.api.tasks.bundling.Tar.html[Tar], link:{groovyDslPath}/org.gradle.api.tasks.bundling.Zip.html[Zip], link:{groovyDslPath}/org.gradle.api.tasks.bundling.Jar.html[Jar], link:{groovyDslPath}/org.gradle.api.tasks.bundling.War.html[War] and link:{groovyDslPath}/org.gradle.plugins.ear.Ear.html[Ear] tasks.

[[sec:conditional_signing]]
=== Conditional Signing

A common usage pattern is to require the signing of build artifacts only under certain conditions.
For example, you may not need to sign artifacts for non-release versions.
To achieve this, you can specify the condition as an argument of the `required()` method.

.Specifying when signing is required
====
include::sample[dir="snippets/signing/conditional/kotlin",files="build.gradle.kts[tags=conditional-signing]"]
include::sample[dir="snippets/signing/conditional/groovy",files="build.gradle[tags=conditional-signing]"]
====

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 link:{javadocPath}/org/gradle/plugins/signing/SigningExtension.html#setRequired-java.lang.Object-[SigningExtension.setRequired(java.lang.Object)] for more information.

If the `required` condition does not hold true, artifacts will only be signed if signatory credentials are configured.
Alternatively, you may want to skip signing entirely whether or not signatory credentials are available.
If so, you can configure the link:{groovyDslPath}/org.gradle.plugins.signing.Sign.html[Sign] tasks to be skipped, for example by attaching a predicate using the `onlyIf()` method shown in the following example:

.Specifying when signing is skipped
====
include::sample[dir="snippets/signing/conditional/kotlin",files="build.gradle.kts[tags=only-if]"]
include::sample[dir="snippets/signing/conditional/groovy",files="build.gradle[tags=only-if]"]
====

[[sec:publishing_the_signatures]]
== Publishing the signatures

When signing <<#sec:signing_publications,publications>>, the resultant signature artifacts are automatically added to the corresponding publication.
Thus, when publishing to a repository, e.g. by executing the `publish` task, your signatures will be distributed along with the other artifacts without any additional configuration.

When signing <<#sec:signing_configurations,configurations>> and <<#sec:signing_tasks,tasks>>, the resultant signature artifacts are automatically added to the `signatures` dependency configuration.
