feat: unattended GPG signing for TUI agents - #25
Conversation
- Add private_* to .gitignore, untrack existing private files - Create gpg-agent.conf with allow-preset-passphrase and long TTLs - Create gpg-sign-preset script (presets passphrase from gnome-keyring) - Hook into zshrc/bashrc to preset at interactive shell start - Add systemd user unit + chezmoiscript to enable at graphical login - Add troubleshooting entry and update AGENTS.md key-files table - One-time manual step: secret-tool store --label=... service gpg-signing keygrip <grip>
- B2: Fix keygrip parser — stateful awk captures grp after matching fpr (subkey-safe) - M2: Move gpg configs from private_dot_gnupg/ to dot_gnupg/ (tracked, no secrets) - M3: Add pinentry-timeout 30 to gpg-agent.conf (fail fast on missed preset) - M4: Convert run_once chezmoiscript to run_onchange tracking unit file - m2: Store secret-tool entry by fingerprint instead of keygrip (survives rotation) - m3: Add empty key guard to preset script - m5: Drop After=graphical-session.target from unit (any-login) - AGENTS.md: Update paths/doc for dot_gnupg/ move
PR Summary
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 643e236044
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| set -euo pipefail | ||
|
|
||
| if command -v systemctl >/dev/null 2>&1; then | ||
| systemctl --user daemon-reload |
There was a problem hiding this comment.
Guard systemd user calls when no user bus exists
In non-systemd user sessions such as devcontainers or headless SSH sessions where systemctl is installed but no user manager is running, this command fails (systemctl --user daemon-reload returns Failed to connect to bus: No medium found in the current container). Because the script has set -e, chezmoi apply aborts before completing; the binary check needs to also verify a usable user bus or tolerate this failure.
Useful? React with 👍 / 👎.
| @@ -0,0 +1,5 @@ | |||
| pinentry-program /usr/bin/pinentry-curses | |||
There was a problem hiding this comment.
Avoid hard-coding a Linux pinentry path
For macOS installs supported by this dotfiles repo, applying this writes a Linux-specific /usr/bin/pinentry-curses into ~/.gnupg/gpg-agent.conf. When the signing cache is empty, gpg-agent will try that missing path instead of the platform's pinentry, so signed commits or decryption fail rather than prompting; this should be templated via lookPath/OS guards or left to GnuPG defaults.
Useful? React with 👍 / 👎.
| key="{{ .gpg_signing_key }}" | ||
| [ -n "$key" ] || exit 0 | ||
|
|
||
| command -v gpg-preset-passphrase >/dev/null 2>&1 || exit 0 |
There was a problem hiding this comment.
Resolve gpg-preset-passphrase outside PATH
On Debian/Ubuntu the gpg-agent package installs this helper under GnuPG's libexec directory (for example gpgconf --list-dirs libexecdir reports /usr/lib/gnupg, containing gpg-preset-passphrase) rather than as a normal PATH command. In those standard shells this guard silently exits, so neither the systemd service nor the shell hook ever presets the passphrase cache and the original commit prompt hang remains.
Useful? React with 👍 / 👎.
What
Makes git commit signing work non-interactively for opencode/codex TUI agents. Passphrase cached in gnome-keyring, presets into gpg-agent at login/shell-start.
Changes
private_*added to.gitignore, untracked existing private-files from indexallow-preset-passphrase,pinentry-timeout 30, cache TTLs (1d/400d)secret-tool, pipes togpg-preset-passphrase. Silent exit on missing deps.gpg-sign-preset.serviceruns at login,WantedBy=default.targetrun_onchangetrigger tracks unit file fordaemon-reload + enablegpg-agent+libsecret-toolsvia apt-getOne-time manual step after merge
secret-tool store --label="GPG signing passphrase" service gpg-signing key C8B994F19E7D34D9(type passphrase on TTY prompt, no echo — then all future commits sign silently)
Verification
chezmoi apply— configs render correctlygpg-agent.conf—allow-preset-passphrasepresent