Summary
authorize_git_read (crates/buzz-relay/src/api/git/transport.rs) requires a repo's kind:30617 announcement to carry a buzz-channel tag naming a channel the requester belongs to, with an explicit, intentional, tested no-owner-bypass:
There is deliberately no repo-owner bypass: an owner removed from the bound channel loses read access, which is the exact exploit shape this gate closes.
This gate is called unconditionally from both info_refs and upload_pack, and since git push fetches info/refs?service=git-receive-pack first, it blocks push too. So any repo announcement with no buzz-channel tag denies read/push to everyone, including its own owner, with a 404 repository not found.
The problem: nothing in the shipped CLI or Desktop app can attach a buzz-channel tag to a repo announcement, at creation or afterward.
buzz repos create (crates/buzz-cli) has no --channel flag — its full arg surface is --id, --name, --description, --clone, --web, --nostr-relay.
buzz repos protect set / protect remove rebuild the announcement via build_updated_repo_announcement, which only ever touches tags matching a protection-rule pattern (or strips auth) — it preserves an existing buzz-channel tag but cannot introduce a new one.
- The only SDK function that can attach the tag (
build_repo_announcement_with_tags) is reachable solely from that same update path, so it inherits the same limitation.
- No Desktop (Tauri) command creates or updates a repo announcement at all — the
project_git* commands are local-workspace git tooling, unrelated to NIP-34 announcements.
Repro
buzz repos create --id test-repo --name "test"
# publishes a kind:30617 announcement with no buzz-channel tag
git clone https://<your-relay>/git/<your-own-64-char-hex-pubkey>/test-repo
# -> 404 repository not found, even though you are the repo's own owner
Confirmed against a real deployment at HEAD 3e48f1b2 (Desktop 0.5.2, 2026-07-29 release) — the read gate itself landed at 9b0f74480 ("resolve findings (#3150)").
Impact
Following the README's own git-hosting quickstart end-to-end, as a solo operator with no existing channel infrastructure, produces a repository nobody — not even the owner — can clone, pull, or push to. The push-policy layer (policy.rs) does give the announcing pubkey an owner bypass, so this is easy to miss by only testing the push-authorization path in isolation; the read gate is the newer, stricter layer and it overrides that bypass because push traverses the read path first.
Suggested directions (not prescriptive — happy to send a PR against whichever is preferred)
- Add a
--channel <uuid> flag to buzz repos create, and a way to set/change it after the fact (e.g. buzz repos set-channel).
- Auto-provision a private, owner-only channel at repo-creation time when none is specified, so a solo repo works out of the box with zero extra steps.
- Surface repo creation (with channel selection) in the Desktop app.
- At minimum, have
buzz repos create fail loudly with a clear message when no channel is bound, rather than silently producing an unreadable repo.
Happy to provide more detail or test a fix against our deployment.
Summary
authorize_git_read(crates/buzz-relay/src/api/git/transport.rs) requires a repo'skind:30617announcement to carry abuzz-channeltag naming a channel the requester belongs to, with an explicit, intentional, tested no-owner-bypass:This gate is called unconditionally from both
info_refsandupload_pack, and sincegit pushfetchesinfo/refs?service=git-receive-packfirst, it blocks push too. So any repo announcement with nobuzz-channeltag denies read/push to everyone, including its own owner, with a404 repository not found.The problem: nothing in the shipped CLI or Desktop app can attach a
buzz-channeltag to a repo announcement, at creation or afterward.buzz repos create(crates/buzz-cli) has no--channelflag — its full arg surface is--id,--name,--description,--clone,--web,--nostr-relay.buzz repos protect set/protect removerebuild the announcement viabuild_updated_repo_announcement, which only ever touches tags matching a protection-rule pattern (or stripsauth) — it preserves an existingbuzz-channeltag but cannot introduce a new one.build_repo_announcement_with_tags) is reachable solely from that same update path, so it inherits the same limitation.project_git*commands are local-workspace git tooling, unrelated to NIP-34 announcements.Repro
Confirmed against a real deployment at HEAD
3e48f1b2(Desktop 0.5.2, 2026-07-29 release) — the read gate itself landed at9b0f74480("resolve findings (#3150)").Impact
Following the README's own git-hosting quickstart end-to-end, as a solo operator with no existing channel infrastructure, produces a repository nobody — not even the owner — can clone, pull, or push to. The push-policy layer (
policy.rs) does give the announcing pubkey an owner bypass, so this is easy to miss by only testing the push-authorization path in isolation; the read gate is the newer, stricter layer and it overrides that bypass because push traverses the read path first.Suggested directions (not prescriptive — happy to send a PR against whichever is preferred)
--channel <uuid>flag tobuzz repos create, and a way to set/change it after the fact (e.g.buzz repos set-channel).buzz repos createfail loudly with a clear message when no channel is bound, rather than silently producing an unreadable repo.Happy to provide more detail or test a fix against our deployment.