skip to content

When using useGpgCmd(), how does Gradle know which key to use and how does the passphrase get supplied? What properties are involved?

level: middleimportance: should knowfreq 28%

answer

  1. useGpgCmd shells out to gpg
  2. signing.gnupg.keyName selects the key
  3. gpg-agent caches/supplies passphrase
  4. executable / useLegacyGpg / homeDir
  5. needs gpg installed + keyring

basics

~10 s

useGpgCmd() invokes the local gpg binary. The signing.gnupg.keyName property selects the key; the gpg-agent normally supplies/caches the passphrase, or you can set signing.gnupg.passphrase. Other signing.gnupg.* properties tune the executable and home dir.

solid answer

~40 s

`useGpgCmd()` switches the signing plugin to delegate to the external **GnuPG** tool, so configuration happens through `signing.gnupg.*` project properties rather than in-memory arguments: - `signing.gnupg.keyName` — which secret key (id/fingerprint) to sign with. - `signing.gnupg.executable` — path to a specific gpg binary (e.g. `gpg2`). - `signing.gnupg.useLegacyGpg` — set true when you must call gpg 1.x, which behaves differently. - `signing.gnupg.homeDir` / `signing.gnupg.optionsFile` — point at a non-default `.gnupg`. - `signing.gnupg.passphrase` — supply the passphrase directly when no interactive agent is available. Normally the **gpg-agent** caches and supplies the passphrase, so Gradle never handles it. That's the big convenience over the in-memory approach: the agent owns the secret. The trade-off is you must have gpg installed and the keyring populated, which is why this path suits workstations rather than ephemeral CI runners.

code

properties · 5 lines
properties
# gradle.properties
signing.gnupg.keyName=0xABCD1234
signing.gnupg.executable=gpg2
# signing.gnupg.passphrase=...   # only if no gpg-agent is available
# signing.gnupg.useLegacyGpg=true

go deeper

for a junior

Know useGpgCmd() uses the local gpg tool and that keyName picks the key.

for a middle

Enumerate the key signing.gnupg.* properties and explain the gpg-agent passphrase flow.

for a senior

Contrast agent-supplied vs property-supplied passphrase security, and when legacy/executable overrides are needed.

for a principal

Decide org policy on where signing happens (workstation vs CI), agent usage, and avoiding passphrases in shared properties.

## What useGpgCmd() actually changes By default the signing plugin signs with an internal BouncyCastle implementation. Calling `useGpgCmd()` tells it instead to **shell out to the gpg executable** for every signature. This means GnuPG's keyring, agent, and configuration are now in charge, and you configure behavior through a family of project properties under the `signing.gnupg.` namespace. ## The signing.gnupg.* properties | Property | Purpose | |---|---| | `signing.gnupg.executable` | Which binary to run (e.g. `gpg`, `gpg2`, or a full path). Useful when the default on PATH is the wrong version. | | `signing.gnupg.useLegacyGpg` | When `true`, Gradle calls gpg using the legacy 1.x command form. Needed on systems where only gpg 1.x exists. | | `signing.gnupg.keyName` | The id/fingerprint of the secret key to sign with. Without it, gpg uses its default key. | | `signing.gnupg.passphrase` | Pass the passphrase directly (for non-interactive runs with no agent). | | `signing.gnupg.homeDir` | Override the GnuPG home directory (default `~/.gnupg`). | | `signing.gnupg.optionsFile` | Use a specific gpg options file. | Set these in `~/.gradle/gradle.properties`, the project `gradle.properties`, `-P` flags, or the `ORG_GRADLE_PROJECT_` env convention. ## How the passphrase is supplied The normal, recommended flow is that the **gpg-agent** holds your unlocked secret key and supplies the passphrase on demand (prompting once, then caching). Gradle never sees the passphrase — a real security advantage. If there is no usable agent (some headless setups), you can provide `signing.gnupg.passphrase`, but that reintroduces a secret into Gradle's configuration, eroding the main benefit. ## Why this is a developer-machine fit The gpg-cmd path assumes: - the gpg binary is installed and on PATH (or located via `executable`), - the secret key is imported into the keyring, - an agent is running to unlock it. Those preconditions are natural on a laptop but awkward on ephemeral CI runners — hence the in-memory keys approach for CI. ```kotlin signing { useGpgCmd() sign(publishing.publications) } ``` ```properties # ~/.gradle/gradle.properties signing.gnupg.keyName=ABCD1234 signing.gnupg.executable=gpg2 # signing.gnupg.useLegacyGpg=true # only if forced onto gpg 1.x ```

  • What's the security advantage of letting the gpg-agent supply the passphrase instead of signing.gnupg.passphrase?
    The agent holds and caches the unlocked key, so the passphrase never enters Gradle's configuration or any properties file, reducing the chance of leaking it.
  • When would you set signing.gnupg.useLegacyGpg=true?
    When the build machine only has GnuPG 1.x, whose command-line interface differs from gpg 2.x; the flag makes Gradle invoke the legacy form.

saying these in an interview costs you the question

  • Claiming useGpgCmd() works on a runner with no gpg installed.
  • Listing in-memory key arguments as if they apply to the gpg-cmd path.
  • Hardcoding signing.gnupg.passphrase in a committed gradle.properties.

context