Files
doos/docs/CI.md
T
retoorandClaude Sonnet 5 4c754b20da
ci / test (push) Waiting to run
ci / audit (push) Waiting to run
ci / build (push) Successful in 54s
ci / valgrind (push) Successful in 1m42s
Add Gitea CI, fix size overflow and helper-path inconsistency from review2.md
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-24 01:20:18 +02:00

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-minutes and concurrency are parsed but ignored. The workflow still sets timeout-minutes on 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-level timeout <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.
  • permissions support 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@v4 is resolved the same way GitHub Actions resolves it (Gitea Actions proxies to GitHub by default); an instance configured without internet access to GitHub needs https://gitea.com/actions/checkout instead, or a plain git clone step.

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).

Back to README, AGENTS, SPEC.