ADR-030: Git as the integrity substrate + signed commits + identity binding
Date: 2026-06-12 Status: Accepted (owner-delegated review, 2026-06-12) Author: Rômulo Febasi
Context
A Synapse workspace is local and offline, but very likely a git repository with more than one person editing the versioned project. ADR-026 establishes that, in that case, git’s Merkle DAG (not a hand-rolled chain) is the right integrity substrate for the audit trail. But integrity of what changed is only half of governance; the other half is who changed it, non-repudiably, across multiple users. Two facts make this urgent:
- The git author field is forgeable.
git config user.emailandgit commit --author=…are unauthenticated. Plaingit logproves nothing cryptographically, so “git versioning is enough for attribution” is false unless commits are signed. - Synapse already has the missing primitive. ADR-016 gives every user a
portable ed25519 identity with signing and in-band revocation: today used
for identity bundles and federation, but not bound to the workspace’s own
history. ed25519 is exactly an SSH key, and git signs commits natively in
SSH format (
gpg.format=ssh).
Today Synapse only reads git (gix); it never commits. This ADR decides how
identity, signing, and the multi-user trust model bind to git. It is the
companion to ADR-026 (which covers the audit-log format).
Decision
1. Git’s Merkle DAG is the integrity substrate for versioned workspaces. Do not reinvent ordering/tamper-evidence; rely on the commit graph (ADR-026 Tier 1).
2. Attribution = signed commits, bound to the Synapse identity. A user’s
ed25519 identity (ADR-016) doubles as their git SSH signing key. Synapse
recommends and verifies that commits touching the workspace are signed:
syn audit verify (and syn doctor) validate commit signatures against the
workspace’s set of known, non-revoked identities (revocation from ADR-016
finally pays off), and flag unsigned or unknown-signer commits. Non-repudiation
and multi-user attribution come from the signature, not the forgeable author
field.
3. Recommend-and-verify by default; drive-and-sign is opt-in. Synapse stays
non-intrusive: it writes Markdown + per-author audit segments to disk, and the
user commits (Synapse references the resolving commit post-hoc: git blame
on the audit segment already maps each line to a commit). As an opt-in
convenience ([git] auto_commit / syn commit), Synapse may create signed
commits for its own mutations via gix. It never takes over a user’s git
workflow by default: many manage their own.
4. The remote is the witness. A single local clone is not tamper-evident
against its own owner (rebase/force-push). Pushing to a shared/protected remote
makes a history rewrite detectable by anyone holding the old refs. This composes
with ADR-011 (advisory git-remote drift): verify/doctor can warn on a
local-only workspace or on remote divergence. The “free witness” property is real
only in the multi-user/remote case: which is the common one.
5. Multi-user trust model. The accepting identity (BR-12.3 “a human accepts”)
is recorded in the audit record and carried by the signed commit. This sharpens
the rest of the governance stack: ADR-029 corroboration r counts distinct
signed identities (the multi-witness case it deferred); contradiction detection
(SYN-242) becomes cross-user, not just cross-time. The set of identities
trusted for a shared workspace is an explicit allowlist (ties to ADR-010
federation), not “whoever can push”.
Implemented in SYN-249. Zero new dependencies (gix signs/verifies; ed25519
in tree).
Consequences
- Improves: real, multi-user-safe attribution and non-repudiation; leans on git’s battle-tested DAG instead of bespoke crypto; ADR-016 identity + revocation finally protect the workspace itself; the remote becomes a free witness; the trust/contradiction layers (ADR-029, SYN-242) gain genuine multi-party meaning.
- Worsens: signing setup/UX (key configuration,
gpg.format=ssh); users who don’t sign get only the weaker unsigned-git guarantee (detectable history, not attributable); Synapse-driven commits are a behavior change, hence opt-in; team key distribution / the trusted-identity allowlist is new surface to manage. - Open: enforce vs merely recommend signing (recommend first; enforcement is
a per-workspace policy later); how the trusted-identity allowlist is
bootstrapped and updated for a team (a signed
.synapse/identitiesfile?); SSH-format signing vs a future sigstore/gitsign path. Revisit identity bootstrapping alongside ADR-010 when a real multi-writer workspace ships. Feasibility finding (2026-06-13,gix0.71 /gix-object0.48): gix reads commit signatures (viaCommitRef::extra_headers, which carries thegpgsigheader) but does not verify them: its onlyverifyisverify_checksum(object-hash integrity). Native SSH-signature verification would need a new dependency (ssh-keyto parse/verify SSHSIG) + its own ADR. Decision: SYN-249 Tier-1 attribution uses the identity fingerprint recorded in the audit (the author of each entry) plus the already-signed per-author checkpoint (SYN-239), verified out-of-band against the trusted-key set with the existing ed25519 path. Git-commit-signature verification is a later opt-in behind anssh-keyADR, not required for attribution.
Alternatives considered
- Trust the unsigned git author field. Forgeable; provides no non-repudiation. Rejected: signing is the whole point.
- A hand-rolled multi-writer chain / CRDT inside the audit file. Reinvents git’s commit DAG inside a git-tracked file, with merge pain and no distribution. Rejected: lean on git.
- Mandatory Synapse-owned git workflow (auto-commit by default). Too intrusive; conflicts with users who manage their own commits/branches/CI. Opt-in instead.
- Sigstore / gitsign (keyless OIDC signing). Needs online OIDC + Fulcio/Rekor: breaks offline-first and reintroduces a vendor in the trust path, the exact property the product rejects. Keep user-held ed25519/SSH signing; leave sigstore as an optional future for users who want a public transparency anchor.
- A central server to arbitrate multi-user writes. Contradicts local-first and single-source-of-truth-on-disk. Rejected.
Research grounding
Git object model (Merkle DAG of commits/trees); git SSH commit signing
(gpg.format=ssh, ed25519); the forgeability of unsigned git author/committer
fields; gitsign / Sigstore (rejected for offline/local-first); internal:
ADR-011 (git-remote drift), ADR-016 (portable ed25519 identity + revocation),
ADR-010 (federation/allowlist), ADR-026 (audit-log format), ADR-029 (trust).