~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A private repository's pusher's mirror takes in their pack as they push

Merged
Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:serve/seed-pusher-mirror

A member who pushes to a private repository through the gateway, then opens it on the pages, waited for their own mirror to download the pack they had just sent (1.35 s of a 1.9 s sync on prod). Now the gateway also puts that pack into their mirror, aside, as it answers the push. Mirrors stay per viewer: only what they sent goes into theirs. Worth a look at the security argument in seed's doc comment.

Claude Opus 5.5 · high

What changes

gateway::push seeds the pusher's own mirror of a private repository. Once a ref moved, and the repository is in a space and the push carried a pack, seed finds the mirror the pages keep for the caller (login::ctx_for(caller), mirror::path(did, key), the path App::as_viewer syncs). If it exists, it runs index-pack --fix-thin of the same pack bytes there, in a task of its own, after the push answers. Their next look syncs the mirror as before, but finds no object missing, so it reads only the records. With no mirror for them, nothing happens. A thin pack whose bases their mirror lacks fails to index; that is ignored, and their next look fetches it as before.

docs/design/gateway.md (Push) and docs/design/access.md (reading a private repository) say so.

Why

Prod's trace at 21:27:33: mirror sync of chadtmiller.com/spec-pds took 1,933 ms, 293 ms of it reading records and 1,352 ms in git index-pack of a pack from the PDS, 5 s after a pushRefs to it. All five of the page's requests (getRepo, listBranches, listTags, getTree, getLastCommits) waited on that one sync.

Sharing one object store between viewers (git alternates on the gateway's mirror) would cut it for every member, but would let any member read by SHA anything ever pushed through the gateway, force-pushed-away commits included, against the threat table's "a private repository's mirror and entry are kept per viewer". This keeps that rule: a pusher's mirror only gains what they themselves sent.

How it was checked

private_repositories_through_a_gateway now has the collaborator open the repository on the pages first, push through the gateway, and asserts their mirror holds the pushed commit before they look again. Pushes through the gateway with no pages mirror (the runners' landing tests) cover the case where nothing is seeded. Left to CI.

Shortcomings

Other members still fetch the pack on their first look after the push. An owner pushing straight to their PDS, not through the gateway, gets nothing from this. Each such push runs one more index-pack on the server, after it answers.

Approved

After a push that moved a ref of a private repository, the gateway now runs index-pack --fix-thin of the caller's own pack into their pages mirror, if that mirror already exists. It does this in a spawned task after the push answers. I found nothing that must change.

  • Per-viewer rule: the mirror comes from ctx_for(caller), so the pack goes only into the sender's mirror. That mirror is theirs alone, and the pack is what they just sent, so the per-viewer rule holds.
  • Failure and races: a thin pack whose bases the mirror lacks fails quietly and the next sync fetches as before. A concurrent sync or tidy should not conflict, since git's object writes are safe to run side by side and repack -a -d only removes the packs it packed.
  • Docs: gateway.md and access.md are updated.
  • Test: the test checks that the pushed commit is in the mirror before the next look.
  • Not verified: I did not run the checks or the test.

One small note, not a request: the HEAD existence check could race with a mirror still being created for the first time. The effect is only that nothing is seeded.

Merged as 9dcaf61