Skip to content

LCORE-1253: Add e2e proxy and TLS networking tests#2

Open
max-svistunov wants to merge 4 commits into
lcore-1253-networking-client-wiringfrom
lcore-1253-e2e-testing-proxies
Open

LCORE-1253: Add e2e proxy and TLS networking tests#2
max-svistunov wants to merge 4 commits into
lcore-1253-networking-client-wiringfrom
lcore-1253-e2e-testing-proxies

Conversation

@max-svistunov

Copy link
Copy Markdown
Owner

Description

Add end-to-end proxy and TLS test infrastructure. This is PR 3 of 3 for LCORE-1253. Depends on PR 2.

What: Adds Behave e2e test feature for proxy/TLS scenarios, test proxy infrastructure (tunnel + interception proxy implementations), integration tests, and documentation updates.

Test infrastructure:

  • TunnelProxy — async HTTP CONNECT tunnel proxy for testing proxy routing. Tracks CONNECT count and target hosts.
  • InterceptionProxy — async TLS-intercepting (MITM) proxy using trustme CA for testing interception proxy scenarios. Generates per-target certificates.
  • Both are Python-only (no Docker dependency) and run in background threads during tests.

Test scenarios:

  • 2 active Behave scenarios: IntermediateType and ModernType TLS profiles verified against running stack
  • 3 @Skip Behave scenarios: tunnel proxy, interception proxy, unreachable proxy — skipped because Llama Stack is HTTP-only locally (CONNECT tunneling requires HTTPS endpoints). These are ready for use when HTTPS endpoints become available.
  • 6 integration tests verifying build_httpx_client with proxy, no_proxy, TLS profile, skip-verification, and empty configs

Reviewer guidance:

  • The @Skip scenarios and the proxy infrastructure (~600 lines) are investment for future HTTPS endpoint support. Proxy routing correctness is verified by unit tests (test_networking.py: _host_matches_no_proxy, _build_no_proxy_mounts, get_aiohttp_proxy bypass) and integration tests.
  • The trustme dev dependency is lightweight (~200 lines, well-maintained) and used only for test CA generation.
  • Step definitions generate configs dynamically (overriding Llama Stack URL from env vars, stripping MCP servers) rather than using static config files.

Type of change

  • End to end tests improvement
  • Integration tests improvement
  • Documentation Update

Tools used to create PR

  • Assisted-by: Claude Opus 4.6
  • Generated by: Claude Opus 4.6

Related Tickets & Documents

  • Related Issue # LCORE-1178
  • Closes # LCORE-1253

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

Run e2e proxy tests against full stack:

E2E_LSC_HOSTNAME=localhost E2E_LSC_PORT=8080 E2E_LLAMA_HOSTNAME=localhost \
  E2E_LLAMA_PORT=8321 FAISS_VECTOR_STORE_ID=test-vector-store \
  uv run behave tests/e2e/features/proxy.feature --tags=-skip --no-capture

Result: 1 feature passed, 2 scenarios passed, 3 skipped (as expected)

Introduce comprehensive end-to-end tests verifying that the Lightspeed
Stack correctly routes outgoing traffic through proxies and enforces
TLS security profiles.

Test proxy infrastructure (tests/e2e/proxy/):
- TunnelProxy: Async HTTP CONNECT tunnel proxy that creates TCP tunnels
  for HTTPS traffic without inspecting it. Tracks connect_count and
  last_connect_target for verification.
- InterceptionProxy: Async TLS-intercepting (MITM) proxy using trustme
  CA to generate per-target server certificates. Simulates corporate
  SSL inspection proxies. Tracks intercepted_hosts for verification.

Behave feature file (tests/e2e/features/proxy.feature):
- AC1: Traffic routes through configured tunnel proxy (verified via
  proxy connect_count).
- AC2: Interception proxy works with correct trustme CA certificate
  (verified via intercepted_hosts).
- AC3: TLS security profiles (IntermediateType, ModernType) are applied
  to outgoing connections.
- Negative: Connection fails when proxy is unreachable.

Step definitions (tests/e2e/features/steps/proxy.py):
- Proxy lifecycle management (start/stop in background threads).
- Dynamic config generation (writes temporary YAML with proxy settings,
  restarts lightspeed-stack with new config).
- Proxy verification assertions.

All proxy tests are tagged @Proxy and @skip-in-library-mode (proxies
only apply to server-mode connections).

Added trustme>=1.2.1 to dev dependencies.
Updated docs/e2e_testing.md with new proxy tags.
Updated docs/e2e_scenarios.md with proxy test scenarios.
Updated tests/e2e/test_list.txt to include proxy.feature.
Add integration tests that verify build_httpx_client creates correctly
configured clients with proxy, TLS profile, and skip-verification
settings.

Mark Behave proxy-restart scenarios as @Skip: the full-stack proxy
restart scenarios require HTTPS endpoints for CONNECT tunneling, but
Llama Stack runs on HTTP locally. Proxy routing correctness is
verified by the integration tests instead.

Fix _restart_lightspeed_stack to pass OPENSSL_CONF="" and log to file
for debugging.

Fix _load_config to override Llama Stack URL from environment vars
and strip MCP servers for proxy tests (Docker hostnames).
Replace async tunnel proxy integration tests with simpler synchronous
tests that verify build_httpx_client creates correctly configured
clients. The async proxy fixture had event loop cleanup issues causing
test hangs in CI-like sequential runs.

Proxy routing correctness is covered by unit tests for no_proxy
pattern matching and httpx mount construction.
Close file handle in proxy step definitions (was passed to Popen
without closing).

Remove unused proxy config path mapping from environment.py (step
definitions generate configs dynamically).
max-svistunov added a commit that referenced this pull request Apr 30, 2026
Apply CodeRabbit's actionable comments and the per-comment nits:

1. PoC results section in spike doc previously listed paths under
   poc-results/ that are deleted before merge per howto-run-a-spike.md
   step 10, leaving broken links in the merged document. Replace the
   file list with a self-contained summary of what the PoC proved
   plus the heading-degradation finding, and a note pointing future
   readers at the PR diff if the raw artifacts are ever needed.

2. Drop the reference to docs/local-stack-testing.md (a local-only
   file, never committed to the repo).

3. Replace fragile line-numbered references (document_processor.py:75,
   :87, byok_guide.md ~106-118) with stable symbol anchors:
   _BaseDB.__init__, _LlamaStackDB.__init__, "Knowledge Sources"
   subsection, "Step 1" subsection. Line numbers rot; section names
   and symbol names rot less.

4. Spec doc now instructs the implementation ticket to extract the
   ("markdown", "html", "pdf") predicate to a single
   MARKDOWN_COMPATIBLE_DOC_TYPES: Final[tuple[str, ...]] constant in
   document_processor.py and reference it from both call sites,
   instead of duplicating the tuple. JIRA #1 scope updated to match.

5. Add R7: PDFReader.load_data emits a logger.warning when its docling
   output is empty / under a small threshold (a likely indicator of a
   scanned PDF given R5's no-OCR scope). Threshold is a module-level
   Final[int] constant. JIRA #1 scope and JIRA #2 test patterns
   updated to require coverage via caplog. Surfacing the silent-
   degradation case in custom_processor.py logs costs nothing and
   makes the OCR-needed signal visible.

Plus the two reviewer nits worth carrying into JIRA #1:

- Use docling's TableFormerMode.ACCURATE enum, not the string literal
  "accurate"; both work via Pydantic coercion but the enum is
  type-checked.
- Mirror HTMLReader's choice on whether to call super().__init__();
  llama-index's BaseReader does not require it but symmetry between
  the two readers is preferred.

The spec doc changelog records this revision and its trigger (the
PR lightspeed-core#1598 CodeRabbit review).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant