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 · 1h ago 4b8c9e1d
history blame raw 3.0 KiB
1[Unit]
2Description=Vole CI runner
3Documentation=https://rodent.software/vole
4After=network-online.target
5Wants=network-online.target
6
7# An instance that is down, or a name that does not resolve yet, is not a reason
8# to give up on the machine: the runner waits and tries again.
9StartLimitIntervalSec=0
10
11[Service]
12Type=simple
13
14# A dedicated unprivileged account with a home directory and a subuid and subgid
15# range, so the container runtime is rootless. docs/deploy/runner.md has the two
16# commands that set it up. The instance's own account is not this one: a job that
17# escapes its container should not find the forge's data on the same machine.
18User=ci-runner
19Group=ci-runner
20Environment=HOME=/var/lib/vole-runner
21WorkingDirectory=/var/lib/vole-runner
22RuntimeDirectory=vole-runner
23RuntimeDirectoryMode=0700
24Environment=XDG_RUNTIME_DIR=/run/vole-runner
25
26# The arguments live in a file so one unit serves every machine: --remote,
27# --label, --dir, --known-hosts, --container-network. See the example shipped as
28# /etc/vole/runner.env.
29EnvironmentFile=-/etc/vole/runner.env
30ExecStartPre=/bin/sh -c 'test -n "$VOLE_RUNNER_ARGS" || { echo "runner is not configured: set VOLE_RUNNER_ARGS in /etc/vole/runner.env" >&2; exit 1; }'
31ExecStart=/usr/bin/vole runner $VOLE_RUNNER_ARGS
32
33Restart=on-failure
34RestartSec=10s
35TimeoutStopSec=60s
36
37# Rootless podman creates a cgroup per container, which it can only do if this
38# service's own cgroup is delegated to it.
39Delegate=yes
40
41# The backstop under the container limits. Each job gets --container-memory, and this
42# bounds the whole runner including every job in flight, for the case where a job gets
43# past its own cgroup: a percentage is of the machine, so the unit does not have to
44# know how big it is. Size --jobs times --container-memory below it, and leave the rest
45# for the kernel and the runtime's own storage. TasksMax is deliberately not set: the
46# container's own --container-pids already applies to everything the runner starts,
47# and a unit-level value would have to track --jobs and --container-pids, failing
48# builds in a way that looks like the workflow's fault when it drifts.
49MemoryMax=90%
50
51# A core dump of this process is a copy of the runner's SSH key, which leases jobs
52# and reports their results.
53LimitCORE=0
54LimitNOFILE=65536
55UMask=0027
56PrivateTmp=true
57
58# Deliberately less sandboxed than vole.service: the isolation a job gets is its
59# container, and the runtime needs user namespaces and a writable home to build
60# one. Nothing here reaches the instance's data, because it is not on this
61# machine.
62#
63# NoNewPrivileges is off for the same reason, and it is the one setting the unit
64# cannot keep. Rootless podman, Docker, and nerdctl all map the calling user into
65# the container through setuid newuidmap and newgidmap, and this setting stops a
66# setuid helper from gaining privilege, so the mapping fails before a container
67# exists: "newuidmap: write to uid_map failed: Operation not permitted". A job's
68# isolation is its container, not this sandbox, so the rest of the hardening stays.
69NoNewPrivileges=false
70
71[Install]
72WantedBy=multi-user.target
73