cli.sgit.ai / Research / Review: "Git security features → sgit: a one-way mapping

Review: "Git security features → sgit: a one-way mapping"

Date2026-10-08 · 16:16 UTCKindreviewTopicssecurity gitWritten bythe sgit-ai CLI team (Claude Code sessions), for Dinis CruzSourceteam/humans/dinis_cruz/claude-code-web/10/08/review__git-to-sgit-security-mapping.md in SGit-AI__CLI at 5597526. Published here as written; the CLI repository is where the work happened.

CLI team, 8 Oct 2026. Review of the research note of the same date, checked against the code, plus what was built from it (on the branch, for 0.21.0).

Verdict

A good, honest map. The framing is right: one direction only, "N/A by model" kept separate from real gaps, and the ranking puts the structural limit (no server-side enforcement) first. Three statements are wrong or overtaken, one important gap is missing, and the four easy gaps are now closed.

Corrections

§The note saysActually
2author_key_id is "reserved / unused"Live since 0.19.0. Every CLI commit carries it; it names the signing key and marks the canonical (JCS) signing form, and check verify uses it. The schema comment still said "reserved", which is what misled the note; the comment is fixed. author_signature and attestations are the genuinely unused fields
6symlink tree entries "unconfirmed; one to verify"Closed, N/A by model. A tree entry is a blob or a tree, nothing else; there is no symlink type and no code that creates one, so a vault cannot plant a symlink to write through
6case/Unicode variants of .git are a "possible gap"Confirmed, and fixed (see below). Your test was exactly right

A gap the note misses

No per-writer authorisation. In git hosting, who may push to which branch is decided per user by the server. In sgit the write key is one per vault and every writer holds it, so authorisation is all-or-nothing among key holders. Signatures give attribution (who wrote this commit), not permission (who was allowed to). A key holder can write anything the server accepts: refs, indexes, objects. The client-side defences (rewind refusal, signatures-required, tag signature checks) detect much of the damage afterwards; nothing prevents it. This belongs next to gap 1 in the ranking, and it is the real reason "server-side enforcement" matters: the server does not know which writer is which.

What was built from the note (branch, all with tests; verified on the live dev API)

Gap (note's rank)Now
3. No tagssgit vault tag create/list/show/delete. A tag is an immutable object (name, commit, message, tagger key, timestamp) signed over its canonical form, encrypted, content-addressed. Names live only in the encrypted branch index. Verification checks the signature and that the index entry's name equals the signed name, so an entry cannot re-point "v1.0" at another tag's object. Only pushed commits can be tagged; tags move only with --force, and pull reports moves. Deletes are tombstones a stale clone cannot undo. Tag names work in history show/reset. A 0.20.0 client drops tags from the index on its first push; the next current pull restores them (seen live)
2. No reflogsgit history reflog: every local ref move, newest first, local only, capped at 1,000; history reset <old id> brings a head back
2. No force-with-leasesgit push --force-with-lease [<commit>]: forces only if the remote is where this clone last saw it before the push (or at the commit given), and writes with compare-and-swap. It deliberately ignores the refresh that push itself does first; git's version has a known footgun there (a fetch silently satisfies the lease)
4. .git spellingsPath guard refuses .GIT, .Git, .git., .git, GIT~1, SG_VAU~1, .git::$INDEX_ALLOCATION, .g‌it and the same for .sg_vault*, on every platform (the vault may be checked out anywhere). .github, .gitignore, src/git, notes.git stay allowed

Found on the way: sgit push --force from a clone that was behind the remote crashed ("object … is not in the local store") on 0.20.0. Fixed.

Still open, and why

Suggested wording changes for the note

This page as markdown · its source, admin/content/articles/git-to-sgit-security-mapping.md