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.

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