Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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.

Code

392 commit(s) on main

Merge change request 01M70WES5ZZDJ6RP226WB11BBZ: Let people rename and remove their own passkeys keenan · 2h ago 4b8c9e1d
source preview history blame raw 7.0 KiB

Packages

A release can be installed with the system package manager instead of unpacking a tarball. Pushing an annotated tag builds the .deb and the .rpm for amd64 and arm64 and attaches them to the release page; nothing is published anywhere else.

dpkg -i vole_0.2.0-1_amd64.deb       # Debian, Ubuntu
dnf install ./vole-0.2.0-1.x86_64.rpm # Fedora, RHEL, Rocky

There is no apt or dnf repository and no signature on these files yet. Each release page also carries SHA256SUMS; compare it before installing.

To have a fresh cloud machine install and configure the package for you, use the deployment guides. They need the URL of the file above, which is how a .deb from a release page is named: .../vole/releases/v0.2.0/artifacts/vole_0.2.0-1_amd64.deb, or arm64 for an arm64 machine.

Both packages depend on git and the system SQLite library: libsqlite3-0 on Debian and Ubuntu, sqlite-libs on Fedora, RHEL, and Rocky. Vole links SQLite dynamically, so the library must be present where the binary runs; the package manager installs it with the package. The system library must include SQLite’s FTS5 module, which every distribution listed above enables in its build; the command palette is what needs it, and the binary carries the tag that asks for it when the driver’s bundled copy is used instead.

What the package installs

Path What it is
/usr/bin/vole The binary, built from the tag with vole version set to it
/usr/lib/systemd/system/vole.service The unit, with hardening and a /var/lib/vole state directory
/usr/lib/systemd/system/vole-runner.service The CI runner’s unit. Not enabled, and inert until /etc/vole/runner.env names an instance
/etc/vole/runner.env Arguments for that unit, as a conffile. See Deploying § CI runners
/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
/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
/etc/vole/vole.toml Configuration, marked as a conffile so your edits survive upgrades
/usr/share/doc/vole/ LICENSE and NOTICE
/var/lib/vole/data The instance: repositories, databases, stores, host key, audit log

The package creates the vole service account and runs vole admin init against the shipped config. It does not create an instance admin and does not enable the service: who may administer the instance is the operator’s decision, not the package’s.

The shipped config listens on 0.0.0.0:2222 for SSH and 127.0.0.1:8080 for the web. Open 2222 in the firewall, set public_url before anyone signs in with a passkey, and either terminate TLS in a proxy in front of 8080 or use https_addr to let Vole obtain certificates itself. See Configuration § Automatic HTTPS with ACME and Configuration § Running behind a proxy.

The unit is written for the packaged layout and is safe to use as shipped: it drops all capabilities, sets UMask=0027, gives the service a private /tmp and device tree, hides other processes, and makes /var/lib/vole the only writable path. If you need to bind a port below 1024 — SSH on 2222 does not, HTTP on 80 and HTTPS on 443 do — add the one capability with a drop-in, which must widen the bounding set as well:

# /etc/systemd/system/vole.service.d/bind.conf
[Service]
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

MemoryDenyWriteExecute=true is safe for the forge because it runs no JIT. A CI runner executes repository code in containers and is a separate process with its own unit; do not relax this unit to accommodate it.

First steps after install

vole admin --config /etc/vole/vole.toml account create you --key ~/.ssh/id_ed25519.pub
vole admin --config /etc/vole/vole.toml repo create demo --owner you
vole admin --config /etc/vole/vole.toml acl set-default-role demo read
systemctl enable --now vole

Run admin commands as the vole user or with --config /etc/vole/vole.toml; the service account owns the files they write. A command that writes as the wrong user leaves state the service cannot open, so prefer:

sudo -u vole vole admin --config /etc/vole/vole.toml account list

Upgrading

users.db is migrated in place the first time a newer binary opens it, and the migration cannot be rolled back. Back up before upgrading:

sudo -u vole vole admin --config /etc/vole/vole.toml account backup /var/lib/vole/users.db.bak
sudo cp /var/lib/vole/data/ssh_host_ed25519_key /var/lib/vole/ssh_host_ed25519_key.bak

Then install the new package. See Operations for what else is worth copying.

How the release is built

.vole/workflows/release.yaml runs on a v* tag and does three things: it runs the tests, it cross-compiles the binary for both architectures, and it packages each one with nfpm from packaging/nfpm.yaml. The .deb, the .rpm, the plain binaries, and SHA256SUMS are attached to the tag’s release with release: true, so they appear on the release page like any other attached file.

Two requirements on the runner:

  • Network. go build fetches modules, and the packaging step fetches a pinned nfpm, and a job container has none unless the runner was started with --container-network bridge. The image build already needs the network; it installs git, the C toolchain, and both architectures’ SQLite development files (see .vole/images/release.yaml).
  • Nothing else. The binaries are cross-compiled, so any runner that can start a Linux container produces the same four packages.

Reproduce a release locally without a runner, from the tag:

git switch --detach v0.2.0
go run ./cmd/vole workflow run release

That runs the steps in your working tree as a check of the commands. It does not publish the artifacts. The packaging step fetches nfpm itself with a pinned go run, so there is no tool to install first — only Go and the network.

The version comes from git describe --tags --exact-match, so a checkout with no tag stops before building anything.

The package definition is checked on every push

The CI workflow (.vole/workflows/verify.yaml) builds one architecture and packages it with the same packaging/nfpm.yaml on every branch push. A broken definition, install path, or unit file therefore fails the push that broke it, instead of the tag that cannot be rebuilt.