Skip to content

Merge pull request #373 from AISecurityLab/dependabot/uv/main/transfo… #672

Merge pull request #373 from AISecurityLab/dependabot/uv/main/transfo…

Merge pull request #373 from AISecurityLab/dependabot/uv/main/transfo… #672

Workflow file for this run

name: CI Checks
on:
push:
branches: ["main"]
pull_request:
branches: ["**"]
jobs:
commit-check:
name: Commit Messages
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Check out code with full history
uses: actions/checkout@v6
with:
fetch-depth: 0 # Needed for commit range check
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: uv sync --group dev
- name: Check commit messages in PR
run: uv run cz check --rev-range ${{ github.event.pull_request.base.sha }}..${{ github.sha }}
python-checks:
name: Linting and Formatting
runs-on: ubuntu-latest
# Skip on main push since PR already validated
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: uv sync --group dev
- name: Run Ruff Linting
run: uv run ruff check .
- name: Run Ruff Formatting Check
run: uv run ruff format --check .
# ── Unit tests: full OS × Python-version matrix ──────────────────────────
# Runs tests/unit/ only (no external services, fast). Coverage artifact
# is uploaded for the canonical ubuntu/3.11 slice and merged later.
test-matrix:
name: Tests (Python ${{ matrix.python-version }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 30
if: github.event_name == 'pull_request' && github.base_ref == 'main'
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --group dev
- name: Run unit tests with coverage
run: uv run pytest tests/unit/ --cov --cov-report=xml:reports/coverage.xml
- name: Upload unit coverage artifact
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
uses: actions/upload-artifact@v7
with:
name: coverage-unit
path: reports/.coverage
include-hidden-files: true
retention-days: 1
# ── Quick test – PRs to non-main branches ────────────────────────────────
test-quick:
name: Tests (Quick)
runs-on: ubuntu-latest
timeout-minutes: 30
if: github.event_name == 'pull_request' && github.base_ref != 'main'
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: uv sync --group dev
- name: Run unit tests with coverage
run: uv run pytest tests/unit/ --cov --cov-report=xml:reports/coverage.xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: reports/coverage.xml
flags: unit
fail_ci_if_error: true
# ── Integration (offline) ─────────────────────────────────────────────────
# Covers tests/integration/storage/ (LocalBackend + SQLite) and
# tests/integration/tui/ (mock-based). No external services required.
integration-offline:
name: Integration Tests (Offline)
runs-on: ubuntu-latest
timeout-minutes: 20
if: github.event_name == 'pull_request' && github.base_ref == 'main'
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: uv sync --group dev
- name: Run offline integration tests with coverage
run: >
uv run pytest
tests/integration/storage/
tests/integration/tui/
--run-integration
-n auto
--dist=loadfile
-m "not slow"
-v --tb=short
--cov --cov-fail-under=0
--cov-report=xml:reports/coverage.xml
- name: Upload offline-integration coverage artifact
uses: actions/upload-artifact@v7
with:
name: coverage-integration-offline
path: reports/.coverage
include-hidden-files: true
retention-days: 1
# ── Integration (Ollama) ──────────────────────────────────────────────────
# Covers tests/integration/adapters/ and tests/integration/attacks/.
# Requires a running Ollama instance with tinyllama.
integration-ollama:
name: Integration Tests (Ollama)
runs-on: ubuntu-latest
timeout-minutes: 30
if: github.event_name == 'pull_request' && github.base_ref == 'main'
env:
HACKAGENT_API_KEY: ${{ secrets.HACKAGENT_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
OLLAMA_MODEL: tinyllama
TEST_MAX_TOKENS_FAST: "15"
TEST_MAX_TOKENS_MEDIUM: "25"
TEST_MAX_TOKENS_SLOW: "40"
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install Ollama
run: |
curl -fsSL https://ollama.com/install.sh | sh
ollama serve &
sleep 5
- name: Cache Ollama models
uses: actions/cache@v5
with:
path: ~/.ollama/models
key: ollama-models-tinyllama-${{ runner.os }}
restore-keys: |
ollama-models-tinyllama-
- name: Pull Ollama model
run: ollama pull tinyllama
- name: Install dependencies
run: uv sync --group dev
- name: Run Ollama integration tests with coverage
run: >
uv run pytest
tests/integration/adapters/
tests/integration/attacks/
--run-integration
-n 2
--dist=loadfile
-m "not slow"
-v --tb=short
--cov --cov-fail-under=0
--cov-report=xml:reports/coverage.xml
- name: Upload Ollama-integration coverage artifact
uses: actions/upload-artifact@v7
with:
name: coverage-integration-ollama
path: reports/.coverage
include-hidden-files: true
retention-days: 1
# ── E2E tests ─────────────────────────────────────────────────────────────
# Requires OPENROUTER_API_KEY (and optionally HACKAGENT_API_KEY).
# Skips gracefully when secrets are absent.
test-e2e:
name: E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 30
if: github.event_name == 'pull_request' && github.base_ref == 'main'
env:
HACKAGENT_API_KEY: ${{ secrets.HACKAGENT_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
TEST_MAX_TOKENS_FAST: "15"
TEST_MAX_TOKENS_MEDIUM: "25"
TEST_MAX_TOKENS_SLOW: "40"
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: uv sync --group dev
- name: Run e2e tests with coverage
run: >
uv run pytest
tests/e2e/
--ignore=tests/e2e/attacks
-v --tb=short
--cov --cov-fail-under=0
--cov-report=xml:reports/coverage.xml
- name: Upload e2e coverage artifact
uses: actions/upload-artifact@v7
with:
name: coverage-e2e
path: reports/.coverage
retention-days: 1
# ── Coverage merge & upload ───────────────────────────────────────────────
# Downloads all per-job .coverage files, combines them into one, generates
# a merged XML report, and uploads to Codecov with full coverage data.
coverage-report:
name: Coverage Report
runs-on: ubuntu-latest
timeout-minutes: 10
if: github.event_name == 'pull_request' && github.base_ref == 'main'
needs:
- test-matrix
- integration-offline
- integration-ollama
- test-e2e
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Install dependencies
run: uv sync --group dev
- name: Download all coverage artifacts
uses: actions/download-artifact@v8
with:
pattern: coverage-*
path: coverage-artifacts/
- name: Combine coverage data
run: |
mkdir -p reports
i=0
while IFS= read -r f; do
cp "$f" "reports/.coverage.$i"
i=$((i + 1))
done < <(find coverage-artifacts -name ".coverage" -type f)
uv run coverage combine reports/
uv run coverage xml -o reports/coverage-merged.xml
uv run coverage report --skip-covered
- name: Upload merged coverage to Codecov
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: reports/coverage-merged.xml
flags: merged
fail_ci_if_error: false