Commit 71832e2
authored
chore(deps): update dependency org.mock-server:mockserver-netty-no-dependencies to v7.3.0 (#2262)
This PR contains the following updates:
| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
|
[org.mock-server:mockserver-netty-no-dependencies](https://www.mock-server.com)
([source](https://redirect.github.com/mock-server/mockserver-monorepo))
| `7.2.0` → `7.3.0` |

|

|
---
### Release Notes
<details>
<summary>mock-server/mockserver-monorepo
(org.mock-server:mockserver-netty-no-dependencies)</summary>
###
[`v7.3.0`](https://redirect.github.com/mock-server/mockserver-monorepo/blob/HEAD/changelog.md#730---2026-07-01)
##### Added
- **Typed client methods for control-plane operations that previously
needed a hand-written REST call.** The
client libraries gain first-class methods for clock control (freeze /
advance / reset / status), metrics
(the JSON counter snapshot and the Prometheus scrape), configuration
read/update, Pact import / export / verify,
the file store (store / retrieve / list / delete), HAR and Postman
import, the high-level operating mode
(`SIMULATE` / `SPY` / `CAPTURE`), and generating expectations from a
WSDL — so these no longer require a manual
`PUT /mockserver/…` request. Rolling out across the Java, Node, Python,
Ruby, Go, .NET, Rust and PHP clients.
##### Security
- **Fixture redaction now also masks credentials in query strings and
streamed bodies, and fails closed on
unparseable secrets.** When redacting recorded traffic (HAR/Postman
imports, the LLM optimisation report, the
MCP capture tools) the redactor previously only masked sensitive headers
and named JSON body fields. It now also
(a) masks the values of credential-bearing query parameters by default
(such as `key`, `api_key`, `apikey`,
`access_token`, `token`, `signature`, `sig`, and the AWS SigV4
`X-Amz-Signature`/`X-Amz-Security-Token`) —
e.g. Gemini's `?key=` API key; (b) redacts configured fields inside each
Server-Sent-Events `data:` payload of
a streamed body, leaving non-JSON markers such as `[DONE]` intact (and
failing closed on a `data:` payload it
cannot parse that still mentions a configured field); and (c) when a
body is configured for field redaction but
cannot be parsed yet still mentions a configured field name, replaces
the whole body rather than risk leaking it.
Ordinary unstructured bodies (plain text, HTML, decoded binary) that
mention no configured field are left
unchanged.
- **A2A client builders: the custom-handler regex `messagePattern` is
now escaped completely.** Every client
library (Java, Node, Python, Ruby, Go, Rust, PHP, .NET) inlines
`messagePattern` into a JSONPath `=~ /…/` regex
literal but previously escaped only the `/` delimiter, so a pattern
ending in a lone backslash (or containing
`\/`) could escape the closing delimiter and break out of the regex
literal into the surrounding JSONPath/JSON
(CodeQL `rb/incomplete-sanitization`). The escaping now preserves valid
regex escape sequences (e.g. `\d`) while
neutralising the delimiter-breakout; normal patterns are unaffected.
- **Dashboard load-scenario report download now validates the URL
scheme.** The "download report" action passed a
URL assembled from the user-configured connection to `window.open`
without checking its scheme; it now opens the
report only when the URL resolves to `http`/`https`, ruling out
`javascript:`/`data:` redirection (CodeQL
`js/client-side-unvalidated-url-redirection`).
- **`/bind` and `/stop` now honour control-plane
authentication/authorization.** These mutating lifecycle
endpoints were serviced before the auth gate; they now require the same
control-plane auth as
`/mockserver/configuration`. Default deployments with no control-plane
auth configured are unaffected, and
`/status` / `/ready` remain open for health probes. Closes the
lifecycle-endpoint gap noted in 7.2.0.
- **MCP tool calls now honour control-plane authorization.** With
`controlPlaneAuthorizationEnabled`, each MCP
tool is classified read vs mutate (fail-closed) and checked against the
same role model as the HTTP control
plane, so a read-only principal can no longer invoke mutating MCP tools
(create/clear/reset/…). Default
(authorization disabled) behaviour is unchanged; enforced across HTTP
and HTTP/3, single and batch. Closes
the per-tool MCP gap noted in 7.2.0.
- **Control-plane JWT validation cross-request race fixed.** A single
shared `JWTValidator` reconfigured the
Nimbus processor (key selector + claims verifier) on every call, so
concurrent control-plane requests could be
verified against another request's policy. The processor is now
configured once and `validate()` is stateless.
- **Remote JWKS / OIDC discovery fetches are now bounded.** JWKS-key-set
and OIDC discovery-document fetches on
the authentication path used the JOSE library defaults (infinite
connect/read timeout, no size limit); they now
use finite timeouts and a size cap, so a slow or hostile
identity-provider endpoint can no longer hang the auth
path or be used as an amplification vector.
- **Velocity templates can no longer fetch arbitrary URLs or read local
files.** The Apache Velocity
`ImportTool` (which exposes `$import.read(url|file)`) was registered in
the template toolbox; it has been
removed, closing an SSRF / local-file-disclosure vector in response
templates.
- **mTLS control-plane authentication rejects expired client
certificates.** Client-certificate authentication
validated only that the certificate chained to the configured CA; it now
also enforces the certificate
validity window, so an expired or not-yet-valid (but correctly signed)
client certificate is rejected.
- **Mock OIDC client-secret comparison is now constant-time.**
##### Added
##### Load injection, chaos & SRE
- **Chaos experiments can assert an SLO and emit a verdict.** A chaos
experiment may now carry an optional
`sloCriteria`; on termination MockServer attaches a terminal
`experimentVerdict` (`PASS` / `FAIL` /
`INCONCLUSIVE`) evaluated strictly over the experiment's window — `PASS`
only if every objective held
throughout, `FAIL` on any breach or auto-halt, `INCONCLUSIVE` below the
minimum sample count. Turns
"inject faults" into "verify resilience held."
- **SLO-breach auto-halt for chaos experiments.** An experiment carrying
`sloCriteria` is halted immediately
(status `halted_by_slo_breach`, verdict `FAIL`) when an SLO objective is
breached mid-run. No behaviour
change when `sloCriteria` is absent. The dashboard's chaos panel now
shows the terminal `experimentVerdict`
(PASS / FAIL / INCONCLUSIVE) with per-objective observed-vs-threshold
detail.
##### Request matching & response generation
- **JavaScript response templates now have a configurable execution
timeout.** A runaway or malicious
JavaScript template (for example one containing an infinite loop) could
previously pin the data-plane
worker thread handling that request indefinitely. A new
`javascriptTemplateExecutionTimeout` property
(milliseconds) caps how long a template may run; on expiry a watchdog
cancels the evaluation and the
request fails fast with a clear, logged timeout error. The default is
`5000` (5 seconds), far longer
than any legitimate template needs. Set it to `0` (or a negative value)
to disable the timeout and
restore the previous unbounded behaviour. NOTE: this introduces a
bounded behaviour change — templates
that genuinely run longer than 5 seconds (previously allowed) will now
be cancelled unless the timeout
is raised or disabled.
- **Mustache response templates can now read scenario state by name.**
Velocity
(`$scenario.get('orderId')`) and JavaScript (`scenario.get('orderId')`)
could already read
scenario/captured state in a response template; the Mustache engine now
exposes the same through a
section lambda — `{{#scenario.get}}orderId{{/scenario.get}}`, where the
state name is the section
body (jmustache cannot pass a method argument inline the way Velocity
and JavaScript can). This
completes `capture` → template value reuse across all three template
engines, so an id captured
from one request can be returned in the response body of a later request
regardless of template
engine. Documented on the Stateful Scenarios page with a per-engine
example.
- **Closest-match hint on unmatched requests**
(`closestMatchHintEnabled`, default **on**). When a request
matches no expectation, the `404` response now carries a compact,
length-bounded
`x-mockserver-closest-match-hint` header naming the closest expectation
and the first field that differed —
answering "why didn't my mock match?" without enabling verbose
diagnostics. Set `closestMatchHintEnabled=false`
to suppress. (The opt-in `attachMismatchDiagnosticToResponse`, which
adds a full JSON diagnostic body, is
unchanged and still off by default.)
##### OpenAPI & contract testing
- **Validate recorded traffic against an OpenAPI spec** (`PUT
/mockserver/trafficValidate`). A new
control-plane endpoint validates the request/response traffic MockServer
has already recorded against a
provided OpenAPI spec (URL, file path, or inline), returning a
structured pass/fail report
(`totalRequests` / `passed` / `failed` / `allPassed` plus per-request
`matchedOperation`, `requestErrors`,
and `responseErrors`) — mirroring the `/contractTest` report. The
endpoint is gated by the same
control-plane authentication as its siblings, and a spec URL is fetched
only after passing the same SSRF
policy enforced on proxy/forward paths.
- **Java client helpers for contract testing & Pact.** The Java
`MockServerClient` now exposes fluent, typed
methods for the contract-testing endpoints: `contractTest(spec,
baseUrl[, operationId])`,
`trafficValidate(spec)`, `pactImport(json)`, `pactExport(consumer,
provider)`, and `pactVerify(json)`. The
contract-test and traffic-validation reports parse into typed
`ContractReport` / `ContractResult` objects so
callers no longer hand-roll raw HTTP.
- **Per-import realistic example generation.** OpenAPI imports can now
request realistic (Datafaker) example
values for a single import via a `"realisticValues": true` entry in the
reserved `__generationOptions__`
map (alongside the existing `seed` and `fieldOverrides` options),
without changing the global
`generateRealisticExampleValues` configuration. When the entry is
absent, behaviour is unchanged and the
global default still applies.
##### Dashboard UI
- **New "MCP Health" dashboard panel.** When a coding-assistant CLI is
proxied through MockServer, its MCP
servers (e.g. `chrome-devtools`, `devbot`) are frequently the real
latency bottleneck. The panel aggregates
captured MCP (JSON-RPC) traffic per server and shows, worst-first, each
server's call count, error count and
rate (JSON-RPC errors or non-2xx responses), median / p95 / max latency,
and its slowest method — with slow
(≥5s) and erroring servers flagged — so it is obvious which MCP server
is stalling, rather than guessing.
- **Anonymous, cookieless dashboard usage analytics (PostHog Cloud
EU).** The dashboard reports coarse, enumerated usage events
(`app_open`, `view_change`, `feature_used`, `error_shown`) to a
cookieless, EU-hosted PostHog project to help improve the UI. No request
URLs, hostnames, headers, bodies, or expectation data are ever sent, and
no tracking cookie is set. The **official Docker images** ship with this
enabled; it is **inactive in any build without
`dashboardAnalyticsEndpoint` + `dashboardAnalyticsKey`** (so plain
JARs/WARs and source/fork builds send nothing). Disable globally with
`dashboardAnalyticsEnabled=false` (or
`MOCKSERVER_DASHBOARD_ANALYTICS_ENABLED=false`); respects Do Not Track,
Global Privacy Control, and a per-browser opt-out banner. See [dashboard
privacy](https://www.mock-server.com/mock_server/dashboard_privacy.html).
- **Official binary launcher bundles now also report anonymous
cookieless dashboard usage analytics**, joining the Docker images and
Helm deployments. The plain downloadable JAR and any
embedded/library/dependency use remain inert (no endpoint or key
configured). Analytics events from all official artefacts now include a
`distribution` label (from the new `dashboardAnalyticsDistribution`
config property) identifying which artefact produced the event
(`docker-standard`, `docker-graaljs`, `docker-clustered`, `helm`, or
`binary`); values outside the closed allow-list are normalised to
`unknown` — free text is never forwarded.
- **SLO verification dashboard panel.** A new dashboard view authors
service-level objectives (latency
p50/p95/p99, error-rate) and runs them against the existing
`/mockserver/verifySLO` endpoint, showing
observed-vs-threshold per objective and an overall PASS / FAIL /
INCONCLUSIVE verdict.
- **Dashboard remembers where you were.** The active view and per-panel
search/filter terms persist across
reloads, and the view is reflected in the URL hash (e.g. `#/contract`)
so views are linkable. A first visit
still opens Get Started.
- **Dashboard search-operator hints.** The search box now advertises its
operators (`status:>=400`,
`method:POST`, `path:/api/*`, `/regex/`) via the placeholder and an
accessible help tooltip.
##### Client libraries
- **All client libraries now expose the full load-scenario surface.**
The Java, Node, Python, Ruby, Go,
.NET, PHP, and Rust clients gained the new scenario fields
(`thresholds`, `abortOnFail`, `abortGraceMillis`,
`pacing`, `feeder`, `stepSelection`, per-step `captures`/`weight`,
profile `shape`), the new run-status
fields (`p999Millis`, `droppedIterations`, `verdict`,
`abortedByThreshold`, `thresholdResults`), and three
new methods — `getLoadScenarioReport` (with optional `junit` format),
`generateLoadScenarioFromOpenAPI`,
and `generateLoadScenarioFromRecording`.
- **Fluent `when().respond()` DSL in the Node client.** The Node client
now offers a chainable
`when(request).respond(response)` — plus `.forward()`, `.error()`,
`.callback()`, and
`.withTimes()` / `.withTimeToLive()` / `.withPriority()` builders —
mirroring the Java client, alongside the
existing procedural methods (which are unchanged).
- **Opt-in per-test reset for the JUnit 5 extension.**
`@MockServerSettings(resetBeforeEach = true)` resets the
shared MockServer before each test (matching the JUnit 4 rule and Spring
listener). Default off, so existing
behaviour is unchanged.
##### Clustering & observability
- **New `mock_server_forward_upstream_protocol` metric.** A Prometheus
counter labeled by `upstream_host` and
`protocol` records the protocol each forward/proxy connection actually
negotiated to the upstream (`http2` via
ALPN, or `http1_1`), with a matching DEBUG log. This is the
authoritative way to confirm whether
`forwardProxyHttp2Upgrade` is taking effect — the recorded request only
carries the inbound protocol, not the
upstream-negotiated one, so a forward stuck on `http1_1` to a backend
that withholds its streaming SSE head
over HTTP/1.1 (a cause of high forward time-to-first-byte) was
previously invisible.
- **Standard OTLP endpoint fallback.** When `mockserver.otelEndpoint` /
`MOCKSERVER_OTEL_ENDPOINT` is unset,
MockServer now falls back to the OpenTelemetry-standard
`OTEL_EXPORTER_OTLP_ENDPOINT` environment variable.
##### Proxy & TLS setup
- **New `forwardProxyHttp2Upgrade` setting (default off).** Forwards a
secure request to the upstream over HTTP/2 even when the inbound client
is HTTP/1.1 (ALPN-negotiated, automatic fallback to HTTP/1.1 if the
upstream does not offer HTTP/2; TLS only). This fixes a header-timeout
some streaming upstreams exhibit, where the Server-Sent Events response
head is sent immediately over HTTP/2 but withheld over HTTP/1.1.
- **Copy-paste proxy setup at startup.** The new
`mockserver.proxySetupLogging` property
(env `MOCKSERVER_PROXY_SETUP_LOGGING`, default `false`; auto-enabled by
the standalone JAR, Docker image,
and `mockserver` CLI) writes the active CA certificate to
`mockserver-ca.pem` in the dynamic-SSL directory
at startup and prints a "Proxy Setup" block with ready-to-paste
environment variable exports (`HTTPS_PROXY`,
`NODE_EXTRA_CA_CERTS`, `SSL_CERT_FILE`, `REQUESTS_CA_BUNDLE`) for both
Unix and Windows PowerShell. The
block includes a security warning when the default public CA is in use.
Embedded usage
(`new ClientAndServer(...)`) stays silent by default to avoid polluting
test output; when `proxySetupLogging`
is off, the CA file is written on the first `GET
/mockserver/proxyConfiguration` call instead. The endpoint
itself is always available regardless of this setting.
- **`GET /mockserver/proxyConfiguration` endpoint.** Returns the CA
certificate path, CA PEM, proxy address,
environment variable exports, and a flag indicating whether the default
public CA is in use. Responds with
JSON by default or a plain copy-paste text block when called with
`Accept: text/plain`. Never exposes the
private key.
- **`--proxy-setup` flag for a unique, secure CA.** The new
`--proxy-setup` CLI flag (property
`mockserver.proxySetup`, env `MOCKSERVER_PROXY_SETUP`, default `false`)
forces generation of a unique local
CA on first startup, equivalent to
`dynamicallyCreateCertificateAuthorityCertificate=true`. Recommended for
any shared, persistent, or team-facing proxy deployment. Without it,
MockServer uses the built-in default CA
whose private key is published in the git repository (safe only for
isolated local development).
- **Bounded-memory event log + disk capture for proxying LLM /
large-body traffic without running out of
memory.** Proxying large request/response bodies (LLM tool schemas,
growing conversation context, accumulated
SSE) previously retained every exchange in full in the in-memory event
log, which is bounded only by entry
*count* (`maxLogEntries`), never by size — so a long capture session
could exhaust the heap and crash the
proxy. Three new opt-in properties address this:
`mockserver.maxEventLogSizeInBytes` (env
`MOCKSERVER_MAX_EVENT_LOG_SIZE_IN_BYTES`, default `0` = disabled) caps
the retained body bytes and evicts the
oldest entries from memory once exceeded;
`mockserver.persistRecordedRequestsToDisk` (env
`MOCKSERVER_PERSIST_RECORDED_REQUESTS_TO_DISK`, default `false`) with
`mockserver.persistedRecordedRequestsPath`
(default `recordedRequests.ndjson`) appends every proxied exchange —
full request and response — as one compact
JSON object per line (NDJSON) to disk as it completes, flushed per line,
so the complete session survives even
as the in-memory window evicts; and `mockserver.maxLoggedBodyBytes` (env
`MOCKSERVER_MAX_LOGGED_BODY_BYTES`,
default `0` = unlimited) truncates bodies kept in memory beyond a byte
limit (marking the copy with an
`x-mockserver-body-truncated` header) without affecting the disk
archive. The NDJSON archive honours
`redactSecretsInLog`, masking credentials on disk exactly as the
dashboard does. The recommended pairing —
byte budget plus disk capture — keeps memory bounded while disk holds
everything; the
`mockserver-ui/scripts/launch-with-llm-capture.sh` capture launcher now
enables it by default (2 GB heap,
256 MB byte budget, NDJSON disk capture).
##### Changed
- **TLS/decoder fault logs now name the SNI host.** When a client's TLS
handshake through the proxy fails
(e.g. `SSLHandshakeException: Received fatal alert: unknown_ca`, meaning
the client does not trust
MockServer's CA), the WARN log now appends the SNI hostname the
connection was for — e.g.
`… closing pipeline [id: 0x…] (SNI: chatgpt.com)` — across the relay,
SOCKS, port-unification, binary-proxy,
MCP and dashboard/websocket handlers, so the failing target/client is
identifiable instead of anonymous. The
message is unchanged when no SNI was negotiated.
- **Dashboard UI titles are now consistently Title Case.** Page/view
headings, section headings, dialog
titles, tab labels, navigation labels, and the tools/clear menu items
now use Title Case throughout
(e.g. "Server configuration" → "Server Configuration", "MCP server
health" → "MCP Server Health"),
so a menu item and the dialog it opens always match. Acronyms and brand
names (MockServer, AsyncAPI,
OpenAPI, gRPC, OIDC, SAML, SLO, CRUD, MCP, LLM, Pact) are preserved, and
descriptive/help text, tooltips,
and form labels are unchanged.
- **`generateFromRecording` in `TEMPLATIZED` mode now reproduces the
recorded traffic mix.** Each generated
step's `weight` is set to the route's observed hit count and the
scenario uses `stepSelection: WEIGHTED`,
so replaying picks routes in proportion to how often they appeared in
the recording (instead of plain
ordered steps). `VERBATIM` mode is unchanged.
- **Docker images cap the JVM heap at 75% of the container memory
limit** (`-XX:MaxRAMPercentage=75.0`, in
every published image that runs the server — standard, snapshot, root,
root-snapshot, graaljs, local, and
clustered), making memory use predictable and avoiding OOM-kills that
looked
like hangs. Always run with an explicit container memory limit. To set a
fixed heap, pass an explicit `-Xmx`
(a second `MaxRAMPercentage` via `JAVA_TOOL_OPTIONS` has no effect — it
is applied before the image's flag).
A build-time guard (`.buildkite/scripts/steps/docker-validate-sync.sh`)
now fails the build if any
server image's entrypoint is missing the cap, so it cannot drift back
out of one variant.
The Helm chart now ships commented `resources` and `app.jvmOptions`
examples.
- **Generated TLS certificate validity extended to 10 years** (was 365
days) for the dynamically generated CA,
leaf/server, and HTTP/3 self-signed certificates, so pinned-CA test
setups no longer expire after a year.
- **Dashboard navigation reorganised into grouped menus.** The
dashboard's views are now organised into six
groups (Mock / Observe / Verify / Resilience / AI / Inspect) with
submenus, replacing the flat overflow tab
bar, so features are easier to discover.
- **The Trace view is now reachable from the AI menu as well as
Observe.** Trace groups related requests —
including LLM agent runs — so it is now listed under AI alongside LLM
Optimise, while remaining under Observe,
making it easier to find when debugging multi-step AI flows.
- **The Trace view collapses a multi-turn LLM conversation into one
growing thread.** A stateless coding-assistant
CLI (e.g. the OpenAI Codex backend used by `opencode`) resends its
entire growing conversation/reasoning context
on every turn, so consecutive recorded requests each "contained
everything so far" and the view read as endless
duplicates. Consecutive requests whose message history is a growing
prefix of the next (same provider and host)
now render as a single conversation showing each turn's *new* content,
instead of N full-history blobs. Grouping
is conservative (edited history, a different provider, or a different
host never merge) and non-destructive — the
raw per-request data is still reachable.
- **Expectation matching scales to large expectation sets.** A candidate
index buckets literal
`(method, exact-path)` expectations so a request evaluates only
plausible candidates instead of scanning
every expectation; non-literal matchers
(regex/notted/optional/schema/path-param) are always checked, so
matching is byte-for-byte unchanged. The index engages automatically
only above a size threshold (default
64, overridable via `-Dmockserver.candidateIndexThreshold`); small
expectation sets run the unchanged
linear scan, so there is no regression at small scale and a large
speed-up at thousands of expectations.
##### Fixed
##### Correctness & reliability
- **HTTP/2 clients through the forward/CONNECT proxy no longer hang when
the upstream is also HTTP/2.** When a client
connected to MockServer's HTTPS forward proxy over HTTP/2 and MockServer
forwarded to an upstream that also served
HTTP/2, Netty's inbound HTTP/2→HTTP adapter tagged the decoded upstream
response with a synthetic
`x-http2-stream-id` header carrying the *upstream* stream id. That
internal header leaked through the response
mappers and was re-emitted to the client, so the response was written on
the wrong (upstream) stream id — the
client's HTTP/2 codec rejected it with a `PROTOCOL_ERROR`/`GO_AWAY` and
the request hung until timeout. The
response mappers now strip the Netty `x-http2-*` extension-header family
so the outbound stream id is governed
solely by the inbound request's stream id. HTTP/1.1 clients and
directly-mocked HTTP/2 responses were never
affected; captured/recorded responses also no longer carry the internal
`x-http2-stream-id` header.
- **Millisecond timeouts are now settable under their unit-bearing
`…InMillis` names, fixing silently-ignored overrides.**
The Java API (e.g. `Configuration.maxSocketTimeoutInMillis()`) and the
`/mockserver/configuration` JSON expose these
settings under `…InMillis` names, but the system property / environment
variable were only read under the unit-less
`mockserver.maxSocketTimeout` / `MOCKSERVER_MAX_SOCKET_TIMEOUT` form.
Setting the natural
`-Dmockserver.maxSocketTimeoutInMillis=…` (the name shown everywhere
else) was therefore silently dropped and the
20s default stood — long enough to 502 a healthy but slow first-byte
response (e.g. a reasoning LLM backend that
takes longer than 20s to emit its first token when proxied/forwarded).
MockServer now also accepts the unit-bearing
`mockserver.maxSocketTimeoutInMillis`,
`mockserver.socketConnectionTimeoutInMillis` and
`mockserver.maxFutureTimeoutInMillis` names (and their
`MOCKSERVER_*_IN_MILLIS` environment-variable forms) as exact
synonyms for the existing names — set whichever you prefer. The primary
(unit-less) name is read first, so a value
applied at runtime via the programmatic setter is never silently
overridden by a launch-time alias.
- **Recorded streaming responses no longer pin the live streaming sink
in memory.** Each captured streaming
(SSE) forward/proxy exchange stored a log entry whose response still
referenced the live streaming body — its
in-memory capture buffer, the upstream event loop, and the per-chunk
callbacks — for the entry's whole lifetime
in the log ring buffer, roughly doubling per-entry memory and pinning
event-loop-adjacent objects. The retained
log copy now holds only the fixed captured bytes and releases the live
streaming reference.
- **`forwardProxyHttp2Upgrade` now applies to every forward route,
fixing slow streaming captures.** The
HTTP/2-upgrade setting was honoured only by matched `forward()`
expectations; it now also covers the
transparent (unmatched) proxy path that most LLM/agent capture uses and
the `proxyPassMappings` reverse-proxy
route. Previously a coding-assistant CLI proxied over HTTP/1.1 was
always forwarded upstream over HTTP/1.1, and
some streaming backends (notably the OpenAI Codex SSE endpoint used by
the `opencode` CLI) withhold the
response head over HTTP/1.1 and only flush at completion, so
time-to-first-byte collapsed to total time and
surfaced as a client-side streaming timeout. With
`forwardProxyHttp2Upgrade` enabled, a secure request on any
forward route is now forwarded upstream over HTTP/2 via ALPN (falling
back to HTTP/1.1 if the upstream
declines), so the backend streams the head immediately. Off by default;
only the opt-in flag with a secure
(`https`) target triggers it.
- **Streamed responses with no `Content-Type` are no longer buffered,
fixing a streaming header-timeout (notably
for `opencode`).** MockServer previously relayed a response
incrementally only when the upstream advertised
`Content-Type: text/event-stream`; a backend that streams Server-Sent
Events with no content-type at all —
notably the OpenAI Codex endpoint used by `opencode` — was buffered to
completion before any headers were sent,
so the client failed with "Provider response headers timed out after
10000ms". Streaming is now driven by the
**client's** streaming intent (an `Accept: text/event-stream` header or
a `"stream": true` request body),
propagated per request to both the forward path and the transparent
(CONNECT) loopback relay, so the response
head reaches the client immediately regardless of the upstream's
content-type. Ordinary buffered responses
(including chunked-without-`Content-Length` servlet responses) and
`FORWARD_REPLACE` overrides are unaffected.
- **A stalled upstream on a reused pooled keep-alive connection now
times out instead of hanging.** With the
opt-in forward connection pool (`forwardConnectionPoolKeepAlive`)
enabled, a pooled keep-alive connection
carries no read timeout while it sits idle in the pool (a blanket one
would fire during legitimate idle
keep-alive). But a request dispatched on such a channel — a reused
connection, or a fresh pooled channel's
first request — was left with nothing to bound it, so an upstream that
connected/kept-alive but then went
silent hung the request until the far larger forward future timeout. An
in-flight read timeout
(`maxSocketTimeout`) is now armed when a request is dispatched on a
pooled channel and removed again when the
channel is returned to the pool, so a stalled reuse fails promptly. The
default (pooling off) path is
unchanged.
- **A streamed response is bounded by the streaming idle timeout, not
the 20s socket read timeout.** When a
response switches to streaming, the per-request socket read timeout
(`maxSocketTimeout`, default 20s) is now
always replaced by the stream-appropriate idle bound
(`streamIdleTimeoutSeconds`, default 60s), so a streaming
LLM response that pauses longer than 20s between chunks (model
reasoning) is not cut off mid-stream. Setting
`streamIdleTimeoutSeconds=0` now genuinely runs the stream unbounded as
documented (previously the 20s socket
timeout was left armed, truncating long inter-chunk gaps). The default
(60s) is unchanged.
- **Large `PUT /mockserver/retrieve` and the LLM optimisation report no
longer stall logging or time out.**
Retrieving logs, requests, recorded expectations, or request-responses
serialized the (potentially large, e.g.
captured streaming bodies) result *inside* the single log-consumer
thread's callback, which could exceed the
retrieve future timeout and — worse — block all further logging (filling
the ring buffer and dropping events)
while it ran. Every retrieve branch — `LOGS`, `REQUESTS`,
`RECORDED_EXPECTATIONS`, and `REQUEST_RESPONSES` in
all its formats (JSON, log entries, HAR, OpenAPI, Postman, Bruno, cURL)
— now materializes the (cheap, redacted)
result on the consumer thread and runs the expensive serialization on
the caller thread; the LLM
optimisation-report endpoint likewise builds its report off the Netty
event loop. Output is byte-for-byte
identical; only the thread doing the work changed.
- **Load-scenario status no longer reports a transient `null` while a
run is completing.** The orchestrator
removed a finishing run from its active map before publishing the run's
terminal status, so a status poll
landing in that brief window saw neither and returned `null`. The
terminal status is now published before the
run is de-registered, so `statusFor`/`getStatus` always observe either
the live or the completed status.
- **SSL/decoder faults in the proxy/relay handlers are now logged at
WARN** instead of being silently dropped,
so genuine TLS/decoder problems are visible without the noise of benign
connection closes.
- **LLM streaming pacing above 1000 tokens/sec is preserved.**
Sub-millisecond per-token delays were
integer-truncated to 0 ms (flattening fast streams); pacing now
accumulates with fractional carry so
cumulative timing stays accurate.
- **Coding-assistant LLM traffic is recognised resiliently, including
opencode's OpenAI Codex backend.** The
`opencode` CLI calls the OpenAI Responses API through its Codex backend
at
`chatgpt.com/backend-api/codex/responses`, a non-standard path the
detectors did not match — so its calls were
recorded under the generic Traffic view but never appeared in the LLM
Traces or LLM Optimise views. Responses-API
detection (`LlmProviderSniffer`, `ProviderDetector`, and the dashboard's
`llmTraffic.ts`) now matches the Codex
path alongside the hosted `/v1/responses`, and the `chatgpt.com` host on
it. Detection also gains a host/path-
independent **body-shape fallback** (read-only analysis only — Traffic,
LLM Traces, LLM Optimise; never the live
forward/cost path): LLM traffic is recognised from its wire format, so a
coding assistant that moves to a new
endpoint or a private gateway, or a new tool, stays classified without a
code change. Claude Code (`/v1/messages`)
and Tabnine CLI (`…/chat/completions`) were already recognised.
- **A streamed proxy response with no `Content-Type` is logged as
readable text, not empty binary.** The captured
body of a streamed forward response with no content-type (opencode's
OpenAI Codex SSE backend) was stored as a
`BINARY` body, so it appeared empty in the dashboard's LLM Traces /
Optimise text views. The captured bytes are
now sniffed when no content-type is present — UTF-8 text (SSE/JSON) is
stored as a readable `STRING`, while
genuinely binary streams stay `BINARY`. Content-typed responses are
unchanged.
- **HTTP/2 forwarded responses now stream incrementally instead of being
buffered.** The HTTP/2 forward client was
rebuilt on the same multiplex stack the server uses (`Http2FrameCodec` +
`Http2MultiplexHandler`), reusing the
existing HTTP/1.1 streaming relay per stream — a streamed upstream
response (SSE) now has its head relayed to the
client as soon as it arrives rather than after the whole body.
Non-streaming HTTP/2 responses are still aggregated.
- **More consistent LLM provider detection across the proxy, traces and
optimise views.** Embeddings/moderations
requests are no longer mis-classified as the OpenAI Responses API; the
MCP `provider=AUTO` analysis now uses the
same host + body-shape detection as the dashboard and optimisation
report; and Cohere, Voyage, Vertex AI Gemini,
and the AWS Bedrock Converse API are now recognised.
- **The LLM optimisation report classifies and prices calls more
honestly.** It now uses the response body when
detecting the provider (a header-less Anthropic call is no longer
mis-labelled OpenAI), and a call whose model
has no known price — or only a placeholder rate — is flagged as
unpriced/approximate instead of being shown as a
confident `$0.00`. The copy-paste optimisation brief also masks obvious
credential shapes in prompt text.
- **The dashboard renders more LLM responses correctly.** Streamed
OpenAI Chat Completions and Gemini responses
that carry no `Content-Type` header now reassemble and display instead
of showing empty; Anthropic prompt-cache
tokens are surfaced; a hostile/malformed Server-Sent Events index can no
longer exhaust browser memory; and a
truncated or unparseable response body now shows a clear notice rather
than a silent blank.
- **Captured credentials are masked in the dashboard.** API keys and
bearer tokens in `Authorization`, `x-api-key`,
`api-key`, cookies and similar headers are masked in the Traffic
raw/diff views (the original value is still used
for replay), so a shared or screen-shared dashboard no longer exposes
live credentials.
- **Forward DNS resolution moved off the calling thread.** Forward
actions hand the connect path an unresolved
address so DNS runs on the Netty event loop; SSRF validation still
resolves and rejects private/loopback
targets first, and a missing SSRF guard was added to the
forward-validate path.
- **Code-review hardening sweep — correctness, concurrency, resources
and performance.** A repo-wide review
surfaced and fixed a set of latent defects:
- **Stale `hashCode` broke matching.**
`KeyToMultiValue.replaceValues()`/`addNottableValues()` mutated the
value list without refreshing the cached `hashCode` (unlike
`addValue()`), so a header/parameter object
reused on the matching hot path (e.g. via `ExpandedParameterDecoder`)
could violate the `equals`/`hashCode`
contract. The cache is now refreshed on every mutation, and the
`0`-sentinel hashCode caches on
`HttpRequest`/`HttpResponse`/`Action`/`Not` no longer defeat themselves
when a hash legitimately computes to 0.
- **`NullPointerException` serialising a chunked response with no body**
— the chunked body encoder now guards a
null body.
- **WebSocket object-callback disconnect bug.** When a callback client
disconnected mid-exchange the
forward-object-callback handler wrote the HTTP response twice and left a
`CompletableFuture` that never
completed (pinning a scheduler thread until the future timeout); the
disconnect path now writes once,
unregisters the callback, and returns. Response/forward callback
registry entries are also unregistered on
every disconnect branch.
- **JavaScript response templates were fully serialised** through an
engine-wide lock even though each call
already builds its own GraalVM context; the lock was removed so
concurrent JS templates run in parallel.
- **Numerous unsynchronised lazy-init / check-then-act races hardened**
(template-engine and body-deserializer
`ObjectMapper`s, the OpenAPI parse cache via `computeIfAbsent`,
`JsonStringMatcher`, the Java client's Netty
client and event bus, action-handler template engines, `LogEntry`
override cache, scheduler thread numbering).
- **Configuration round-trip gaps.** `controlPlaneScopeMapping`, the
proxy-pass mappings, and
`proxyRemoteHost`/`proxyRemotePort` now round-trip through `PUT
/mockserver/config`; an unrecognised
`logLevel` now fails fast with a clear message instead of an NPE during
start-up; the conventional
`mockserver.perExpectationMetricsEnabled` property key is accepted (the
legacy key still works).
- **Event loop no longer blocked.** Connection-delay sleeps and
`awaitUninterruptibly()` calls were removed
from the proxy/SOCKS/relay event-loop paths; the outbound HTTP client
now applies a read timeout so a
stalled upstream cannot pin a connection/future indefinitely;
CONNECT-relay aggregators are bounded to the
configured maximum body size instead of \~2 GB.
- **Resource & memory leaks fixed.** `MemoryMonitoring` now unregisters
its log/expectation listeners on stop
(and writes its CSV via try-with-resources); the LLM completion cache
and quota registry are now bounded;
gRPC gzip frames are capped on *decompressed* size (decompression-bomb
guard).
- **Async broker mocking** publish/subscribe lifecycle is synchronised,
Kafka send failures are logged, and
subscribers expose a health flag after a broker disconnect.
- **Clustered in-memory CAS** no longer loses a concurrent write when an
entry is swapped under the same key
(identity-conditional remove/replace).
- **Hot-path allocations removed** (case-insensitive header/parameter
lookups, matcher-listener notification,
load-metric label arrays), and generated TLS certificates are now
anchored to issuance time rather than the
JVM start time.
- **Control-plane endpoints can no longer be hijacked by an early
(`respondBeforeBody`) expectation.** A
catch-all `respondBeforeBody` expectation (for example one seeded from
an initialization file) was matched
before the control-plane dispatch, so it could answer the server's own
management requests (e.g.
`PUT /mockserver/reset`). Early header matching now excludes the
reserved `/mockserver` control-plane path
prefix, so management endpoints always reach the control plane.
##### Dashboard UI
- **Dashboard LLM pricing corrected.** The dashboard cost estimates were
\~1 year stale and up to \~3× too high
(e.g. Opus 4.8 shown at 15/75 instead of 5/25); the table is now synced
to the server's pricing and guarded
by a drift test.
##### IDE extensions (VS Code & JetBrains)
- **JetBrains plugin no longer uses internal/deprecated IntelliJ
Platform APIs.** A blocking IntelliJ Plugin
Verifier gate now runs in CI against the full recommended IDE set
(IntelliJ IDEA 2024.3 through the 2026.2 EAP)
and rejects internal, deprecated, and scheduled-for-removal API usages —
the same classes the Marketplace
flags. The plugin's self-version lookup is resolved from its own plugin
class loader
(`PluginAwareClassLoader.pluginDescriptor.version`), because the
id-based `PluginManager.getPluginByClass(...)` /
`PluginManagerCore.getPlugin(PluginId)` lookups are both marked internal
on newer platforms; the tool-window
buttons fire their actions via the stable
`AnActionEvent.createEvent(...)` + `update`/`actionPerformed`
primitives instead of the deprecated `ActionUtil.invokeAction(...)`; and
the deprecated `JBCefBrowser(...)`
constructors use the `JBCefBrowser.createBuilder()...build()` API. No
behaviour change; keeps the plugin
installable on current and future IDE builds.
##### OpenAPI & contract testing
- **OpenAPI `format: date`/`date-time` examples render as ISO strings
again**
([#​2370](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2370)).
An inline `example: '2021-01-30'` on a `type: string, format: date`
property was serialised in generated
responses as epoch-millis (`1611964800000`) instead of the ISO string,
because swagger-parser deserialises
the example into a `java.util.Date` that the explicit-example path
handed straight to Jackson. Date/date-time
examples are now normalised back to their schema string form before
serialisation (regression since 6.0.0).
##### Client libraries & integrations
- **Spring `@MockServerTest` works with JUnit 5 `@Nested` classes
again**
([#​2371](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2371)).
Injecting the `MockServerClient` declared on an outer test class into a
`@Nested` inner test instance threw
`IllegalArgumentException` because the field was set on the inner
instance rather than the enclosing instance
that declares it. Injection now resolves the correct enclosing instance
via the synthetic outer reference
(regression since 6.0.0).
##### Build & dependencies
- **`mockserver-core` no longer triggers dependency-convergence errors
in downstream builds**
([#​1970](https://redirect.github.com/mock-server/mockserver-monorepo/issues/1970)).
Projects that depend on
`mockserver-core` and run `maven-enforcer`'s `dependencyConvergence`
rule saw conflicts for guava, jsr305,
rhino, libphonenumber, snakeyaml, commons-*, slf4j-api, jackson-* and
jakarta.xml.bind-api, because those
versions are pinned in MockServer's parent `dependencyManagement` (which
is not transitive) while
swagger-parser, json-patch, velocity and protobuf-java-util dragged in
older transitive copies. The stale
transitive edges are now pruned with `<exclusion>`s (the resolved
classpath is unchanged — the pinned/newer
versions already won nearest-wins), and `jackson-dataformat-yaml` and
`jsr305` are declared directly so a
single version of each reaches consumers. (The `mockserver-client-java`
half of this was fixed in 7.1.0.)
</details>
---
### Configuration
📅 **Schedule**: (UTC)
- Branch creation
- At any time (no schedule defined)
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Enabled.
♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box
---
This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/prometheus/client_java).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>1 parent b37723e commit 71832e2
1 file changed
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
0 commit comments