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.
Make the packaged runner able to create a container on Debian and Ubuntu
9704d735dbcce94c67307e0ac4bbef76819768e8 · Keenan Nemetz · 2h ago · parent b7396a11
Make the packaged runner able to create a container on Debian and Ubuntu Three failures in a row stop a machine built exactly as docs/deploy/runner.md says, and each one is a setting the distributions either get wrong or leave out: - The unit sets NoNewPrivileges=true. Rootless podman, Docker, and nerdctl all map the caller into the container through setuid newuidmap and newgidmap, and that setting stops a setuid helper from gaining privilege, so the mapping fails before a container exists. Turn it off and say why: the isolation a job gets is its container, so the rest of the hardening stays. - Debian and Ubuntu ship /etc/containers/registries.conf entirely commented out, so a digest-pinned base image written as a short name has no registry to resolve against. Install unqualified-search-registries = ["docker.io"] as a drop-in. The reference's digest is the pin; the list only says where to ask, and a site can override it with a higher-numbered file. Chosen over qualifying the repository's own .vole/images, because a contributor adding a workflow later hits the same wall on a machine they cannot edit. - vole-runner runs as a system service, so the runner's account has no systemd user manager for podman to ask for a cgroup scope; crun falls back to sd-bus, which answers Interactive authentication required, and the first RUN step dies. Install [engine] cgroup_manager = "cgroupfs" as a drop-in, which writes into the subtree Delegate=yes already gives the service. Both drop-ins merge with the distribution's configuration instead of replacing it, and reach the runner's account because system configuration is read for rootless users too. Every install path installs the package, so the cloud-init template needs no second copy of either setting to drift. docs/deploy/runner.md says what each file is for and what the failure looks like without it, and names the user-unit-with-enable-linger arrangement as the alternative an operator may choose, including the /run/user/<uid> conflict with the unit's XDG_RUNTIME_DIR. scripts/check-deploy.py now fails when the package stops installing either drop-in, or when the unit goes back to defeating the uid mapping: a runner missing one takes a job and fails it before a step runs, which reads on the instance as a repository whose build broke. Closes 01M6YW9ZWB69GVFN7BR53SPWC6 Closes 01M6YWA3JX0WWHJ55JCVDZ2QTP Closes 01M6YWA79EWR97YYK5NR7R19CK
scripts/check-deploy.py +29−1
| @@ -190,7 +190,10 @@ def check_runner_template(names): | |||
| 190 | 190 | ||
| 191 | 191 | Three files describe one runner by hand: the template writes its arguments, | |
| 192 | 192 | the unit reads them, and the package ships the example the operator copies. | |
| 193 | A name that drifts between them leaves a machine enabled and idle. | ||
| 193 | A name that drifts between them leaves a machine enabled and idle. The same | ||
| 194 | goes for the two runtime drop-ins and the one sandbox setting that lets a | ||
| 195 | rootless runtime map the caller into a container: a machine that loses any of | ||
| 196 | them takes a job and fails it before a step runs. | ||
| 194 | 197 | """ | |
| 195 | 198 | bad = 0 | |
| 196 | 199 | where = "deploy/cloud-init/runner.yaml" | |
| @@ -233,6 +236,31 @@ def check_runner_template(names): | |||
| 233 | 236 | for needed in ("packaging/systemd/vole-runner.service", "packaging/runner.env"): | |
| 234 | 237 | if needed not in package: | |
| 235 | 238 | bad |= fail(f"{needed} is not in the package", "packaging/nfpm.yaml") | |
| 239 | |||
| 240 | # What makes a fresh Debian or Ubuntu machine able to create a container at | ||
| 241 | # all: no unit sandbox that defeats setuid newuidmap, a registry to resolve a | ||
| 242 | # short image name against, and a cgroup manager that needs no user session. | ||
| 243 | # Missing any of them reads on the instance as a repository whose build | ||
| 244 | # failed, so each is checked by name and by the setting it exists for. | ||
| 245 | if "NoNewPrivileges=false" not in unit: | ||
| 246 | bad |= fail("the unit stops rootless runtimes from mapping the caller into a container", | ||
| 247 | "packaging/systemd/vole-runner.service") | ||
| 248 | dropins = ( | ||
| 249 | ("packaging/containers/registries.conf", | ||
| 250 | "/etc/containers/registries.conf.d/50-vole-runner.conf", | ||
| 251 | "unqualified-search-registries"), | ||
| 252 | ("packaging/containers/containers.conf", | ||
| 253 | "/etc/containers/containers.conf.d/50-vole-runner.conf", | ||
| 254 | "cgroup_manager"), | ||
| 255 | ) | ||
| 256 | for src, dst, setting in dropins: | ||
| 257 | if not os.path.exists(os.path.join(ROOT, src)): | ||
| 258 | bad |= fail("missing", src) | ||
| 259 | continue | ||
| 260 | if setting not in read(src): | ||
| 261 | bad |= fail(f"does not set {setting}", src) | ||
| 262 | if f"src: {src}" not in package or f"dst: {dst}" not in package: | ||
| 263 | bad |= fail(f"{src} is not installed as {dst}", "packaging/nfpm.yaml") | ||
| 236 | 264 | return bad | |
| 237 | 265 | ||
| 238 | 266 | ||