10 — Tabletop: one repo carrying the key, the files, and the vault
What is happening in this document — and why it is unusual
A tabletop exercise is a security-practice staple: before you build or deploy something, you walk the scenario end to end with every party at the table — here an author, a host (GitHub), a reader, an archivist who refuses keys, and a CI runner — and find out where the plan breaks while it is still cheap to fix. Normally a tabletop is a conversation: people around a whiteboard saying “the author would now push, and we assume the push succeeds”.
This one is different, and it is worth pausing on. It was run by the development agent (an LLM) inside the real codebase, and it is executed, not imagined. Every sgit command in the document actually ran — init, commit, push, derive-keys, key classification, the read-only static clone, decryption, verification — against a real local server, with the agent playing all five roles and pasting the genuine output. Only two things are simulated, and the document marks them every time they appear: the sgit publish command (not built yet — its stand-in uses the product's real cryptography classes) and GitHub's hosting (a local git repo plus a plain HTTP server).
This is not a common use of LLMs. Agents are mostly asked to write code or write prose; here the agent used the codebase as a laboratory — it designed the experiment, executed it, measured what happened (git blob dedup counts, cache lifetimes, object tallies), and reported findings that reading the specification could not have produced. Four live findings (F1–F4) came out of the run, one of which reversed an assumption the pack itself held: a repo that commits the vault store is already statically clonable with shipped code, no publish step involved. The CI drill even fails first — a fresh checkout holds no key material — and the recovery (a full republish from the committed public read key alone, zero secrets) was demonstrated rather than asserted.
What makes the result trustworthy is the discipline around it: every simulated element is labelled at each appearance, every claim is tied to real output, and the lab scripts are committed so the whole exercise re-runs. The design was tested before it was built — the same dated, re-runnable, evidence-over-assumption practice the rest of this site argues for, applied by an agent to its own team's specification.
Summary
The maintainer posed the scenario — one GitHub repo, served by Pages, carrying all three at once: the public read key, the decrypted files, and the encrypted vault store with its history — and the agent ran it rather than reasoning about it. Results, all from real runs: publish → push is a no-op, so the amplification loop is impossible by construction (invariant I6 checked with the shipped CLI); git content-addressing makes the double-commit nearly free — all 17 ciphertext projection copies share blobs with the store; the reader's clone over plain GETs comes back identical to the author's tree in both deployment modes; keyless custody verified every content-addressed object with zero key material; and the ordered commit list needed only the read key, so sgit publish never needs the vault key. The final table records what every party ends up holding — and that the one deliberate act that made the host able to read was publishing the key.
Key concepts
- Executed, not imagined — every command block is real shipped-CLI output; the two simulated stand-ins (publish, GitHub hosting) are marked at every appearance and use the real crypto inside
- F4: the repo is already a static vault — the committed bare store cloned with no publish step involved — what publish adds is the browser, custody and key discovery, not clonability
- The zero-secret CI republish — a fresh checkout fails first (no key material — correct), then republishes from the committed public-read-key filename alone; a private vault's CI needs the read key as a secret and an explicit --visibility
Key ideas
- Two systems ignore each other's private half mechanically: .git is in sgit's always-ignored set, .sg_vault/local/ is in .gitignore — and the tabletop caught the one leak (F1: the root .gitignore is itself vault content).
- A refused push still rewrote mutable ref bytes (F2) — spurious git dirty states, filed as a code issue: the kind of bug only an executed exercise surfaces.
- Pages' max-age=600 means a reader can see the old head ref for up to ten minutes after a redeploy; immutable objects are unaffected.