Skip to content

ci: fold bubblewrap into the backends matrix as a docker leg #81

ci: fold bubblewrap into the backends matrix as a docker leg

ci: fold bubblewrap into the backends matrix as a docker leg #81

Workflow file for this run

name: CI
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
name: Lint & Format
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install 3.13
- name: Install dependencies
run: uv sync --extra dev
- name: Ruff check
run: uv run ruff check src/ tests/
- name: Ruff format
run: uv run ruff format --check src/ tests/
typecheck:
runs-on: ubuntu-latest
name: Type Check
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install 3.13
- name: Install dependencies
run: uv sync --extra dev
- name: Mypy
run: uv run mypy src/
test:
runs-on: ubuntu-latest
strategy:
matrix:
python: ["3.12", "3.13"]
name: Unit Tests (Python ${{ matrix.python }})
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install ${{ matrix.python }}
- name: Install dependencies
run: uv sync --extra dev
- name: Run unit tests
run: uv run pytest tests/unit/ --tb=short -q
backends:
runs-on: ubuntu-latest
name: ${{ matrix.name }}
# Daytona secrets are exposed job-wide so the credential gate below can read
# them in step `if:` expressions; empty/harmless for the other backends.
env:
DAYTONA_API_URL: ${{ secrets.DAYTONA_API_URL }}
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
strategy:
fail-fast: false
matrix:
include:
# In-process backends run on the host via uv.
- backend: mirage
name: Mirage Backend Conformance
- backend: agentfs
name: AgentFS Backend Conformance
- backend: daytona
name: Daytona Backend Conformance
gated: true
# bwrap needs privileged namespace ops (netns/loopback, procfs mount) a
# bare runner denies, so this leg runs inside a privileged container.
- backend: bubblewrap
name: Bubblewrap Backend Conformance
docker: true
steps:
- uses: actions/checkout@v6
# --- host path: in-process backends (mirage / agentfs / daytona) ---
- uses: astral-sh/setup-uv@v7
if: ${{ !matrix.docker }}
- name: Install Python
if: ${{ !matrix.docker }}
run: uv python install 3.13
- name: Install dependencies
if: ${{ !matrix.docker }}
run: uv sync --extra dev --extra ${{ matrix.backend }}
- name: Run ${{ matrix.backend }} conformance
if: ${{ !matrix.docker && (!matrix.gated || env.DAYTONA_API_KEY != '') }}
run: uv run pytest tests/integration/test_backend_protocol.py -k ${{ matrix.backend }} --tb=short -v
- name: Skip ${{ matrix.backend }} (no credentials)
if: ${{ matrix.gated && env.DAYTONA_API_KEY == '' }}
run: echo "::notice::Skipping ${{ matrix.backend }} conformance — DAYTONA_API_KEY secret not configured"
# --- container path: bubblewrap. Privilege is on the OUTER container only;
# the inner bwrap sandbox still drops caps and applies its own seccomp, so
# what BubblewrapBackend enforces is unchanged. See tests/docker/Dockerfile.
- name: Build bubblewrap test image
if: ${{ matrix.docker }}
run: docker build -f tests/docker/Dockerfile -t akit-bwrap .
- name: Run ${{ matrix.backend }} conformance (privileged container)
if: ${{ matrix.docker }}
run: |
docker run --rm --privileged akit-bwrap sh -c '
uv run pytest tests/integration/test_backend_protocol.py -k bubblewrap --tb=short -v &&
uv run pytest tests/integration/test_bubblewrap_security.py --tb=short -v
'
evals:
runs-on: ubuntu-latest
name: LLM Evals
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install 3.13
- name: Install dependencies
run: uv sync --extra dev --extra eval
- name: Run evals
if: env.OPENAI_API_KEY != ''
run: uv run pytest tests/evals/ -m eval --tb=short -v
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Skip evals (no API key)
if: env.OPENAI_API_KEY == ''
run: echo "::notice::Skipping evals — OPENAI_API_KEY secret not configured"
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}