Skip to content

Global API traffic control: rate limiting, circuit breakers, retry policies (v1.0 - comprehensive) #543

Global API traffic control: rate limiting, circuit breakers, retry policies (v1.0 - comprehensive)

Global API traffic control: rate limiting, circuit breakers, retry policies (v1.0 - comprehensive) #543

Workflow file for this run

name: CI
on:
push:
branches: [main]
paths-ignore:
- "**/*.md"
- "docs/**"
- "modules/**"
pull_request:
branches: [main]
paths-ignore:
- "**/*.md"
- "docs/**"
- "modules/**"
workflow_dispatch:
jobs:
forbidden-paths:
name: Forbidden Paths Guard
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Ensure docs_dev is not changed in branch
run: |
python3 scripts/block_docs_dev_tracked.py
- name: Ensure core does not import module code directly
run: |
set -euo pipefail
if rg -n '\.\./\.\./\.\./modules/' web-next venom_core scripts \
--glob '!web-next/lib/generated/optional-modules.generated.ts' \
--glob '!web-next/scripts/generate-optional-modules.mjs'; then
echo "Forbidden direct import/path to modules/ found in core repo code."
exit 1
fi
backend-lite:
name: Backend lite (pytest)
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [forbidden-paths]
env:
CI: "true"
PYTHONUNBUFFERED: "1"
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-ci-lite.txt
- name: Install lightweight system tools
run: |
sudo apt-get update
sudo apt-get install -y ripgrep
- name: Run backend lite hard gate + Sonar new-code coverage
timeout-minutes: 10
run: |
set -o pipefail
# Global per-test timeout guard: prevents infinite hangs/deadlocks from
# stalling the whole job. Timeout must still be tuned to avoid false positives.
export PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} --timeout=120 --timeout-method=thread"
make audit-ci-lite
mkdir -p test-results/sonar
DIFF_BASE="origin/main"
if [ "${{ github.event_name }}" = "push" ] && [ -n "${{ github.event.before }}" ] && [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]; then
DIFF_BASE="${{ github.event.before }}"
elif [ "${{ github.event_name }}" = "pull_request" ] && [ -n "${{ github.base_ref }}" ]; then
DIFF_BASE="origin/${{ github.base_ref }}"
fi
echo "Using NEW_CODE_DIFF_BASE=${DIFF_BASE}"
make check-new-code-coverage \
NEW_CODE_INCLUDE_BASELINE=1 \
NEW_CODE_AUTO_INCLUDE_CHANGED=1 \
NEW_CODE_BASELINE_GROUP=config/pytest-groups/ci-lite.txt \
NEW_CODE_TEST_GROUP=config/pytest-groups/sonar-new-code.txt \
NEW_CODE_COV_TARGET=venom_core \
NEW_CODE_COVERAGE_MIN=0 \
NEW_CODE_CHANGED_LINES_MIN=80 \
NEW_CODE_DIFF_BASE="${DIFF_BASE}" \
| tee test-results/sonar/backend-lite.log
- name: Upload backend Sonar artifacts
uses: actions/upload-artifact@v4
with:
name: sonar-backend-reports
path: test-results/sonar/**
if-no-files-found: error
frontend-lite:
name: Frontend lite (lint)
runs-on: ubuntu-latest
timeout-minutes: 12
needs: [forbidden-paths]
env:
CI: "true"
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "18.19.1"
cache: npm
cache-dependency-path: web-next/package-lock.json
- name: Install dependencies
run: npm --prefix web-next ci
- name: Lint
timeout-minutes: 5
run: npm --prefix web-next run lint
- name: Unit Tests
timeout-minutes: 5
run: npm --prefix web-next run test:unit
openapi-contract:
name: OpenAPI Contract (export + TS codegen)
runs-on: ubuntu-latest
timeout-minutes: 12
needs: [forbidden-paths]
env:
CI: "true"
PYTHONUNBUFFERED: "1"
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install backend dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-ci-lite.txt
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "18.19.1"
- name: Export OpenAPI
run: |
mkdir -p test-results/openapi
python3 scripts/export_openapi.py --output test-results/openapi/openapi.json
- name: Generate TypeScript types from OpenAPI
run: |
npx --yes openapi-typescript@7.10.1 test-results/openapi/openapi.json -o test-results/openapi/api-types.d.ts
- name: Upload OpenAPI contract artifacts
uses: actions/upload-artifact@v4
with:
name: openapi-contract
path: test-results/openapi/**
if-no-files-found: error
sonar:
name: SonarCloud Scan
runs-on: ubuntu-latest
timeout-minutes: 20
needs: [backend-lite, frontend-lite, openapi-contract]
# secrets context is not available in job-level `if`, so gate by event/repo only.
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
env:
CI: "true"
PYTHONUNBUFFERED: "1"
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Download backend Sonar artifacts
uses: actions/download-artifact@v4
with:
name: sonar-backend-reports
path: test-results/sonar
- name: SonarCloud Scan
uses: SonarSource/sonarqube-scan-action@bfd4e558cda28cda6b5defafb9232d191be8c203
with:
args: >
-Dsonar.newCode.referenceBranch=main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}