5.6 KiB
CI: Gitea Actions
Docs: README · SPEC · ARCHITECTURE · RESEARCH · COMPARISON · AGENTS · CHANGELOG · CI
The workflow is .gitea/workflows/ci.yml. It needs two kinds of
runner, because the thing doos tests is the thing most CI containers are built to prevent: a
process creating its own user, mount and pid namespaces and an overlayfs mount.
What runs where
| Job | Runner | Needs | Proves |
|---|---|---|---|
build |
any docker:// runner (label ubuntu-latest) |
a C++20 toolchain and CMake | the binary still compiles with -Werror and the documentation set is still fully cross-linked |
valgrind |
any docker:// runner (label ubuntu-latest) |
the above, plus valgrind |
no new memory error or leak in doos's own code (see valgrind/README.md); this still gives a real answer even when the container's own AppArmor/seccomp policy blocks the user namespace doos tries to create, because scripts/valgrind.sh only fails on what valgrind itself reports, never on doos's own exit code |
test |
self-hosted, host mode, label doos-host |
see below | the real end-to-end suite (tests/run.sh, currently 88 checks): real overlayfs, real namespaces, real downloads, real cgroup v2 limits |
audit |
self-hosted, host mode, label doos-host |
see below | the named CVE regression set in audit/ against the binary this run just built |
build and valgrind run in an ephemeral Docker-mode act_runner container and need nothing this
repository does not already ask of any build machine. test and audit need a real Linux host
(or VM) that act_runner reaches in host mode (a plain label, not a docker:// one), because the
things under test are precisely the things a container runtime's own default policy restricts: an
unprivileged user namespace that creates an overlayfs mount, a systemd user manager with cgroup v2
delegated to it, and (on Ubuntu 24.04+) an AppArmor profile that permits user namespaces for this
one binary path. Running those two jobs inside another container would either need that container
privileged (defeating the point of isolating the runner) or would silently test less than it claims
to, the same vacuous-pass risk review2.md section 2 warns about for the audit script's own design.
One-time host runner setup (by whoever administers the runner, not by the workflow)
The workflow never runs anything with sudo, on purpose (same rule as everywhere else in this
project: AppArmor and system changes are requested from a human, never done by an agent or a CI
job on its own). Before registering the doos-host runner:
sudo apt-get install -y build-essential cmake slirp4netns passt gnupg uidmap curl tar
# /etc/subuid and /etc/subgid must list the runner's own user; uidmap's postinst usually does this.
grep "^$(whoami):" /etc/subuid /etc/subgid
# cgroup v2 must be delegated to this user's systemd manager (loginctl enable-linger helps it
# survive without an interactive session):
loginctl enable-linger "$(whoami)"
cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers
# Build doos once at the exact path the runner will use, then install its AppArmor profile
# (needed on Ubuntu 24.04+; see README's Troubleshooting table for the symptom this fixes):
cmake -S . -B build && cmake --build build
build/doos apparmor | sudo tee /etc/apparmor.d/doos-runner >/dev/null
sudo apparmor_parser -r /etc/apparmor.d/doos-runner
Then register the runner itself (see Gitea's act_runner docs for the current command and token source):
./act_runner register --instance https://<your-gitea> --token <runner-token> \
--name doos-host --labels doos-host
./act_runner daemon
A docker://-labelled runner for build and valgrind needs no special setup; any act_runner in
its default Docker mode works (the Gitea docs' own suggested registration labels, such as
ubuntu-latest:docker://gitea/runner-images:ubuntu-latest, are enough).
Known Gitea Actions gaps versus GitHub Actions (checked against the 1.25 docs)
timeout-minutesandconcurrencyare parsed but ignored. The workflow still setstimeout-minuteson every job for readability and for anyone who later runs the same file under real GitHub Actions, but the actual, enforced cap in each job is a shell-leveltimeout <seconds>wrapped around the one command that matters, consistent with this project's own rule that every automated process gets a hard, enforced ceiling, not a cap that only works if the runner happens to honor it.permissionssupport is version-dependent and GitHub-only scopes (checks,id-token,security-events,pages, ...) are not supported at all. The workflow does not rely on it.uses: actions/checkout@v4is resolved the same way GitHub Actions resolves it (Gitea Actions proxies to GitHub by default); an instance configured without internet access to GitHub needshttps://gitea.com/actions/checkoutinstead, or a plaingit clonestep.
Running it without Gitea
Every job is one or two make targets with a timeout in front; none of it depends on Gitea
Actions syntax beyond on/jobs/runs-on/steps, so the same file works, unmodified, as a
GitHub Actions workflow (just move it to .github/workflows/) with the one exception that
timeout-minutes would then actually be enforced by the platform instead of being a label only
(harmless either way).