fix(executors): rotate to the next account on network throws, not just 429 #12984
Workflow file for this run
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: DAST smoke (PR) | |
| on: | |
| pull_request: | |
| branches: ["main", "release/**"] | |
| # Runner-cost guard (#8084): the CLI-bundle build alone is 6-11min; a docs-only PR | |
| # cannot change DAST behavior, so skip the whole workflow for pure docs/markdown | |
| # changes. Any code path in the diff still runs the full smoke. | |
| paths-ignore: | |
| - "docs/**" | |
| - "**/*.md" | |
| permissions: | |
| contents: read | |
| # Superseded runs on the same PR must not stack 25-minute advisory builds | |
| # (force-push storms were holding 2-3 runners each). Same group rule as quality.yml. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| dast-smoke: | |
| runs-on: ubuntu-latest | |
| # ADVISORY while this new gate matures (repo convention: advisory -> blocking). | |
| # Flip to blocking (remove continue-on-error) once it's proven stable across a few PRs. | |
| continue-on-error: true | |
| # Build CLI bundle alone varies 6-11min on GitHub-hosted runners (3 consecutive | |
| # timeouts observed on 2026-07-14 with the old 12min cap killing schemathesis | |
| # mid-run) — 25min leaves real headroom for the actual DAST steps. | |
| timeout-minutes: 25 | |
| env: | |
| JWT_SECRET: ci-build-secret-with-sufficient-length-for-validation | |
| API_KEY_SECRET: ci-api-key-secret-with-sufficient-length-aaaa | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | |
| with: | |
| node-version: "24" | |
| cache: npm | |
| - run: npm ci | |
| - name: Build CLI bundle | |
| env: | |
| OMNIROUTE_BUILD_BACKEND_ONLY: "1" | |
| run: npm run build:cli | |
| - name: Start OmniRoute | |
| env: | |
| PORT: "20128" | |
| INJECTION_GUARD_MODE: block | |
| run: | | |
| node dist/server.js > server.log 2>&1 & | |
| echo $! > server.pid | |
| for _ in $(seq 1 30); do | |
| if curl -sf http://localhost:20128/api/monitoring/health >/dev/null; then echo up; break; fi | |
| sleep 2 | |
| done | |
| - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 | |
| with: | |
| python-version: "3.12" | |
| - run: pip install schemathesis | |
| - name: Schemathesis smoke (high-risk endpoints, blocking) | |
| run: | | |
| # /api/auth/oidc/* is a BROWSER redirect flow (302 to the IdP, 302 back to | |
| # /login?oidc_error=... on every failure), not a REST endpoint: Schemathesis reads | |
| # those 302s as "the API accepted a schema-violating request" and the configured-off | |
| # 400 as "rejected a schema-compliant request". Documenting the flow in the spec is | |
| # still right (operators need it); fuzzing it is not what this smoke is for. | |
| schemathesis run docs/openapi.yaml --url http://localhost:20128 \ | |
| --include-path-regex '^/v1/(chat/completions|models)$|^/api/(auth|keys)' \ | |
| --exclude-path-regex '^/api/auth/oidc/' \ | |
| --max-examples 8 --workers 4 --checks all --max-response-time 30 \ | |
| --request-timeout 20 --suppress-health-check all --no-color | |
| - name: promptfoo injection-guard (blocking) | |
| env: | |
| OMNIROUTE_URL: http://localhost:20128 | |
| OMNIROUTE_API_KEY: not-needed-blocked-before-upstream | |
| run: npx --yes promptfoo@latest eval -c promptfooconfig.yaml --no-cache | |
| - name: Stop server | |
| if: always() | |
| run: kill "$(cat server.pid)" || true | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| if: always() | |
| with: | |
| name: dast-smoke-logs | |
| path: server.log | |
| retention-days: 7 |