From 62d2443f639e2f643f04c0073920cb2b2c416116 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:43:11 +0200 Subject: [PATCH 01/54] chore(deps): update dependency aqua:grafana/oats to v0.9.0 (#2352) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Update | Change | |---|---|---| | [aqua:grafana/oats](https://redirect.github.com/grafana/oats) | minor | `0.8.0` → `0.10.0` | --- ### Release Notes
grafana/oats (aqua:grafana/oats) ### [`v0.10.0`](https://redirect.github.com/grafana/oats/blob/HEAD/CHANGELOG.md#0100-2026-07-28) [Compare Source](https://redirect.github.com/grafana/oats/compare/v0.9.0...v0.10.0) ##### Features - add opt-in HTTP input retries ([#​453](https://redirect.github.com/grafana/oats/issues/453)) ([82a973d](https://redirect.github.com/grafana/oats/commit/82a973d528a9dab8b8ac69091db53e41b92cf8b6)) ##### Bug Fixes - **release:** ensure gcx updates trigger releases ([#​454](https://redirect.github.com/grafana/oats/issues/454)) ([8e52488](https://redirect.github.com/grafana/oats/commit/8e52488956da7273f36937a8cbdfe97918e67278)) ### [`v0.9.0`](https://redirect.github.com/grafana/oats/blob/HEAD/CHANGELOG.md#090-2026-07-28) [Compare Source](https://redirect.github.com/grafana/oats/compare/v0.8.0...v0.9.0) ##### Features - support one-shot Compose inputs ([#​451](https://redirect.github.com/grafana/oats/issues/451)) ([c43e6cb](https://redirect.github.com/grafana/oats/commit/c43e6cb6964d486c8a27df9f2d43b821f5a1ac62)) ##### Bug Fixes - **deps:** update module go.opentelemetry.io/collector/pdata to v1.63.0 ([#​438](https://redirect.github.com/grafana/oats/issues/438)) ([6f3524a](https://redirect.github.com/grafana/oats/commit/6f3524a215886baf03e78e2493d235d1fb8ac131))
--- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) đŸšĻ **Automerge**: Enabled. â™ģ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] 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). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- mise.lock | 44 ++++++++++++++++++++++---------------------- mise.toml | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/mise.lock b/mise.lock index f09cb34a5..ba618bcba 100644 --- a/mise.lock +++ b/mise.lock @@ -126,49 +126,49 @@ url = "https://github.com/grafana/gcx/releases/download/v1.0.0/gcx_1.0.0_windows url_api = "https://api.github.com/repos/grafana/gcx/releases/assets/492677462" [[tools."aqua:grafana/oats"]] -version = "0.8.0" +version = "0.10.0" backend = "aqua:grafana/oats" [tools."aqua:grafana/oats"."platforms.linux-arm64"] -checksum = "sha256:82eaf1e836cea916b96cef6745423efd8256ceab64bbabd1fa8f13b3883a1212" -url = "https://github.com/grafana/oats/releases/download/v0.8.0/oats_0.8.0_linux_arm64.tar.gz" -url_api = "https://api.github.com/repos/grafana/oats/releases/assets/487171323" +checksum = "sha256:be195aeeafce644c8a59438bbc8c472f5ca51df6f9570c6b646373a703d686b0" +url = "https://github.com/grafana/oats/releases/download/v0.10.0/oats_0.10.0_linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/grafana/oats/releases/assets/493772122" provenance = "github-attestations" [tools."aqua:grafana/oats"."platforms.linux-arm64-musl"] -checksum = "sha256:82eaf1e836cea916b96cef6745423efd8256ceab64bbabd1fa8f13b3883a1212" -url = "https://github.com/grafana/oats/releases/download/v0.8.0/oats_0.8.0_linux_arm64.tar.gz" -url_api = "https://api.github.com/repos/grafana/oats/releases/assets/487171323" +checksum = "sha256:be195aeeafce644c8a59438bbc8c472f5ca51df6f9570c6b646373a703d686b0" +url = "https://github.com/grafana/oats/releases/download/v0.10.0/oats_0.10.0_linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/grafana/oats/releases/assets/493772122" provenance = "github-attestations" [tools."aqua:grafana/oats"."platforms.linux-x64"] -checksum = "sha256:ea4368c6d7f62244ce959ba60512f271d46d133b50350077257e2bb81c03a5ca" -url = "https://github.com/grafana/oats/releases/download/v0.8.0/oats_0.8.0_linux_amd64.tar.gz" -url_api = "https://api.github.com/repos/grafana/oats/releases/assets/487171351" +checksum = "sha256:b72a7a587148d1eaa15ccea3ce1adfd67e040d1cd9f9e267c850154035ef9a18" +url = "https://github.com/grafana/oats/releases/download/v0.10.0/oats_0.10.0_linux_amd64.tar.gz" +url_api = "https://api.github.com/repos/grafana/oats/releases/assets/493772131" provenance = "github-attestations" [tools."aqua:grafana/oats"."platforms.linux-x64-musl"] -checksum = "sha256:ea4368c6d7f62244ce959ba60512f271d46d133b50350077257e2bb81c03a5ca" -url = "https://github.com/grafana/oats/releases/download/v0.8.0/oats_0.8.0_linux_amd64.tar.gz" -url_api = "https://api.github.com/repos/grafana/oats/releases/assets/487171351" +checksum = "sha256:b72a7a587148d1eaa15ccea3ce1adfd67e040d1cd9f9e267c850154035ef9a18" +url = "https://github.com/grafana/oats/releases/download/v0.10.0/oats_0.10.0_linux_amd64.tar.gz" +url_api = "https://api.github.com/repos/grafana/oats/releases/assets/493772131" provenance = "github-attestations" [tools."aqua:grafana/oats"."platforms.macos-arm64"] -checksum = "sha256:156bb14787a09093de8ad0370c95e8104b771ca0b3ede382541f9837db797f27" -url = "https://github.com/grafana/oats/releases/download/v0.8.0/oats_0.8.0_darwin_arm64.tar.gz" -url_api = "https://api.github.com/repos/grafana/oats/releases/assets/487171322" +checksum = "sha256:570d5c3b43c0cbe0d88c527d2fcecb9ee565e2f9d1a4d49fb4b6bbf5c3fa47e5" +url = "https://github.com/grafana/oats/releases/download/v0.10.0/oats_0.10.0_darwin_arm64.tar.gz" +url_api = "https://api.github.com/repos/grafana/oats/releases/assets/493772124" provenance = "github-attestations" [tools."aqua:grafana/oats"."platforms.macos-x64"] -checksum = "sha256:034bc120d0d8bbf8aff05f61a6b569efec821df19bd25bb602ee77d4a6368235" -url = "https://github.com/grafana/oats/releases/download/v0.8.0/oats_0.8.0_darwin_amd64.tar.gz" -url_api = "https://api.github.com/repos/grafana/oats/releases/assets/487171352" +checksum = "sha256:c3579f73928df56d1cf6d6bbb90d20424649ff08c228daa4810914017f8620d8" +url = "https://github.com/grafana/oats/releases/download/v0.10.0/oats_0.10.0_darwin_amd64.tar.gz" +url_api = "https://api.github.com/repos/grafana/oats/releases/assets/493772123" provenance = "github-attestations" [tools."aqua:grafana/oats"."platforms.windows-x64"] -checksum = "sha256:166a5577c66efa9e4d677856ae1780212ee27c081042c8d54db0c996019adbc0" -url = "https://github.com/grafana/oats/releases/download/v0.8.0/oats_0.8.0_windows_amd64.zip" -url_api = "https://api.github.com/repos/grafana/oats/releases/assets/487171324" +checksum = "sha256:b52112bf0932ea8dea1fb051bc04e29efa5ef138f67d09d775c4eb716d3d92f9" +url = "https://github.com/grafana/oats/releases/download/v0.10.0/oats_0.10.0_windows_amd64.zip" +url_api = "https://api.github.com/repos/grafana/oats/releases/assets/493772125" provenance = "github-attestations" [[tools."aqua:jonwiggins/xmloxide"]] diff --git a/mise.toml b/mise.toml index 569a2f3bd..eb899bbe5 100644 --- a/mise.toml +++ b/mise.toml @@ -1,6 +1,6 @@ [tools] "aqua:grafana/gcx" = "v1.0.0" -"aqua:grafana/oats" = "0.8.0" +"aqua:grafana/oats" = "0.10.0" hugo = "0.164.0" java = "temurin-25.0.3+9.0.LTS" node = "24.18.0" From 23ae29aa71825c2a83abf249fc45cca2a46e3c8b Mon Sep 17 00:00:00 2001 From: Subhramit Basu Date: Thu, 30 Jul 2026 05:13:15 +0530 Subject: [PATCH 02/54] docs: add API design guideline to contributing docs (#2350) --- AGENTS.md | 7 +++++++ CONTRIBUTING.md | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 24481b8e5..9c229117a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -125,6 +125,13 @@ commits. CI will fail if these checks fail. - Build succeeds (tests are skipped; run `mise run test` or `mise run test-all` for tests) +## API Design + +- For internal or SDK-facing classes, prefer static factories and builders + over adding new public constructors. +- Keep constructors non-public unless they are intentionally part of the + stable API. + ## Testing - JUnit 5 (Jupiter) with `@Test` annotations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 519b98fea..ece7e11e5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,6 +73,13 @@ This requires native lint tools, which you can install with `mise run setup:native-lint-tools`. These are optional but catch formatting and lint issues before CI. +## API Design + +For internal or SDK-facing classes, prefer static factories and builders over +adding new public constructors. Constructors are difficult to evolve +compatibly, so keep them non-public unless they are intentionally part of the +stable API. + ## Running Tests If you're getting errors when running tests: From ee64917c53c0c8698a2b70ad48342f3bb2ca535d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:43:44 -0400 Subject: [PATCH 03/54] chore(deps): update dependency org.mock-server:mockserver-netty-no-dependencies to v7.5.0 (#2354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > â„šī¸ **Note** > > This PR body was truncated due to platform limits. 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.4.0` → `7.5.0` | ![age](https://developer.mend.io/api/mc/badges/age/maven/org.mock-server:mockserver-netty-no-dependencies/7.5.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/maven/org.mock-server:mockserver-netty-no-dependencies/7.4.0/7.5.0?slim=true) | --- ### Release Notes
mock-server/mockserver-monorepo (org.mock-server:mockserver-netty-no-dependencies) ### [`v7.5.0`](https://redirect.github.com/mock-server/mockserver-monorepo/blob/HEAD/changelog.md#750---2026-07-29) ##### Security - **BREAKING: response templates can no longer reach arbitrary Java classes by default, closing the template remote-code-execution path reported as [GHSA-7pwj-xvc2-hfpc](https://redirect.github.com/mock-server/mockserver-monorepo/security/advisories/GHSA-7pwj-xvc2-hfpc).** A caller who can reach the management API can register an expectation, and a response template was able to load `java.lang.Runtime` and execute OS commands in the MockServer process. Both engines that could do this are now sandboxed out of the box: - `velocityDisallowClassLoading` now defaults to **`true`** (was `false`), installing Velocity's `SecureUberspector` so a template cannot reach classes through `$request.class.classLoader.loadClass(...)`. This is the more exposed half of the issue, and the half the report did not cover: Velocity ships in the DEFAULT distribution, whereas the JavaScript engine does not. - JavaScript templates now resolve **no** Java classes unless an operator grants them. Previously an empty `javascriptAllowedClasses` *and* empty `javascriptDisallowedClasses` meant unrestricted `Java.type(...)` access; that combination — the out-of-the-box state — now denies every class. - The GraalJS guest context no longer grants access to the members of `java.lang.Class` or `java.lang.ClassLoader`. Denying classes at `Java.type(...)` alone was **not** sufficient: real host objects are bound into the context (`faker` and the other built-in helpers), and under the previous `HostAccess.ALL` a template could walk from one of them to a classloader — `faker.getClass().getClassLoader().loadClass('java.lang.Runtime')` — reaching `Runtime` without the class filter ever being consulted. That walk is now closed, so host-class lookup is the single complete gate; a regression test drives four such walks (including through `request`) and fails if any resolves. Velocity's `SecureUberspector` already blocked the equivalent walk through its own bound helpers, which is now covered by a test too. Both flips are fully reversible with one property and remove no functionality: set `mockserver.velocityDisallowClassLoading=false`, or list the classes your templates need in `mockserver.javascriptAllowedClasses` (the single entry `*` lets any class resolve again). Templates that do not touch Java classes are unaffected, which is the overwhelming majority — JavaScript templates have the full ES2023 standard library available regardless of this setting. A refused class is logged once at WARN naming the class and the property to set, because GraalJS otherwise surfaces a refusal only as the class being undefined ("... is not a function"); the log is bounded and de-duplicated so a hostile template cannot flood it. `mockserver.javascriptAllowedClasses` is now also settable through the Spring test listener's `@MockServerTest` properties, which it was not before — it was a nice-to-have while the default was unrestricted, and is the only way to grant a class now that it is not. The insecure-mode WARN now fires when an operator has explicitly opened the sandbox rather than when it is closed. Proven end-to-end by a Netty integration test that registers the reported payload through the real management API and asserts the OS command creates no marker file, with a negative control on a deliberately unsandboxed server that DOES create it — so a regression cannot pass as an inert payload. This lands DEF-2 and DEF-3 of `docs/plans/later/security-defaults.md` ahead of the other default flips listed there; JavaScript went further than that plan proposed (deny everything, not a built-in "safe types" allow-list) because deny-by-default is the only form that stays safe as the JDK grows new reachable classes. ##### Fixed - **A property file that cannot be read is now reported instead of ignored in silence ([#​2358](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2358)).** When a `mockserver.propertyFile` an operator had explicitly configured could not be read, MockServer applied none of its properties and said nothing about it — at any log level. The only symptom was that every property in the file appeared to be at its default, which surfaces far downstream as unexplained behaviour: in the reported case an unreadable (but present) mounted file meant `initializationJsonPath` was never set, so no expectations loaded, no `loading JSON initialization file:` line appeared, and no error was logged either. The message existed but was unreachable in practice — gated at DEBUG *and* emitted during static initialisation, before any log level has been applied, so neither `-Dmockserver.logLevel=DEBUG` nor a `-logLevel` argument could surface it. Such a file is now logged at WARN, naming the path and the underlying reason verbatim; because `FileNotFoundException` covers "not there" and "not allowed to read it" alike, that reason is usually the whole answer (`Permission denied` in the reported case, typically SELinux labelling or a rootless/user-namespace UID mismatch). A property file that is merely absent at its default location stays quiet, as does the Docker image's built-in `-Dmockserver.propertyFile=/config/mockserver.properties`, which the entrypoint always passes and which therefore expresses no intent — otherwise every container started without a mounted config would warn. Inside the image, only `MOCKSERVER_PROPERTY_FILE` can express that intent, and it does. - **The `mockserver-node` launcher suite no longer fails intermittently on a TLS handshake reset.** The two tests that exercise `jvmOptions` did so over HTTPS against a server started with `dynamicallyCreateCertificateAuthorityCertificate=true`, and issued that HTTPS request as soon as `start_mockserver` resolved. `start_mockserver` only proves the HTTP control plane is answering — it polls `PUT /mockserver/retrieve` over plain HTTP — but with a dynamically created certificate authority the server still has to generate a CA key pair and a leaf certificate before it can serve TLS on that same (port-unified) port. A handshake arriving in that window was closed mid-negotiation and surfaced as `ECONNRESET` "Client network socket disconnected before secure TLS connection was established", failing whichever of the two tests lost the race. This accounted for every `mockserver-node` failure on `master` over the preceding 40 builds (5 of 40, \~12%), so it was the sole cause of the pipeline's intermittent red. Both tests now wait for an actual TLS handshake to complete before asserting, which gates them on the condition they really depend on rather than retrying the assertions. The new `waitForTlsReady` helper is verified to reject — not resolve — both when nothing is listening and when a listener accepts the TCP connection then destroys it mid-handshake, which is exactly the failure signature it exists to absorb. The readiness budget is deliberately generous (120s): waiting costs nothing when the server is healthy, since a ready server completes the handshake on the first attempt in milliseconds, so the limit only decides how much CI contention is tolerated before a slow start is misreported as a fault. An earlier 30s budget went green five builds running and then expired on a loaded agent — the same flake wearing a clearer error message. A start that takes over 5s is now reported even when it passes, because readiness creeping towards the limit is the signal that the next run will not make it. - **`archiver.glob()` works again in `@mockserver/testcontainers` (Node), and CVE-2026-14257 stays closed.** The previous remedy for the `brace-expansion` denial of service (GHSA-mh99-v99m-4gvg, patched only in 5.0.8) was a blanket `"brace-expansion": "^5.0.8"` override. That resolved the whole tree to a single hoisted 5.0.8 and `npm audit` reported zero vulnerabilities — but 5.x changed the CommonJS export from a callable function to an object (`{ expand, EXPANSION_MAX, ... }`), while the minimatch copies actually installed (3.1.5, 5.1.9, 9.0.9) all call it as `expand(pattern)`. Every glob containing a brace therefore threw `TypeError: expand is not a function`, crashing `archiver.glob()`. The blast radius is narrower than it first looks — `testcontainers` copies files with `archiver.directory()`/`.append()`, which pass no brace pattern and still work — so what broke is brace globbing for anything in this module's runtime tree that does use it. The failure was invisible because minimatch short-circuits patterns with no `{`, so plain globs kept working and the unit suite stayed green. The override is now targeted: `readdir-glob` and `archiver-utils`' `glob` take `minimatch@^10.2.5`, which depends on `brace-expansion@^5.0.5` and is written against the new API, so both runtime copies land on the patched 5.0.8 with a matching minimatch. jest keeps its own `minimatch@3.1.5` + `brace-expansion@1.1.16` pairing and is untouched. `npm audit --omit=dev` still reports 0 vulnerabilities, and a new `dependency-integrity` unit test drives a brace pattern through both runtime minimatch copies and through a real `archiver.glob()` tar, plus asserts expansion stays bounded — it fails against the blanket override, so the silent half of this cannot return. - **A forward `responseOverride` that replaces the body no longer inherits the upstream response's `Content-Length`, which truncated the response on the wire.** The override swapped the body but left the upstream header in place, so the client read only as many bytes as the body it replaced — a 34-byte override behind an upstream `Content-Length: 13` arrived as 13 bytes — or hung waiting for bytes that never came. The stale header is now dropped so the encoder recomputes it from what is actually written; a `Content-Length` set by the override itself, and `connectionOptions.contentLengthHeaderOverride`, are still honoured, and a header-only override (one that sets no body) is untouched. This affects every body override, and it was the remaining reason a `FILE` response body returned from a `responseOverride` still reached the client wrong after [#​2450](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2450): the file was materialised correctly and then cut short by the stale length. Covered by a Netty integration test that drives a real forward-with-override through a real upstream and asserts the bytes the client receives. - **The JetBrains plugin's LLM tool window now sends a valid expectation ([#​2455](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2455)).** "Load into Server" was rejected with `400 incorrect expectation json format` because the builder emitted a shape that never existed on the server: a flat `completion` string, a top-level `finishReason`, `stream`, and `usage`, and a `provider` of `OPEN_AI`. The completion text, streaming flag, stop reason, and token usage belong INSIDE the `completion` object (`text`, `streaming`, `stopReason`, `usage.inputTokens` / `usage.outputTokens`), and providers are the `Provider` enum names (`OPENAI`, `AZURE_OPENAI`, â€Ļ). The provider and field catalogues shared with the VS Code extension are corrected the same way — they offered `OPEN_AI`, `VERTEX_AI`, `messages`, `stream`, `finishReason` and a top-level `usage`, none of which the server accepts — and completion inside a `completion` object now offers the nested fields. The plugin has always bundled the correct schema; it simply never validated its own output against it, and the previous tests asserted the builder matched the same invented shape it produced. Both editors now validate against the bundled schema in their test suites. - **`httpLlmResponse.provider` now accepts every provider MockServer implements.** The JSON Schema enum listed 9 of the 14 `org.mockserver.model.Provider` constants, so `MISTRAL`, `XAI`, `DEEPSEEK`, `GROQ`, and `OPENROUTER` were rejected with `400 incorrect expectation json format` even though each has a fully registered response codec. The five missing values are added to the core schema, the generated VS Code and JetBrains schemas, and both copies of the OpenAPI specification, and a new parity test fails if the enum and `Provider` ever diverge again in either direction. The provider list on the LLM response mocking documentation and in the Rust client's field docs is updated to match. - **The cloud blob-store, async-broker and transparent-proxy CI steps no longer OOM-kill their own build before any test runs.** Each ran its Docker container with `--memory=4g`, but `mockserver/.mvn/jvm.config` pins the Maven JVM to `-Xmx6144m` and the wrapper prepends it to `MAVEN_OPTS`, so the `-am` dependency build was permitted a 6 GB heap inside a 4 GB cgroup and the kernel intermittently killed it with exit 137 — losing the very coverage those fail-closed steps exist to guarantee. Raised each to `--memory=7g`, the value every other `./mvnw` step already uses and which fits the single-agent `c5.2xlarge`/`m5.2xlarge` default-queue instances with margin. ##### Added - **A cassette is now auto-registered when a fixture is loaded or recorded via the MCP tools, so it appears under `GET /mockserver/cassettes` without a separate `PUT /mockserver/cassettes` call.** Previously the server-side cassette registry was populated only by an explicit `PUT /mockserver/cassettes`, so a fixture loaded with the `load_expectations_from_file` MCP tool, or written with `record_llm_fixtures`, never showed up in the dashboard's Cassettes tab unless the caller also registered it by hand. Both MCP tool handlers now register the fixture in `CassetteRegistry` at the point the file is loaded/written — the file path as the key, the loaded/ written expectation count, and an `origin` of `loaded` or `recorded` respectively — so `GET /mockserver/cassettes` (which serialises that registry) lists it automatically. Re-loading or re-recording the same path updates the existing entry in place rather than duplicating it. - **Clustered (Infinispan) expectation reload-on-startup is now proven end-to-end.** A new test (`ClusteredExpectationPersistenceReloadTest` in `mockserver-state-infinispan`) forms an in-JVM JGroups cluster consisting of a bare "fleet keeper" `InfinispanStateBackend` that stays up for the whole test plus a full MockServer node started with `stateBackend=infinispan`, `clusterEnabled=true` and `persistExpectations=true`. An expectation is created on that node over the wire, the persisted document is polled for through the *keeper's* backend (proving it really replicated across the REPL\_SYNC blob cache), the node is then stopped completely, and a fresh node is started against the same cluster and the same `persistedExpectationsPath` — which must restore the expectation and MATCH a real HTTP request with it. The local persisted file is asserted to be empty first, so the restore cannot be coming from the filesystem-initializer route. The reload path in `ExpectationFileSystemPersistence` was already covered at unit level in `mockserver-core` (`ExpectationBlobStoreRestoreTest`, against an `InMemoryBlobStore`, with no server and no cluster) and end-to-end only against S3/MinIO behind a Docker gate; what no test proved is that a clustered node's `InfinispanBlobStore` is the store `HttpState` wires into that restore, nor that a real restarted member of a live cluster recovers the fleet's shared expectations. A second test sets `blobStoreRestoreTimeoutSeconds=0` (the documented way to skip the restore) and asserts the fresh node does NOT serve the expectation, which permanently pins the fact that no other mechanism — JGroups state transfer of the expectations cache, a stray invalidation event, or the local file — restores expectations when a node starts. Verified by a positive control: disabling the reload path in production makes the restarted node answer with an empty body and turns the test red. - **The response-aware arm of the eviction false-green guard is now proven end-to-end over HTTP.** A new Netty integration test (`EvictedResponseVerificationIntegrationTest`) boots a real server with `maxLogEntries=2` and `failVerificationOnEvictedLog=true`, registers an expectation so a `GET /was-responded` exchange is recorded as a real `EXPECTATION_RESPONSE` request-response pair, then floods the bounded event log with further unmatched traffic so that pair is evicted. A subsequent `verify(request("/was-responded"), response().withStatusCode(418), never())` through the Java client must throw an `AssertionError` saying the **response** "could not be verified" because entries were discarded after reaching `maxLogEntries`. `MockServerEventLog` implements this guard twice — once in `verifyRequest` and once, through a completely separate counting path over recorded pairs, in `verifyResponse` — and only the request arm had an `*IntegrationTest`; the response arm was covered solely by an engine-level test against an in-process event log. The test uses `never()` because it is the simplest shape that reaches the guard: the guard sits on the PASS branch behind any asserted upper bound (`getAtMost() != -1` — so `atMost(n)`, `between(0,n)` and `exactly(0)` reach it too), whereas an `atLeast(1)`/`once()` verification of an evicted pair fails earlier with an ordinary "Response not found" message and proves nothing. `never()` is exactly the case a guard-less server would answer with a silent false green. The assertion pins the message to `Response could not be verified` so it cannot be satisfied by the request-side arm. Verified by a positive control (disabling only the response-side guard in production makes the verification pass silently and turns the test red). - **The eviction false-green guard is now proven end-to-end over HTTP.** A new Netty integration test (`EvictedLogVerificationIntegrationTest`) boots a real server with `maxLogEntries=2` and `failVerificationOnEvictedLog=true`, records a `GET /was-called` request, then floods the bounded request-log ring with further traffic so the `/was-called` entry is evicted. A subsequent `verify(request("/was-called"), never())` through the Java client must throw an `AssertionError` whose message says the log "could not be verified" because entries were discarded after reaching `maxLogEntries` — proving the guard refuses to certify absence it can no longer see, rather than silently passing. Previously the guard was only covered by an engine-level test against an in-process `MockServerEventLog` and no `*IntegrationTest` exercised it across the wire. Verified by a positive control (disabling the guard in production makes `verify(never())` pass silently and turns the test red). - **Custom gRPC response metadata and trailing metadata are now proven against a real `grpc-java` client.** Two new tests in `GrpcUnaryClientIntegrationTest` register an expectation whose gRPC response carries both custom response metadata authored with `withHeader(...)` and custom trailing metadata authored with `withTrailer(...)`, drive it with a live `grpc-java` client, and read the values back off the real `io.grpc.Metadata` objects the client receives (via a capturing `ClientInterceptor`, and via `StatusRuntimeException.getTrailers()` on the error path). The assertions are deliberately discriminating: the response metadata must arrive in the *initial headers* and not in the trailers, the trailing metadata must arrive in the *trailers* and not be folded into the initial headers, and both values must round-trip byte-for-byte including a value carrying `=`, `;`, `,` and spaces. Previously this behaviour was exercised only structurally (`EmbeddedChannel` / model-level assertions, which cannot tell a trailer emitted as a trailer from one folded into the headers) and by the existing `-bin` metadata tests, which deliberately accept the value from either side because a body-less unary response may legitimately collapse to Trailers-Only. Verified by positive controls: dropping the user-authored trailers turns both tests red, and dropping the user-authored response headers turns the header assertion red. - **The `maxResponseBodySize` limit is now proven behaviourally against a real upstream.** A new integration test (`MaxResponseBodySizeIntegrationTest`) boots a forwarding MockServer configured with a 4KB `maxResponseBodySize`, points it at a raw upstream socket that returns a 64KB body, and drives it over a plain client socket: the oversized body fails the forward and the client receives **502 Bad Gateway** with none of the payload relayed, while a control request whose body sits under the limit is forwarded intact. A third case repeats the oversized body with `Transfer-Encoding: chunked` and no `Content-Length`, proving the cap is enforced against the bytes actually accumulated by the forward client's aggregator rather than merely against a declared header. Previously this documented, memory-protecting bound — read whenever a forward-client pipeline is built — had no behavioural coverage at all, so a regression that dropped the wiring (or passed an unbounded value) would have removed the limit silently; only the inbound analogue `maxRequestBodySize` was verified. The new test covers the HTTP/1.1 forward aggregator; the HTTP/2 forward path reads the same property (for the per-stream aggregator and to derive the client's `maxFrameSize`) and remains uncovered. `maxResponseBodySize` accordingly moves from `ENFORCEMENT_EXEMPT` to `ENFORCEMENT_VERIFIED` in `ConfigurationEnforcementClassificationTest`. Verified by a positive control (restoring an unbounded aggregator lets the oversized body through with a 200 and turns both over-limit assertions red). - **The Ruby client now proves live SSE stream consumption over the wire.** New integration examples (`spec/integration_spec.rb` → `SSE streaming`) register an `httpSseResponse` expectation via the Ruby client against a running MockServer, then open a real streaming HTTP consumer and assert every `data:` frame arrives in order, that the reconstructed multi-delta message matches, and that a multi-line `data:` payload survives the framing intact (`Content-Type: text/event-stream`). Previously the Ruby suite only asserted the JSON keys of a built streaming expectation (`a2a_spec`) and never consumed a live SSE stream, so a silent server-emission or client-parsing drop would have gone uncaught. Verified by a positive control (dropping events from the emitted stream turns the received-frames assertion red). - **The `assumeAllRequestsAreHttp` protocol-detection fallback now has direct unit coverage.** Two paired `EmbeddedChannel` tests in `DirectProxyUnificationHandlerTest` drive `PortUnificationHandler.decode()` with an HTTP request using a non-standard method (`PURGE`, which is not one of GET/POST/PUT/HEAD/OPTIONS/PATCH/DELETE/TRACE/CONNECT): with `assumeAllRequestsAreHttp=true` the full HTTP pipeline is added (rather than falling to binary request proxying), and with the flag disabled the HTTP codec is not added — proving the flag is the only difference. Previously the fallback branch was exercised only by a live-socket integration test and the config getter's own unit test, so the `EmbeddedChannel` protocol-detection path for the flag was unexercised. - **HTTP/3 streaming response bodies are now proven end-to-end through the action pipeline with a real QUIC client.** A new integration test (`Http3StreamingForwardIntegrationTest`) registers a `forward` expectation on the HTTP/3 port (with `streamingResponsesEnabled`) pointing at an upstream Server-Sent Events stream that serves an early event immediately and withholds the late event for 1.5s, then drives it with a live Netty QUIC client and asserts both events arrive as SEPARATE DATA frames spread across that delay — proving the streaming relay funnels through `HttpActionHandler` -> `ResponseWriter.writeResponse` -> `Http3ResponseWriter.writeStreamingResponse` and emits chunks incrementally. Previously `Http3StreamingIntegrationTest` drove `Http3ResponseWriter` directly from a hand-built QUIC server (bypassing expectation matching), and `Http3MockingMatrixIntegrationTest` exercised the real pipeline over QUIC but only with non-streaming actions, so incremental delivery of a streamed body through the full pipeline was untested. QUIC-gated like the sibling HTTP/3 tests so it skips cleanly where the native transport is unavailable. - **The dashboard's Monaco code editor is now proven in a real browser end-to-end.** A new Playwright e2e test (`mockserver-ui/e2e/dashboard.spec.ts`) drives the actual bundled Monaco editor in the served dashboard's composer against a live MockServer: it asserts Monaco's own DOM (`.monaco-editor` / `.view-lines`) renders, authors a JSON response body via real editor input, raises and clears a live validation marker from Monaco's JSON language web worker, then registers the mock and confirms the Monaco-authored body round-trips to the server (present in `PUT /mockserver/retrieve` and served verbatim on the matching request). Previously the 178 jsdom/vitest specs globally replaced Monaco with a bare ` + ``` Biome now prints the content of these elements exactly as it appears in the source, matching the existing behavior for `
`.

- [#​11194](https://redirect.github.com/biomejs/biome/pull/11194)
[`abfbb11`](https://redirect.github.com/biomejs/biome/commit/abfbb11da260852f0b4aa15f36207314ccfae436)
Thanks [@​dyc3](https://redirect.github.com/dyc3)! - Fixed the
HTML formatter refusing to format a Svelte file containing an array
pattern that skips a position:

  ```svelte
  {#each animals as [, value]}
  	

{value}

{/each} ``` - [#​10094](https://redirect.github.com/biomejs/biome/pull/10094) [`e007143`](https://redirect.github.com/biomejs/biome/commit/e00714360807115210e549caca0f235431ca9a8a) Thanks [@​THEjacob1000](https://redirect.github.com/THEjacob1000)! - Fixed [`useSortedClasses`](https://biomejs.dev/linter/rules/use-sorted-classes/) to correctly detect unsorted classes in static member expression tagged templates (e.g. `tw.div\`...\`\`). Previously, these were silently skipped due to surrounding whitespace trivia not being stripped from the tag name. - [#​11078](https://redirect.github.com/biomejs/biome/pull/11078) [`10da30e`](https://redirect.github.com/biomejs/biome/commit/10da30e0013c35fe2f4d3e335b88a539ae6eb87a) Thanks [@​dyc3](https://redirect.github.com/dyc3)! - Fixed Vue single-file components failing to parse when they contain a custom block such as `` or ``, or a `