# foxygit A mostly-read-only git web frontend, in the spirit of [stagit](https://codemadness.org/stagit.html) and [cgit](https://git.zx2c4.com/cgit/about/) — but a single PHP application instead of a static-site generator or a C CGI program. No database, no framework, no build step. It shells out to the `git` binary and renders what comes back; accounts and API keys live in one flat JSON file, not a database. git push/pull itself is **not** handled here — that's SSH or authenticated HTTPS against your bare repos (see [`server/`](server/)). The web app is the "shop window" (browse repos), plus login, API key management, and a repo admin panel. ## Features - Browse repos: file tree, commit log (grouped by day), branches/tags, colorized commit diffs. - README/LICENSE auto-detected from the repo root and rendered (a small, dependency-free markdown → HTML converter — headings, lists, code, links, bold/italic). - Atom feeds for commits and tags. - Raw file download with correct `Content-Type` sniffing. - Anonymous, unauthenticated `git clone` over HTTPS (see `server/setup-anon-clone.sh`); push works over SSH for people with a key, or over HTTPS with an API key (see Accounts below) — the same split GitHub/GitLab use for public repos. - Log in, create/revoke your own API keys, and (as an admin) create/delete repos and add other accounts — all from the browser, no shell access needed. - Themeable: colors live entirely in small CSS custom-property files under `themes/`; the structural CSS in `assets/base.css` never hardcodes a color. Ships with a dark/light pair in its own style plus a GitHub Primer–inspired dark/light pair. A sun/moon toggle switches within a theme's family; a dropdown in the footer switches families. - Careful about the things a "just shell out to git" app can get wrong: leading-dash arguments that could be read as flags, path traversal, unicode filenames, binary blobs, oversized diffs, and command/argument injection in general. ## Accounts, API keys, and admin Visiting the site with no accounts yet shows a one-time "set up an admin account" screen. Once logged in: - **Account** (`?a=account`) — anyone can create and revoke their own API keys. An API key is a personal-access-token-style credential: use it as the password when `git push` asks for one over HTTPS (any username works, same convention as GitHub). Any valid key can push to any repo — the same trust level SSH keyholders already have; there's no per-repo ACL. - **Admin** (`?a=admin`, admin accounts only) — create and delete repos from the browser (delete requires retyping the repo name to confirm, same guard as the SSH `delete` command), and create additional accounts (with or without admin rights) — the HTTPS-login equivalent of `add-key.sh`. Enabling the HTTPS-push side of this (beyond anonymous clone) needs one more server-side setup step: `sudo bash server/setup-http-push.sh` — see that script and `server/git-http-backend-auth` for how it works (a small CGI wrapper in front of `git-http-backend` that checks push requests' Basic Auth password against the stored API keys; reads stay anonymous, unchanged). ## Architecture ``` index.php router only — resolves the request, asks inc/ for data, hands it to views/ inc/ config.php site-specific values (gitignored — see config.example.php) functions.php all git/data logic; never prints HTML auth.php accounts, API keys, sessions — one JSON file (AUTH_STORE), no database render.php the one bridge between index.php and views/ views/ partials/ header (incl. the login/account/admin nav), footer, tabs, subnav *.php one file per page (tree, log, commit, ..., login, account, admin) assets/ structural CSS (base.css) + the one bit of JS (clone-to-clipboard) themes/ *.css files, each just a set of CSS custom properties server/ git hosting over SSH: user setup, key management, self-serve `create`/`describe`/`delete`; the anonymous-HTTPS-clone route (setup-anon-clone.sh); and the authenticated-HTTPS-push route (setup-http-push.sh, git-http-backend-auth, verify-api-key.php) — independent of the web frontend except for sharing inc/auth.php ``` `inc/functions.php` never emits HTML; `views/*.php` never talks to git. `index.php` is the only place that knows both sides exist. ## Deploy 1. `cp inc/config.example.php inc/config.php` and fill in your domain and paths. 2. `sudo bash install.sh` — sets up git hosting over SSH (dedicated user, bare-repo storage, self-serve repo creation/description/deletion) *and* the web frontend (a php-fpm pool running as that user, since the bare repos aren't readable by the default `www-data` pool, plus the Caddy block). Both halves are idempotent and can be run standalone too — `server/setup-server.sh` for just the git side, `deploy.sh` for just the web frontend. 3. Optional: `sudo bash server/setup-anon-clone.sh` for unauthenticated HTTPS clone. 4. Optional: `sudo bash server/setup-http-push.sh` (needs step 3 first) so people can push over HTTPS with an API key instead of only SSH — see "Accounts, API keys, and admin" above. 5. Add collaborators' SSH keys with `sudo bash server/add-key.sh`, or have them log in on the site and create their own API key instead (once an admin has created their account). Everything assumes Debian + Caddy + php-fpm; adjust the paths in `inc/config.php` and the `server/` scripts for a different setup. ## Requirements PHP 8+ with `exec()` and `proc_open()` enabled (on by default), and the `git` binary on `PATH`. That's the whole dependency list.