Docs menuCommit attribution

Docs / Commit attribution

Commit attribution

Sign each agent's commits with a key of its own, and check who signed what.

Setup

Teams want to know which commits an agent made. Curb gives each agent on each device a signing key of its own, and has git sign the agent's commits with it. Your own commits are left alone.

flanner curb attribution --setup

Makes a key for each agent found here and routes its commits through the signer. Asks your operating system once, for all of it.

flanner curb attribution --setup --github

Also adds each new public key to GitHub as a signing key, with your own gh sign-in. Without --github it prints the gh command for you to run.

flanner curb attribution

Each agent's key fingerprint, whether it is registered, and whether rotation is due. --json gives the same.

The keys. Each is a random Ed25519 key, not derived from the device's own identity key. The private half lives only in your OS credential store. With no credential store, setup refuses: a key in a file is one the agent could read.

The settings it writes. Setup puts git configuration into each agent's environment, in Claude Code's env and Codex's shell_environment_policy.set. It turns on SSH commit signing and names flanner-curb-sign as the signing program. It also installs the action log hooks, because the signer needs them. One approval covers both.

The signer. flanner-curb-sign signs only while the action log shows that agent running a shell command. It logs each commit it signs, with the key and the session. A commit outside a recorded agent session is refused: git says signing failed, nothing is signed, and the refusal is logged.

Registration. On a device signed in to Flanner Mesh, each public key is registered with your organization, at setup or at the next check-in. The request carries proof that the device holds the key, and a key stays with the device that registered it. Signatures are OpenSSH's own format, so git, ssh-keygen and GitHub read them too. GitHub shows a commit as verified only once the public key is added there.

Rotation

flanner curb attribution warns when a key is over 90 days old.

flanner curb attribution --rotate

Replaces each agent's key. Add --github to put the new public keys on GitHub.

The retired key's private half is deleted, so it can sign nothing new. The commits it signed stay attributed, shown as signed with a retired key. The new key is registered as the replacement of the old one.

Verify and the five states

flanner curb verify

The last commit's attribution.

flanner curb verify main..HEAD

Every commit in a range. --json gives each commit's state, key fingerprint, agent and device.

Each commit gets exactly one state.

attributed

A valid signature, by a key that a fresh registry lists as active.

attributed, retired key

A valid signature, by a key that a fresh registry lists as retired. Its private half was deleted at rotation, so it can sign nothing new.

untrusted: revoked

The key is revoked in a registry this device has accepted, however old. A revocation is never undone.

key status unknown

A valid signature and no known revocation, but no fresh registry to check against. Curb cannot say whether the key is registered and unrevoked now.

unattributed

No signature, a bad one, or a key that a fresh registry does not list.

The registry. Your organization has one signed list of every registered key, with its agent, its device and its status: active, retired or revoked. verify fetches the newest one when it can reach your organization, and uses the one held on this device when it cannot. A registry is fresh until it expires, 7 days after it was signed by default.

A device accepts a registry only if it is signed by a key the device already trusts and names its own organization. It refuses one that is older than the one it holds, that changed without a new version, that moves a key to another device, or that drops a revocation it has seen.

Offline. Revocations this device has seen always apply. Everything else becomes “key status unknown” once the held registry expires, and at once on a device that never fetched one. An expired registry never counts as current. A fresh one settles the unknown results.

What a signature shows

A signature shows which key signed a commit. It does not show who wrote the code. That is why this is called attribution, and not identity.

It does not protect against you, or against malware running as you. Either can call the signer inside an agent session, and the commit will carry the agent's key. The signer labels agent commits. It cannot tell who drove the session. The action log is your own file too, so a forged log could fake a session.

What it does hold up against: another machine claiming to be your agent, one device registering or revoking another device's key, an old registry replayed to undo a revocation, and a signature moved to other content.

Every commit signed by a revoked key counts as untrusted, whatever its date. A commit's date can be forged, so Curb does not trust it.

Inside Codex's sandbox the signer still has to reach the OS credential store. Where it cannot, the commit fails to sign. It is never signed without the key.