Component: buzz CLI (repos create) + relay git read gate
Severity: High — the CLI cannot produce a working repository; the failure is silent and misdiagnoses as "repo doesn't exist"
Relay source referenced: commit 3a4bf51
Summary
buzz repos create announces a NIP-34 repository (kind:30617) but provides no way to set the buzz-channel tag. The relay's git read gate (authorize_git_read) requires that tag to resolve the repo's bound channel, and denies any request whose announcement lacks it. The denial is HTTP 404 "repository not found" — byte-identical to a repository that was never announced. Result: every repository created through the CLI is unreachable over git, permanently, with an error that points away from the cause.
Steps to reproduce
buzz repos create --id my-repo --name "My Repo" \
--clone "https://<relay>/git/<owner-hex>/my-repo"
# Announcement is accepted and renders as a Project in Desktop.
git clone https://<relay>/git/<owner-hex>/my-repo
# remote: repository not found
# fatal: repository '.../my-repo' not found
ls-remote, clone, fetch, and push all return 404 repository not found, whether or not the caller is a member of any channel — because the announcement carries no channel binding for the gate to check against.
Root cause
-
CLI: repos create exposes --id --name --description --clone --web --nostr-relay and no --channel. The signed kind:30617 therefore never contains a buzz-channel tag. (buzz.exe contains zero occurrences of the string buzz-channel.)
-
Relay read gate (crates/buzz-relay/src/handlers/transport.rs, ~line 381): resolving the bound channel is mandatory, and its absence is denied with the same response as a missing repo:
fn denied() -> Response {
(StatusCode::NOT_FOUND, "repository not found").into_response()
}
// ...
let Some(channel_id) = repo_bound_channel_id(&repo_event.event) else {
warn!(repo = %repo_name, "git read gate: missing/malformed buzz-channel binding (deny)");
return Err(denied());
};
Three distinct conditions collapse into one indistinguishable 404 — (a) no announcement, (b) announcement present but no buzz-channel binding, (c) caller has no role in the bound channel — which is good for not leaking repo existence, but means the CLI's omission is undiagnosable from the client side.
Fix
Add a required (or strongly-encouraged) --channel <UUID> flag to buzz repos create that emits a buzz-channel tag on the kind:30617. Given that an unbound repo can never be served, consider making it required and rejecting creation without it, rather than announcing a dead repo.
Secondary, optional: have the read gate distinguish "announced but unbound" from "not found" in a way that doesn't leak existence to unauthorized callers — e.g. a distinct log/metric, or a 409 to the owner only. Not required for the fix; the flag is the fix.
Workaround (in use on this nest)
Publish the announcement with a small signer that adds the buzz-channel tag and completes the NIP-42 AUTH challenge (tools/announce-repo.mjs in the buzz-nest-activation repo). Verified end-to-end: with the tag added and nothing else changed, ls-remote goes 404 → 200 and push/clone succeed.
Note on a related dead end
Reports of this symptom are easy to misattribute to "the relay has no git storage for this community" — because probing three repos under three keys all return 404. That inference is wrong: the gate checks the caller's role in each repo's bound channel, so a non-member gets 404 for a perfectly healthy repo. Git hosting over HTTPS with NIP-98 auth works on this deployment (proven by push + fresh clone once the binding is present). No relay-admin provisioning is involved.
Component:
buzzCLI (repos create) + relay git read gateSeverity: High — the CLI cannot produce a working repository; the failure is silent and misdiagnoses as "repo doesn't exist"
Relay source referenced: commit
3a4bf51Summary
buzz repos createannounces a NIP-34 repository (kind:30617) but provides no way to set thebuzz-channeltag. The relay's git read gate (authorize_git_read) requires that tag to resolve the repo's bound channel, and denies any request whose announcement lacks it. The denial isHTTP 404 "repository not found"— byte-identical to a repository that was never announced. Result: every repository created through the CLI is unreachable over git, permanently, with an error that points away from the cause.Steps to reproduce
ls-remote,clone,fetch, andpushall return404 repository not found, whether or not the caller is a member of any channel — because the announcement carries no channel binding for the gate to check against.Root cause
CLI:
repos createexposes--id --name --description --clone --web --nostr-relayand no--channel. The signed kind:30617 therefore never contains abuzz-channeltag. (buzz.execontains zero occurrences of the stringbuzz-channel.)Relay read gate (
crates/buzz-relay/src/handlers/transport.rs, ~line 381): resolving the bound channel is mandatory, and its absence is denied with the same response as a missing repo:Three distinct conditions collapse into one indistinguishable 404 — (a) no announcement, (b) announcement present but no
buzz-channelbinding, (c) caller has no role in the bound channel — which is good for not leaking repo existence, but means the CLI's omission is undiagnosable from the client side.Fix
Add a required (or strongly-encouraged)
--channel <UUID>flag tobuzz repos createthat emits abuzz-channeltag on the kind:30617. Given that an unbound repo can never be served, consider making it required and rejecting creation without it, rather than announcing a dead repo.Secondary, optional: have the read gate distinguish "announced but unbound" from "not found" in a way that doesn't leak existence to unauthorized callers — e.g. a distinct log/metric, or a 409 to the owner only. Not required for the fix; the flag is the fix.
Workaround (in use on this nest)
Publish the announcement with a small signer that adds the
buzz-channeltag and completes the NIP-42 AUTH challenge (tools/announce-repo.mjsin thebuzz-nest-activationrepo). Verified end-to-end: with the tag added and nothing else changed,ls-remotegoes 404 → 200 andpush/clonesucceed.Note on a related dead end
Reports of this symptom are easy to misattribute to "the relay has no git storage for this community" — because probing three repos under three keys all return 404. That inference is wrong: the gate checks the caller's role in each repo's bound channel, so a non-member gets 404 for a perfectly healthy repo. Git hosting over HTTPS with NIP-98 auth works on this deployment (proven by push + fresh clone once the binding is present). No relay-admin provisioning is involved.