name: Integration Tests # Per-PR journey-suite matrix (tests/integration/), once per wrapped harness # using the mock LLM server (no real gateway credentials required). All tests # are mock_only: they script the LLM responses via configure_mock_llm and run # against a local mock FastAPI server. Because it uses NO secrets, it runs on # ALL PRs -- same-repo AND fork -- directly via `pull_request`, like ci.yml; no # fork-e2e/** mirror needed. Triggers: daily schedule, the PR gate, and # workflow_dispatch. on: schedule: - cron: "30 9 * * *" pull_request: # No labeled/unlabeled: a skip-security-scan waiver re-runs this workflow's # Security Gate via rerun-security-gate.yml, so label churn need not re-run # the heavy integration suite. (#399 added these for the gate; superseded.) types: [opened, synchronize, reopened, ready_for_review] paths-ignore: ['web/**', 'tests/e2e_ui/**'] workflow_dispatch: permissions: contents: read env: # No web SPA build during `uv sync`: this job never serves the bundle # and the hardened runner has no npm mirror (build would time out). OMNIGENT_SKIP_WEB_UI: "true" # Never let the test server pick up the runner's own credentials. ANTHROPIC_API_KEY: "" OPENAI_API_KEY: "" DATABRICKS_TOKEN: "" CODEX: "" CLAUDE_CODE: "" concurrency: # Key by PR number so re-syncs cancel; push/dispatch key by SHA/branch. group: integration-${{ github.workflow }}-${{ github.event.pull_request.number || github.event.inputs.branch || github.sha }} cancel-in-progress: true jobs: # Security precondition gate: untrusted PRs hold until the scan passes # (see security-gate.yml); trusted authors / non-PR events pass instantly. gate: uses: ./.github/workflows/security-gate.yml # Harness matrix (integration-matrix.sh). Fork PRs run by default; draft PRs # resolve to an empty matrix. setup: name: setup needs: gate runs-on: ubuntu-latest timeout-minutes: 5 outputs: matrix: ${{ steps.matrix.outputs.matrix }} steps: - name: Check out CI scripts uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # Triggering ref (not pinned to main): the script must exist on the # running ref, and it is not a security gate -- it only selects which # harness legs run and can't expose secrets, so the PR's own copy is # fine. sparse-checkout: .github/scripts/ci persist-credentials: false - name: Compute integration matrix id: matrix env: EVENT_NAME: ${{ github.event_name }} IS_DRAFT: ${{ github.event.pull_request.draft }} run: bash .github/scripts/ci/integration-matrix.sh integration: name: Integration (${{ matrix.name }}) # Draft PRs resolve to an EMPTY matrix in `setup`, so this job produces zero # leg runs (and thus no skipped placeholder check). Fork PRs DO run (mock # LLM, no secrets) -- same as ci.yml. needs: setup runs-on: ubuntu-latest # Per-leg ceiling; inner test step caps at 25 min, rest covers install + # junit upload. Legs run in parallel; longest gates wall-time. timeout-minutes: 30 strategy: # Don't cancel sibling harnesses on failure; surface which is red. fail-fast: false # Harness legs (per-leg model + worker pinning) come from `setup`; [] when # skipped. The ``Integration (...)`` leg-name prefix is load-bearing -- # the notify job's jq keys on it. Pinning rationale + codex worker halving # live in .github/scripts/ci/integration-matrix.sh. matrix: ${{ fromJSON(needs.setup.outputs.matrix) }} steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ github.event.inputs.branch || github.ref }} # Shared verbatim with server-compat.yml's backcompat-integration job via # the composite action, so the two never drift. server_version is omitted # here -> normal gate (tests the checked-out server, mock LLM). - name: Run integration suite uses: ./.github/actions/integration-run with: harness: ${{ matrix.harness }} model: ${{ matrix.model }} workers: ${{ matrix.workers }}