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/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Add packaging, a CI workflow, and containerised local runs

3b39a84c913cabe15bfa6a60dd176ff2dd28d241 · Keenan Nemetz · 15d ago · parent 30a72490

Add packaging, a CI workflow, and containerised local runs

A v* tag now builds a .deb and a .rpm for amd64 and arm64 with nfpm and attaches them, with checksums, to the release. The package ships the systemd unit, a config at /etc/vole/vole.toml, and a postinstall that creates the service account and prepares the instance that config names; `vole admin init --config` is what makes that possible, and the binary's version is stamped from the tag instead of the source tree.

scripts/ci.sh becomes .vole/workflows/ci.yaml, so `vole workflow run ci` executes exactly what a push runs, and the Markdown link check moves to scripts/check-links.py. Local runs now always execute in the job image and share ci/container with the runner; --no-container is gone, because a run in a different environment proves nothing about CI.

The runner mounts a per-repository namespace at /cache and sets no variable for it: a job opts in through its image's env or the new job-level env, which is pinned with the queue and delivered with the lease. Whole namespaces are evicted least-recently-written first so a module cache is never half-deleted, and contributor branches get their own namespace so an untrusted tip cannot seed the cache a protected branch builds into.

Running the suite in that container found four bugs worth naming: /tmp was mounted noexec, which broke `go test` and `go run`; the read-only root is gone, because images make toolchain directories world-writable deliberately and the mount set is what protects the host; OpenSSH needs a passwd entry for the job's uid; and a lost metadata push reported as "cannot lock ref" was not classified as a race, so concurrent CLI writes gave up on the first collision. That retry now backs off exponentially with jitter.

.vole/images/ci.yaml +24

@@ -0,0 +1,24 @@
1 # The image CI runs in. It carries everything the steps call: the Go toolchain
2 # (with gcc, so -race works), git and the ssh client and keygen the server tests
3 # spawn, and python3 for the link check.
4 #
5 # The ci user exists for OpenSSH: ssh and ssh-keygen call getpwuid() and exit 255
6 # with "No user exists for uid N" when the running uid has no passwd entry, which
7 # the server tests hit. The container runs as the host's uid (so the bind-mounted
8 # working tree stays writable), so this needs to be that uid: 1000 is what a normal
9 # user has on Debian and Ubuntu. A runner whose user has another uid should pass
10 # --container-user.
11
12 # nfpm is not installed here: the packaging step fetches it at a pinned version, so
13 # that a local run and a pushed run execute the same command.
14 version: 1
15 from: golang:1.27-bookworm
16 env:
17 CGO_ENABLED: "1"
18 # Opt in to the cache the runner mounts at /cache. Nothing is cached unless the
19 # job points at it; see docs/runner.md.
20 GOMODCACHE: "/cache/go-mod"
21 GOCACHE: "/cache/go-build"
22 run:
23 - apt-get update && apt-get install -y --no-install-recommends git git-lfs openssh-client python3 ca-certificates && rm -rf /var/lib/apt/lists/*
24 - useradd --uid 1000 --create-home --shell /bin/sh ci