| 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. |