vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys
keenan · 17m ago
4b8c9e1d
| 1 | # Packages |
| 2 | |
| 3 | A release can be installed with the system package manager instead of unpacking a |
| 4 | tarball. Pushing an annotated tag builds the `.deb` and the `.rpm` for `amd64` and |
| 5 | `arm64` and attaches them to the release page; nothing is published anywhere else. |
| 6 | |
| 7 | ```sh |
| 8 | dpkg -i vole_0.2.0-1_amd64.deb # Debian, Ubuntu |
| 9 | dnf install ./vole-0.2.0-1.x86_64.rpm # Fedora, RHEL, Rocky |
| 10 | ``` |
| 11 | |
| 12 | There is no apt or dnf repository and no signature on these files yet. Each release |
| 13 | page also carries `SHA256SUMS`; compare it before installing. |
| 14 | |
| 15 | To have a fresh cloud machine install and configure the package for you, use the |
| 16 | [deployment guides](deploy/README.md). They need the URL of the file above, which |
| 17 | is how a `.deb` from a release page is named: |
| 18 | `.../vole/releases/v0.2.0/artifacts/vole_0.2.0-1_amd64.deb`, or `arm64` for an |
| 19 | `arm64` machine. |
| 20 | |
| 21 | Both packages depend on `git` and the system SQLite library: `libsqlite3-0` on |
| 22 | Debian and Ubuntu, `sqlite-libs` on Fedora, RHEL, and Rocky. Vole links SQLite |
| 23 | dynamically, so the library must be present where the binary runs; the package |
| 24 | manager installs it with the package. The system library must include SQLite's |
| 25 | FTS5 module, which every distribution listed above enables in its build; the |
| 26 | command palette is what needs it, and the binary carries the tag that asks for it |
| 27 | when the driver's bundled copy is used instead. |
| 28 | |
| 29 | ## What the package installs |
| 30 | |
| 31 | | Path | What it is | |
| 32 | |---|---| |
| 33 | | `/usr/bin/vole` | The binary, built from the tag with `vole version` set to it | |
| 34 | | `/usr/lib/systemd/system/vole.service` | The unit, with hardening and a `/var/lib/vole` state directory | |
| 35 | | `/usr/lib/systemd/system/vole-runner.service` | The CI runner's unit. Not enabled, and inert until `/etc/vole/runner.env` names an instance | |
| 36 | | `/etc/vole/runner.env` | Arguments for that unit, as a conffile. See [Deploying § CI runners](deploy/runner.md) | |
| 37 | | `/etc/containers/registries.conf.d/50-vole-runner.conf` | Where a short image name is looked up, as a conffile. Debian and Ubuntu ship no unqualified search registries, so a digest-pinned base written as a short name cannot resolve without it. See [Deploying § CI runners](deploy/runner.md#what-the-package-configures-in-the-container-runtime) | |
| 38 | | `/etc/containers/containers.conf.d/50-vole-runner.conf` | `cgroup_manager = "cgroupfs"` for the runner's rootless runtime, as a conffile. A system service has no systemd user manager for podman to ask for a cgroup scope. See [Deploying § CI runners](deploy/runner.md#what-the-package-configures-in-the-container-runtime) | |
| 39 | | `/etc/vole/vole.toml` | Configuration, marked as a conffile so your edits survive upgrades | |
| 40 | | `/usr/share/doc/vole/` | `LICENSE` and `NOTICE` | |
| 41 | | `/var/lib/vole/data` | The instance: repositories, databases, stores, host key, audit log | |
| 42 | |
| 43 | The package creates the `vole` service account and runs `vole admin init` against |
| 44 | the shipped config. It does not create an instance admin and does not enable the |
| 45 | service: who may administer the instance is the operator's decision, not the |
| 46 | package's. |
| 47 | |
| 48 | The shipped config listens on `0.0.0.0:2222` for SSH and `127.0.0.1:8080` for the |
| 49 | web. Open 2222 in the firewall, set `public_url` before anyone signs in with a |
| 50 | passkey, and either terminate TLS in a proxy in front of 8080 or use `https_addr` |
| 51 | to let Vole obtain certificates itself. See |
| 52 | [Configuration § Automatic HTTPS with ACME](configuration.md#automatic-https-with-acme) |
| 53 | and [Configuration § Running behind a proxy](configuration.md#running-behind-a-proxy). |
| 54 | |
| 55 | The unit is written for the packaged layout and is safe to use as shipped: it |
| 56 | drops all capabilities, sets `UMask=0027`, gives the service a private `/tmp` and |
| 57 | device tree, hides other processes, and makes `/var/lib/vole` the only writable |
| 58 | path. If you need to bind a port below 1024 — SSH on 2222 does not, HTTP on 80 and |
| 59 | HTTPS on 443 do — add the one capability with a drop-in, which must widen the |
| 60 | bounding set as well: |
| 61 | |
| 62 | ```ini |
| 63 | # /etc/systemd/system/vole.service.d/bind.conf |
| 64 | [Service] |
| 65 | CapabilityBoundingSet=CAP_NET_BIND_SERVICE |
| 66 | AmbientCapabilities=CAP_NET_BIND_SERVICE |
| 67 | ``` |
| 68 | |
| 69 | `MemoryDenyWriteExecute=true` is safe for the forge because it runs no JIT. A CI |
| 70 | runner executes repository code in containers and is a separate process with its |
| 71 | own unit; do not relax this unit to accommodate it. |
| 72 | |
| 73 | ## First steps after install |
| 74 | |
| 75 | ```sh |
| 76 | vole admin --config /etc/vole/vole.toml account create you --key ~/.ssh/id_ed25519.pub |
| 77 | vole admin --config /etc/vole/vole.toml repo create demo --owner you |
| 78 | vole admin --config /etc/vole/vole.toml acl set-default-role demo read |
| 79 | systemctl enable --now vole |
| 80 | ``` |
| 81 | |
| 82 | Run admin commands as the `vole` user or with `--config /etc/vole/vole.toml`; the |
| 83 | service account owns the files they write. A command that writes as the wrong user |
| 84 | leaves state the service cannot open, so prefer: |
| 85 | |
| 86 | ```sh |
| 87 | sudo -u vole vole admin --config /etc/vole/vole.toml account list |
| 88 | ``` |
| 89 | |
| 90 | ## Upgrading |
| 91 | |
| 92 | `users.db` is migrated in place the first time a newer binary opens it, and the |
| 93 | migration cannot be rolled back. Back up before upgrading: |
| 94 | |
| 95 | ```sh |
| 96 | sudo -u vole vole admin --config /etc/vole/vole.toml account backup /var/lib/vole/users.db.bak |
| 97 | sudo cp /var/lib/vole/data/ssh_host_ed25519_key /var/lib/vole/ssh_host_ed25519_key.bak |
| 98 | ``` |
| 99 | |
| 100 | Then install the new package. See [Operations](operations.md) for what else is |
| 101 | worth copying. |
| 102 | |
| 103 | ## How the release is built |
| 104 | |
| 105 | `.vole/workflows/release.yaml` runs on a `v*` tag and does three things: it runs |
| 106 | the tests, it cross-compiles the binary for both architectures, and it packages |
| 107 | each one with [nfpm](https://nfpm.goreleaser.com) from `packaging/nfpm.yaml`. The |
| 108 | `.deb`, the `.rpm`, the plain binaries, and `SHA256SUMS` are attached to the tag's |
| 109 | release with `release: true`, so they appear on the release page like any other |
| 110 | attached file. |
| 111 | |
| 112 | Two requirements on the runner: |
| 113 | |
| 114 | - **Network.** `go build` fetches modules, and the packaging step fetches a pinned |
| 115 | `nfpm`, and a job container has none unless the runner was started with |
| 116 | `--container-network bridge`. The image build already needs the network; it |
| 117 | installs `git`, the C toolchain, and both architectures' SQLite development |
| 118 | files (see `.vole/images/release.yaml`). |
| 119 | - **Nothing else.** The binaries are cross-compiled, so any runner that can start a |
| 120 | Linux container produces the same four packages. |
| 121 | |
| 122 | Reproduce a release locally without a runner, from the tag: |
| 123 | |
| 124 | ```sh |
| 125 | git switch --detach v0.2.0 |
| 126 | go run ./cmd/vole workflow run release |
| 127 | ``` |
| 128 | |
| 129 | That runs the steps in your working tree as a check of the commands. It does not |
| 130 | publish the artifacts. The packaging step fetches nfpm itself with a pinned |
| 131 | `go run`, so there is no tool to install first — only Go and the network. |
| 132 | |
| 133 | The version comes from `git describe --tags --exact-match`, so a checkout with no |
| 134 | tag stops before building anything. |
| 135 | |
| 136 | ## The package definition is checked on every push |
| 137 | |
| 138 | The CI workflow (`.vole/workflows/verify.yaml`) builds one architecture and packages |
| 139 | it with the same `packaging/nfpm.yaml` on every branch push. A broken definition, |
| 140 | install path, or unit file therefore fails the push that broke it, instead of the |
| 141 | tag that cannot be rebuilt. |
| 142 |