fix(web): close model selector before opening provider dialogs #38191
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Run Integration Tests v2 | |
| concurrency: | |
| group: Run-Integration-Tests-${{ github.workflow }}-${{ github.head_ref || github.event.workflow_run.head_branch || github.run_id }} | |
| cancel-in-progress: true | |
| on: | |
| merge_group: | |
| pull_request: | |
| branches: | |
| - main | |
| - "release/**" | |
| # NOTE: Intentionally no `paths:` filter. We always trigger and let the | |
| # `changes` job below decide whether the real test matrix runs. This | |
| # avoids the dual-workflow skip pattern where a `paths-ignore`'d skip | |
| # workflow can race the real workflow's same-named status check under | |
| # branch protection. | |
| push: | |
| tags: | |
| - "v*.*.*" | |
| permissions: | |
| contents: read | |
| env: | |
| # Test Environment Variables | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} | |
| SLACK_BOT_TOKEN_TEST_SPACE: ${{ secrets.SLACK_BOT_TOKEN_TEST_SPACE }} | |
| CONFLUENCE_TEST_SPACE_URL: ${{ vars.CONFLUENCE_TEST_SPACE_URL }} | |
| CONFLUENCE_USER_NAME: ${{ vars.CONFLUENCE_USER_NAME }} | |
| CONFLUENCE_ACCESS_TOKEN: ${{ secrets.CONFLUENCE_ACCESS_TOKEN }} | |
| CONFLUENCE_ACCESS_TOKEN_SCOPED: ${{ secrets.CONFLUENCE_ACCESS_TOKEN_SCOPED }} | |
| JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} | |
| JIRA_ADMIN_USER_EMAIL: ${{ vars.JIRA_ADMIN_USER_EMAIL }} | |
| JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} | |
| JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} | |
| JIRA_API_TOKEN_SCOPED: ${{ secrets.JIRA_API_TOKEN_SCOPED }} | |
| PERM_SYNC_SHAREPOINT_CLIENT_ID: ${{ secrets.PERM_SYNC_SHAREPOINT_CLIENT_ID }} | |
| PERM_SYNC_SHAREPOINT_PRIVATE_KEY: ${{ secrets.PERM_SYNC_SHAREPOINT_PRIVATE_KEY }} | |
| PERM_SYNC_SHAREPOINT_CERTIFICATE_PASSWORD: ${{ secrets.PERM_SYNC_SHAREPOINT_CERTIFICATE_PASSWORD }} | |
| PERM_SYNC_SHAREPOINT_DIRECTORY_ID: ${{ secrets.PERM_SYNC_SHAREPOINT_DIRECTORY_ID }} | |
| EXA_API_KEY: ${{ secrets.EXA_API_KEY }} | |
| GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN: ${{ secrets.ONYX_GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN }} | |
| GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN_CLASSIC: ${{ secrets.ONYX_GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN_CLASSIC }} | |
| GITHUB_ADMIN_EMAIL: ${{ secrets.ONYX_GITHUB_ADMIN_EMAIL }} | |
| GITHUB_TEST_USER_1_EMAIL: ${{ secrets.ONYX_GITHUB_TEST_USER_1_EMAIL }} | |
| GITHUB_TEST_USER_2_EMAIL: ${{ secrets.ONYX_GITHUB_TEST_USER_2_EMAIL }} | |
| jobs: | |
| changes: | |
| # Decides whether the integration test matrix runs. On pull_request / | |
| # merge_group we use paths-filter; on push (tags) we default to `true` so | |
| # everything runs. | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| # paths-filter needs pull-requests:read to list PR files on private repos (no-op on public). | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| integration: ${{ steps.filter.outputs.integration || 'true' }} | |
| gateway: ${{ steps.filter.outputs.gateway || 'true' }} | |
| steps: | |
| - name: Checkout code | |
| if: github.event_name == 'pull_request' || github.event_name == 'merge_group' | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - uses: dorny/paths-filter@7b450fff21473bca461d4b92ce414b9d0420d706 | |
| id: filter | |
| if: github.event_name == 'pull_request' || github.event_name == 'merge_group' | |
| with: | |
| filters: | | |
| integration: | |
| - 'backend/**' | |
| - 'cli/**' | |
| - 'deployment/docker_compose/**' | |
| - '.devcontainer/**' | |
| - 'docker-bake.hcl' | |
| - 'pyproject.toml' | |
| - 'uv.lock' | |
| - '.github/workflows/pr-integration-tests.yml' | |
| - '.github/actions/setup-test-license/**' | |
| - '.github/actions/install-python-deps/**' | |
| - '.github/actions/login-ecr-pullthrough-cache/**' | |
| gateway: | |
| - 'backend/onyx/server/gateway/**' | |
| - 'backend/tests/integration/tests/gateway_clients/**' | |
| discover-test-dirs: | |
| # NOTE: Github-hosted runners have about 20s faster queue times and are preferred here. | |
| needs: changes | |
| if: needs.changes.outputs.integration == 'true' | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 5 | |
| outputs: | |
| test-dirs: ${{ steps.set-matrix.outputs.test-dirs }} | |
| editions: ${{ steps.set-editions.outputs.editions }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Discover test directories | |
| id: set-matrix | |
| env: | |
| GATEWAY_CHANGED: ${{ needs.changes.outputs.gateway }} | |
| run: | | |
| # Find all leaf-level directories in both test directories. | |
| # ``craft`` excluded: needs sandbox infra this lane doesn't set up; | |
| tests_dirs=$(find backend/tests/integration/tests -mindepth 1 -maxdepth 1 -type d ! -name "__pycache__" ! -name "mcp" ! -name "no_vectordb" ! -name "migrations" ! -name "craft" ! -name "gateway_clients" -exec basename {} \; | sort) | |
| if [[ "$GATEWAY_CHANGED" == "true" ]]; then | |
| tests_dirs="$tests_dirs gateway_clients" | |
| fi | |
| connector_dirs=$(find backend/tests/integration/connector_job_tests -mindepth 1 -maxdepth 1 -type d ! -name "__pycache__" -exec basename {} \; | sort) | |
| # Create JSON array with directory info | |
| all_dirs="" | |
| for dir in $tests_dirs; do | |
| all_dirs="$all_dirs{\"path\":\"tests/$dir\",\"name\":\"tests-$dir\"}," | |
| done | |
| for dir in $connector_dirs; do | |
| all_dirs="$all_dirs{\"path\":\"connector_job_tests/$dir\",\"name\":\"connector-$dir\"}," | |
| done | |
| # Remove trailing comma and wrap in array | |
| all_dirs="[${all_dirs%,}]" | |
| echo "test-dirs=$all_dirs" >> $GITHUB_OUTPUT | |
| - name: Determine editions to test | |
| id: set-editions | |
| run: | | |
| # On PRs, only run EE tests. On merge_group and tags, run both EE and MIT. | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| echo 'editions=["ee"]' >> $GITHUB_OUTPUT | |
| else | |
| echo 'editions=["ee","mit"]' >> $GITHUB_OUTPUT | |
| fi | |
| build-model-server-image: | |
| needs: changes | |
| if: needs.changes.outputs.integration == 'true' | |
| runs-on: | |
| [ | |
| runs-on, | |
| runner=1cpu-linux-arm64, | |
| "run-id=${{ github.run_id }}-build-model-server-image", | |
| "extras=ecr-cache", | |
| ] | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Build model server image | |
| uses: ./.github/actions/build-model-server-image | |
| with: | |
| runs-on-ecr-cache: ${{ env.RUNS_ON_ECR_CACHE }} | |
| ref-name: ${{ github.ref_name }} | |
| pr-number: ${{ github.event.pull_request.number }} | |
| github-sha: ${{ github.event.pull_request.head.sha || github.sha }} | |
| run-id: ${{ github.run_id }} | |
| tag-prefix: integration-test-model-server-test | |
| ecr-registry: ${{ vars.ECR_REGISTRY }} | |
| docker-username: ${{ secrets.DOCKER_USERNAME }} | |
| docker-token: ${{ secrets.DOCKER_TOKEN }} | |
| build-devcontainer-image: | |
| needs: changes | |
| if: needs.changes.outputs.integration == 'true' | |
| runs-on: | |
| [ | |
| runs-on, | |
| runner=2cpu-linux-arm64, | |
| "run-id=${{ github.run_id }}-build-devcontainer-image", | |
| "extras=ecr-cache", | |
| ] | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Format branch name for cache | |
| id: format-branch | |
| env: | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| REF_NAME: ${{ github.ref_name }} | |
| run: | | |
| if [ -n "${PR_NUMBER}" ]; then | |
| CACHE_SUFFIX="${PR_NUMBER}" | |
| else | |
| # shellcheck disable=SC2001 | |
| CACHE_SUFFIX=$(echo "${REF_NAME}" | sed 's/[^A-Za-z0-9._-]/-/g') | |
| fi | |
| echo "cache-suffix=${CACHE_SUFFIX}" >> $GITHUB_OUTPUT | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # ratchet:docker/setup-buildx-action@v4 | |
| - name: Log in to ECR pull-through cache | |
| uses: ./.github/actions/login-ecr-pullthrough-cache | |
| with: | |
| ecr-registry: ${{ vars.ECR_REGISTRY }} | |
| - name: Build and push Devcontainer Docker image | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a | |
| with: | |
| context: .devcontainer | |
| file: .devcontainer/Dockerfile | |
| push: true | |
| build-args: | | |
| BASE_IMAGE_REGISTRY=${{ env.BASE_IMAGE_REGISTRY }} | |
| tags: ${{ env.RUNS_ON_ECR_CACHE }}:integration-test-devcontainer-${{ github.run_id }} | |
| # Attestations attach as ECR referrers to the image digest, which is | |
| # stable across runs and caps out at 100 per subject. | |
| provenance: false | |
| sbom: false | |
| cache-from: | | |
| type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:devcontainer-cache-${{ github.event.pull_request.head.sha || github.sha }} | |
| type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:devcontainer-cache-${{ steps.format-branch.outputs.cache-suffix }} | |
| type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:devcontainer-cache | |
| type=registry,ref=${{ env.BASE_IMAGE_REGISTRY }}/onyxdotapp/onyx-devcontainer:latest | |
| cache-to: | | |
| type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:devcontainer-cache-${{ github.event.pull_request.head.sha || github.sha }},mode=max | |
| type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:devcontainer-cache-${{ steps.format-branch.outputs.cache-suffix }},mode=max | |
| type=registry,ref=${{ env.RUNS_ON_ECR_CACHE }}:devcontainer-cache,mode=max | |
| no-cache: ${{ vars.DOCKER_NO_CACHE == 'true' }} | |
| integration-tests: | |
| needs: | |
| [ | |
| discover-test-dirs, | |
| build-model-server-image, | |
| build-devcontainer-image, | |
| ] | |
| permissions: | |
| id-token: write # Required for OIDC-based AWS credential exchange | |
| contents: read | |
| runs-on: | |
| - runs-on | |
| - runner=4cpu-linux-arm64 | |
| - ${{ format('run-id={0}-integration-tests-{1}-job-{2}', github.run_id, matrix.edition, strategy['job-index']) }} | |
| - extras=ecr-cache | |
| timeout-minutes: 25 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test-dir: ${{ fromJson(needs.discover-test-dirs.outputs.test-dirs) }} | |
| edition: ${{ fromJson(needs.discover-test-dirs.outputs.editions) }} | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Setup test license | |
| uses: ./.github/actions/setup-test-license | |
| with: | |
| aws-oidc-role-arn: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| - name: Log in to ECR pull-through cache | |
| uses: ./.github/actions/login-ecr-pullthrough-cache | |
| with: | |
| ecr-registry: ${{ vars.ECR_REGISTRY }} | |
| # NOTE: Use pre-ping/null pool to reduce flakiness due to dropped connections | |
| # NOTE: don't need web server for integration tests | |
| - name: Create .env file for Docker Compose | |
| env: | |
| ECR_CACHE: ${{ env.RUNS_ON_ECR_CACHE }} | |
| RUN_ID: ${{ github.run_id }} | |
| EDITION: ${{ matrix.edition }} | |
| run: | | |
| # Base config shared by both editions | |
| cat <<EOF > deployment/docker_compose/.env | |
| COMPOSE_PROFILES=s3-filestore | |
| AUTH_TYPE=basic | |
| POSTGRES_POOL_PRE_PING=true | |
| POSTGRES_USE_NULL_POOL=true | |
| REQUIRE_EMAIL_VERIFICATION=false | |
| DISABLE_TELEMETRY=true | |
| ONYX_MODEL_SERVER_IMAGE=${ECR_CACHE}:integration-test-model-server-test-${RUN_ID} | |
| INTEGRATION_TESTS_MODE=true | |
| MCP_SERVER_ENABLED=true | |
| # The MCP client tests register a mock MCP server on a private/loopback | |
| # host (TEST_WEB_HOSTNAME); opt in so the SSRF guard allows it. Loopback | |
| # needs its own gate on top of the private one; cloud-metadata stays | |
| # blocked regardless. | |
| MCP_SERVER_ALLOW_PRIVATE_NETWORK=true | |
| MCP_SERVER_ALLOW_LOOPBACK=true | |
| AUTO_LLM_UPDATE_INTERVAL_SECONDS=10 | |
| ENABLE_CRAFT=true | |
| # Lowered upload/bundle caps so cap-enforcement tests can use | |
| # small payloads instead of multi-MiB allocations. | |
| BUILD_MAX_UPLOAD_FILE_SIZE_MB=2 | |
| BUILD_MAX_TOTAL_UPLOAD_SIZE_MB=4 | |
| BUILD_MAX_UPLOAD_FILES_PER_SESSION=5 | |
| MAX_EMBEDDED_IMAGES_PER_FILE=50 | |
| USER_LIBRARY_MAX_FILES_PER_UPLOAD=5 | |
| SKILL_BUNDLE_PER_FILE_MAX_BYTES=1048576 | |
| EOF | |
| # EE-only config | |
| if [ "$EDITION" = "ee" ]; then | |
| cat <<EOF >> deployment/docker_compose/.env | |
| ENABLE_PAID_ENTERPRISE_EDITION_FEATURES=true | |
| CHECK_TTL_MANAGEMENT_TASK_FREQUENCY_IN_HOURS=0.001 | |
| EOF | |
| fi | |
| # NOTE: only `inference_model_server` runs. `indexing_model_server` is the | |
| # same image with the same routes (INDEXING_ONLY only changes the log | |
| # request-id prefix), so the tests point both hosts at the one container | |
| # and skip a second load of the embedding model. | |
| - name: Start Docker containers | |
| run: | | |
| cd deployment/docker_compose | |
| docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d \ | |
| --wait --wait-timeout 300 \ | |
| relational_db \ | |
| opensearch \ | |
| cache \ | |
| minio \ | |
| inference_model_server | |
| id: start_docker | |
| - name: Start Mock Services | |
| if: matrix.test-dir.path == 'tests/indexing' | |
| run: | | |
| cd backend/tests/integration/mock_services | |
| docker compose -f docker-compose.mock-it-services.yml \ | |
| -p mock-it-services-stack up -d | |
| - name: Build CLI binary (for CLI integration tests) | |
| if: contains(matrix.test-dir.path, 'tests/cli') | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # zizmor: ignore[cache-poisoning] | |
| with: | |
| go-version: "1.26.5" | |
| cache-dependency-path: "cli/go.sum" | |
| - name: Compile CLI binary | |
| if: contains(matrix.test-dir.path, 'tests/cli') | |
| run: | | |
| cd cli | |
| GOARCH=arm64 GOOS=linux go build -o ${{ github.workspace }}/onyx-cli-test . | |
| - name: Install Python deps | |
| uses: ./.github/actions/install-python-deps | |
| with: | |
| devcontainer-image: ${{ env.RUNS_ON_ECR_CACHE }}:integration-test-devcontainer-${{ github.run_id }} | |
| - name: Run Integration Tests (${{ matrix.edition }}) for ${{ matrix.test-dir.name }} | |
| uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # ratchet:nick-fields/retry@v4.0.0 | |
| with: | |
| timeout_minutes: 20 | |
| max_attempts: 3 | |
| retry_wait_seconds: 10 | |
| command: | | |
| echo "Running ${{ matrix.edition }} integration tests for ${{ matrix.test-dir.path }}..." | |
| # gateway_clients drives real CLI subprocesses, which need a real | |
| # TCP api_server; run one inside the test container and make every | |
| # missing prerequisite a hard failure instead of a skip. | |
| GATEWAY_CLIENTS_STRICT="" | |
| RUN_CMD="uv run --no-sync pytest -v --tb=short -rs tests/integration/${{ matrix.test-dir.path }}" | |
| if [ "${{ matrix.test-dir.path }}" = "tests/gateway_clients" ]; then | |
| GATEWAY_CLIENTS_STRICT="true" | |
| RUN_CMD="bash tests/integration/tests/gateway_clients/run_with_server.sh" | |
| fi | |
| # Mount CLI binary into the container if it exists (CLI tests only) | |
| CLI_VOLUME="" | |
| if [ -f "${{ github.workspace }}/onyx-cli-test" ]; then | |
| CLI_VOLUME="-v ${{ github.workspace }}/onyx-cli-test:/usr/local/bin/onyx-cli-test:ro" | |
| CLI_VOLUME="$CLI_VOLUME -e ONYX_CLI_BINARY=/usr/local/bin/onyx-cli-test" | |
| fi | |
| docker run --rm --network onyx_default \ | |
| --name test-runner \ | |
| --env-file deployment/docker_compose/.env \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace/backend \ | |
| $CLI_VOLUME \ | |
| -e INTEGRATION_TESTS_MODE=true \ | |
| -e POSTGRES_HOST=relational_db \ | |
| -e POSTGRES_USER=postgres \ | |
| -e POSTGRES_PASSWORD=password \ | |
| -e POSTGRES_DB=postgres \ | |
| -e DB_READONLY_USER=db_readonly_user \ | |
| -e DB_READONLY_PASSWORD=password \ | |
| -e POSTGRES_POOL_PRE_PING=true \ | |
| -e POSTGRES_USE_NULL_POOL=true \ | |
| -e OPENSEARCH_HOST=opensearch \ | |
| -e REDIS_HOST=cache \ | |
| -e MODEL_SERVER_HOST=inference_model_server \ | |
| -e INDEXING_MODEL_SERVER_HOST=inference_model_server \ | |
| -e S3_ENDPOINT_URL=http://minio:9000 \ | |
| -e S3_AWS_ACCESS_KEY_ID=minioadmin \ | |
| -e S3_AWS_SECRET_ACCESS_KEY=minioadmin \ | |
| -e OPENAI_API_KEY=${OPENAI_API_KEY} \ | |
| -e ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} \ | |
| -e GATEWAY_CLIENT_TESTS_REQUIRED=${GATEWAY_CLIENTS_STRICT} \ | |
| -e EXA_API_KEY=${EXA_API_KEY} \ | |
| -e SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN} \ | |
| -e SLACK_BOT_TOKEN_TEST_SPACE=${SLACK_BOT_TOKEN_TEST_SPACE} \ | |
| -e CONFLUENCE_TEST_SPACE_URL=${CONFLUENCE_TEST_SPACE_URL} \ | |
| -e CONFLUENCE_USER_NAME=${CONFLUENCE_USER_NAME} \ | |
| -e CONFLUENCE_ACCESS_TOKEN=${CONFLUENCE_ACCESS_TOKEN} \ | |
| -e CONFLUENCE_ACCESS_TOKEN_SCOPED=${CONFLUENCE_ACCESS_TOKEN_SCOPED} \ | |
| -e JIRA_BASE_URL=${JIRA_BASE_URL} \ | |
| -e JIRA_ADMIN_USER_EMAIL=${JIRA_ADMIN_USER_EMAIL} \ | |
| -e JIRA_USER_EMAIL=${JIRA_USER_EMAIL} \ | |
| -e JIRA_API_TOKEN=${JIRA_API_TOKEN} \ | |
| -e JIRA_API_TOKEN_SCOPED=${JIRA_API_TOKEN_SCOPED} \ | |
| -e PERM_SYNC_SHAREPOINT_CLIENT_ID=${PERM_SYNC_SHAREPOINT_CLIENT_ID} \ | |
| -e PERM_SYNC_SHAREPOINT_PRIVATE_KEY="${PERM_SYNC_SHAREPOINT_PRIVATE_KEY}" \ | |
| -e PERM_SYNC_SHAREPOINT_CERTIFICATE_PASSWORD=${PERM_SYNC_SHAREPOINT_CERTIFICATE_PASSWORD} \ | |
| -e PERM_SYNC_SHAREPOINT_DIRECTORY_ID=${PERM_SYNC_SHAREPOINT_DIRECTORY_ID} \ | |
| -e GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN=${GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN} \ | |
| -e GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN_CLASSIC=${GITHUB_PERMISSION_SYNC_TEST_ACCESS_TOKEN_CLASSIC} \ | |
| -e GITHUB_ADMIN_EMAIL=${GITHUB_ADMIN_EMAIL} \ | |
| -e GITHUB_TEST_USER_1_EMAIL=${GITHUB_TEST_USER_1_EMAIL} \ | |
| -e GITHUB_TEST_USER_2_EMAIL=${GITHUB_TEST_USER_2_EMAIL} \ | |
| -e TEST_WEB_HOSTNAME=test-runner \ | |
| -e MOCK_CONNECTOR_SERVER_HOST=mock_connector_server \ | |
| -e MOCK_CONNECTOR_SERVER_PORT=8001 \ | |
| -e ENABLE_PAID_ENTERPRISE_EDITION_FEATURES=${{ matrix.edition == 'ee' && 'true' || 'false' }} \ | |
| -e ENABLE_CRAFT=true \ | |
| -e ONYX_DEV_LICENSE \ | |
| ${{ env.RUNS_ON_ECR_CACHE }}:integration-test-devcontainer-${{ github.run_id }} \ | |
| $RUN_CMD | |
| # ------------------------------------------------------------ | |
| # Always gather logs BEFORE "down". The test-runner container's | |
| # stdout (in-process api_server logs from pytest) is captured | |
| # directly in the workflow log for the "Run Integration Tests" step. | |
| - name: Dump all-container logs (optional) | |
| if: always() | |
| run: | | |
| cd deployment/docker_compose | |
| docker compose logs --no-color > $GITHUB_WORKSPACE/docker-compose.log || true | |
| - name: Upload logs | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a | |
| with: | |
| name: docker-all-logs-${{ matrix.edition }}-${{ matrix.test-dir.name }} | |
| path: ${{ github.workspace }}/docker-compose.log | |
| # ------------------------------------------------------------ | |
| onyx-lite-tests: | |
| needs: [build-devcontainer-image] | |
| permissions: | |
| id-token: write # Required for OIDC-based AWS credential exchange | |
| contents: read | |
| runs-on: | |
| [ | |
| runs-on, | |
| runner=4cpu-linux-arm64, | |
| "run-id=${{ github.run_id }}-onyx-lite-tests", | |
| "extras=ecr-cache", | |
| ] | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Setup test license | |
| uses: ./.github/actions/setup-test-license | |
| with: | |
| aws-oidc-role-arn: ${{ secrets.AWS_OIDC_ROLE_ARN }} | |
| - name: Log in to ECR pull-through cache | |
| uses: ./.github/actions/login-ecr-pullthrough-cache | |
| with: | |
| ecr-registry: ${{ vars.ECR_REGISTRY }} | |
| - name: Create .env file for Onyx Lite Docker Compose | |
| run: | | |
| cat <<EOF > deployment/docker_compose/.env | |
| ENABLE_PAID_ENTERPRISE_EDITION_FEATURES=true | |
| AUTH_TYPE=basic | |
| POSTGRES_POOL_PRE_PING=true | |
| POSTGRES_USE_NULL_POOL=true | |
| REQUIRE_EMAIL_VERIFICATION=false | |
| DISABLE_TELEMETRY=true | |
| INTEGRATION_TESTS_MODE=true | |
| EOF | |
| # The api_server runs in-process inside pytest via FastAPI TestClient | |
| # (see tests/integration/conftest.py); only Postgres is needed from | |
| # compose for Onyx Lite. | |
| - name: Start Docker containers (onyx-lite) | |
| run: | | |
| cd deployment/docker_compose | |
| docker compose -f docker-compose.yml -f docker-compose.onyx-lite.yml -f docker-compose.dev.yml up -d \ | |
| --wait --wait-timeout 300 \ | |
| relational_db | |
| id: start_docker_onyx_lite | |
| - name: Install Python deps | |
| uses: ./.github/actions/install-python-deps | |
| with: | |
| devcontainer-image: ${{ env.RUNS_ON_ECR_CACHE }}:integration-test-devcontainer-${{ github.run_id }} | |
| - name: Run Onyx Lite Integration Tests | |
| uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # ratchet:nick-fields/retry@v4.0.0 | |
| with: | |
| timeout_minutes: 20 | |
| max_attempts: 3 | |
| retry_wait_seconds: 10 | |
| command: | | |
| echo "Running onyx-lite integration tests..." | |
| docker run --rm --network onyx_default \ | |
| --name test-runner \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace/backend \ | |
| -e INTEGRATION_TESTS_MODE=true \ | |
| -e POSTGRES_HOST=relational_db \ | |
| -e POSTGRES_USER=postgres \ | |
| -e POSTGRES_PASSWORD=password \ | |
| -e POSTGRES_DB=postgres \ | |
| -e DB_READONLY_USER=db_readonly_user \ | |
| -e DB_READONLY_PASSWORD=password \ | |
| -e POSTGRES_POOL_PRE_PING=true \ | |
| -e POSTGRES_USE_NULL_POOL=true \ | |
| -e DISABLE_VECTOR_DB=true \ | |
| -e FILE_STORE_BACKEND=postgres \ | |
| -e CACHE_BACKEND=postgres \ | |
| -e AUTH_BACKEND=postgres \ | |
| -e OPENAI_API_KEY=${OPENAI_API_KEY} \ | |
| -e TEST_WEB_HOSTNAME=test-runner \ | |
| -e ONYX_DEV_LICENSE \ | |
| ${{ env.RUNS_ON_ECR_CACHE }}:integration-test-devcontainer-${{ github.run_id }} \ | |
| uv run --no-sync pytest -v --tb=short -rs tests/integration/tests/no_vectordb | |
| - name: Dump all-container logs (onyx-lite) | |
| if: always() | |
| run: | | |
| cd deployment/docker_compose | |
| docker compose -f docker-compose.yml -f docker-compose.onyx-lite.yml -f docker-compose.dev.yml \ | |
| logs --no-color > $GITHUB_WORKSPACE/docker-compose-onyx-lite.log || true | |
| - name: Upload logs (onyx-lite) | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a | |
| with: | |
| name: docker-all-logs-onyx-lite | |
| path: ${{ github.workspace }}/docker-compose-onyx-lite.log | |
| - name: Stop Docker containers (onyx-lite) | |
| if: always() | |
| run: | | |
| cd deployment/docker_compose | |
| docker compose -f docker-compose.yml -f docker-compose.onyx-lite.yml -f docker-compose.dev.yml down -v | |
| multitenant-tests: | |
| needs: [build-model-server-image, build-devcontainer-image] | |
| runs-on: | |
| [ | |
| runs-on, | |
| runner=8cpu-linux-arm64, | |
| "run-id=${{ github.run_id }}-multitenant-tests", | |
| "extras=ecr-cache", | |
| ] | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: runs-on/action@4e5f72399b6b17f2e79c511c1b38a315a64d22dc | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # ratchet:actions/checkout@v6 | |
| with: | |
| persist-credentials: false | |
| - name: Log in to ECR pull-through cache | |
| uses: ./.github/actions/login-ecr-pullthrough-cache | |
| with: | |
| ecr-registry: ${{ vars.ECR_REGISTRY }} | |
| # NOTE: `indexing_model_server` is intentionally not started. See the | |
| # integration-tests job above. | |
| - name: Start Docker containers for multi-tenant tests | |
| env: | |
| ECR_CACHE: ${{ env.RUNS_ON_ECR_CACHE }} | |
| RUN_ID: ${{ github.run_id }} | |
| run: | | |
| cd deployment/docker_compose | |
| ENABLE_PAID_ENTERPRISE_EDITION_FEATURES=true \ | |
| LICENSE_ENFORCEMENT_ENABLED=false \ | |
| MULTI_TENANT=true \ | |
| AUTH_TYPE=cloud \ | |
| REQUIRE_EMAIL_VERIFICATION=false \ | |
| DISABLE_TELEMETRY=true \ | |
| OPENAI_DEFAULT_API_KEY=${OPENAI_API_KEY} \ | |
| ONYX_MODEL_SERVER_IMAGE=${ECR_CACHE}:integration-test-model-server-test-${RUN_ID} \ | |
| DEV_MODE=true \ | |
| docker compose -f docker-compose.multitenant-dev.yml up -d \ | |
| --wait --wait-timeout 300 \ | |
| relational_db \ | |
| opensearch \ | |
| cache \ | |
| minio \ | |
| inference_model_server | |
| id: start_docker_multi_tenant | |
| - name: Install Python deps | |
| uses: ./.github/actions/install-python-deps | |
| with: | |
| devcontainer-image: ${{ env.RUNS_ON_ECR_CACHE }}:integration-test-devcontainer-${{ github.run_id }} | |
| - name: Run Multi-Tenant Integration Tests | |
| env: | |
| ECR_CACHE: ${{ env.RUNS_ON_ECR_CACHE }} | |
| RUN_ID: ${{ github.run_id }} | |
| run: | | |
| echo "Running multi-tenant integration tests..." | |
| docker run --rm --network onyx_default \ | |
| --name test-runner \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace/backend \ | |
| -e INTEGRATION_TESTS_MODE=true \ | |
| -e POSTGRES_HOST=relational_db \ | |
| -e POSTGRES_USER=postgres \ | |
| -e POSTGRES_PASSWORD=password \ | |
| -e DB_READONLY_USER=db_readonly_user \ | |
| -e DB_READONLY_PASSWORD=password \ | |
| -e POSTGRES_DB=postgres \ | |
| -e POSTGRES_USE_NULL_POOL=true \ | |
| -e OPENSEARCH_HOST=opensearch \ | |
| -e REDIS_HOST=cache \ | |
| -e MODEL_SERVER_HOST=inference_model_server \ | |
| -e INDEXING_MODEL_SERVER_HOST=inference_model_server \ | |
| -e S3_ENDPOINT_URL=http://minio:9000 \ | |
| -e S3_AWS_ACCESS_KEY_ID=minioadmin \ | |
| -e S3_AWS_SECRET_ACCESS_KEY=minioadmin \ | |
| -e S3_FILE_STORE_BUCKET_NAME=onyx-file-store-bucket \ | |
| -e OPENAI_API_KEY=${OPENAI_API_KEY} \ | |
| -e OPENAI_DEFAULT_API_KEY=${OPENAI_API_KEY} \ | |
| -e EXA_API_KEY=${EXA_API_KEY} \ | |
| -e SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN} \ | |
| -e SLACK_BOT_TOKEN_TEST_SPACE=${SLACK_BOT_TOKEN_TEST_SPACE} \ | |
| -e TEST_WEB_HOSTNAME=test-runner \ | |
| -e AUTH_TYPE=cloud \ | |
| -e MULTI_TENANT=true \ | |
| -e SKIP_RESET=true \ | |
| -e REQUIRE_EMAIL_VERIFICATION=false \ | |
| -e DISABLE_TELEMETRY=true \ | |
| -e DEV_MODE=true \ | |
| -e ENABLE_PAID_ENTERPRISE_EDITION_FEATURES=true \ | |
| -e LICENSE_ENFORCEMENT_ENABLED=false \ | |
| ${ECR_CACHE}:integration-test-devcontainer-${RUN_ID} \ | |
| uv run --no-sync pytest -v --tb=short -rs tests/integration/multitenant_tests | |
| - name: Dump all-container logs (multi-tenant) | |
| if: always() | |
| run: | | |
| cd deployment/docker_compose | |
| docker compose -f docker-compose.multitenant-dev.yml logs --no-color > $GITHUB_WORKSPACE/docker-compose-multitenant.log || true | |
| - name: Upload logs (multi-tenant) | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a | |
| with: | |
| name: docker-all-logs-multitenant | |
| path: ${{ github.workspace }}/docker-compose-multitenant.log | |
| - name: Stop multi-tenant Docker containers | |
| if: always() | |
| run: | | |
| cd deployment/docker_compose | |
| docker compose -f docker-compose.multitenant-dev.yml down -v | |
| required: | |
| # NOTE: Github-hosted runners have about 20s faster queue times and are preferred here. | |
| # This job is the single required status check for the integration suite. It | |
| # always runs so branch protection has something to wait on, and it passes | |
| # cleanly when `changes` reports no relevant paths changed (i.e. the test | |
| # matrix was legitimately skipped). | |
| runs-on: ubuntu-slim | |
| timeout-minutes: 5 | |
| needs: [changes, integration-tests, onyx-lite-tests, multitenant-tests] | |
| if: ${{ always() }} | |
| steps: | |
| - name: Check job status | |
| env: | |
| CHANGES_RESULT: ${{ needs.changes.result }} | |
| RUN_TESTS: ${{ needs.changes.outputs.integration }} | |
| INTEGRATION_RESULT: ${{ needs.integration-tests.result }} | |
| LITE_RESULT: ${{ needs.onyx-lite-tests.result }} | |
| MULTITENANT_RESULT: ${{ needs.multitenant-tests.result }} | |
| run: | | |
| # Fail closed if `changes` didn't succeed. Otherwise an empty | |
| # RUN_TESTS (which is what we'd see when `changes` failed/cancelled) | |
| # would be indistinguishable from "no relevant paths changed" and we | |
| # would incorrectly pass the required check. | |
| if [ "${CHANGES_RESULT}" != "success" ]; then | |
| echo "changes job did not succeed (result: ${CHANGES_RESULT})" | |
| exit 1 | |
| fi | |
| if [ "${RUN_TESTS}" != "true" ]; then | |
| echo "No relevant paths changed — required check passes." | |
| exit 0 | |
| fi | |
| if [ "${INTEGRATION_RESULT}" != "success" ] \ | |
| || [ "${LITE_RESULT}" != "success" ] \ | |
| || [ "${MULTITENANT_RESULT}" != "success" ]; then | |
| echo "Test results: integration-tests=${INTEGRATION_RESULT}, onyx-lite-tests=${LITE_RESULT}, multitenant-tests=${MULTITENANT_RESULT}" | |
| exit 1 | |
| fi | |
| echo "All tests passed." |