Add Gitea CI, fix size overflow and helper-path inconsistency from review2.md
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Architecture
|
||||
|
||||
**Docs:** [README](../README.md) · [SPEC](../SPEC.md) · [ARCHITECTURE](ARCHITECTURE.md) · [RESEARCH](RESEARCH.md) · [COMPARISON](../COMPARISON.md) · [AGENTS](../AGENTS.md) · [CHANGELOG](../CHANGELOG.md)
|
||||
**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)
|
||||
|
||||
How doos works internally. The behavior contract is [SPEC](../SPEC.md); this explains the code. Why it was built this way and what was measured: [RESEARCH](RESEARCH.md); how it compares with other tools: [COMPARISON](../COMPARISON.md).
|
||||
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
# 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://<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](../README.md), [AGENTS](../AGENTS.md), [SPEC](../SPEC.md).
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
# Research: user-level containers with overlayfs
|
||||
|
||||
**Docs:** [README](../README.md) · [SPEC](../SPEC.md) · [ARCHITECTURE](ARCHITECTURE.md) · [RESEARCH](RESEARCH.md) · [COMPARISON](../COMPARISON.md) · [AGENTS](../AGENTS.md) · [CHANGELOG](../CHANGELOG.md)
|
||||
**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)
|
||||
|
||||
Measured on this machine: Ubuntu, kernel 7.0.0-38, AppArmor 5.0.2, slirp4netns 1.3.3, uid 1000, no root at runtime.
|
||||
|
||||
@@ -63,6 +63,9 @@ removed afterwards. Rows marked "unmeasured" have no run behind them.
|
||||
| G6 | No seccomp, nested userns allowed | Capability drop + seccomp-bpf denylist | **done in 1.1.0** (`--hardening`) | `hardening.cpp` |
|
||||
| G7 | Host-owned lower dirs unwritable, `chown` of host files fails, empty `/var` | Image layer + subuid; skeleton and seeding for host mode | **done in 1.0.0** | `image.cpp`, `container.cpp` |
|
||||
| G8 | `fsutil::mkdirs` followed a symlink planted at a container's path under `$DOOS_HOME/containers/<name>`, same bug class as [`audit/CVE-2021-30465`](../audit/CVE-2021-30465/README.md) | walk the path component by component from a pinned base fd with `mkdirat`/`openat(O_NOFOLLOW\|O_DIRECTORY)`, refusing any symlink instead of following it | **done in 1.3.0**, re-measured: `make -C audit/CVE-2021-30465 test` now PASSes | `fsutil::mkdirs` in `src/util.cpp` |
|
||||
| G9 | `parseSize` left-shifted without an overflow check: `--size 16777217t` wrapped to exactly `1.0T` and was accepted instead of rejected | check `v > (UINT64_MAX >> shift)` before shifting, reject instead of wrapping | **done in 1.3.2**, reproduced before the fix, re-run after: rejected | `parseSize` in `src/util.cpp` |
|
||||
| G10 | `newuidmap`/`newgidmap`/`slirp4netns`/`pasta` were pinned to a single hardcoded `/usr/bin/...` path, unlike `curl`/`tar`/`sha256sum`/`gpg` which go through `resolveBinary()`'s state-dir-override-then-fixed-dirs search; a distro installing them elsewhere would fail even though PATH-poisoning was never possible either way | route all four through `resolveBinary()`, same as the other helpers | **done in 1.3.2** | `idmap.cpp`, `network.cpp` |
|
||||
| G11 | Alpine's `latest-releases.yaml` and Debian's `index.json` (embedded base64 manifest) are read with fixed string/byte-offset search, not a YAML/JSON library; a publisher reformatting either file breaks extraction with a thrown error (fails closed) rather than silently misreading it | none: a dependency to parse two small, publisher-controlled files is a worse trade than failing loudly when their format changes, given the project's own "fewer dependencies" rule | **accepted, not fixed**; this row exists so the trade-off is written down, not rediscovered | `Catalog::resolve` in `src/image.cpp` |
|
||||
|
||||
### G1: memory, cpu and pids limits (cgroup v2)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user