name: CI on: pull_request: push: branches: - main - master workflow_dispatch: schedule: - cron: '0 3 * * *' # nightly 03:00 UTC for adversarial-extended permissions: contents: read jobs: import-smoke: name: Import Smoke Test (ComfyUI loader) strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.10' - uses: actions/setup-node@v5 with: node-version: '20' - name: Install import deps run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt python -m pip install numpy pillow - name: R120 preflight run: | python scripts/preflight_check.py --strict - name: Import smoke test env: MOLTBOT_STATE_DIR: ${{ github.workspace }}/moltbot_state/_ci_smoke run: | python scripts/run_unittests.py --module tests.test_comfyui_loader_import frontend-e2e: name: Frontend E2E (Playwright) strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.10' - uses: actions/setup-node@v5 with: node-version: '20' - name: Install preflight deps run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt - name: R120 preflight run: | python scripts/preflight_check.py --strict - name: Install Node deps run: | npm install - name: Install Playwright browsers run: | npx playwright install chromium - name: Run E2E run: | npm test unit-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.10' - uses: actions/setup-node@v5 with: node-version: '20' - name: Install test deps run: | python -m pip install --upgrade pip # Keep aligned with local pre-push/full-test scripts. # aiohttp is required by multiple unit-test import paths. python -m pip install -r requirements.txt python -m pip install numpy pillow aiohttp - name: R120 preflight run: | python scripts/preflight_check.py --strict - name: Run MAE hard-guarantee suites env: MOLTBOT_STATE_DIR: ${{ github.workspace }}/moltbot_state/_ci_mae run: | # CRITICAL: keep these as explicit CI gates so public MAE route-plane # classification/regression drift cannot silently bypass full discovery. python scripts/run_unittests.py --module tests.test_s60_mae_route_segmentation --enforce-skip-policy tests/skip_policy.json --max-skipped 0 python scripts/run_unittests.py --module tests.test_s60_routes_startup_gate --enforce-skip-policy tests/skip_policy.json --max-skipped 0 python scripts/run_unittests.py --module tests.security.test_endpoint_drift --enforce-skip-policy tests/skip_policy.json --max-skipped 0 - name: Run unit tests env: MOLTBOT_STATE_DIR: ${{ github.workspace }}/moltbot_state/_ci_unit run: | python scripts/run_unittests.py --start-dir tests --pattern "test_*.py" --enforce-skip-policy tests/skip_policy.json backend-e2e-real: name: Backend E2E (real-backend lane, low-mock) runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.10' - uses: actions/setup-node@v5 with: node-version: '20' - name: Install test deps run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt python -m pip install numpy pillow aiohttp - name: R120 preflight run: | python scripts/preflight_check.py --strict - name: Run real-backend lane env: MOLTBOT_STATE_DIR: ${{ github.workspace }}/moltbot_state/_ci_backend_e2e_real run: | # CRITICAL: this lane must stay low-mock and exercise real aiohttp request flow. python scripts/run_unittests.py --module tests.test_r122_real_backend_lane --enforce-skip-policy tests/skip_policy.json --max-skipped 0 # R123: model-list loopback/private-IP SSRF parity must remain no-skip. python scripts/run_unittests.py --module tests.test_r123_real_backend_model_list_lane --enforce-skip-policy tests/skip_policy.json --max-skipped 0 contract-tests: name: Contract Tests (R52) strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.10' - uses: actions/setup-node@v5 with: node-version: '20' - name: Install test deps run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt python -m pip install numpy pillow aiohttp pytest-asyncio - name: R120 preflight run: | python scripts/preflight_check.py --strict - name: Run contract tests run: | python -m pytest tests/contract -v security-audit: name: Security Audit (S23) runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v5 with: node-version: '20' - name: Frontend Audit (npm) run: | # Audit only production dependencies, ignore dev npm audit --production - uses: actions/setup-python@v6 with: python-version: '3.10' - name: Install backend deps run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt - name: Install pip-audit run: pip install pip-audit - name: Backend Audit (pip) run: | # IMPORTANT: audit declared project deps, not the whole CI tool environment. # Env-wide `pip-audit` also scans pip-audit's own transient dependencies and # can fail on toolchain-only packages that are outside the repo dependency contract. pip-audit -r requirements.txt adversarial-smoke: name: Adversarial Gate (adaptive) runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 with: fetch-depth: 0 - uses: actions/setup-python@v6 with: python-version: '3.10' - name: Install test deps run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt python -m pip install numpy pillow aiohttp - name: R120 preflight run: | python scripts/preflight_check.py --strict - name: R118 adversarial adaptive (auto profile) env: MOLTBOT_STATE_DIR: ${{ github.workspace }}/moltbot_state/_ci_adversarial OPENCLAW_DIFF_BASE: ${{ github.event.pull_request.base.sha || github.event.before }} OPENCLAW_DIFF_HEAD: ${{ github.event.pull_request.head.sha || github.sha }} run: | python scripts/run_adversarial_gate.py --profile auto --seed 42 --artifact-dir .tmp/adversarial - name: Upload adversarial artifacts if: always() uses: actions/upload-artifact@v6 with: name: adversarial-adaptive-manifest path: .tmp/adversarial/ retention-days: 30 adversarial-extended: name: Adversarial Gate (extended, nightly/manual) runs-on: ubuntu-latest if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v6 with: python-version: '3.10' - name: Install test deps run: | python -m pip install --upgrade pip python -m pip install -r requirements.txt python -m pip install numpy pillow aiohttp - name: R120 preflight run: | python scripts/preflight_check.py --strict - name: R118 adversarial extended env: MOLTBOT_STATE_DIR: ${{ github.workspace }}/moltbot_state/_ci_adversarial_ext run: | python scripts/run_adversarial_gate.py --profile extended --artifact-dir .tmp/adversarial-extended - name: Upload adversarial artifacts if: always() uses: actions/upload-artifact@v6 with: name: adversarial-extended-manifest path: .tmp/adversarial-extended/ retention-days: 90