skip to content

How would you roll out commit signing across a team, and what does it actually buy?

level: principalimportance: should knowfreq 20%

answer

  1. Start where there are few artifacts
  2. The trust list is the real work
  3. Signatures nobody verifies are decoration
  4. The key lives on the machine you fear losing
  5. Rotation and revocation are day-one concerns

basics

~20 s

Start with signed release tags, then extend to commits on protected branches. Signing only pays off if verification runs somewhere that matters and a trust list of principals and keys is actively maintained, including rotation and revocation.

solid answer

~50 s

Sequence it by value: signed annotated tags first, because releases are the artifacts whose provenance matters most and there are few of them, then commits on the branches you actually protect. The hard part is not `commit.gpgSign` — it is the trust list. Somebody has to maintain the mapping from principals to keys (an OpenPGP keyring, or a `gpg.ssh.allowedSignersFile` you can keep in a repository and update on joins and leaves), handle rotation, and wire up `gpg.ssh.revocationFile` when a key is retired. Decide where verification runs and make it fail closed: signatures nobody checks are decoration. Be honest about the threat model — signing binds commits to a key holder and defeats fabricated authorship, but it does not stop a compromised developer machine where the key and agent live, and it does not review code. Budget the friction too: rewrite-heavy workflows drop signatures, and bots and automation need key material of their own.

code

text · 3 lines
text
[email protected] namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...
[email protected] namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...
[email protected] namespaces="git" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...

go deeper

for a junior

Know that signing needs a key on your machine and that somebody must trust that key before anyone else's tooling can verify what you signed.

for a middle

Explain the two halves — creating signatures with commit.gpgSign and tag.gpgSign, verifying them against a trust list — and why the second half is the one teams forget.

for a senior

Show you have operated it: key distribution and rotation, bots needing their own identities, agents to survive long rebases, and a verification step that fails closed and has been tested with an unsigned commit.

for a principal

Own the sequencing and the honest threat model — what signing proves, what it cannot, the ongoing cost of maintaining a trust list, and whether the control is worth the friction for this organisation.

## Decide what you are trying to prove Before any configuration, write down the claim. Usually it is one of: *every change that reached production came from a key we recognise*, or *this release artifact was cut by our release process*, or *fabricated authorship is detectable*. Those need different amounts of machinery, and the second is far cheaper than the first. Without that statement, teams turn on `commit.gpgSign` and get a repository full of signatures that nothing verifies — pure ceremony. ## A staged rollout **Stage one: sign release tags.** Annotated tags signed with `git tag -s` are the highest-value, lowest-friction step. There are few of them, they are created by a small number of people or by one release process, and they are what downstream consumers actually pin. The release script verifies with `git verify-tag` and refuses to build on a non-zero exit. **Stage two: sign commits, opt-in.** Get maintainers signing with `commit.gpgSign` and collect the keys. Nothing is enforced yet; you are building and testing the trust list. **Stage three: verify on the branches you protect.** Only now does a check exist that can block. Whatever runs that check must fail closed — treating "cannot check" as a pass is the failure mode that makes the whole programme theatre. ## The trust list is the project Verification compares a signature against a public key and needs an assertion about who that key belongs to. With OpenPGP that is a keyring plus trust settings; with SSH signing it is the file named by `gpg.ssh.allowedSignersFile`, whose lines pair a principal with a public key under the `git` namespace, and optionally a `gpg.ssh.revocationFile` listing keys that must be rejected. That file is an access-control artifact with a lifecycle: it changes on every join and departure, it must be distributed to every place verification happens, and it needs a review path of its own — whoever can add a line to it can add a trusted signer. Many teams keep it in a repository so changes are reviewable and auditable. Plan rotation before the first key expires, not after, and rehearse the case where a key must be revoked immediately. ## What signing does and does not buy **Buys:** a checkable link from a commit to a key holder, which makes fabricated authorship detectable rather than free; tamper-evidence for content served through mirrors or untrusted paths; a defensible provenance story for release artifacts. **Does not buy:** protection from a compromised developer machine, where the key and its agent live and an attacker can simply sign; any statement about code quality or review; retroactive protection for history created before the programme; protection from a trusted signer acting badly. State these plainly when the requirement arrives from a compliance direction, because "we require signed commits" is often bought as a security control when what it delivers is attribution. ## Friction to budget for - **Rewrites drop signatures.** Amend, rebase and cherry-pick create new commit objects, so a rewrite-heavy workflow needs signing to be automatic (`commit.gpgSign`) or it will be forgotten. - **Automation needs identities.** Bots, release jobs and merge automation that create commits need their own keys and their own entries in the trust list, with a decision about where that key material lives. - **Passphrase prompts.** A long rebase is one signing operation per commit; without an agent this is unbearable, and people will disable signing rather than endure it. - **Onboarding.** Every new machine needs key setup, and every new person needs a trust-list entry. If that takes a week, people work around it. - **Enforcement lives outside Git.** Git itself gives you commands to sign and verify; making the rule mandatory requires a gate on the receiving side, and choosing and operating that gate is a separate decision from anything in the repository. ## How to know it is working Audit rather than assume: walk the range on protected branches with `git log --pretty="%h %G? %GS %s"` and confirm the signer column is populated and matches the trust list, and confirm that a deliberately unsigned commit is actually rejected by the gate. A programme nobody has tested with a negative case has not been tested. ## Interview framing The answer that reads as principal-level is not the config — it is the sequencing (tags before commits), the recognition that the trust list is the real system with a real lifecycle, the honest threat-model boundaries, and the insistence that verification fail closed and be tested with a negative case.

  • Why start with signed tags rather than signed commits?
    Tags are few, are produced by a small number of principals, and are what consumers actually pin, so the provenance benefit per unit of friction is highest. They also exercise the whole pipeline — key setup, trust list, a verification step that fails closed — on a small population before you impose it on every commit everyone makes.
  • What is the strongest argument against mandating signed commits everywhere?
    It taxes every developer on every commit and every rewrite while defending against a narrow threat: fabricated authorship. It does nothing against a compromised machine, where the key and agent sit. If the trust list is not actively maintained and verification does not fail closed, you pay the whole cost for none of the benefit.
  • How do you handle a signing key that must be revoked immediately?
    Remove the principal's line from the allowed-signers file and add the key to the file named by `gpg.ssh.revocationFile` so it is rejected explicitly, then push that change everywhere verification runs. Decide in advance whether previously signed commits should still verify, because revocation makes past signatures fail too.
  • How do build bots fit into a signing programme?
    They are principals like anyone else: they need their own key, their own entry in the trust list, and a decision about where that key material lives and who can reach it. A shared human key handed to automation destroys the attribution the programme exists to provide.

saying these in an interview costs you the question

  • Turns on signing without any verification step
  • Treats cannot-check results as passing
  • Claims signing protects against a compromised developer machine
  • Has no plan for key rotation or revocation
  • Ignores that rewrite-heavy workflows discard signatures

context