From a7383510fb05abc98b992240cb76ad4b6c598956 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 4 Oct 2026 01:05:10 +0900 Subject: test/sandbox: migrate tests This significantly improves performance, removing overhead of nix, python, and virtualisation. Running this in an unprivileged container required patching the kernel, but since special runner setup was already needed, that was an acceptable tradeoff. Signed-off-by: Ophestra --- internal/workflows/doc.go | 18 +++++++++++++++--- internal/workflows/step.go | 3 ++- internal/workflows/test.go | 45 +++++++++++++++++++++++++++++++++------------ 3 files changed, 50 insertions(+), 16 deletions(-) (limited to 'internal/workflows') diff --git a/internal/workflows/doc.go b/internal/workflows/doc.go index e34c59c8..a8f18ab4 100644 --- a/internal/workflows/doc.go +++ b/internal/workflows/doc.go @@ -20,7 +20,8 @@ The Gitea act_runner simply bind mounts whatever socket it sees into the container. With a regular docker daemon, this allows not only a simple container escape, but also privilege escalation as unconstrained root in the init namespace. To mitigate this, set up an unprivileged podman daemon and expose its -socket to the container instead. +socket to the container instead. Since mountinfo always use credentials from the +init user namespace, subordinate user and group ID must always be 100000. On Alpine Linux, this is achieved by: @@ -67,6 +68,7 @@ Before starting the container, configure act_runner via config.yaml: -v /var/lib/rosa:/rosa --security-opt='unmask=/proc/*' --cap-add=SYS_ADMIN + --cap-add=SYS_PTRACE --device=/dev/kvm --device=/dev/fuse valid_volumes: @@ -76,8 +78,9 @@ where /var/lib/rosa is the absolute pathname of the cache directory in the init namespace. Setting MBF_POISON_OPEN enables cmd/mbf to run as root. It is also a good idea here to set runner.capacity to reflect the capacity of the guest, so jobs can be consumed quicker. Removing mount points covering /proc enables -testing of cmd/hakurei. Exposing the fuse device and adding capability SYS_ADMIN -enables testing of cmd/sharefs. +testing of cmd/hakurei. Exposing the fuse device and adding capability +CAP_SYS_ADMIN enables testing of cmd/sharefs. Adding capability CAP_SYS_PTRACE +enables dumping seccomp filters via ptrace on the patched kernel. Build a statically-linked cmd/mbf: @@ -120,6 +123,15 @@ this can be achieved by the init script: It is often a good idea to populate the cache from a mirror service before the first workflow job is started and re-populate it after every cmd/mbf update. +# Configuring the kernel + +In order to attach to the container process, the sysctl kernel.yama.ptrace_scope +must be set to 0. After which, apply the patch test/sandbox/seccomp.patch to +your kernel sources, compile and install the new kernel. Refer to +https://wiki.alpinelinux.org/wiki/Custom_Kernel if the guest runs Alpine Linux. +If running podman or docker as root, the patch is not required. Do not apply +this patch on a system meant to be secure. + # Security The design of Microsoft Github workflows is inherently insecure: it requires diff --git a/internal/workflows/step.go b/internal/workflows/step.go index 83d9c5f3..199f82d9 100644 --- a/internal/workflows/step.go +++ b/internal/workflows/step.go @@ -76,11 +76,12 @@ func newTestsuite(name, prefix string) Step { // newPackages returns a job for installing the specified packages with // best-effort caching. Package names must not contain spaces. -func newPackages(rev int, packages ...string) Step { +func newPackages(rev int, repos []string, packages ...string) Step { return Step{ Name: "Install packages", Uses: "awalsh128/cache-apt-pkgs-action@v1", With: []KV[any]{ + {"add-repository", strings.Join(repos, " ")}, {"packages", strings.Join(packages, " ")}, {"version", rev}, {"execute_install_scripts", true}, diff --git a/internal/workflows/test.go b/internal/workflows/test.go index 723cf463..c81574ea 100644 --- a/internal/workflows/test.go +++ b/internal/workflows/test.go @@ -8,7 +8,7 @@ var _ = (&Workflow{ Jobs: Map[Job]{ {"hakurei", Job{ - Name: "Hakurei", + Name: "Hakurei (legacy)", On: "nix", Steps: []Step{ @@ -19,7 +19,7 @@ var _ = (&Workflow{ }}, {"race", Job{ - Name: "Hakurei (race detector)", + Name: "Hakurei (legacy with race instrument)", On: "nix", Steps: []Step{ @@ -31,23 +31,46 @@ var _ = (&Workflow{ {"sandbox", Job{ Name: "Sandbox", - On: "nix", + On: "rosa", Steps: []Step{ + fixup, checkout, - newNixOSTest("sandbox"), - newUploadArtifact("test output", "sandbox-vm-output"), + toolchain, + newPackages(0, []string{"ppa:savoury1/pipewire"}, + "libmount-dev", + "sway", + "xwayland", + "xdg-dbus-proxy", + "pipewire", + ), + + newCIRequest("distribution", "dist -o result", "dist"), + install, + newTestsuite("sandbox", ""), }, }}, {"sandbox-race", Job{ - Name: "Sandbox (race detector)", - On: "nix", + Name: "Sandbox (with race instrument)", + On: "rosa", Steps: []Step{ + fixup, checkout, - newNixOSTest("sandbox-race"), - newUploadArtifact("test output", "sandbox-race-vm-output"), + toolchain, + + newPackages(0, []string{"ppa:savoury1/pipewire"}, + "libmount-dev", + "sway", + "xwayland", + "xdg-dbus-proxy", + "pipewire", + ), + + newCIRequest("distribution", "race -o result", "dist"), + install, + newTestsuite("sandbox", ""), }, }}, @@ -59,7 +82,7 @@ var _ = (&Workflow{ fixup, checkout, toolchain, - newPackages(0, "fuse3", "fsmark"), + newPackages(0, nil, "fuse3", "fsmark"), newCIRequest("distribution", "dist -o result", "dist"), install, @@ -90,8 +113,6 @@ var _ = (&Workflow{ Needs: []string{ "hakurei", "race", - "sandbox", - "sandbox-race", }, Steps: []Step{ -- cgit v1.3.1