Skip to content

Add Java integration tests for phantom proxy tracing#4

Merged
epli2 merged 12 commits into
mainfrom
claude/add-springboot-tests-ZiHDa
Jul 6, 2026
Merged

Add Java integration tests for phantom proxy tracing#4
epli2 merged 12 commits into
mainfrom
claude/add-springboot-tests-ZiHDa

Conversation

@epli2

@epli2 epli2 commented Mar 7, 2026

Copy link
Copy Markdown
Owner

Summary

This PR adds comprehensive integration tests for phantom's proxy backend with Java applications, verifying non-invasive HTTP/HTTPS traffic capture without requiring application code changes.

Key Changes

  • Two new integration test suites:

    • proxy_springboot_integration.rs: Tests phantom's proxy tracing with a Spring Boot CommandLineRunner application that makes HTTP and HTTPS requests via JDK HttpClient, reading HTTP_PROXY automatically set by phantom
    • proxy_java_clients_integration.rs: Tests phantom's proxy with four major Java HTTP client libraries (JDK HttpClient, AsyncHttpClient, Jetty HttpClient, Apache HttpClient 5), verifying each client can be transparently traced
  • Test applications:

    • tests/apps/springboot-app/: Spring Boot application with CommandLineRunner that makes HTTP/HTTPS requests to mock backends, demonstrating proxy-aware configuration via environment variables
    • tests/apps/java-http-clients/: Plain Java CLI application testing four different HTTP client libraries with proxy configuration, each adding an x-phantom-client header for trace identification
  • Mock backend infrastructure:

    • HTTP and HTTPS (rustls-based) mock backends in both test files
    • Request routing for /api/health, /api/users (GET), and /api/users (POST) endpoints
    • Self-signed certificate generation for HTTPS testing with MITM interception
  • Test verification:

    • Validates JSONL trace output format with required fields (trace_id, span_id, timestamp_ms, request/response headers)
    • Confirms correct HTTP methods, status codes, and response bodies
    • Verifies both HTTP and HTTPS traffic capture through phantom's proxy
    • Validates per-client identification via request headers

Implementation Details

  • Tests require java (17+) and mvn on PATH; gracefully skip if unavailable
  • Applications use trust-all SSLContext to accept phantom's dynamically-generated MITM CA certificate
  • Proxy configuration is entirely environment-based (HTTP_PROXY env var), demonstrating non-invasive tracing
  • Maven builds produce fat JARs with all dependencies included for easy execution
  • Mock backends use simple TCP socket handling with HTTP/1.1 responses

https://claude.ai/code/session_01E3FVEjny7BKfgUeAGTM955

claude and others added 11 commits July 6, 2026 13:29
Adds two new integration test suites that verify phantom's proxy backend
captures traffic from JVM-based applications:

1. tests/proxy_springboot_integration.rs — tests a minimal Spring Boot
   CommandLineRunner app (phantom-springboot-client) that reads HTTP_PROXY
   (injected by phantom) and uses java.net.http.HttpClient to make 2 HTTP
   and 2 HTTPS requests. Verifies all 4 traces are captured with correct
   status codes, bodies, and required trace fields.

2. tests/proxy_java_clients_integration.rs — tests four major Java HTTP
   client libraries (JDK HttpClient, AsyncHttpClient, Jetty HttpClient,
   Apache HttpClient 5) in a single plain-Java CLI app. Each client adds
   an x-phantom-client header for trace identification. Verifies 8 traces
   (4 clients × 2 schemes).

Both apps use a trust-all SSLContext for HTTPS MITM capture and are built
with mvn package before the test runs. Tests skip gracefully when java or
mvn are not on PATH.

https://claude.ai/code/session_01E3FVEjny7BKfgUeAGTM955
Spring Boot adds unnecessary framework overhead. The java-http-clients
integration test covers the same proxy-capture scenarios using four major
Java HTTP client libraries (JDK HttpClient, AsyncHttpClient, Jetty
HttpClient, Apache HttpClient 5) without the Spring Boot dependency.

https://claude.ai/code/session_01E3FVEjny7BKfgUeAGTM955
- Use wagon transport for Maven 3.9+ so settings.xml proxy auth works
- Skip mvn package if JAR already built (faster re-runs)
- Fix Java compile errors: add ProxyServer import, remove setSslContext
  from AsyncHttpClient (use setUseInsecureTrustManager only), replace
  TrustAllStrategy.INSTANCE with lambda for HttpClient 5 compatibility

https://claude.ai/code/session_01E3FVEjny7BKfgUeAGTM955
Instead of requiring the Java test app to read HTTP_PROXY and configure
each HTTP client library explicitly, phantom now injects the proxy
settings transparently via JAVA_TOOL_OPTIONS when the child command is
a java/javaw executable.

Changes:
- src/main.rs: add is_java_command() detection; when spawning a Java
  process, append -Dhttp.proxyHost, -Dhttps.proxyHost, -Dhttp.proxyPort,
  -Dhttps.proxyPort and -Dhttp.nonProxyHosts= to JAVA_TOOL_OPTIONS so
  any JVM application is proxied without app-level changes
- Client.java: remove proxyAddress() and all explicit proxy setup;
  remove AsyncHttpClient and Jetty (they bypass JVM ProxySelector);
  keep JDK HttpClient (uses ProxySelector.getDefault() automatically)
  and Apache HttpClient 5 with SystemDefaultRoutePlanner
- pom.xml: remove async-http-client, jetty-client, slf4j-nop deps
- proxy_java_clients_integration.rs: update to 2 clients × 2 schemes
  = 4 traces; update comment to reflect transparent tracing concept

https://claude.ai/code/session_01E3FVEjny7BKfgUeAGTM955
- Introduce Phantom Java Agent to force global ProxySelector and bypass SSL verification (trust-all).
- Automatically inject -javaagent via JAVA_TOOL_OPTIONS when spawning Java processes in Rust.
- Extend Java integration tests to cover 5 major clients: JDK HttpClient, Apache HC 5, OkHttp, Netty, and Jetty.
- Update documentation with Java usage instructions.
- Update .gitignore to exclude Java build artifacts.
- Use include_bytes! to embed phantom-java-agent.jar at compile time.
- Extract JAR to a temporary file at runtime when tracing Java processes.
- Ensure the temporary JAR is cleaned up after the process exits using RAII.
- This enables a single-binary distribution for both Node.js and Java observability.
- Add build.rs to automatically compile and package the Java Agent JAR.
- Rerun build.rs only if the Java source code changes.
- This ensures the embedded phantom-java-agent.jar is always up-to-date and included in the binary.
@epli2 epli2 force-pushed the claude/add-springboot-tests-ZiHDa branch from 8ded14c to bed9559 Compare July 6, 2026 13:32
- crates/phantom-agent/src/lib.rs: rewrite two HTTP/2 frame-processing loops
  as while-let and collapse a nested if into the match guard, per clippy's
  own suggested fixes (while_let_loop, collapsible_match). This pre-existing
  code was clean under the toolchain previously cached locally but is flagged
  by CI's newer stable clippy.
- build.rs: write an empty placeholder phantom-java-agent.jar when javac is
  not on PATH. src/main.rs embeds this file unconditionally via
  include_bytes!, so its absence broke compilation entirely in JDK-less
  environments (e.g. the Docker integration-test image), not just the
  -javaagent feature. Verified by building with a PATH that hides javac/jar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EgPcomgY5nj8RuU8V1G82Y
@epli2 epli2 merged commit 7c68c07 into main Jul 6, 2026
3 checks passed
epli2 pushed a commit that referenced this pull request Jul 6, 2026
Analyze current implementation and open PRs (#2, #4), redefine phantom's
concept as a local-first API development toolbox (observe / perturb /
record-replay / spec-gen), and lay out a 5-phase roadmap (P0-P4) with
per-task dependencies, implementation steps, acceptance criteria, and an
LLM-agent working protocol.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EgPcomgY5nj8RuU8V1G82Y
epli2 pushed a commit that referenced this pull request Jul 6, 2026
…(P1-6)

- tests/apps/python-app/client.py + tests/proxy_python_integration.rs: Python
  3 stdlib (urllib.request) HTTP+HTTPS capture, verified working out of the
  box via phantom's auto-injected HTTP_PROXY/HTTPS_PROXY + SSL_CERT_FILE.
- tests/apps/go-app/client.go + tests/proxy_go_integration.rs: Go net/http
  HTTP capture, verified working — scoped to HTTP only after discovering two
  real limitations while building this (documented, not silently worked
  around):
    1. Go's net/http.ProxyFromEnvironment unconditionally refuses to proxy
       requests to "localhost" or any loopback IP, regardless of
       HTTP_PROXY/HTTPS_PROXY/NO_PROXY — confirmed directly against go1.24.
       Not a phantom bug; the test backend binds to a dynamically-discovered
       non-loopback address so the request actually reaches the proxy.
    2. phantom's MITM leaf certificates only ever carry a DNS-name SAN, never
       an IP SAN, even for IP-literal CONNECT targets — so any client with
       strict RFC 6125 IP-literal verification (Go's crypto/tls confirmed;
       likely others) rejects the cert. This is a phantom/hudsucker gap
       affecting IP-literal HTTPS targets for every language, not Go-specific;
       tracked as future work rather than fixed here.
- docs/compatibility.md: new runtime support matrix (Node/curl/Python
  verified; Go verified with the HTTP-only caveat; Java per PR #4; several
  runtimes honestly marked untested) plus write-ups of both limitations
  above with the exact repro. Linked from README and AGENTS.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EgPcomgY5nj8RuU8V1G82Y
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.

2 participants