Commit c303cdc
authored
chore(deps): update dependency org.mock-server:mockserver-netty-no-dependencies to v7.6.0 (#2386)
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.5.0` → `7.6.0` |

|

|
---
### Release Notes
<details>
<summary>mock-server/mockserver-monorepo
(org.mock-server:mockserver-netty-no-dependencies)</summary>
###
[`v7.6.0`](https://redirect.github.com/mock-server/mockserver-monorepo/blob/HEAD/changelog.md#760---2026-08-17)
##### Changed
- The three Kubernetes container-integration cases that need Java-built
images — `helm_sidecar_injection`
(admission-webhook sidecar injection), `helm_clustered_convergence`, and
`helm_jgroups_dns_ping` (both the
`-clustered` Infinispan image) — now run **blocking in CI** instead of
recording a skip. Previously the CI helm step
ran with no JDK and never built those images, so all three recorded an
honest but permanent SKIP — coverage that
looked green while proving nothing. A new `:maven: build container-test
images (jars)` step in the
`mockserver-container-tests` pipeline builds the `mockserver-netty`,
`mockserver-k8s-webhook`, and
`mockserver-state-infinispan` jars **from the tree** (once, via the
Maven-in-Docker reactor) and hands them to the
helm step as Buildkite artifacts; the helm step downloads them and does
cheap `docker build`s (a COPY into
distroless) to produce the `-clustered` and `mockserver-webhook` images,
then runs the suite. The jars travel as
artifacts (\~200 MB total) rather than `docker save`d images (\~1.3 GB),
mirroring the node-launcher / WAR hand-off. Both
layers **fail closed**: the helm step exits non-zero if any jar artifact
is absent, and the harness runs with
`REQUIRE_CLUSTERED_IMAGE=true`/`REQUIRE_WEBHOOK_IMAGE=true` so an image
that is expected-but-absent is recorded as a
**FAILURE**, never a skip — a skip in CI is now impossible. Local
`container_integration_tests/integration_tests.sh`
is unchanged for a developer without the images: it still records a
comprehensible SKIP (no fail-closed flag set),
and the harness now also builds the `mockserver-webhook` image locally
(`build_webhook_docker`) so the sidecar case
runs blocking in local dev too — it was never built by the harness
before, so that case had always skipped.
##### Added
- Two new rules in the always-on `check-false-green-guards.sh` CI gate.
**Rule 4** fails the build if a CI step runs the
container-integration harness with the helm/k3d cases active but does
not export both `REQUIRE_CLUSTERED_IMAGE=true` and
`REQUIRE_WEBHOOK_IMAGE=true` — the exact way the three image-dependent
Kubernetes cases could silently revert to a green
SKIP. It is keyed on the step's *behaviour* (invokes
`integration_tests.sh` without `SKIP_HELM_TESTS=true`), not on a
filename, so a rename or a second helm-running step is covered
automatically. **Rule 5** fails the build if a
`mockserver-core` test that performs a JVM-global logging side effect
(reaching `LogManager.readConfiguration`'s handler
`reset()` via the static `ConfigurationProperties` logging setters or a
forced fresh `<clinit>`) is not in the
`sequential-tests` include list — the shape behind a release-blocking
flake that `ParallelStaticStateGuardTest`
structurally cannot catch. Both rules fail closed on an empty corpus and
carry a rotating allow-list. See
[docs/operations/false-green-guards.md](docs/operations/false-green-guards.md).
- A `jarPath` launcher option and matching `MOCKSERVER_JAR_PATH`
environment variable for `mockserver-node`, pointing
`start_mockserver` at a pre-provisioned `mockserver-netty`
jar-with-dependencies instead of downloading one from
Maven Central. When set, that exact jar is launched and no download is
attempted; a configured-but-missing path is a
**hard error** (`... refusing to fall back to downloading a release`)
rather than a silent fall-back to a released
jar, so a missing artifact fails loudly. Mirrors the existing
`MOCKSERVER_BINARY_BASE_URL` bring-your-own-artifact
path for the standalone binary, and serves air-gapped/corporate installs
as well as testing a locally-built jar
(`jarPath` takes precedence over `mockServerVersion`/`artifactory*`; the
option beats the env var). The Node launcher
integration tests now use it in CI: a new `:maven: build node launcher
jar` step builds the jar **from the tree** and
the launcher-test step downloads it as an artifact and launches it via
`MOCKSERVER_JAR_PATH` — so the suite finally
tests the repo's own code instead of the last release. Previously it ran
a downloaded release chosen by
`package.json`'s version, so a `mockserver-core` fix could not green it
and a regression could not red it; that
released jar also carried the shipped dynamic-CA generation race (fixed
on master in `4cff56e61`) and flaked \~8% of
runs. The launcher step **fails closed** if the tree-built jar is absent
rather than reverting to a download, and
local `npm test` outside CI is unchanged (with neither the option nor
the env var set it still downloads as before).
- A structural wire-contract test for the LLM provider codecs
(`LlmCodecStructuralContractTest`), breaking the
self-derivation weakness in the golden-file drift test.
`LlmCodecGoldenFileTest` regenerates its golden **bodies**
from the codec itself (`-Dmockserver.updateLlmGoldens=true`), so a
structural codec defect — a renamed field, a
wrong SSE event name, a dropped `finish_reason` — bakes straight into
its own golden and the byte-for-byte drift
test then passes forever, confirming only that the codec is consistent
with itself (token *counts* were already
pinned separately by `shouldEncodeCanonicalTokenUsageCounts`; the bodies
were not). The new test asserts the live
codec output against **hand-authored expectations taken from each
provider's published API schema** — required
fields, JSON types, the enum discriminators each provider uses
(`object`/`type`/`finish_reason`/`stop_reason`/
`finishReason`/`status`/`done`), the tool-call envelope shape (arguments
as a JSON *string* for OpenAI/Responses
vs a structured *object* for Anthropic/Gemini/Ollama), and the exact SSE
event-name sequence for the event-typed
providers — across all seven chat/completion providers (Azure and
Bedrock via their delegate codecs). Crucially it
**never reads the golden files and is unaffected by
`-Dmockserver.updateLlmGoldens=true`**, so regenerating goldens
cannot silence it. Each named defect class was injected into a codec and
confirmed to turn the test red without
regenerating goldens (OpenAI renamed `finish_reason`; Anthropic SSE
`content_block_delta`→`content_delta`; Gemini
dropped `finishReason`; Responses renamed `status`; Ollama renamed
terminal `done`), then reverted. Residual
streaming-over-the-wire behaviour remains covered by
`LlmAgentLoopE2eTest`.
- Endpoint-level test (`HttpStateCassetteEndpointTest`) and an
authoritative `CassetteRegistry` javadoc note pinning
the settled decision that **loading and recording register a cassette
automatically**. The `record_llm_fixtures`
and `load_expectations_from_file` MCP tools already auto-register the
fixture in the process-wide `CassetteRegistry`
(keyed by file path, origin `recorded`/`loaded`, upserting on
re-load/re-record) so it surfaces under
`GET /mockserver/cassettes` and in the dashboard's Cassettes tab without
a manual `PUT /mockserver/cassettes` — but
nothing pinned that a so-registered cassette is actually retrievable
*through the GET endpoint*, and the registration
policy lived only in the two MCP callers, inviting the question to be
re-opened. The new test drives
`GET /mockserver/cassettes` (and the bare `/cassettes` alias) against a
registry populated the way the load/record
handlers populate it and asserts the documented body shape (path,
derived filename, expectation count, origin,
lastUsed), that record-then-load on one path yields a single upserted
entry, and that a server reset clears it. The
MCP tools and consumer docs (`ai_mcp_tools.html`) already stated this
behaviour; both are now clarified to say the
fixture is registered automatically. This closes the "CassetteRegistry
auto-population" product-decision item by
recording the decision in code, docs, and a test rather than leaving it
to resurface.
- Compile gates for the dashboard composer's generated client code in
Python, Ruby, Go and Rust
(`.buildkite/scripts/steps/ui-client-codegen-compile.sh`, wired into
`pipeline-ui.yml`), closing the gap where
five of the composer's seven languages had no compile check — only Java
(`ui-java-codegen-compile.sh`) and C#
(`ComposerCodegenEquivalenceTests.cs`) were gated, so an emitter bug or
a client-API rename would ship broken
generated code to users caught by nothing (the existing per-language
tests only string/byte-compare the emitter
output, never feed it to a compiler). Each gate drives the shared
representative composer matrix
(`extractParityCases.ts` — the exact `combos` the byte-identity parity
tests use) through that language's emitter
and runs the lightest credible toolchain check: `python -m py_compile`
and `ruby -c` catch any emitter bug that
produces malformed source (the strongest static check for a
dynamically-typed client with no shipped type stubs),
while **Go** (`go build`/`go vet ./...`) and **Rust** (`cargo check`)
compile the generated code against the real
in-repo `mockserver-client-go` / `mockserver-client-rust`, so a renamed
client method fails the build — the direct
analog of the Java `javac` gate. Node was already covered: the `tsc`
type-proof in `node.test.ts`
(`typecheck-node-codegen.mjs`) runs under `npm test`, so the
orphaned-script concern was already resolved by that
test. All four new gates are proven to go red (emitter drift → non-zero
exit) and green. Each phase runs in its
toolchain's Docker image via `run-in-docker.sh`; set
`CODEGEN_COMPILE_USE_DOCKER=false` for host validation.
- Config-to-client wiring tests for the GCS and Azure blob-store
backends
(`GcsBlobStoreRegistrarConfigWiringTest`,
`AzureBlobStoreRegistrarConfigWiringTest`), closing the gap where
only S3 (`S3BlobStoreRegistrarConfigWiringTest`) proved that
`blobStoreType` configuration is turned into a
working client. The GCS and Azure contract tests hand-build their
clients (`new GcsBlobStore(storage, …)`,
`new AzureBlobStore(containerClient, …)`), so the registrar that reads
the bucket/container name, endpoint,
credentials and project from configuration and constructs the client was
never exercised — a wiring bug there
would ship silently because the contract tests bypass it. The new tests
drive each registrar from configuration
only (as production does) against the same Docker emulator the contract
tests use (fake-gcs-server for GCS,
Azurite `3.36.0 --skipApiVersionCheck` for Azure) and assert the wiring
that can actually be got wrong:
endpoint override, credentials, project id, and that a round-tripped
object lands in the *configured*
bucket/container under the *configured* key prefix — verified through an
independent admin client so a
mis-wired name cannot pass. Docker-gated via the canonical
`DockerAvailability.isAvailable(...)` probe.
- The Node and Python Testcontainers modules
(`mockserver-testcontainers/node`, `mockserver-testcontainers/python`)
now start a real MockServer container in CI and assert against it,
closing a false-green gap where both published
client libraries had jobs that passed having exercised nothing (`npm run
test:unit` and `pytest -m "not docker"`
both skipped the container). Their CI steps now mount the Docker socket,
run the existing integration tests that
start a `mockserver/mockserver` container and drive it over HTTP, and —
mirroring the Go/.NET/Rust steps — fail
closed by grepping for an evidence marker the test prints only after a
real container answered
`PUT /mockserver/status` with `200`. A skip (test filtered out, renamed,
or Docker unusable) therefore fails the
CI build loudly instead of reading as green, while the tests still
degrade gracefully to a skip off-CI.
- A GitHub Actions workflow
(`.github/workflows/dependency-submission.yml`) now submits the resolved
Maven dependency
graph so Dependabot vulnerability **alerts** stay accurate for the
monorepo layout. GitHub's managed Maven
auto-submission only discovers a project at the repository root, so it
silently stopped when the Java project moved
into `mockserver/` — freezing the alerting graph at a pre-move snapshot
that produced phantom Spring advisories and
hid already-landed `log4j-api`/`jsoup` fixes. The workflow resolves and
submits the `mockserver/` reactor (which
includes `examples/java`) and the separate `mockserver-maven-plugin`
build under distinct correlators, path-gated to
`mockserver/**/pom.xml`. Dependabot's security-update pull requests were
unaffected — they read manifests directly;
it was only the alerting graph that had gone stale.
- A CI guard (`.buildkite/scripts/steps/check-certificate-expiry.sh`,
wired into the Java pipeline) now sweeps every
committed certificate PEM and fails the build when any certificate is
already expired or expires within 30 days,
warning between 30 and 180 days. It checks every certificate in a chain
file, allow-lists the one intentional
expired test fixture while asserting it stays expired, and enforces two
structural invariants that previously had
no automation: every `leaf-cert.pem` must expire on or before its
sibling `ca.pem`, and the shipped default CA
files must stay in lockstep (the
[PKCS#1](https://redirect.github.com/PKCS/mockserver-monorepo/issues/1)
and
[PKCS#8](https://redirect.github.com/PKCS/mockserver-monorepo/issues/8)
CA private keys are the same key, that key matches the CA
certificate, and the two committed copies of the CA certificate remain
byte-identical). Certificate expiry had
previously only ever been discovered by the build going red.
- A standing CI guard (`check-false-green-guards.sh`) that fails closed
when a new "false-green" test shape is
introduced — a test or CI step that reports success while verifying
nothing. The 2026-07-21 coverage audit named
these shapes but they lived only in plan documents, and the repository
then produced \~a dozen fresh instances in a
single day. The guard enforces the three that can be pinned down
precisely and each caused a real shipped false
green: (1) every JUnit suite gated by
`Assume.assumeTrue(DockerAvailability.isAvailable(...))` must be paired
with
`assert-suite-ran.sh` over its reports, or a broken Docker socket skips
it while the build stays green; (2) no CI
step may mount the Docker socket and then deselect the Docker-marked
tests (e.g. `pytest -m "not docker"`),
starting no container yet passing; (3) no container-integration
`logTestSkip` may park deferred work ("CI wiring is
a follow-up") as a green skip. It runs always-on (a new false green can
enter from any of several pipelines) and
carries a justified, self-verifying allow-list that fails if an entry no
longer names what it claims. Wiring this
up also closed a live gap it found — the `Gcs`/`Azure`
`RegistrarConfigWiringTest` cloud suites ran under a Docker
socket in CI but were not fail-closed-asserted. See
`docs/operations/false-green-guards.md`.
- A local-only, opt-in `K3D_LOCAL_CA_BUNDLE` hook in
`container_integration_tests/helm-deploy.sh` so the Helm
integration suite's k3d cluster can be stood up on a developer machine
behind a corporate TLS-inspection proxy.
When set, `start-up-k8s` overmounts the given **combined** CA bundle
(system/public roots + corporate root) as the
k3s node's containerd trust store at cluster-create time; when unset the
`k3d cluster create` command is
byte-identical to before, so CI (which never sets it) is unchanged.
Warns rather than fails if the variable is set
but the file is missing, mirroring `LOCAL_DOCKER_CA_BUNDLE` in
`.buildkite/scripts/run-in-docker.sh`. This unblocks
the three Kubernetes test-coverage gaps that were previously (and
incorrectly) deferred as impossible behind the
proxy: the host Docker daemon already trusts the corporate root so the
node image pulls, but the *in-node*
containerd has its own public-roots-only trust store and otherwise
cannot pull even the `rancher/mirrored-pause`
sandbox image (every pod fails sandbox creation with `x509: certificate
signed by unknown authority`). See
`docs/operations/build-system.md` → *Local Development Behind a
Corporate TLS-Inspection Proxy*.
- Two live Kubernetes container-integration tests that exercise
admission-webhook and JGroups discovery paths which
previously shipped unproven. `helm_sidecar_injection` deploys the chart
with `webhook.enabled=true` (self-signed TLS
bootstrap Jobs + webhook handler Deployment +
`MutatingWebhookConfiguration`), drives a real labelled pod `CREATE`
through the admission path, and asserts the resulting pod **spec**
carries the injected `mockserver-sidecar` container,
`mockserver-iptables-init` init container, and `mockserver.org/injected`
annotation — with a negative-control pod (no
opt-in annotation) that must **not** be injected, so a webhook that
injects unconditionally fails the test.
`helm_jgroups_dns_ping` deploys two clustered replicas and asserts the
headless Service is truly headless
(`clusterIP: None`), that `JGROUPS_DNS_QUERY` is wired to its FQDN, that
it resolves to ≥2 pod IPs (Endpoints plus an
in-cluster `nslookup`), that a ≥2-node JGroups/Infinispan view forms
(the anti "two clusters of one" guard), and that
state converges across the pods — exercising the Kubernetes DNS
discovery path that `JGroupsKubernetesStackTest`
(XML-parse only) and `ClusteredTwoNodeTest` (loopback MPING) never run.
Both were proven red by degrading the exact
behaviour they name (deleting the `MutatingWebhookConfiguration`;
deleting the headless Service and rolling the pods).
Both depend on Java-built images (the `-clustered` variant and the
`mockserver-webhook` handler); when those images
are absent — e.g. the CI helm step runs with `SKIP_JAVA_BUILD=true` and
no JDK — the cases record an honest **SKIP**
rather than a misleading pass, and run **blocking** only where the
images exist.
##### Changed
- `helm_clustered_convergence` is now a **blocking**
container-integration test rather than `non_blocking || true`. The
swallowed `k3d image import ... 2>/dev/null || true` is replaced by a
deterministic import that verifies the image is
present in the k3d node's containerd (via `crictl`) before deploying,
and a pre-deploy `ensure_namespace_absent` guard
removes the real back-to-back flake (`helm install` into a
still-`Terminating` namespace left by a prior run/retry).
When the `-clustered` image is absent (CI helm step, no JDK) the case
records an honest **SKIP**; when present it runs
blocking so a genuine clustering regression reds the suite.
- The `docker_compose_war_tomcat` container integration test (MockServer
deployed as a WAR into Tomcat 10.1) now
actually runs in CI, closing a false-green gap where it silently skipped
with *"WAR artifact not present … CI wiring
is a follow-up"* — a working behavioural test that never ran, in a
demonstrated weak spot (the ROOT-context
percent-decode regression `66b5d51d2` shipped and broke builds, and this
is the suite that would have caught it).
Buildkite steps share no filesystem, so the WAR (already built by the
reactor in the `:maven: build` step but never
published) is now uploaded via that step's `artifact_paths` and
downloaded by `container-tests-run.sh` into the path
the test globs. A missing WAR now fails the step **closed** (both an
explicit presence check in `container-tests-run.sh`
and, defensively, `prepare_war` in `integration_test.sh` red the case)
instead of skipping — a skip that reads as green
is the exact defect being closed. The case runs in the Java pipeline's
master-only `:docker: container integration
tests` step (triggered by `mockserver/`, `mockserver-ui/`,
`test-fixtures/` changes); it was already declared required
in `expected_tests.manifest`, so no manifest change was needed.
- Upgraded Netty from `4.2.16.Final` to `4.2.17.Final` and, in lockstep,
`netty-tcnative-boringssl-static` from
`2.0.78.Final` to `2.0.81.Final` (the tcnative version the Netty 4.2.17
BOM aligns to). The two must move together:
the Netty BOM pins the transitively-resolved native-classifier tcnative
jars to `2.0.81.Final`, so a mismatched
main-artifact pin fails the enforcer `DependencyConvergence` rule in
`mockserver-core`. The `NETTY_TCNATIVE` build
args in every `docker/*/Dockerfile` were updated to match. This unblocks
Dependabot PRs
[#​2523](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2523)
and
[#​2532](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2532).
- Removed the manual `netty-tcnative` version-synchronisation step that
made every Netty upgrade a convergence trap.
`netty-tcnative-boringssl-static` no longer has its own version property
or `dependencyManagement` override — the
imported `netty-bom` now governs the base artifact and every OS/arch
native classifier together, so the two can no
longer diverge and break the enforcer `DependencyConvergence` rule. The
server jars (which ship tcnative classes
but, per
[#​1778](https://redirect.github.com/mock-server/mockserver-monorepo/issues/1778),
no natives) are stamped at build time with their resolved tcnative
version at
`META-INF/mockserver-tcnative.version`, and every `docker/*/Dockerfile`
now derives the native `.so` download from
that stamp instead of a hardcoded `NETTY_TCNATIVE=` build arg (SHA256
verification of the download is unchanged).
Both jars a Dockerfile can consume carry the stamp: the shaded
`mockserver-netty-no-dependencies` jar used by the
`source=copy` path (release/snapshot/CI) and the `mockserver-netty`
assembly `-jar-with-dependencies.jar` used by
the default `source=download` path (the public reference build), stamped
via the same script so they cannot drift. A
Netty bump therefore needs no tcnative pin update and no Docker edit,
and the native `.so` can never be a different
version than the tcnative classes it pairs with.
- **BREAKING BEHAVIOUR: the default enabled TLS protocols are now
`TLSv1.2,TLSv1.3` (previously
`TLSv1,TLSv1.1,TLSv1.2`), and `tlsAllowInsecureProtocols` now defaults
to `false` (previously `true`).**
TLSv1 and TLSv1.1 are deprecated by RFC 8996 and vulnerable to
BEAST/POODLE, and TLSv1.3 was previously never
negotiated unless explicitly configured. This is a breaking change for a
client that can only speak TLSv1 or
TLSv1.1: its handshake to MockServer will now fail. To
restore the legacy protocols set
`mockserver.tlsProtocols=TLSv1,TLSv1.1,TLSv1.2` AND
`mockserver.tlsAllowInsecureProtocols=true` (both are required — the
insecure-protocol filter strips TLSv1/TLSv1.1
unless it is explicitly allowed). The inbound server always applies the
strong `Http2SecurityUtil` cipher suites, so
no weak-cipher combination becomes reachable as a result of this change.
- Renewed the TLS/mTLS test-certificate fixtures. The two mutual-TLS
authentication CAs (which were 151 days from
expiry) and the three Netty TLS integration CAs were re-issued with a
10-year validity, and every leaf they sign
was re-issued with a shorter 5-year validity so that a leaf can no
longer outlive its issuing CA. The existing CA
and leaf private keys were preserved (so key encodings,
Subject/Authority Key Identifiers and existing signatures
are unchanged); only the certificates were re-minted.
##### Security
- Pinned `org.apache.logging.log4j:log4j-api` to `2.25.5` to resolve
GHSA-qv9r-c865-cp47. It is pulled in transitively
at compile scope (via `spring-boot-starter-logging` -> `log4j-to-slf4j`)
and lands in a shaded artifact, so it is
shipped; the pin manages `log4j-api` only (`log4j-core` is not on the
dependency tree).
- Pinned `org.jsoup:jsoup` to `1.23.1` to resolve GHSA-pmhh-3w7g-xqp8.
jsoup is used only at test scope (never shipped);
the pin guards against a future transitive downgrade below the fixed
version.
- Upgraded `com.azure:azure-storage-blob` from `12.29.1` to `12.35.0` in
the optional `mockserver-blob-azure` module to
resolve the `io.projectreactor.netty:reactor-netty-http`
chained-redirect credential-leak advisory (fixed in
reactor-netty `1.2.8`). The old stack pulled
`azure-core-http-netty:1.15.10`, which pins the vulnerable
reactor-netty `1.0.48` pair transitively; `12.35.0` pulls
`azure-core-http-netty:1.16.5`, which advances both
`reactor-netty-http` and `reactor-netty-core` to `1.2.18` as a matched
pair. This exposure surfaced only when
GitHub's Maven dependency-graph submission was restored (submission had
silently frozen at a pre-move snapshot, so
the alert had been invisible to Dependabot). The whole Azure stack
(azure-core `1.58.1`, reactor-netty `1.2.18`,
reactor-core `3.7.19`) remains Java-8 bytecode, so the Java 17 floor is
preserved. A module-scoped
`dependencyManagement` pin of `io.projectreactor:reactor-core` to
`3.7.19` reconciles the one internal off-by-one in
the 12.35.0 stack (azure-core declares `3.7.18`, reactor-netty declares
`3.7.19`) so the enforcer
`DependencyConvergence` rule stays satisfied. The Docker-gated Azurite
contract test moves to Azurite `3.36.0` with
`--skipApiVersionCheck`, since the newer SDK negotiates a Storage REST
API version that runs ahead of every released
Azurite build.
- Pinned three transitive dependencies to close vulnerability alerts
that surfaced only when GitHub's Maven
dependency-graph submission was restored (submission had silently frozen
at a pre-move snapshot on 5 May, so these
real exposures had been invisible to Dependabot). None required moving
the direct dependency that introduces them:
- Jackson 3 (`tools.jackson.core:jackson-databind`, `:jackson-core`,
`tools.jackson.dataformat:jackson-dataformat-yaml`)
pinned to `3.1.5` to resolve GHSA-5gvw-p9qm-jgwh (vulnerable `>=3.0.0,
<=3.1.4`). It arrives at compile scope via
`com.networknt:json-schema-validator:3.0.6` and is shade-relocated into
`shaded_package.tools.jackson`, so it
ships in every distributed jar — the one broad, shipped, runtime
exposure of the three. All three artifacts
resolve in lockstep and are pinned together so the enforcer
`DependencyConvergence` rule stays satisfied. The pin
is inherited by the separate `mockserver-maven-plugin` build (same
parent pom), closing its alert too.
- `at.yawk.lz4:lz4-java` pinned to `1.11.1` to resolve
GHSA-6qcp-4vqm-vf35 (native XXHash JVM crash; vulnerable
`<=1.11.0`). Arrives via `org.apache.kafka:kafka-clients:3.9.2` —
optional in `mockserver-netty`, runtime in
`mockserver-async`. Note this is the `at.yawk.lz4` fork coordinate, not
`org.lz4`.
- `org.apache.commons:commons-compress` pinned to `1.27.1` to resolve
the `>=1.21, <1.26.0` advisories. Arrives at
test scope via `org.testcontainers:testcontainers:1.21.4`, which
resolves it at `1.24.0`. The direct pin overrides
that transitive version without bumping Testcontainers, which is
deliberately held at `1.21.4` for Docker Desktop
4.67+ compatibility.
- Made outbound TLS host name verification consistent and controllable
for the forward/proxy client (Wave 3). When
`forwardProxyTLSX509CertificatesTrustManagerType` is `JVM` or `CUSTOM` —
the modes that actually validate the
upstream certificate chain — MockServer now verifies the upstream host
name against the certificate (RFC 2818 / HTTPS
endpoint identification) on every outbound path. Netty already enabled
this for client connections opened with a
known host/port, but NOT for the no-host relay paths, so verification
was silently skipped on some paths and there
was no way to turn it off; without the host-name binding a certificate
signed by a trusted CA for any host name would
be accepted, leaving a user who had opted into real upstream validation
open to a man-in-the-middle. It is now forced
uniformly at the single point every outbound path shares (HTTP/1.1,
HTTP/2, CONNECT-tunnelled relay, websocket relay,
the reverse-proxy relay — which verifies against the CONNECT target
host/port, not the connected socket address — and
the LLM forward paths). It has no effect on
the default `ANY` trust manager, which deliberately trusts everything
and performs no host-name verification. A new
`forwardProxyTLSHostnameVerificationEnabled` property (default `true`)
turns off just the host-name check while
keeping chain validation, for the legitimate testing case of an upstream
whose certificate host name does not match
the address connected to (it actively clears the algorithm Netty would
otherwise default on); it is carried by
`ConfigurationDTO` and folded into the client SSL-context cache key so a
runtime change takes effect. The
trust-manager javadoc, which previously implied only `ANY` skipped
host-name verification, has been corrected.
- Added a single startup WARN when the publicly-published bundled
Certificate Authority (whose private key ships in the
MockServer jar) is the trust anchor signing served traffic, naming the
two supported fixes
(`dynamicallyCreateCertificateAuthorityCertificate=true`, or
`--proxy-setup`). Shipping the CA key is intentional and
documented and the default is unchanged; the warning just makes the
trade-off visible so an operator does not mistake
the bundled CA for real interception security. Logged once per JVM,
never per handshake.
- A user-supplied FIXED server certificate is now re-checked on a cheap,
time-bounded schedule (at most once a minute,
stat only — never a per-handshake re-parse) so a long-running server
surfaces a problem instead of silently serving
it: a certificate rotated in place on disk forces a rebuild (which
re-runs validation and picks up the replacement,
failing loudly if it too is expired), and an unchanged-but-expired
certificate is surfaced with a single WARN. Wave 1
had deliberately left this gap (self-generated leaves already
self-renew; fixed certificates were validated only at
startup).
- Added a control-plane audit WARN when a `PUT
/mockserver/configuration` lowers or alters TLS security posture —
downgrading the forward-proxy trust manager to `ANY`, turning off
`tlsMutualAuthenticationRequired`, turning off
`forwardProxyTLSHostnameVerificationEnabled`, or repointing the TLS
key/certificate/CA paths. Control-plane
authentication is off by default, so such a runtime downgrade would
otherwise be silent. The change is audited, not
blocked (blocking would be an init-only breaking change).
- Hardened the dynamic TLS certificate cache so it can no longer serve
stale, torn or over-broad material (Wave 1,
resilience only — certificate validity periods and extensions are
unchanged). The cached server SSL context now
regenerates a fresh leaf once the current one passes a renewal threshold
(80% of its validity elapsed) instead of
serving an expired certificate for the JVM lifetime; the cache-reuse
decision is driven by a content signature over
the Subject-Alternative-Name set, certificate-authority identity,
key/cert paths, mTLS and protocol inputs
(replacing a single consumable boolean that could return a certificate
missing a just-added SAN under concurrency);
client SSL contexts and the memoised certificate authority now
self-invalidate when their inputs are rotated at
runtime. Certificate generation now publishes the new private key and
certificate atomically (a mid-flight failure
keeps the previous working pair instead of leaving a new key paired with
the old certificate), and SNI-driven
provisioning runs off the Netty event loop with per-host coalescing.
Only the leaf drives that renewal trigger: a
dynamically-generated certificate authority nearing its own expiry is
warned about once (it is never rotated
automatically, which would invalidate every client trust store that
imported it) rather than demanding a leaf
regeneration the certificate-authority guard can never satisfy — which
would otherwise re-mint the leaf on every
handshake indefinitely.
- Bounded the dynamically-grown Subject-Alternative-Name list with a new
`maxSubjectAlternativeNames` property
(default 100; when the cap is reached the genuinely oldest
dynamically-discovered entry is evicted first, in FIFO
order, with a warning, while configured and default SANs such as
localhost are never evicted) and now
normalise/validate each SNI hostname and `Host` header (lowercase,
length and label-charset checked) before it is
added, closing a denial-of-service vector where any client could force
the leaf certificate to be re-minted with an
unbounded SAN list. Both `maxSubjectAlternativeNames` and
`sslCertificateLeafValidityInDays` are now carried by
`ConfigurationDTO`, so they round-trip through `GET`/`PUT
/mockserver/configuration` and can be set per-instance
rather than only via the static store (a runtime change to
`maxSubjectAlternativeNames` takes effect on the next SAN
added).
- Dynamically-generated private key material (leaf key,
certificate-authority key, and the JKS key store) is now
written owner-readable-only (`0600`) and atomically, and public
certificates `0644`; a corrupt or unreadable
certificate-authority PEM now fails loudly instead of being silently
treated as absent and overwritten (which would
invalidate every pinned client trust store), with cross-process locking
around certificate-authority generation.
- Deferred BouncyCastle registration in `PEMToFile` off the class-load
path, restoring the lazy-BouncyCastle startup
optimisation.
- Shortened the auto-generated TLS **leaf** (server) certificate to a
397-day validity by default (Wave 2), so it
stays inside Apple's 825-day maximum for TLS server certificates (iOS 13
/ macOS 10.15) — the previous 10-year leaf
exceeded that cap and is the likely cause of TLS handshake failures on
Apple platforms
([#​2531](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2531)).
The generated Certificate Authority keeps
its long (10-year) life, and the Wave 1 proactive renewal (regenerating
the leaf once 80% of its validity has
elapsed) means a long-running server never serves an expired leaf; the
previous long-lived behaviour can be restored
with the new `sslCertificateLeafValidityInDays` property (e.g. `3650`).
That override is clamped to a usable range of
30–3650 days (a WARN is logged when a value is clamped): a value below
30 would mint a leaf that — because the
`notBefore` is back-dated 5 days — is either already expired at issuance
or already past its renewal threshold (so it
would be re-minted on every handshake), and a value above 3650 could
push the expiry past the X.509 date ceiling; a
non-positive value still falls back to the 397-day default. The
generated leaf now also carries a
`serverAuth`+`clientAuth` extended-key-usage (Apple requires
`serverAuth` on the leaf independently of validity), a
critical `digitalSignature`+`keyEncipherment` key-usage, and an
authority-key-identifier derived from the CA; the
root CA no longer carries a (non-idiomatic) extended-key-usage.
Certificate serial numbers are now forced positive
as required by RFC 5280, and the HTTP/3 legacy echo-mode self-signed
fallback gained a back-dated `notBefore`,
subject-alternative-names, `serverAuth` extended-key-usage and a
key-usage (it keeps the long validity because it is
both trust anchor and server certificate with no renewal loop).
##### Removed
- Removed the unused `PKCS1CertificateAuthorityPrivateKey.pem` resource
from the published `mockserver-core` jar. It
was the explicit
[PKCS#1](https://redirect.github.com/PKCS/mockserver-monorepo/issues/1)
half of an encoding pair added in 2020 for the since-removed JDK
key/certificate builder,
whose deletion in 2022 left it with no references for around four years.
It was byte-identical to the original
`CertificateAuthorityPrivateKey.pem`, which is retained (it backs a
published raw-URL link and remains the stable
[PKCS#1](https://redirect.github.com/PKCS/mockserver-monorepo/issues/1)
form); the code continues to load
`PKCS8CertificateAuthorityPrivateKey.pem`.
##### Fixed
- Fixed a rare `mockserver-core` unit-test flake
(`ConfigurationValueRedactionTest` /
`ConfigurationDTOCredentialMaskingTest` failing with `Expected: is <1>
but: was <0>` when asserting an exact count of
captured log records). These tests attach a `java.util.logging` handler
and assert what is emitted. Two other tests —
`ClassInitializationDeadlockTest` and
`ConfigurationPropertiesInitializationTest` — force a fresh `<clinit>`
of
MockServer classes in an isolated child-first classloader; that
initialisation reaches
`MockServerLogger.installDefaultJavaLoggingFormat()` →
`LogManager.getLogManager().readConfiguration(...)`, and
`java.util.logging.LogManager` is a **JVM-global singleton the
child-first classloader does not isolate**, so its
`readConfiguration` performs a `reset()` that removes every handler from
every logger in the JVM. When one of those
classes ran in the parallel Surefire phase alongside a handler-capturing
test, the reset detached the capturing
handler mid-test and a subsequent emit went uncounted. Both
fresh-`<clinit>` classes are now pinned to the sequential
(`parallel=none`) Surefire phase in `mockserver-core/pom.xml`, so they
can never run concurrently with a
handler-capturing test. No production behaviour changes.
- Fixed the Helm chart's sidecar-injection webhook being broken out of
the box. The default TLS-bootstrap image
`webhook.tls.setupImage: bitnami/kubectl:1.31` no longer exists —
Bitnami withdrew the tag from Docker Hub — so both
bootstrap Jobs failed, the `MutatingWebhookConfiguration`'s `caBundle`
was never patched, and because
`failurePolicy: Fail` the webhook then **rejected every matched pod
CREATE**. Anyone enabling `webhook.enabled=true`
from the shipped defaults got an admission path that blocked pod
creation rather than injecting a sidecar. The
bootstrap now uses `registry.k8s.io/ingress-nginx/kube-webhook-certgen`,
the purpose-built tool for exactly this
job, published on the most stable-publication registry available and
self-contained (no shell, no `openssl` CLI, no
install-at-runtime step that would fail on an airgapped or proxied
cluster). Phase 2's ClusterRole also gains the
`update` verb, which the patch step genuinely needs.
`helm_sidecar_injection` now renders and asserts the **chart
default** is pullable rather than overriding it, so this cannot silently
rot again.
- Fixed the Kubernetes sidecar-injection webhook rejecting valid TLS
private keys. `WebhookServer` parsed
[PKCS#8](https://redirect.github.com/PKCS/mockserver-monorepo/issues/8)
only
and explicitly rejected anything else, which broke the **cert-manager**
path as well: the chart's `Certificate`
requests `algorithm: RSA` without `encoding: PKCS8`, i.e.
[PKCS#1](https://redirect.github.com/PKCS/mockserver-monorepo/issues/1),
so a cert-manager-issued key could not be loaded.
It now accepts any standard unencrypted PEM private key —
[PKCS#8](https://redirect.github.com/PKCS/mockserver-monorepo/issues/8),
[PKCS#1](https://redirect.github.com/PKCS/mockserver-monorepo/issues/1),
and SEC1 EC. This coupling is why the
broken bootstrap image above could not simply be swapped: the handler
only tolerated the one format that one
withdrawn image happened to emit.
- Fixed a thread race in dynamic Certificate Authority generation that
could leave a standalone / CLI / Docker
MockServer serving broken TLS for the rest of the process's lifetime.
When
`dynamicallyCreateCertificateAuthorityCertificate` is enabled, two
startup paths could generate the CA
concurrently — the proxy-setup log (`proxySetupLogging`, on by default
in the CLI) writing the CA to disk, and the
first HTTPS handshake building the server certificate. Generation was
serialised only by a cross-process file lock;
a second lock attempt **within the same JVM** threw
`OverlappingFileLockException`, which was caught and treated as
"proceed without serialisation", so both threads minted different CA key
pairs and interleaved their writes. The
result was a torn CA key/certificate pair on disk: every leaf
certificate was then signed with one generation's CA
key but verified against the other's CA public key, failing with
`SignatureException: certificate does not verify
with supplied key` — and because the mismatched CA was memoised, **every
subsequent TLS handshake failed for the
life of the process**. CA generation (and the paired load of the CA key
+ certificate) is now serialised within the
JVM on a per-directory monitor in addition to the cross-process file
lock, so the key and certificate are always
published from the same generation. Embedded `ClientAndServer` users
were unaffected (they default
`proxySetupLogging` off); standalone, CLI and Docker users generating a
dynamic CA could hit it intermittently.
- Unblocked the daily Dependabot updater, which had been failing and
raising no PRs. The Maven wrappers under
`mockserver/` and `mockserver/mockserver-maven-plugin/` were modernised
from the legacy Takari format to the
Apache `only-script` wrapper (`wrapperVersion` 3.3.4, Maven pinned at
3.9.16), so the `maven-wrapper-updater` can
parse them; `mockserver-vscode` was split into its own npm job (a
lockfile `EOVERRIDE` there no longer aborts the
other npm directories) and pinned `js-yaml` to `^4.1.1` via `overrides`;
and `/.opencode` (which had only an
orphan lockfile and no tracked manifest) was removed from the npm
directories and its lockfile untracked.
- Cloning an `X509Certificate` model that contains certificate metadata
without an underlying Java certificate no
longer throws a `NullPointerException`; metadata-only and
certificate-backed models now both preserve their state
when cloned
([#​2527](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2527)).
- JSON body matching no longer depends on which JSON provider
[json-unit](https://redirect.github.com/lukas-krecan/JsonUnit)
resolves to. MockServer parses both documents with Jackson and hands
json-unit the resulting nodes to avoid
re-parsing on every match, but json-unit picks its provider by asking
each in turn whether it claims the value
and falling back to the last one registered — and only its Jackson
provider claims a Jackson node. Where another
provider won (for example `org.json`, whether because Jackson was not
visible to json-unit or because
`json-unit.libraries` pinned it) every JSON match threw `Unsupported
type class
com.fasterxml.jackson.databind.node.ObjectNode` and **no JSON body ever
matched**. MockServer now falls back to
giving json-unit the raw JSON text, which it parses with whichever
provider it resolved to
([#​2496](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2496)).
- Match failures from the JSON body matcher now report why the match
failed. When JSON matching threw, the log said
only `exception while perform json match failed` and the exception was
recorded solely at `TRACE`, so at the
default log level there was no way to tell a malformed body from a
missing class from a runtime error. The cause
is now included in the reported difference, as it already was for the
XML schema, JSON path and JSON-RPC matchers.
- Resolved the outstanding npm security advisories in the shipped and
published Node packages: `dompurify`
`3.4.12` → `3.4.13` in the bundled dashboard (`mockserver-ui`),
`brace-expansion`
`5.0.8` → `5.0.9` (ReDoS) in `mockserver-testcontainers/node`, and
`js-yaml`
`4.3.0` → `4.3.1` in `mockserver-client-node`, `mockserver-node` and
`mockserver-testcontainers/node`. The `brace-expansion` fix bumps only
the parent so the `minimatch`/`archiver`
glob split is preserved (a blanket override previously broke
`archiver`); no `brace-expansion` override was added.
- Documented and mitigated a clustered-deployment TLS trust defect: with
the default dynamic Certificate Authority
generation, every MockServer node in a cluster mints its own distinct
CA, so a client that trusts one node's
`mockserver-ca.pem` gets an intermittent TLS validation failure when a
load balancer routes it to another node.
`StateBackendFactory.create()` now logs a WARN when it detects
`clusterEnabled=true` together with
`dynamicallyCreateCertificateAuthorityCertificate=true`, and the
limitation and its fix are now documented in
`docs/code/clustered-state.md`, `docs/code/tls-and-security.md`, the
Helm chart README, and the Centralized
Deployment consumer page.
- Added first-class Helm chart support for supplying **one shared TLS
Certificate Authority to every replica** via a
Kubernetes Secret — the supported fix for the clustered CA defect above.
New opt-in values `app.tls.*` create (or
reference an existing) Secret, mount it read-only, and set
`certificateAuthorityCertificate` /
`certificateAuthorityPrivateKey` with
`dynamicallyCreateCertificateAuthorityCertificate=false` on every pod. A
CA
private key now lands in a Secret rather than a ConfigMap. Also added
`app.dynamicCertificateDir.*` (a writable
`emptyDir` for the single-replica dynamic-CA case, so certificate writes
no longer depend on a non-writable working
directory) and `app.extraEnv` (arbitrary container environment
variables, enabling any `MOCKSERVER_*` property the
chart does not expose directly). All new values are opt-in and default
to today's behaviour.
- Fixed a latent dead condition in the Helm chart Deployment template:
the `MOCKSERVER_PROPERTY_FILE` env var was
gated on an undeclared `app.mountConfigMap` value (always false).
`app.mountConfigMap` is now a declared value
(default `false`, preserving prior behaviour) so external-ConfigMap
users can opt into having MockServer pointed at
the mounted `mockserver.properties`.
</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:eyJjcmVhdGVkSW5WZXIiOiI0NC4yOS41IiwidXBkYXRlZEluVmVyIjoiNDQuMjkuNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiZGVwZW5kZW5jaWVzIl19-->
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>1 parent 1bcb903 commit c303cdc
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