gitweb
Serves git repositories stored in upspin over HTTPS at
https://git.cosmocr.at: a read-only browse UI and the git smart-HTTP
protocol for clone/fetch/push with stock git (no git extensions).
gitweb runs as one upspin user (git@cosmocr.at) and reads/writes repos on the
owner's behalf. All access control lives in upspin Access files — gitweb
never has its own permission database.
The URL path is the upspin path, so a bare repo at upspin path
u@example.com/proj.git is served at
https://git.cosmocr.at/u@example.com/proj.git.
Public vs private
The repo's governing Access file (the nearest Access file at or above the
repo directory) decides visibility:
- Public — grants read to all (
read: all). Anyone may browse and clone, no credentials. - Private — readable by
git@cosmocr.atbut not by all. Browsing and cloning require authentication; pushing requireswrite.
Because gitweb reads as git@cosmocr.at, a private repo's Access file must
grant that user read (and, for push, create,write,delete) in addition to the
human collaborators.
Example Access files (in the repo directory, e.g. u@example.com/proj.git/Access):
# public, read-only to the world; owner keeps full control
read,list: all
*: u@example.com
# private; alice can push, bob can only read; the service can serve+write
*: u@example.com
read,list,create,write,delete: alice@example.com, git@cosmocr.at
read,list: bob@example.com
Authenticating (clients)
Credentials go over HTTPS Basic auth. There are two ways to get them.
Passkey login via the credential helper (recommended)
Install the helper and point git at it once:
# clone the repo somewhere:
# $ git clone https://git.cosmocr.at/git@cosmocr.at/gitweb.git $REPO && cd $REPO
$ make helper && cp bin/git-credential-cosmocr ~/bin/ # anywhere on $PATH
$ git config --global credential.https://git.cosmocr.at.helper cosmocr
Now git clone https://git.cosmocr.at/u@example.com/proj.git opens your browser
to vault.cosmocr.at, you approve with your passkey, and git receives a
short-lived token automatically. On a headless machine (no browser) the helper
prints a URL and code to approve from another device (device-code flow); force
it with COSMOCR_DEVICE=1.
The token is a cosmocr.at SSO token minted by vault and signed with vault's
upspin key; gitweb verifies it against the upspin keyserver. Tokens live ~12h
and are cached in ~/.config/cosmocr/tokens.json (mode 0600).
Personal access token (CI / automation)
For non-interactive use, generate a token and store its SHA-256 hash in your own upspin tree:
tok=$(openssl rand -hex 32)
printf '%s laptop-ci\n' "$(printf %s "$tok" | sha256sum | cut -d' ' -f1)" \
| upspin put u@example.com/gitweb/tokens
# let the service read your token file
printf 'read: git@cosmocr.at\n' | upspin put u@example.com/gitweb/Access
echo "$tok" # use as the Basic-auth password
Then clone with the token as the password (username = your upspin user):
git clone https://u%40example.com:$tok@git.cosmocr.at/u@example.com/proj.git
Revoke by deleting the line from u@example.com/gitweb/tokens (effective within
~1 minute).
Creating a repo
gitweb serves existing bare repos; it does not create them. Bootstrap one, then push to it:
git init --bare proj.git
upspin mkdir u@example.com/proj.git
upspin cp -R proj.git/ u@example.com/proj.git/
printf '*: u@example.com\nread,list,create,write,delete: git@cosmocr.at\n' \
| upspin put u@example.com/proj.git/Access
git remote add origin https://git.cosmocr.at/u@example.com/proj.git
git push -u origin main
Markdown & diagrams
READMEs and .md files are rendered (GitHub-flavored markdown, class-based
syntax highlighting, sanitized with bluemonday). Fenced ```mermaid blocks
are drawn client-side: the block becomes <pre class="mermaid"> and a small
same-origin script (web/mermaid-init.js) lazy-loads a vendored mermaid
bundle (web/mermaid.min.js, no CDN) only on pages that contain a diagram, then
renders it with mermaid's securityLevel: "strict".
This is why the Content-Security-Policy allows script-src 'self' (our own
scripts only — no 'unsafe-inline', so markdown-injected inline script still
cannot run) and style-src 'self' 'unsafe-inline' (mermaid injects diagram
styles at render time). See docs/ARCHITECTURE.md, whose diagrams render when
this file is browsed through gitweb itself.
Limitations
git clone --depth N(shallow) is not supported by the underlying go-git server; clone fully.fetchre-sends the full history (the server ignores client "have" lines); fine for clone, wasteful for incremental fetch.- Push is not atomic across refs; each ref updates independently.
- A repo/push is capped at 256 MiB.
Running
make run-dev— local file store (./devdata), no upspin/TLS, for hacking.- Production:
-upspin_config,-tls_cert,-tls_key, listens on:8446. SeeDEPLOY.md. SSO token verification is enabled by-sso_issuer(defaultvault@cosmocr.at); set it to""to accept only PATs. The token's signature is checked against the issuer's upspin keyserver public key, so gitweb never calls the issuer at runtime. - Browser SSO ("Sign in" for private repos): additionally set
-sso_authorize_url(defaulthttps://vault.cosmocr.at/authorize) and-base_url(defaulthttps://git.cosmocr.at). The browser is redirected there to log in with a passkey; the issuer returns a token in the callback URL fragment, which gitweb verifies and stores in an HttpOnly session cookie. The issuer must allow-list<base_url>/_auth/callback(for vault:-sso_redirect gitweb=…/_auth/callback).
Layout
internal/store— read/write access to upspin (or a local dir in dev).internal/gitrepo— materialize bare repos into memory, cache, push write-back.internal/githttp— git smart-HTTP wire protocol over go-git sessions.internal/auth— Access-file authorization; PAT and vault-token verification.internal/server— routing, browse UI, git endpoints, auth gating.cmd/git-credential-cosmocr— the passkey/device git credential helper.