# CI/CD Pipeline and Branch Protection This document describes the CI/CD pipeline, branch protection rules, and merge requirements for the CleverAgents project. For quality tooling details (pre-commit hooks, nox sessions, security scanning), see [Quality Automation Guide](quality-automation.md). ## Branch Protection Rules ### Protected Branch: `master` The `master` branch is the primary integration branch. All changes must go through pull requests with the following protections enforced. #### Required Status Checks Every pull request targeting `master` must pass **all** of the following CI jobs before merging is allowed: | CI Job | What It Checks | Failure Means | |--------|---------------|---------------| | `lint` | Ruff format and lint (nox) | Code style violations or lint errors | | `typecheck` | Pyright strict type checking (nox) | Type errors in `src/` | | `security` | Security scan + dead code (nox) | Security vulnerabilities or dead code | | `quality` | Radon complexity (nox) | Extremely complex methods (31+ cyclomatic complexity) | | `unit_tests` | BDD unit tests via `nox -s unit_tests` | Failing unit test scenarios | | `integration_tests` | Robot integration tests via `nox -s integration_tests` | Failing integration tests | | `coverage` | Test coverage measurement (nox) | Coverage dropped below 97% | | `build` | Wheel build | Build failure | **Deployment-gating jobs** (run after core checks pass): | CI Job | Depends On | What It Checks | |--------|-----------|----------------| | `docker` | `lint`, `typecheck`, `unit_tests`, `security` | Docker image builds and runs | #### Required Reviews - **Minimum 1 approving review** required before merge. - Reviews are selective (see [Review Priority Matrix](#review-priority-matrix) below). - Stale reviews are dismissed when new commits are pushed. - Code owners can be configured per directory if needed. #### Additional Protections - **No direct pushes** to `master`. All changes must come via pull request. The `no-commit-to-branch` pre-commit hook enforces this locally. - **No force pushes** to `master`. History must be preserved. - **No deletions** of the `master` branch. - **Require branches to be up-to-date** before merging (prevents merge skew). ### Setting Up Branch Protection in Forgejo To configure these rules in Forgejo: 1. Navigate to **Repository Settings** > **Branches** > **Branch Protection**. 2. Add a rule for branch name pattern: `master`. 3. Enable the following settings: ``` [x] Enable branch protection [x] Block push (no direct pushes) [x] Block force push [x] Block branch deletion [x] Require pull request reviews before merging - Required approvals: 1 - Dismiss stale reviews: Yes [x] Require status checks to pass before merging - Required checks: - lint - typecheck - security - quality - behave - coverage - build [x] Require branches to be up-to-date before merging ``` 4. Save the branch protection rule. ## Review Process ### Review Priority Matrix Not all code changes require the same level of review attention. Use this matrix to determine review depth: | Priority | Category | Review Depth | Examples | |----------|----------|-------------|----------| | **P0** | Architecture and Security | Deep review required | Service layer design, DB schema, API contracts, sandbox boundaries, authentication | | **P1** | Complex Business Logic | Careful review | Decision tree traversal, merge conflict resolution, dependency closure, state machines | | **P2** | Normal Features | Standard review | CLI commands, model definitions, straightforward service methods | | **P3** | Tests, Docs, Refactoring | Trust automation | Behave scenarios, documentation updates, import reorganization, formatting | ### What Reviewers Should Focus On **Always review** (P0 items): - Service layer design choices and dependency injection patterns - Database schema decisions and Alembic migrations - API contract definitions and interface boundaries - Sandbox security boundaries and isolation guarantees - Input validation and sanitization logic - Any code touching `eval()`, `exec()`, `compile()`, or `subprocess` **Review carefully** (P1 items): - Algorithm implementations (decision tree, merge, closure computation) - State machine transitions and lifecycle management - Error propagation across actor and plan boundaries - Concurrent access patterns and thread safety **Standard review** (P2 items): - Verify tests exist for new functionality - Check that argument validation follows `CONTRIBUTING.md` guidelines - Confirm type annotations are complete (no bare `Any`) **Trust automation** (P3 items): - If `nox` passes (lint, typecheck, tests, coverage, security), formatting and style are covered. - Behave test scenarios and Robot integration tests follow established patterns. - Documentation changes are verified by `nox -s docs` (MkDocs build). ### Review Checklist Every PR should pass this checklist (also available in the PR template at `.forgejo/pull_request_template.md` in the repository root): - [ ] Code follows `CONTRIBUTING.md` coding standards - [ ] All public/protected methods have argument validation - [ ] Static typing is complete (no bare `Any` unless justified) - [ ] `nox -s typecheck` passes - [ ] `nox -s lint` passes - [ ] Unit tests written/updated (Behave scenarios in `features/`) - [ ] Integration tests written/updated (Robot suites in `robot/`) if applicable - [ ] Coverage remains above 97% - [ ] No security issues introduced - [ ] No dead code introduced - [ ] Documentation updated if behavior changed ## CI Pipeline Reference ### Workflow Files | Workflow | File | Trigger | Purpose | |----------|------|---------|---------| | CI | `.forgejo/workflows/ci.yml` | Push to `master`/`develop`, PRs to `master` | Full nox-based validation pipeline | | Nightly Quality | `.forgejo/workflows/nightly-quality.yml` | Midnight UTC (cron), manual | Comprehensive quality monitoring | ### CI Job Dependency Graph ``` lint ──────────────────┐ typecheck ─────────────┤ ├── coverage (needs lint + typecheck) security ──────────────┤ ├── docker (needs lint + typecheck + unit_tests + security) unit_tests ────────────┘ integration_tests ──────── (independent) quality ────────────────── (independent) build ──────────────────── (independent) push-validation ────────── (independent — validates CI push credentials) ``` ### Nox-Based CI All CI jobs now run their checks through nox sessions rather than invoking tools directly. This ensures that the CI environment matches local development exactly. Each job runs `pip install uv nox` and then delegates to the appropriate nox session. ### Quality Gates Summary All gates must pass for a PR to be mergeable: | Gate | Threshold | Enforced By | |------|-----------|-------------| | Formatting | Zero violations | `lint` job (ruff format) | | Linting | Zero violations | `lint` job (ruff check) | | Type Safety | Zero errors | `typecheck` job (pyright strict) | | Security | Zero HIGH severity | `security` job (bandit) | | Dead Code | Zero findings | `security` job (vulture) | | Complexity | No grade-F methods | `quality` job (radon) | | Unit Tests | All pass (3.11-3.13) | `behave` job | | Coverage | >= 97% | `coverage` job (nox) | | Build | Wheel builds | `build` job | | Push Access | Credentials valid | `push-validation` job | ### Nightly Quality Monitoring The nightly workflow provides trend data beyond PR-level checks: - Full lint, type check, and security scan (all severities, not just HIGH) - Complete Behave test suite with coverage measurement - Complexity and maintainability index analysis - Quality trend JSON with timestamps (90-day artifact retention) Reports are uploaded as artifacts under `nightly-quality-reports` and can be downloaded from the Forgejo Actions UI. ## Local Development Workflow ### Before Pushing a PR ```bash # Quick validation (runs default nox sessions: lint, format, typecheck, # unit_tests, integration_tests, docs, build, benchmark, coverage_report) nox # Or run individual checks matching CI jobs nox -s lint # Formatting and linting (CI: lint job) nox -s format -- --check # Format check only (CI: lint job) nox -s typecheck # Type checking (CI: typecheck job) nox -s unit_tests # Behave tests (CI: unit_tests job) nox -s integration_tests # Robot tests (CI: integration_tests job) nox -s coverage_report # Coverage (must be >=97%) (CI: coverage job) nox -s security_scan # Bandit security scanning (CI: security job) nox -s dead_code # Vulture dead code detection (CI: security job) nox -s complexity # Radon complexity check (CI: quality job) nox -s build # Wheel build (CI: build job) ``` ### Local Reproduction of CI Failures To reproduce a CI failure locally, run the exact nox session that failed: ```bash # Example: coverage job failed nox -s coverage_report # Example: typecheck job failed nox -s typecheck # Example: security job failed nox -s security_scan nox -s dead_code ``` ### Caching Notes CI jobs install `uv` (for fast dependency resolution) and `nox`. The nox sessions use `uv` as the venv backend (`venv_backend="uv"`) and reuse existing virtualenvs (`reuse_venv=True`) for speed. On CI, each job starts fresh but `uv` provides fast installs via its built-in caching. ### CI Secrets Some CI jobs require secrets configured in the Forgejo UI. Secrets are managed under **Repository Settings > Actions > Secrets** and are automatically masked in job logs. | Secret Name | Required By | Purpose | |-------------|-------------|---------| | `ANTHROPIC_API_KEY` | `integration_tests` | Anthropic API key for Robot Framework integration tests | | `OPENAI_API_KEY` | `integration_tests` | OpenAI API key for Robot Framework integration tests | | `AWS_ACCESS_KEY_ID` | `benchmark-regression`, `benchmark-publish` | AWS credentials for ASV benchmark S3 storage | | `AWS_SECRET_ACCESS_KEY` | `benchmark-regression`, `benchmark-publish` | AWS credentials for ASV benchmark S3 storage | | `AWS_DEFAULT_REGION` | `benchmark-regression`, `benchmark-publish` | AWS region for ASV benchmark S3 storage | | `ASV_S3_BUCKET` | `benchmark-regression`, `benchmark-publish` | S3 bucket name for ASV benchmark storage | | `FORGEJO_TOKEN` | `release` (`create-release` job) | Forgejo API token with **repository write** scope — used to authenticate `git push` and create releases | | `FORGEJO_URL` | `release` (`create-release` job) | Base URL of the Forgejo instance (e.g., `https://git.cleverthis.com`) | | `CONTAINER_REGISTRY` | `release` (`build-docker` job) | Container registry URL for Docker image pushes | | `CONTAINER_REGISTRY_USER` | `release` (`build-docker` job) | Username for container registry authentication | | `CONTAINER_REGISTRY_PASSWORD` | `release` (`build-docker` job) | Password/token for container registry authentication | **Unit tests vs. integration tests:** - **Unit tests** (Behave BDD, `nox -s unit_tests`) do **not** require any API keys. They test internal logic without calling external services. - **Integration tests** (Robot Framework, `nox -s integration_tests`) **do** require real LLM API keys (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`). These tests exercise end-to-end workflows that interact with live LLM providers. If the LLM secrets are not configured, integration tests will fail with authentication errors at runtime. ### Repository Push Authentication Any CI workflow step that writes back to the repository (e.g., pushing tags, committing auto-generated files, or creating changelog commits) **must** use explicit token authentication. The `push-validation` job in `ci.yml` validates that push credentials are correctly configured on every CI run. **Fix applied (issue #1541):** The `actions/checkout@v4` action was not configured with `token: ${{ forgejo.token }}` and `persist-credentials: true`, and no git user config (`user.name` / `user.email`) was set. Both are required for push operations. The `push-validation` job now validates these on every run. #### Root Cause of "Unable to Push" Failures The most common cause of CI push failures is missing or misconfigured credentials. Symptoms include: ``` remote: Permission denied fatal: unable to access 'https://...': The requested URL returned error: 403 ``` or: ``` ERROR: Repository not found. fatal: Could not read from remote repository. ``` #### Fix: HTTPS Token Authentication The canonical fix is to configure git to use the `FORGEJO_TOKEN` secret via HTTPS credential store. This is done in the `create-release` job of `release.yml`: ```yaml - uses: actions/checkout@v4 with: fetch-depth: 0 token: ${{ secrets.FORGEJO_TOKEN }} # Use write-scoped token - name: Configure git identity for push operations env: FORGEJO_URL: ${{ secrets.FORGEJO_URL }} FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} run: | git config user.name "CleverAgents CI" git config user.email "ci@cleverthis.com" FORGEJO_HOST=$(echo "${FORGEJO_URL}" | sed 's|https\?://||' | cut -d/ -f1) git config credential.helper store echo "https://ci:${FORGEJO_TOKEN}@${FORGEJO_HOST}" > ~/.git-credentials chmod 600 ~/.git-credentials ``` #### Smoke-Test Step The `create-release` job includes a smoke-test step that validates push access **before** attempting the real push. This catches credential issues early with a clear error message: ```yaml - name: Smoke-test push access env: FORGEJO_URL: ${{ secrets.FORGEJO_URL }} FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} run: | REPO="${{ forgejo.repository }}" API_URL="${FORGEJO_URL}/api/v1/repos/${REPO}" HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: token ${FORGEJO_TOKEN}" \ "${API_URL}") if [ "${HTTP_STATUS}" != "200" ]; then echo "ERROR: FORGEJO_TOKEN cannot access repository API (HTTP ${HTTP_STATUS})." exit 1 fi PUSH_ALLOWED=$(curl -s \ -H "Authorization: token ${FORGEJO_TOKEN}" \ "${API_URL}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(str(d.get('permissions',{}).get('push',False)).lower())") if [ "${PUSH_ALLOWED}" != "true" ]; then echo "ERROR: FORGEJO_TOKEN does not have push (write) permission." exit 1 fi echo "Push access verified." ``` #### Setting Up the FORGEJO_TOKEN Secret 1. Create a Forgejo personal access token (PAT) with **repository write** scope: - Navigate to **User Settings** > **Applications** > **Access Tokens** - Create a token with `repository` scope (read + write) - Copy the token value (shown only once) 2. Add the token as a repository secret: - Navigate to **Repository Settings** > **Actions** > **Secrets** - Add secret `FORGEJO_TOKEN` with the PAT value - Add secret `FORGEJO_URL` with the Forgejo base URL (e.g., `https://git.cleverthis.com`) 3. **Never hardcode tokens** in workflow files. Always use `${{ secrets.SECRET_NAME }}`. #### Security Notes - The `FORGEJO_TOKEN` secret is automatically masked in job logs by Forgejo Actions. - The `~/.git-credentials` file is created with `chmod 600` (owner-read-only). - The credential file is ephemeral — it exists only for the duration of the job in the container's filesystem and is destroyed when the container exits. - No SSH deploy keys are required; HTTPS token authentication is sufficient and simpler to manage. ### Pre-commit Hooks Pre-commit hooks run automatically on `git commit` and catch most issues before they reach CI. See [Quality Automation Guide](quality-automation.md) for the full list of hooks. If hooks are not installed: ```bash bash scripts/setup-dev.sh # Or manually: pre-commit install pre-commit install --hook-type commit-msg ```