gpg --batch and --pinentry-mode loopback
gpg --batch plus --pinentry-mode loopback and --passphrase-fd let GnuPG run with no terminal and no prompts.
This is the flag combination that makes gpg behave in CI. Without it, GnuPG 2.x tries to open pinentry and fails on a runner with no TTY.
What it does
--batch disables interactive prompts and makes gpg fail rather than ask. --yes auto-confirms overwrites. --pinentry-mode loopback tells GnuPG 2.x to take the passphrase from gpg itself instead of launching pinentry. --passphrase-fd reads the passphrase from a file descriptor, and --passphrase passes it directly (less safe).
Common usage
# pass the passphrase on fd 0 (stdin) rather than the command line
echo "$GPG_PASSPHRASE" | gpg --batch --yes \
--pinentry-mode loopback --passphrase-fd 0 \
--detach-sign --armor file.tar.gz
# direct passphrase (simpler, but visible in process list)
gpg --batch --pinentry-mode loopback \
--passphrase "$GPG_PASSPHRASE" --clearsign notes.txtOptions
| Flag | What it does |
|---|---|
| --batch | Non-interactive mode; never prompt |
| --yes | Assume yes to questions like overwrite |
| --pinentry-mode loopback | Take the passphrase from gpg, not pinentry |
| --passphrase-fd <n> | Read the passphrase from a file descriptor |
| --passphrase <x> | Pass the passphrase inline (can leak via ps) |
| --no-tty | Never write to or read from the terminal |
In CI
Non-interactive batch mode is essential in CI; a runner has no terminal for pinentry to attach to. Prefer --passphrase-fd over --passphrase so the secret does not appear in the process list. Loopback mode also requires that gpg-agent allows it: with older agents add allow-loopback-pinentry to gpg-agent.conf.
Common errors in CI
"gpg: signing failed: Inappropriate ioctl for device" means loopback mode is not set and gpg tried to prompt. "gpg: setting pinentry mode 'loopback' failed: Not supported" means the agent forbids loopback; add allow-loopback-pinentry to gpg-agent.conf and reload the agent. "gpg: Sorry, no terminal at all requested" appears when --batch is set but a prompt was still reached.