collin/anvil
16222f4845fdaa56261bb793d0a3444b7a7808bc / README.md
RenderedSource
| 1 | # anvil |
| 2 | |
| 3 | A git forge built using [gitoxide](https://github.com/GitoxideLabs/gitoxide). |
| 4 | |
| 5 | ## Architecture |
| 6 | |
| 7 | A Cargo workspace. The keystone is **`anvil-git`**: gix is a *client* library |
| 8 | with no server-side protocol, so anvil supplies its own transport-agnostic |
| 9 | `upload-pack`/`receive-pack` (smart-HTTP and SSH share one implementation). |
| 10 | |
| 11 | | Crate | Responsibility | |
| 12 | |--------------|----------------| |
| 13 | | `anvil-core` | Domain model, SQLite persistence, on-disk bare-repo storage | |
| 14 | | `anvil-git` | Server-side git wire protocol on gix (upstream-candidate) | |
| 15 | | `anvil-web` | axum HTTP server: web UI + smart-HTTP git endpoints | |
| 16 | | `anvil-ssh` | git-over-SSH (russh) | |
| 17 | | `anvil-cli` | `anvild` daemon + admin CLI | |
| 18 | |
| 19 | ## Quick start |
| 20 | |
| 21 | ```sh |
| 22 | cargo run -- migrate # create data/ + database |
| 23 | cargo run -- user create alice --password secret # create a user |
| 24 | cargo run -- repo create alice/hello # create a bare repo on disk |
| 25 | cargo run -- serve # start the server |
| 26 | ``` |
| 27 | |
| 28 | Configuration is optional; see [`anvil.example.toml`](anvil.example.toml). |
| 29 | `PORT`/`HOST` and `ANVIL_BASE_URL` (or `PORTLESS_URL`) override the listen |
| 30 | address and public URL, so a proxy can place anvil without a config file. |
| 31 | |
| 32 | To run it in Docker the way it runs in production, `compose.override.yaml` |
| 33 | layers local settings over the deployment file and compose merges it |
| 34 | automatically: |
| 35 | |
| 36 | ```sh |
| 37 | ./deploy/build.sh --debug # stage the binary the image COPYs in |
| 38 | docker compose up -d --build # then http://127.0.0.1:20640 |
| 39 | docker compose logs -f |
| 40 | docker compose down |
| 41 | ``` |
| 42 | |
| 43 | The override swaps in `deploy/anvil.dev.toml` (so agent sessions are on and the |
| 44 | SSO issuer is `https://login.localhost`), publishes to loopback instead of the |
| 45 | droplet's public IP, uses the `anvil-dev-data` volume, and mounts the Docker |
| 46 | socket that agent sessions need. `hag` passes `-f compose.yaml` explicitly, so |
| 47 | none of it reaches the host. |
| 48 | |
| 49 | `./deploy/dev.sh` is the fuller path and still there: it also generates the |
| 50 | `deploy/dev-ca.crt` bundle the override mounts, waits for `/-/healthz`, and |
| 51 | points [portless](https://www.npmjs.com/package/portless) at the container for |
| 52 | `https://anvil.localhost`. |
| 53 | |
| 54 | ## Deploying |
| 55 | |
| 56 | `compose.yaml` describes the deployment; `hag`, the shared deploy tool for |
| 57 | every project on hagrid, runs it there. The image carries a prebuilt static |
| 58 | binary rather than compiling in Docker, so one step comes first: |
| 59 | |
| 60 | ```sh |
| 61 | ./deploy/deploy.sh # cross-compile, build, push, then restart on the host |
| 62 | ./deploy/deploy.sh -n # dry run: print every step, change nothing |
| 63 | hag status # what the host is running |
| 64 | hag logs -f # its logs |
| 65 | ``` |
| 66 | |
| 67 | Full details, including first-run setup and the CD webhook, are in |
| 68 | [DEPLOY.md](DEPLOY.md). |
| 69 | |
| 70 | ## Docs |
| 71 | |
| 72 | - [CI artifacts](docs/ci-artifacts.md) |
| 73 | - [Remote runners](docs/remote-runners.md) — dial-out runners so CI executes |
| 74 | off-box; design, not yet built |
| 75 | - [Single sign-on](docs/oidc.md) — OIDC sign-in, alongside passwords |
| 76 | - [Repository secrets](docs/secrets.md) — encrypted to your ssh keys in the |
| 77 | browser; anvil stores ciphertext it cannot open |
| 78 | - [Threat model for untrusted users](docs/untrusted-mode.md) |