git@cosmocr.at/gitweb.git · summary refs
documentation: mention cloning for helper setup
commit f85e00a122b2dcfcc1438c783048734967447185
Patrick Gallagher <rpg137@gmail.com> · 2026-07-05 16:17 -0400
parent ebb14439
README.md
# gitweb
Serves git repositories stored in [upspin](https://upspin.io) 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.at` but not by all. Browsing and
cloning require authentication; pushing requires `write`.
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:
```
-make helper && cp bin/git-credential-cosmocr ~/bin/ # anywhere on $PATH
-git config --global credential.https://git.cosmocr.at.helper cosmocr
+# 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.
- `fetch` re-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`.
See `DEPLOY.md`. SSO verification is enabled by `-vault_issuer`
(default `vault@cosmocr.at`); set it to `""` to accept only PATs.
## 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.