Skip to content

feat(proxy): request body cap + per-tenant rate limit plumbing #45

feat(proxy): request body cap + per-tenant rate limit plumbing

feat(proxy): request body cap + per-tenant rate limit plumbing #45

Workflow file for this run

# E2E PR-Gate Workflow (Loop E2E-L9 of #91, issue #99).
#
# Fast must-green subset of the adversarial test framework. Runs on
# every PR that touches the proxy, security analyzers, e2e harness, the
# corpus, or the workflow file itself. Wall-clock target ≤ 5 min;
# 10 min hard cap per L9 acceptance.
#
# Selection: scenarios tagged `pr-gate` (20 of 50 today). Drives the
# `--tag=pr-gate` filter in `tests/e2e/conftest.py::pytest_addoption`.
#
# The full corpus runs nightly (Loop E2E-L10, e2e-nightly.yml). Adding
# new must-green scenarios = tag them `pr-gate`; the workflow picks
# them up on the next PR with no edits here.
name: E2E PR Gate
on:
pull_request:
paths:
- 'crates/llmtrace-proxy/**'
- 'crates/llmtrace-security/**'
- 'crates/llmtrace-core/**'
- 'crates/llmtrace-storage/**'
- 'config*.yaml'
- 'benchmarks/attacks/**'
- 'tests/e2e/**'
- 'scripts/e2e/**'
- 'requirements-e2e.txt'
- 'Cargo.lock'
- 'pytest.ini'
- '.github/workflows/e2e-pr.yml'
workflow_dispatch:
# Cancel in-flight runs when a PR is force-pushed; only the latest
# state matters and the proxy build is the slow step.
concurrency:
group: e2e-pr-${{ github.ref }}
cancel-in-progress: true
jobs:
e2e-pr-gate:
name: E2E PR Gate
runs-on: ubuntu-latest
# 10-minute hard cap per L9 acceptance. If we hit this, the
# `pr-gate` tag set is the knob: drop scenarios from it rather
# than raising the cap. The full corpus is nightly's job.
timeout-minutes: 10
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: "3.12"
- name: Install Python deps
run: python3 -m pip install -r requirements-e2e.txt
# E2E-012 from L2: validate the corpus before we boot anything.
# Cheap (<1 s) and saves 5+ min when a malformed YAML lands.
- name: Validate scenarios
run: python3 scripts/e2e/validate_scenarios.py
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
# protoc is required by llmtrace-proto build.rs.
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
# Cargo cache keyed on Cargo.lock per L9 spec. The release build of
# the proxy is the dominant cost (~3 min cold, <30 s warm).
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-e2e-pr-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-e2e-pr-
# Release build of the proxy only — the cascade fixture spawns
# this binary. Avoid `cargo build --workspace` which would compile
# bindings (nodejs, python, wasm) we don't need at runtime.
- name: Build llmtrace-proxy (release)
run: cargo build --release --manifest-path crates/llmtrace-proxy/Cargo.toml
# Run the pr-gate subset against the in-process FastAPI mock
# upstream. Mock-only here because real-LLM cost belongs in
# nightly (L10). JUnit XML lets the Actions UI render per-scenario
# rows on a failure.
- name: Run pr-gate scenarios
run: |
python3 -m pytest tests/e2e/test_cascade.py \
--tag=pr-gate \
-v \
--junit-xml=tests/e2e/.logs/junit-pr-gate.xml \
--color=yes
# Upload artifacts unconditionally so a failed run still gives the
# triager something to download. Logs include proxy stdout/stderr
# captured by the conftest fixture, which is the highest-ROI thing
# to read first when a scenario fails.
- name: Upload junit + proxy logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: e2e-pr-gate-artifacts
path: |
tests/e2e/.logs/
if-no-files-found: warn
# Help the next reader if the job times out. The Actions UI shows
# "the operation was canceled" on timeout-minutes hit; this echoes
# the actionable knob into the same step output.
- name: Timeout helper
if: cancelled()
run: |
echo "::error::PR-gate exceeded 10 min cap."
echo "Knob: edit benchmarks/attacks/**/*.yaml to drop"
echo "scenarios from the 'pr-gate' tag set, or move slow"
echo "scenarios to the nightly job (e2e-nightly.yml, L10)."
exit 1