# CI: Gitea Actions **Docs:** [README](../README.md) · [SPEC](../SPEC.md) · [ARCHITECTURE](ARCHITECTURE.md) · [RESEARCH](RESEARCH.md) · [COMPARISON](../COMPARISON.md) · [AGENTS](../AGENTS.md) · [CHANGELOG](../CHANGELOG.md) · [CI](CI.md) The workflow is [`.gitea/workflows/ci.yml`](../.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](../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/`](../audit/README.md) 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](https://docs.gitea.com/usage/actions/act-runner) for the current command and token source): ``` ./act_runner register --instance https:// --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 ` 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](../README.md), [AGENTS](../AGENTS.md), [SPEC](../SPEC.md).