Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.email and git commit --author=… are unauthenticated. Plain git log proves 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/identities file?); 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, gix 0.71 / gix-object 0.48): gix reads commit signatures (via CommitRef::extra_headers, which carries the gpgsig header) but does not verify them: its only verify is verify_checksum (object-hash integrity). Native SSH-signature verification would need a new dependency (ssh-key to 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 an ssh-key ADR, 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).