/ .github / workflows / ci.yml
ci.yml
  1  name: CI
  2  
  3  on:
  4    pull_request:
  5      branches: [main, release]
  6    push:
  7      branches: [main]
  8    workflow_dispatch:  # Manual trigger for docker-tests
  9  
 10  jobs:
 11    # Job 1: Fast checks (GitHub-hosted, no Docker needed)
 12    fast-checks:
 13      runs-on: ubuntu-latest
 14      steps:
 15        - uses: actions/checkout@v4
 16  
 17        - uses: actions/setup-python@v5
 18          with:
 19            python-version: '3.13'
 20  
 21        - uses: actions/setup-node@v4
 22          with:
 23            node-version: '20'
 24  
 25        - name: Install Python lint dependencies
 26          run: pip install flake8==7.3.0 bandit==1.8.3
 27  
 28        - name: Flake8
 29          run: flake8 src/ tools/ tests/ --config=.flake8
 30  
 31        - name: Bandit (security lint)
 32          run: bandit -r src/ tools/ -c bandit.yaml -ll -ii
 33  
 34        - name: Frontend setup
 35          working-directory: src/web_terminal_client
 36          run: npm install --no-fund --no-audit --legacy-peer-deps
 37  
 38        - name: Frontend type check (tsc — informational)
 39          working-directory: src/web_terminal_client
 40          continue-on-error: true
 41          run: npx tsc --noEmit -p tsconfig.lint.json
 42  
 43        - name: Frontend lint (ESLint)
 44          working-directory: src/web_terminal_client
 45          run: npx eslint src/ --max-warnings 55
 46  
 47        # NOTE: Frontend tests (vitest) run in the docker-tests job.
 48        # The vitest config has Docker-specific paths (/app/, AG3NTUM_ROOT=/)
 49        # that require the container environment.
 50  
 51    # Job 2: Structural tests (GitHub-hosted, no Docker needed)
 52    structural-tests:
 53      runs-on: ubuntu-latest
 54      steps:
 55        - uses: actions/checkout@v4
 56  
 57        - uses: actions/setup-python@v5
 58          with:
 59            python-version: '3.13'
 60  
 61        - name: Install test dependencies
 62          run: pip install pytest pyyaml
 63  
 64        - name: Run structural tests
 65          run: python -m pytest tests/structural/ -v --tb=long
 66  
 67    # Job 3: Dependency audit (informational — non-blocking)
 68    dependency-audit:
 69      runs-on: ubuntu-latest
 70      continue-on-error: true
 71      steps:
 72        - uses: actions/checkout@v4
 73  
 74        - uses: actions/setup-python@v5
 75          with:
 76            python-version: '3.13'
 77  
 78        - name: Install pip-audit
 79          run: pip install pip-audit==2.9.0
 80  
 81        - name: Run dependency audit
 82          run: pip-audit --requirement requirements-base.txt --desc
 83  
 84    # Job 4: Docker-based tests (self-hosted runner at extractum VPS)
 85    docker-tests:
 86      runs-on: [self-hosted, linux, docker]
 87      needs: [fast-checks, structural-tests]
 88      steps:
 89        - name: Fix workspace ownership
 90          run: |
 91            # Docker builds leave files owned by UID 45045. Use a container to reclaim.
 92            docker run --rm -v "$GITHUB_WORKSPACE":/ws alpine chown -R "$(id -u):$(id -g)" /ws || true
 93  
 94        - uses: actions/checkout@v4
 95  
 96        - name: Create secrets config for CI
 97          run: |
 98            echo "anthropic_api_key: ${ANTHROPIC_API_KEY:-sk-ant-api03-ci-placeholder-key-00000000000000000000000000000000000000000000000000000000000000}" > config/secrets.yaml
 99          env:
100            ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
101  
102        - name: Build test containers
103          run: ./run.sh build
104  
105        - name: Run backend tests
106          run: ./run.sh test --backend
107  
108        - name: Run security tests
109          run: ./run.sh test --security
110  
111        - name: Run core tests
112          run: ./run.sh test --core
113  
114        - name: Run sandboxing tests
115          run: ./run.sh test --sandboxing
116  
117        - name: Run frontend tests
118          run: ./run.sh test --ui
119  
120        - name: Dump container logs on failure
121          if: failure()
122          run: docker compose logs --tail=100 ag3ntum-api 2>/dev/null || true
123  
124        - name: Remove secrets file
125          if: always()
126          run: rm -f config/secrets.yaml
127  
128        - name: Cleanup
129          if: always()
130          run: ./run.sh cleanup