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.

Add packaging, a CI workflow, and containerised local runs

3b39a84c913cabe15bfa6a60dd176ff2dd28d241 · Keenan Nemetz · 14d 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.

docs/packaging.md +102

@@ -0,0 +1,102 @@
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 ## What the package installs
16
17 | Path | What it is |
18 |---|---|
19 | `/usr/bin/vole` | The binary, built from the tag with `vole version` set to it |
20 | `/usr/lib/systemd/system/vole.service` | The unit, with hardening and a `/var/lib/vole` state directory |
21 | `/etc/vole/vole.toml` | Configuration, marked as a conffile so your edits survive upgrades |
22 | `/usr/share/doc/vole/` | `LICENSE` and `NOTICE` |
23 | `/var/lib/vole/data` | The instance: repositories, databases, stores, host key, audit log |
24
25 The package creates the `vole` service account and runs `vole admin init` against
26 the shipped config. It does not create an administrator and does not enable the
27 service: who may administer the instance is the operator's decision, not the
28 package's.
29
30 The shipped config listens on `0.0.0.0:2222` for SSH and `127.0.0.1:8080` for the
31 web. Open 2222 in the firewall, terminate TLS in a proxy in front of 8080, and set
32 `public_url` before anyone signs in with a passkey. See
33 [Configuration § Running behind a proxy](configuration.md#running-behind-a-proxy).
34
35 ## First steps after install
36
37 ```sh
38 vole admin --config /etc/vole/vole.toml user create you --key ~/.ssh/id_ed25519.pub
39 vole admin --config /etc/vole/vole.toml repo create demo --owner you
40 vole admin --config /etc/vole/vole.toml acl default demo read
41 systemctl enable --now vole
42 ```
43
44 Run admin commands as the `vole` user or with `--config /etc/vole/vole.toml`; the
45 service account owns the files they write. A command that writes as the wrong user
46 leaves state the service cannot open, so prefer:
47
48 ```sh
49 sudo -u vole vole admin --config /etc/vole/vole.toml user list
50 ```
51
52 ## Upgrading
53
54 `users.db` is migrated in place the first time a newer binary opens it, and the
55 migration cannot be rolled back. Back up before upgrading:
56
57 ```sh
58 sudo -u vole vole admin --config /etc/vole/vole.toml user backup /var/lib/vole/users.db.bak
59 sudo cp /var/lib/vole/data/ssh_host_ed25519_key /var/lib/vole/ssh_host_ed25519_key.bak
60 ```
61
62 Then install the new package. See [Operations](operations.md) for what else is
63 worth copying.
64
65 ## How the release is built
66
67 `.vole/workflows/release.yaml` runs on a `v*` tag and does three things: it runs
68 the tests, it cross-compiles the binary for both architectures, and it packages
69 each one with [nfpm](https://nfpm.goreleaser.com) from `packaging/nfpm.yaml`. The
70 `.deb`, the `.rpm`, the plain binaries, and `SHA256SUMS` are attached to the tag's
71 release with `release: true`, so they appear on the release page like any other
72 attached file.
73
74 Two requirements on the runner:
75
76 - **Network.** `go build` fetches modules, and the packaging step fetches a pinned
77 `nfpm`, and a job container has none unless the runner was started with
78 `--container-network bridge`. The image build already needs the network; it
79 installs `git` (see `.vole/images/release.yaml`).
80 - **Nothing else.** The binaries are cross-compiled, so any runner that can start a
81 Linux container produces the same four packages.
82
83 Reproduce a release locally without a runner, from the tag:
84
85 ```sh
86 git switch --detach v0.2.0
87 go run ./cmd/vole workflow run release
88 ```
89
90 That runs the steps in your working tree as a check of the commands. It does not
91 publish the artifacts. The packaging step fetches nfpm itself with a pinned
92 `go run`, so there is no tool to install first — only Go and the network.
93
94 The version comes from `git describe --tags --exact-match`, so a checkout with no
95 tag stops before building anything.
96
97 ## The package definition is checked on every push
98
99 The CI workflow (`.vole/workflows/ci.yaml`) builds one architecture and packages
100 it with the same `packaging/nfpm.yaml` on every branch push. A broken definition,
101 install path, or unit file therefore fails the push that broke it, instead of the
102 tag that cannot be rebuilt.