Git smart HTTP: read-only deploy tokens for non-Nostr consumers (Flux/ArgoCD/go-git)
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Problem
The git transport requires NIP-98 on every route (`transport.rs`: "Auth: NIP-98 on all routes (clone + push). No public repos for v1"), with a ±60s freshness window on the signed event. This is right for interactive humans and agents using `git-credential-nostr` — but it structurally excludes an important class of consumers: **GitOps reconcilers** (Flux, ArgoCD) and anything else built on go-git/libgit2, which can present static Basic/Bearer credentials from a Secret but cannot run a credential helper or produce fresh Schnorr signatures per fetch.
We hit this self-hosting a relay as the system of record for a Kubernetes estate: Flux cannot pull manifests from relay-hosted repos, so deploy repos must stay mirrored to an external forge — which undercuts the sovereign single-relay story for exactly the "repo is the deployment source" use case.
Empirical confirmation on a v0.5.3 relay: anonymous `info/refs` → 401; NIP-98 round-trip works; no Basic/Bearer path exists.
## Proposal
Relay-minted **deploy tokens**: long-lived, revocable, **read-only** (upload-pack + info/refs only), scoped to one repo (or one bound channel), minted by the repo owner or a relay admin — the same bounded-delegation philosophy as relay invites (TTL/scope/use bounds, persisted server-side, auditable).
Presentation: HTTP Basic — `Authorization: Basic base64("x-nostr-deploy:")` — so vanilla Flux `secretRef` (username/password) works with zero changes on the consumer side. The transport tries the existing `Nostr` scheme first, falls back to deploy-token verification for read routes only. Push routes never accept tokens.
Security notes:
- Tokens are server-side records (hash-stored), not signatures — revocation is a DB delete; rotation is mint+revoke.
- Scope ceiling: read-only, single repo/channel; a leaked token exposes read access to one repo until revoked, never write.
- Mint/audit events can land in the audit chain like invite mint/claim already do.
## Alternatives considered
- Per-fetch NIP-98 sidecar/proxy in-cluster: works, but every operator rebuilds the same shim and holds an agent key whose blast radius exceeds read-one-repo.
- Anonymous public repos: solves OSS but not private deploy repos, and "no public repos for v1" is explicitly out of scope today.
Happy to contribute the implementation (transport fallback + mint/revoke endpoints + CLI verbs + conformance tests) if the direction is acceptable.
Contributor guide
Assessment
This issue has not been assessed yet.