From 42ab4acc1bd18df708f92e6529f34d9a744429c7 Mon Sep 17 00:00:00 2001 From: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com> Date: Fri, 2 Oct 2026 02:44:19 +0100 Subject: [PATCH] ci: enable functional containment in pytest --- .github/workflows/ci.yml | 53 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e60561c7..6e82d65fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -102,7 +102,8 @@ jobs: python-tests: name: Python tests (pytest) - runs-on: ubuntu-latest + # Keep the namespace/AppArmor setup tied to the audited Ubuntu release. + runs-on: ubuntu-24.04 # Make Python test validation authoritative for the configured scope. steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -159,5 +160,55 @@ jobs: command -v ffmpeg ffmpeg -version | head -n 1 + - name: Establish functional bubblewrap containment + if: steps.docs-check.outputs.docs_only != 'true' + shell: bash + run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install -y --no-install-recommends bubblewrap + bwrap --version + sysctl kernel.unprivileged_userns_clone user.max_user_namespaces \ + kernel.apparmor_restrict_unprivileged_userns + if [ "$(sysctl -n kernel.unprivileged_userns_clone)" != 1 ] || \ + [ "$(sysctl -n user.max_user_namespaces)" -eq 0 ]; then + echo '::error::The pytest runner must allow unprivileged user namespaces; kernel namespace support is disabled.' + exit 1 + fi + + # Match containment._bwrap_available(): PID and mount namespaces, + # including fresh proc/dev mounts, as the unprivileged runner user. + bwrap_probe() { + timeout 3s bwrap --die-with-parent --unshare-pid --ro-bind / / \ + --proc /proc --dev /dev /bin/true + } + + if ! bwrap_probe && [ "$(sysctl -n kernel.apparmor_restrict_unprivileged_userns)" = 1 ]; then + # Ubuntu 24.04 restricts userns for unconfined applications. Allow + # only the distro bwrap entry point on this ephemeral pytest VM; + # retain the global restriction and all unrelated AppArmor policy. + sudo tee /etc/apparmor.d/odysseus-ci-bwrap > /dev/null <<'PROFILE' + abi , + include + profile odysseus-ci-bwrap /usr/bin/bwrap flags=(unconfined) { + userns, + } + PROFILE + sudo apparmor_parser -r /etc/apparmor.d/odysseus-ci-bwrap + fi + + if ! bwrap_probe; then + echo '::error::Functional bubblewrap PID/mount namespaces are required for pytest; containment setup failed.' + exit 1 + fi + # Also gate on the runtime probe so a future requirements change + # cannot silently leave this job without real containment coverage. + python - <<'PY' + from src import containment + if not containment._bwrap_available(): + raise SystemExit("::error::Runtime bubblewrap functionality probe failed; pytest must not start.") + print("Runtime bubblewrap PID/mount namespace probe passed.") + PY + - run: python -m pytest -q -rs if: steps.docs-check.outputs.docs_only != 'true'