ProxyWhirl Docs

Operations

Production-minded checks for docs, sources, API health, and runtime validation.

Operations

Operational checks should validate runtime surfaces, docs generation, proxy-list publication, and CI logs independently. Treat each surface as its own gate; do not call a release production-ready from one passing lane.

Production Gate Matrix

SurfaceCommandExpected result
Python qualitytask quality-gatesRuff, ty, fast tests, and coverage pass with no actionable warnings.
Expanded testsuv run pytest tests/ -q -m "not slow" --ignore=tests/benchmarks --timeout=120API, contract, property, unit, and integration coverage pass outside benchmark/slow browser lanes.
Docs generationpnpm --dir web run docs:generateGenerated Fumadocs references and JSON data match source code.
Docs lintpnpm --dir web run lintESLint exits with --max-warnings 0.
Docs unit testspnpm --dir web run test:runVitest docs/UI tests pass.
Docs buildpnpm --dir web run buildNext.js + Fumadocs build succeeds with no actionable warnings.
Strict source healthuv run proxywhirl sources --validate --fail-on-unhealthy --timeout 5 --concurrency 5Every enabled built-in source is reachable and healthy at the stable CI concurrency.
Package build.venv/bin/python -m buildWheel and sdist build with the same interpreter used for dependency install.

Docs Pipeline

pnpm --dir web run docs:generate
pnpm --dir web run lint
pnpm --dir web run test:run
pnpm --dir web run build

Run pnpm --dir web run test:e2e when browser dependencies are installed and the change affects rendered behavior, routing, or interactive docs components.

CLI Smoke

tmpdir="$(mktemp -d)"
config_path="$tmpdir/.proxywhirl.toml"
uv run python - <<PY
from pathlib import Path
from proxywhirl.config import CLIConfig, save_config

save_config(CLIConfig(encrypt_credentials=False), Path("$config_path"))
PY

uv run proxywhirl --no-lock --config "$config_path" config set max_retries 0
uv run proxywhirl --no-lock --config "$config_path" --format json config get max_retries \
  > "$tmpdir/max_retries.json"
rg '"max_retries": 0' "$tmpdir/max_retries.json"
uv run proxywhirl --no-lock --config "$config_path" pool add http://user:pass@proxy.example.com:8080
uv run proxywhirl --no-lock --config "$config_path" pool add http://proxy.example.com:8081
uv run proxywhirl --no-lock --config "$config_path" --format json pool list > "$tmpdir/pool.json"
if rg 'user|pass' "$tmpdir/pool.json"; then
  echo "credential leaked in pool list" >&2
  exit 1
fi
printf 'http://proxy.example.com:8082\n' > "$tmpdir/proxies.txt"
uv run proxywhirl --no-lock --config "$config_path" --format json import-proxies \
  "$tmpdir/proxies.txt" --format text
uv run proxywhirl --no-lock --config "$config_path" pool remove http://proxy.example.com:8081
set +e
uv run proxywhirl --no-lock --config "$config_path" --format json validate-proxy \
  http://127.0.0.1:9 --target http://example.com --timeout 0.2 > "$tmpdir/validate.json"
exit_code=$?
set -e
if [ "$exit_code" -eq 0 ]; then
  echo "expected closed-port validation to fail" >&2
  exit 1
fi
rg '"status": "UNHEALTHY"' "$tmpdir/validate.json"
uv run proxywhirl sources --validate --fail-on-unhealthy --timeout 5 --concurrency 5

The closed-port validate-proxy smoke should exit non-zero with structured UNHEALTHY output. The pool smoke should preserve credentials in the config file while keeping userinfo out of CLI output.

API Smoke

Use a temporary storage path and a disposable localhost port:

tmpdir="$(mktemp -d)"
PROXYWHIRL_STORAGE_PATH="$tmpdir/api.db" \
  uv run uvicorn proxywhirl.api:app --host 127.0.0.1 --port 8765

In another shell, verify health and readiness:

uv run python - <<'PY'
import httpx

for path in ("/api/health", "/api/ready"):
    response = httpx.get(f"http://127.0.0.1:8765{path}", timeout=5)
    if path == "/api/ready":
        response.raise_for_status()
    elif response.status_code not in {200, 503}:
        response.raise_for_status()
    payload = response.json()
    assert payload.get("status") == "success", payload
    print(path, response.status_code, payload["data"])
PY

With an empty temporary database, /api/health can report 503 with a successful unhealthy response body because no proxies are loaded yet. /api/ready should return 200. Stop the server after the smoke. Use a temporary PROXYWHIRL_API_KEY only when testing authenticated write paths; never commit or print real keys.

GitHub Actions Assurance

After pushing, monitor these runs on the target SHA:

  1. CI
  2. Security Scan
  3. Validate Proxy Sources (manual workflow_dispatch when source health is in scope)

Scan completed logs for actionable markers:

gh run view <run-id> --log | rg '##\[warning\]|##\[error\]|::warning::|::error::|DeprecationWarning|RuntimeWarning|ResourceWarning|Traceback|Token required|not valid tokenless upload'

Literal environment assignments such as PYTHONWARNINGS="ignore::UserWarning" are not emitted warnings. Codecov upload is optional and skipped when no CODECOV_TOKEN is configured; local coverage threshold enforcement and coverage artifact upload remain required.

Keep documentation generation read-only with respect to proxy runtime behavior and database schema unless a separate implementation task explicitly changes those contracts.

On this page