# Git - Commit Signing with SSH Agents and gitsign SSH commit and tag signing fails in specific, diagnosable ways. The wrong `SSH_AUTH_SOCK` hides the signing key from non-interactive shells. A signing wrapper like gitsign needs its `gpg.ssh.program` entry, and a cryptographic signature does not replace a `Signed-off-by:` trailer. ## Key points - When `SSH_AUTH_SOCK` points at the password-manager agent instead of the mux socket, the gitsign signing key is invisible and commits fail with `failed to write commit object`. Prefix git with the mux socket path. - The socket pin belongs in `.zshenv`, the only file every zsh reads. A `.zshrc` pin reaches only interactive shells, so tool-spawned shells inherit the wrong socket. Signing then fails as socket inheritance, not a key problem. - `SSH_AUTH_SOCK` alone does not enable signing when `gpg.ssh.program` is unset. The fallback `ssh-keygen` refuses the forced socket. Route signing through the configured program. - Signed release tags must be annotated: `git tag -a <tag> <sha> -m "<msg>"`. A signing configuration that requires a tag message cannot sign a lightweight tag. - Allowed-signers entries are `<email> <key-type> <public-key>`, one per line, with multiple emails allowed per key. Verify the file parses with `ssh-keygen -l`. - An SSH key can authenticate yet lack organization SSO authorization for signing. A managed account may need a separate registered signing key and a refreshed `admin:ssh_signing_key` scope. - Export `SSH_AUTH_SOCK="$HOME/.ssh/ssh-agent-mux.sock"` so one agent session serves both the password-manager auth keys and the gitsign signing key. The inline export fixes running shells, and the `.zshenv` pin heals new ones. - Verify mux routing in isolation: `ssh-add -l` for the union key listing, then a signed `git commit`, then an SSH auth test. Failures localize to a layer. - On macOS, `launchctl getenv SSH_AUTH_SOCK` finds the launchd agent socket. It resolves to the mux socket when the interactive one points at the password manager. - Password-manager agents fail intermittently from per-use approval expiry, not key absence. The key signs standalone while in-the-moment git calls fail. Retry after the approval lands. - When the agent socket is broken but GitHub CLI auth is valid, push via HTTPS. The CLI holds a token in the system keyring and pushes without touching SSH config. - `git commit -s` adds a `Signed-off-by:` trailer, a legal attestation distinct from cryptographic signing. A commit can be SSH-signed and still fail DCO. Neither implies the other. - A commit pushed without the trailer has no non-force remedy. `git commit --amend -s && git push --force-with-lease` with owner approval is the only recovery path, safe against races. - GitHub squash merges authored under a private-email noreply address fail DCO when the sign-off uses the real address. The sign-off matches neither author nor committer, because GitHub sets the author itself. Fix it account-level: uncheck "Keep my email addresses private", or use the noreply address as the git identity. ## How to apply 1. Pin `export SSH_AUTH_SOCK="$HOME/.ssh/ssh-agent-mux.sock"` in `.zshenv`. Inline `SSH_AUTH_SOCK=~/.ssh/ssh-agent-mux.sock git commit -S` in a running shell. 2. Set `gpg.ssh.program` to gitsign, not the `ssh-keygen` fallback. 3. Verify layers alone: `ssh-add -l`, signed commit, SSH auth test. On macOS, `launchctl getenv SSH_AUTH_SOCK` shows the launchd socket. 4. Allowed-signers lines: `<email> <key-type> <public-key>`, checked with `ssh-keygen -l`. 5. Release tags: `git tag -a <tag> <sha> -m "<tag>"`. 6. DCO: `git commit -s` on every commit. Recover with `git commit --amend -s && git push --force-with-lease` (owner approval). 7. Squash merges: uncheck "Keep my email addresses private", or use the noreply address as the git identity. 8. Broken socket, valid GitHub CLI auth: push over HTTPS. 9. Managed accounts: register a separate signing key and refresh the `admin:ssh_signing_key` scope. 10. Retry a password-agent signature after the approval lands. ## Observations - [ssh] An `SSH_AUTH_SOCK` at the password manager hides the gitsign signing key. Prefix git with the mux socket. #git (source: agent sessions, 2026-06) - [shell] The mux pin belongs in `.zshenv` so non-interactive shells inherit the right socket. #zsh (source: agent sessions, 2026-06) - [git] Signing needs `gpg.ssh.program` set. The `ssh-keygen` fallback refuses the forced socket. #git (source: agent sessions, 2026-09) - [git] Signed release tags must be annotated. The signing config requires a tag message. #git (source: agent sessions, 2026-07) - [ssh] Allowed-signers lines are `<email> <key-type> <public-key>`. Verify with `ssh-keygen -l`. #ssh (source: agent sessions, 2026-06) - [security] An SSH key can authenticate yet lack SSO authorization for signing. Managed accounts need a registered signing key and the `admin:ssh_signing_key` scope. #github (source: agent sessions, 2026-09) - [workflow] Verify mux routing layer by layer: `ssh-add -l`, signed commit, SSH auth test. #git (source: agent sessions, 2026-06) - [ops] Password-manager signatures fail intermittently from approval expiry. Retry after the approval lands. #ssh (source: agent sessions, 2026-10) - [git] Push via HTTPS when the socket is broken but GitHub CLI auth is valid. #github (source: agent sessions, 2026-07) - [dco] A cryptographic signature and a `Signed-off-by:` trailer are independent attestations. #dco (source: agent sessions, 2026-07) - [dco] Squash merges under a noreply address fail DCO when the sign-off uses the real address. Fix at the account level. #dco (source: agent sessions, 2026-10) ## Relations - relates_to [[resources/documentation/Git Configuration]] (git config keys like `gpg.ssh.program`) - relates_to [[resources/documentation/Zsh Configuration]] (socket pin lives in `.zshenv`) - relates_to [[resources/documentation/SSH - Debugging Config, Agents, and Forwards]] (agent socket mechanics) - relates_to [[resources/documentation/Git - Rebase, Stash, and Recovery]] (`--force-with-lease`) ## Sources Personal agent-session notes, April 2026 to October 2026