mirror of
https://github.com/semantic-release/semantic-release.git
synced 2026-10-25 15:39:35 +00:00
alpha
2230 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1beed123fa |
feat: integrate @semantic-release/core engine (#4256)
This pull request refactors the core logic of the package to use the `@semantic-release/core` engine directly, removes legacy and duplicated code, and centralizes configuration. The changes simplify the codebase by delegating most of the release logic to the upstream core package, making the CLI wrapper thinner and easier to maintain. Several internal utility files for branch and tag handling are also removed, as their logic is now handled by `@semantic-release/core`. ### Migration to Core Engine * The CLI now delegates release logic to `@semantic-release/core`, using its `resolveConfig`, `getLogger`, and other helpers, instead of maintaining a custom implementation. This reduces maintenance overhead and ensures alignment with the core release logic. * The documentation is updated to explain that `semantic-release` uses `@semantic-release/core` as its engine, and provides guidance for advanced use cases. ### Configuration and Defaults * A new `SEMANTIC_RELEASE_DEFAULT_CONFIG` constant is introduced, centralizing the default plugin stack for releases. ### Codebase Simplification * Removes internal implementations for branch expansion, tag retrieval, and normalization, as well as related validation and error handling logic. These are now handled by the core engine.v25.1.0-alpha.1 |
||
|
|
04c1923646 |
build(deps): bump undici (#4309)
Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
e8c2436e57 |
build(deps-dev): bump fast-uri from 3.1.4 to 3.1.7 (#4293)
Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
a1def89ffd |
build(deps): bump js-yaml from 3.15.0 to 3.15.2 (#4298)
Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
64b5e0ba5b |
chore(deps): update dependency got to v16 (#4305)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [got](https://redirect.github.com/sindresorhus/got) | [`15.1.0` → `16.0.0`](https://renovatebot.com/diffs/npm/got/15.1.0/16.0.0) |  |  | --- ### Release Notes <details> <summary>sindresorhus/got (got)</summary> ### [`v16.0.0`](https://redirect.github.com/sindresorhus/got/releases/tag/v16.0.0) [Compare Source](https://redirect.github.com/sindresorhus/got/compare/v15.1.0...v16.0.0) #### Breaking changes - Rewrite HTTP/2 support and drop the `http2-wrapper` dependency ([#​2464](https://redirect.github.com/sindresorhus/got/issues/2464)) [`1e157c4`](https://redirect.github.com/sindresorhus/got/commit/1e157c4) - Got now has a built-in HTTP/2 client: ALPN negotiation, a pooled session cache with multiplexing, `GOAWAY` retirement, request and response trailers, informational (1xx) responses, abort signals, response caching, IPv6 authorities, and `h2c` through `h2session`. - `agent.http2` is no longer an agent slot. It is only an opt-out flag now: pass `false` to skip session pooling. Passing an agent instance throws. - Response headers no longer contain HTTP/2 pseudo-headers. Use `response.statusCode` instead of `response.headers[':status']`. - A custom `agent.https` combined with `http2: true` makes Got use the native HTTP/1.1 path, because the built-in session pool does not support custom HTTPS agents. - HTTP/2 proxy support is gone. It came from `http2-wrapper`. It was very buggy anyway. - If `options.request` returns a request or response, it controls the transport and the HTTP/2 client is bypassed. Return `undefined` to fall back to Got's own transport. - Rewrite DNS cache and drop the `cacheable-lookup` dependency ([#​2463](https://redirect.github.com/sindresorhus/got/issues/2463)) [`bfc400b`](https://redirect.github.com/sindresorhus/got/commit/bfc400b) - `dnsCache: true` now uses Got's own cache. The option accepts any object with a `lookup` function and an optional `clear(hostname?)` function, so an existing `CacheableLookup` instance still works if you keep the dependency yourself. - The built-in cache resolves A and AAAA records separately, so it cannot preserve OS-specific `verbatim` address ordering from `dns.lookup()`. - A `beforeRequest` hook, an `afterResponse` retry, or a pagination step that moves the request to a different origin now strips credentials and drops the body ([#​2465](https://redirect.github.com/sindresorhus/got/issues/2465)) [`dd3b295`](https://redirect.github.com/sindresorhus/got/commit/dd3b295) - `authorization`, `cookie`, `cookie2`, `host`, and `proxy-authorization` are removed, URL credentials are dropped, and an unchanged body is cleared. Set the headers or body explicitly inside the hook if you want them to cross the origin boundary. - This applies whether the origin changes through `url` or through `prefixUrl`. - `copyPipedHeaders` no longer copies credentials [`1d233ba`](https://redirect.github.com/sindresorhus/got/commit/1d233ba) - `authorization`, `cookie`, `cookie2`, `set-cookie`, and `set-cookie2` are now omitted along with `host`, the hop-by-hop headers, and anything nominated by `Connection` / `Proxy-Connection`. Pass credentials explicitly in `headers` when the upstream is trusted. - Remove the deprecated `searchParameters`, `followRedirects`, and `auth` option stubs [`1d233ba`](https://redirect.github.com/sindresorhus/got/commit/1d233ba) - They only existed to throw a guidance message. Passing them now throws `Unexpected option: …`. - Remove the `OptionsOfUnknownResponseBody` type [`1d233ba`](https://redirect.github.com/sindresorhus/got/commit/1d233ba) - It was a pure alias for `StrictOptions`. #### Improvements - Add support for the [`QUERY`](https://www.rfc-editor.org/rfc/rfc10008.html) HTTP method ([#​2466](https://redirect.github.com/sindresorhus/got/issues/2466)) [`e3924aa`](https://redirect.github.com/sindresorhus/got/commit/e3924aa) - Adds `got.query()` and `got.stream.query()`. `QUERY` is safe and idempotent, so it is retried by default and keeps a replayable body across `301` and `302` redirects as well as `307` and `308`. It is not stored by the built-in cache, because correct `QUERY` caching needs cache keys that include the request content. - `allowGetBody` now also works over HTTP/2 [`1e157c4`](https://redirect.github.com/sindresorhus/got/commit/1e157c4) - `timeout.socket` now applies during HTTP/2 TLS negotiation and session setup [`c6bbb8a`](https://redirect.github.com/sindresorhus/got/commit/c6bbb8a) - It was previously folded into the connection setup timeout and reported as a `request` timeout. It now produces a real `socket` timeout and no longer counts DNS lookup time. - Two fewer dependencies: `cacheable-lookup` and `http2-wrapper` [`bfc400b`](https://redirect.github.com/sindresorhus/got/commit/bfc400b) [`1e157c4`](https://redirect.github.com/sindresorhus/got/commit/1e157c4) #### Fixes - Retry on connection errors reported by `request.end()` instead of failing the request ([#​2470](https://redirect.github.com/sindresorhus/got/issues/2470)) [`67919b2`](https://redirect.github.com/sindresorhus/got/commit/67919b2) - Retry immediately when the server answers with `Retry-After: 0` instead of falling back to the backoff delay ([#​2471](https://redirect.github.com/sindresorhus/got/issues/2471)) [`d35ce87`](https://redirect.github.com/sindresorhus/got/commit/d35ce87) - Preserve the response body when a cookie jar write throws [`c6bbb8a`](https://redirect.github.com/sindresorhus/got/commit/c6bbb8a) - `error.response.body` is now complete, decompressed, and decoded with the configured `encoding`, and a decoding failure no longer masks the original error. - Wait for async cookie jar writes on terminal redirect responses, for example with `followRedirect: false` [`c6bbb8a`](https://redirect.github.com/sindresorhus/got/commit/c6bbb8a) - Only buffer the response body for cookie handling when the response actually sends `set-cookie` [`c6bbb8a`](https://redirect.github.com/sindresorhus/got/commit/c6bbb8a) - Fix `got.stream` finalizing the response before the `response` event and before piped server response headers are set [`c6bbb8a`](https://redirect.github.com/sindresorhus/got/commit/c6bbb8a) - Fix `strictContentLength` counting bytes from responses that were not actually decompressed [`c6bbb8a`](https://redirect.github.com/sindresorhus/got/commit/c6bbb8a) - Freeze `hooks.beforeCache` along with the other hook arrays on non-mutable defaults [`1d233ba`](https://redirect.github.com/sindresorhus/got/commit/1d233ba) - Keep URL credentials when `prefixUrl` is changed to a same-origin value, and treat credentials in `prefixUrl` as explicit [`dd3b295`](https://redirect.github.com/sindresorhus/got/commit/dd3b295) #### Migration guide ##### HTTP/2 Remove `http2-wrapper` from your code. Got's HTTP/2 client is built in. **Before:** ```js import http2wrapper from 'http2-wrapper'; const {headers} = await got(url, { http2: true, request: http2wrapper.auto, agent: { http2: new http2wrapper.Agent() } }); console.log(headers[':status']); ``` **After:** ```js const {statusCode} = await got(url, {http2: true}); console.log(statusCode); ``` To opt out of HTTP/2 session pooling for a request, set `agent.http2` to `false`. If you need an HTTP/2 proxy, keep using `http2-wrapper` through the `request` option. Returning a request from `request` bypasses Got's HTTP/2 client. ##### `h2c` The `h2session` hook example no longer needs `request` or `http2`. **Before:** ```js import http2 from 'http2-wrapper'; got.extend({ hooks: { beforeRequest: [ options => { options.h2session = getSession(options.url); options.http2 = true; options.request = http2.request; } ] } }); ``` **After:** ```js got.extend({ hooks: { beforeRequest: [ options => { options.h2session = getSession(options.url); } ] } }); ``` ##### `dnsCache` `dnsCache: true` keeps working and now uses Got's built-in cache. If you depend on `cacheable-lookup` specific options, install it yourself and pass the instance: ```js import CacheableLookup from 'cacheable-lookup'; const dnsCache = new CacheableLookup({maxTtl: 60}); await got(url, {dnsCache}); ``` ##### Cross-origin hooks If a `beforeRequest` hook, an `afterResponse` retry, or a pagination step sends the request to a different origin, set the headers and body you want to keep explicitly: ```js got.extend({ hooks: { beforeRequest: [ options => { options.url = new URL('https://other.example.com/path'); options.headers.authorization = 'Bearer …'; } ] } }); ``` ##### `copyPipedHeaders` Credentials are no longer forwarded from a piped request. Pass them explicitly when the upstream is trusted: ```js got.stream(url, { copyPipedHeaders: true, headers: { authorization: request.headers.authorization } }); ``` *** </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
afe0ddbbdf |
ci(action): update github/codeql-action action to v4.38.0 (#4304)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | minor | `v4.37.6` → `v4.38.0` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.38.0`](https://redirect.github.com/github/codeql-action/releases/tag/v4.38.0) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.9...v4.38.0) - On GitHub-hosted runners, the CodeQL Action now deletes unused CodeQL bundles from the toolcache before downloading a different bundle, which frees up disk space for the analysis. We expect to roll this change out to everyone in September. [#​4124](https://redirect.github.com/github/codeql-action/pull/4124) - The CodeQL Action now supports CodeQL releases that are compatible with Linux Arm64 and downloads the native `linux-arm64` CodeQL bundle when available. [#​4072](https://redirect.github.com/github/codeql-action/pull/4072) - Update default CodeQL bundle version to [2.27.0](https://redirect.github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.0). [#​4129](https://redirect.github.com/github/codeql-action/pull/4129) ### [`v4.37.9`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.9) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.8...v4.37.9) - Update default CodeQL bundle version to [2.26.4](https://redirect.github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.4). [#​4106](https://redirect.github.com/github/codeql-action/pull/4106) ### [`v4.37.8`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.8) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.7...v4.37.8) No user facing changes. ### [`v4.37.7`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.7) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.6...v4.37.7) - Update default CodeQL bundle version to [2.26.3](https://redirect.github.com/github/codeql-action/releases/tag/codeql-bundle-v2.26.3). [#​4085](https://redirect.github.com/github/codeql-action/pull/4085) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
ddab29d3cf |
chore(deps): update dependency testcontainers to v12.1.0 (#4303)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [testcontainers](https://redirect.github.com/testcontainers/testcontainers-node) | [`12.0.4` → `12.1.0`](https://renovatebot.com/diffs/npm/testcontainers/12.0.4/12.1.0) |  |  | --- ### Release Notes <details> <summary>testcontainers/testcontainers-node (testcontainers)</summary> ### [`v12.1.0`](https://redirect.github.com/testcontainers/testcontainers-node/releases/tag/v12.1.0) [Compare Source](https://redirect.github.com/testcontainers/testcontainers-node/compare/v12.0.4...v12.1.0) #### Changes #### 🚀 Features - Add MongoDB Atlas Local support [@​jbl428](https://redirect.github.com/jbl428) ([#​1396](https://redirect.github.com/testcontainers/testcontainers-node/issues/1396)) - Add Mosquitto module [@​ChxGuillaume](https://redirect.github.com/ChxGuillaume) ([#​1390](https://redirect.github.com/testcontainers/testcontainers-node/issues/1390)) #### 📖 Documentation - Document review-comment style and approval gate in AGENTS.md [@​cristianrgreco](https://redirect.github.com/cristianrgreco) ([#​1397](https://redirect.github.com/testcontainers/testcontainers-node/issues/1397)) #### 🧹 Maintenance - Declare the supported Node.js version [@​gameroman](https://redirect.github.com/gameroman) ([#​1414](https://redirect.github.com/testcontainers/testcontainers-node/issues/1414)) - Use default stale issue timings [@​cristianrgreco](https://redirect.github.com/cristianrgreco) ([#​1420](https://redirect.github.com/testcontainers/testcontainers-node/issues/1420)) #### 📦 Dependency Updates - Bump undici @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1424](https://redirect.github.com/testcontainers/testcontainers-node/issues/1424)) - Bump ip-address from 10.2.0 to 10.4.0 @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1426](https://redirect.github.com/testcontainers/testcontainers-node/issues/1426)) - Bump brace-expansion from 2.1.2 to 2.1.4 @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1423](https://redirect.github.com/testcontainers/testcontainers-node/issues/1423)) - Bump fast-uri from 3.1.4 to 3.1.5 @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1422](https://redirect.github.com/testcontainers/testcontainers-node/issues/1422)) - Apply npm audit fixes [@​cristianrgreco](https://redirect.github.com/cristianrgreco) ([#​1421](https://redirect.github.com/testcontainers/testcontainers-node/issues/1421)) - Bump the actions group across 1 directory with 2 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1415](https://redirect.github.com/testcontainers/testcontainers-node/issues/1415)) - Bump the dependencies group across 11 directories with 10 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1416](https://redirect.github.com/testcontainers/testcontainers-node/issues/1416)) - Bump the dependencies group across 1 directory with 15 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1417](https://redirect.github.com/testcontainers/testcontainers-node/issues/1417)) - Bump mkdocs-material from 9.7.6 to 9.7.7 in the dependencies group @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1403](https://redirect.github.com/testcontainers/testcontainers-node/issues/1403)) - Bump the dependencies group across 10 directories with 10 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1404](https://redirect.github.com/testcontainers/testcontainers-node/issues/1404)) - Bump the dependencies group with 14 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1405](https://redirect.github.com/testcontainers/testcontainers-node/issues/1405)) - Bump the dependencies group across 7 directories with 6 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1400](https://redirect.github.com/testcontainers/testcontainers-node/issues/1400)) - Bump the dependencies group with 14 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1401](https://redirect.github.com/testcontainers/testcontainers-node/issues/1401)) - Bump the dependencies group across 14 directories with 13 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1398](https://redirect.github.com/testcontainers/testcontainers-node/issues/1398)) - Bump the dependencies group with 16 updates @​[dependabot\[bot\]](https://redirect.github.com/apps/dependabot) ([#​1399](https://redirect.github.com/testcontainers/testcontainers-node/issues/1399)) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
474058bd12 |
chore(deps): update dependency mockserver-client to v7.6.0 (#4302)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [mockserver-client](http://mock-server.com) ([source](https://redirect.github.com/mock-server/mockserver-monorepo/tree/HEAD/mockserver-client-node)) | [`7.5.0` → `7.6.0`](https://renovatebot.com/diffs/npm/mockserver-client/7.5.0/7.6.0) |  |  | --- ### Release Notes <details> <summary>mock-server/mockserver-monorepo (mockserver-client)</summary> ### [`v7.6.0`](https://redirect.github.com/mock-server/mockserver-monorepo/blob/HEAD/changelog.md#760---2026-08-17) [Compare Source](https://redirect.github.com/mock-server/mockserver-monorepo/compare/d23b63077056bc3f6196620e7ce2362d7d043ea8...6b63551f98e64d16759ddc9c5b01bb9bedb271f0) ##### 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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
9122e05f4b |
chore(deps): update dependency publint to v0.3.24 (#4301)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [publint](https://publint.dev) ([source](https://redirect.github.com/publint/publint/tree/HEAD/packages/publint)) | [`0.3.22` → `0.3.24`](https://renovatebot.com/diffs/npm/publint/0.3.22/0.3.24) |  |  | --- ### Release Notes <details> <summary>publint/publint (publint)</summary> ### [`v0.3.24`](https://redirect.github.com/publint/publint/blob/HEAD/packages/publint/CHANGELOG.md#0324) [Compare Source](https://redirect.github.com/publint/publint/compare/publint@0.3.23...publint@0.3.24) ##### Patch Changes - [#​257](https://redirect.github.com/publint/publint/pull/257) [`7c4d25a`](https://redirect.github.com/publint/publint/commit/7c4d25a4a03d8a8332221248df8c386d4cd97f30) - Check the `repository.url` value even when `repository.type` is omitted. `type` is optional and defaults to git, so packages using the object form without it were previously skipped for the deprecated-protocol, invalid-git-url, and shorthand-URL checks. ### [`v0.3.23`](https://redirect.github.com/publint/publint/blob/HEAD/packages/publint/CHANGELOG.md#0323) [Compare Source](https://redirect.github.com/publint/publint/compare/publint@0.3.22...publint@0.3.23) ##### Patch Changes - [#​248](https://redirect.github.com/publint/publint/pull/248) [`9ff88ac`](https://redirect.github.com/publint/publint/commit/9ff88ac3784a33cb36d9d78064586588de07e9e1) - Recursively detect test files (e.g. `*.test.js`, `*.spec.ts`) for the `USE_FILES` suggestion. - [#​245](https://redirect.github.com/publint/publint/pull/245) [`ad737a3`](https://redirect.github.com/publint/publint/commit/ad737a386b1b8e8e4b2dce1bf7a7ce8d4506ebba) - The `USE_FILES` message now reports which internal files or directories triggered it via `args.internalFilePaths` </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
906922fbf1 |
chore(deps): update dependency p-retry to v8.0.1 (#4300)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [p-retry](https://redirect.github.com/sindresorhus/p-retry) | [`8.0.0` → `8.0.1`](https://renovatebot.com/diffs/npm/p-retry/8.0.0/8.0.1) |  |  | --- ### Release Notes <details> <summary>sindresorhus/p-retry (p-retry)</summary> ### [`v8.0.1`](https://redirect.github.com/sindresorhus/p-retry/releases/tag/v8.0.1) [Compare Source](https://redirect.github.com/sindresorhus/p-retry/compare/v8.0.0...v8.0.1) - Fix error for invalid fractional retry counts [`3c22035`](https://redirect.github.com/sindresorhus/p-retry/commit/3c22035) *** </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
44df47d1ff |
chore(deps): update dependency lockfile-lint to v5.0.1 (#4299)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [lockfile-lint](https://redirect.github.com/lirantal/lockfile-lint/tree/master/packages/lockfile-lint) ([source](https://redirect.github.com/lirantal/lockfile-lint/tree/HEAD/packages/lockfile-lint)) | [`5.0.0` → `5.0.1`](https://renovatebot.com/diffs/npm/lockfile-lint/5.0.0/5.0.1) |  |  | --- ### Release Notes <details> <summary>lirantal/lockfile-lint (lockfile-lint)</summary> ### [`v5.0.1`](https://redirect.github.com/lirantal/lockfile-lint/blob/HEAD/packages/lockfile-lint/CHANGELOG.md#501) [Compare Source](https://redirect.github.com/lirantal/lockfile-lint/compare/lockfile-lint@5.0.0...lockfile-lint@5.0.1) ##### Patch Changes - [`6ca1c1871c861888744c314652dd0e59da17fad2`](https://redirect.github.com/lirantal/lockfile-lint/commit/6ca1c1871c861888744c314652dd0e59da17fad2) Thanks [@​lirantal](https://redirect.github.com/lirantal)! - chore: release patch for security fix </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
11157f1a7c |
chore(deps): update dependency @types/node to v24.13.4 (#4297)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@types/node](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node) ([source](https://redirect.github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)) | [`24.13.3` → `24.13.4`](https://renovatebot.com/diffs/npm/@types%2fnode/24.13.3/24.13.4) |  |  | --- ### 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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
16e5603f38 |
chore(deps): update dependency js-yaml to v4.3.2 [security] (#4296)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [js-yaml](https://redirect.github.com/nodeca/js-yaml) | [`4.3.1` → `4.3.2`](https://renovatebot.com/diffs/npm/js-yaml/4.3.1/4.3.2) |  |  | --- ### JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026-59870 fix not backported [GHSA-5p4m-2wfm-xmqj](https://redirect.github.com/advisories/GHSA-5p4m-2wfm-xmqj) <details> <summary>More information</summary> #### Details ##### Quadratic CPU consumption in `!!omap` resolution (js-yaml 3.x and 4.x) ##### Summary `resolveYamlOmap()` enforces key uniqueness for `!!omap` sequences with a linear scan (`objectKeys.indexOf(...)`) inside the per-element loop, making resolution **O(n²)** in the number of entries. A modestly sized YAML document therefore consumes disproportionate CPU inside `yaml.load()`, giving a denial of service against any consumer that parses untrusted YAML. `!!omap` is registered in the **default schema** (`lib/schema/default.js` → `require('../type/omap')`), so a plain `yaml.load(untrustedInput)` with no options is affected — no custom schema or non-default configuration is required. **This is the same weakness as CVE-2026-59870 / GHSA-724g-mxrg-4qvm**, which was fixed in the 5.x line in 5.2.1. That fix was never backported: both currently maintained legacy lines still carry the original implementation. ##### Affected versions | Line | Latest tested | Status | |---|---|---| | 3.x | **3.15.0** | Affected — `objectKeys.indexOf(pairKey)` at `lib/type/omap.js:29` | | 4.x | **4.3.0** | Affected — `objectKeys.indexOf(pairKey)` at `lib/type/omap.js:30` | | 5.x | 5.2.2 | **Not affected** — fixed in 5.2.1 (uses a `Set`) | Both figures are the newest release of each line at the time of writing, so this is not a "you are on an old version" issue. ##### Details `lib/type/omap.js` (js-yaml 4.3.0): ```js if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey) else return false ``` `objectKeys` grows by one element per entry, and `Array.prototype.indexOf` is a linear scan, so resolving an `n`-entry `!!omap` performs roughly `1 + 2 + … + n` comparisons — quadratic in `n`. The work happens synchronously inside `yaml.load()`, blocking the event loop for its whole duration. The 5.x line already solves exactly this by tracking seen keys in a `Set` (`src/tag/sequence/omap.ts`): ```ts if (carrier.seen.has(key)) return 'duplicate key in ordered map' carrier.seen.add(key) ``` ##### Proof of concept ```js // poc.js — node poc.js const yaml = require('js-yaml'); const doc = n => '!!omap\n' + Array.from({length: n}, (_, i) => `- k${i}: ${i}`).join('\n') + '\n'; for (const n of [10000, 20000, 40000, 80000]) { const d = doc(n), t = Date.now(); yaml.load(d); // default schema, no options console.log(`n=${n} bytes=${d.length} load=${Date.now() - t}ms`); } ``` ##### Measured (node v20.20.2, default heap, no flags) **js-yaml 4.3.0** ``` n=10000 bytes=137787 load=54ms n=20000 bytes=297787 load=169ms n=40000 bytes=617787 load=646ms n=80000 bytes=1257787 load=2607ms ``` **js-yaml 3.15.0** ``` n=10000 bytes=137787 load=53ms n=20000 bytes=297787 load=166ms n=40000 bytes=617787 load=641ms n=80000 bytes=1257787 load=2567ms ``` Runtime grows by a factor of ~4 for each doubling of `n`, which is the signature of O(n²) (linear growth would be ~2×). Scaling further: a **2.48 MB** document with 150,000 entries blocked `yaml.load()` for **10.8 seconds**. ##### Impact Any service that parses attacker-influenced YAML with js-yaml 3.x or 4.x can be stalled with a small input. Because the loop is synchronous, a single request blocks the Node.js event loop and stalls every other request in the process — so the amplification is per-process, not just per-request. Suggested severity: consistent with **CVE-2026-59870** (the same weakness in 5.x), i.e. Availability-only impact, network attack vector, no privileges or user interaction required. ##### Suggested fix Mirror the 5.x fix — replace the linear scan with a `Set`: ```js // lib/type/omap.js const seen = new Set() // ... if (seen.has(pairKey)) return false seen.add(pairKey) ``` This preserves the existing duplicate-key rejection semantics exactly while making resolution O(n). A `maxOmapLength`-style cap would also work, but the `Set` matches what 5.x already ships and requires no new option. ##### References - CVE-2026-59870 / GHSA-724g-mxrg-4qvm — same weakness in 5.0.0–5.2.0, fixed in 5.2.1 - `lib/type/omap.js` (3.x, 4.x) — the affected resolver - `lib/schema/default.js` — registers `!!omap` in the default schema ##### Discovery Found by an automated static-analysis and executed-proof-of-concept scanner run against js-yaml 4.2.0, then manually verified against 3.15.0 and 4.3.0 by executing the proof of concept above. All timings in this report were measured on the **current** releases of each line, not on the version originally scanned. #### Severity - CVSS Score: 7.5 / 10 (High) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` #### References - [https://github.com/nodeca/js-yaml/security/advisories/GHSA-5p4m-2wfm-xmqj](https://redirect.github.com/nodeca/js-yaml/security/advisories/GHSA-5p4m-2wfm-xmqj) - [https://github.com/advisories/GHSA-5p4m-2wfm-xmqj](https://redirect.github.com/advisories/GHSA-5p4m-2wfm-xmqj) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-5p4m-2wfm-xmqj) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources [CVE-2026-84375](https://nvd.nist.gov/vuln/detail/CVE-2026-84375) / [GHSA-2883-xcg3-v3hh](https://redirect.github.com/advisories/GHSA-2883-xcg3-v3hh) <details> <summary>More information</summary> #### Details ##### Summary `maxTotalMergeKeys` does not count empty mappings. An attacker can repeatedly merge a large sequence of them and consume significant CPU without reaching the configured limit. ##### Example ```yaml arr: &arr [{}, {}, {}, ...] # N empty mappings targets: - <<: *arr # repeated K times ``` For every target, the loader iterates all `N` elements of `arr`. This results in `O(N * K)` work while `totalMergeKeys` remains unchanged. ##### PoC ```js import { performance } from 'node:perf_hooks' import { load, YAML11_SCHEMA } from 'js-yaml' const n = 20000 const src = 'arr: &arr [' + '{},'.repeat(n).slice(0, -1) + ']\n' + 'targets:\n' + ' - <<: *arr\n'.repeat(n) const started = performance.now() load(src, { schema: YAML11_SCHEMA }) console.log(`${(performance.now() - started).toFixed(1)} ms`) ``` Observed results: | N | YAML size | Time | |---:|---:|---:| | 800 | ~13 KB | ~20 ms | | 3200 | ~50 KB | ~180 ms | | 20000 | ~500 KB | ~13 s | ##### Impact An attacker can submit a relatively small YAML document that causes prolonged CPU consumption despite the default `maxTotalMergeKeys` limit. ##### Fix Count each merge-source mapping as one budget unit, in addition to counting its keys. ##### Difference with v5 In v3 & v4, merge is enabled by default. So, the severity score is higher. #### Severity - CVSS Score: 7.5 / 10 (High) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` #### References - [https://github.com/nodeca/js-yaml/security/advisories/GHSA-2883-xcg3-v3hh](https://redirect.github.com/nodeca/js-yaml/security/advisories/GHSA-2883-xcg3-v3hh) - [https://nvd.nist.gov/vuln/detail/CVE-2026-84375](https://nvd.nist.gov/vuln/detail/CVE-2026-84375) - [https://github.com/nodeca/js-yaml/pull/797](https://redirect.github.com/nodeca/js-yaml/pull/797) - [https://github.com/nodeca/js-yaml/commit/3485bc06ff8a0251505f44a00414d90df2466639](https://redirect.github.com/nodeca/js-yaml/commit/3485bc06ff8a0251505f44a00414d90df2466639) - [https://github.com/nodeca/js-yaml/commit/6a8e05f9a485188ed730ac81e81ae221352ef480](https://redirect.github.com/nodeca/js-yaml/commit/6a8e05f9a485188ed730ac81e81ae221352ef480) - [https://github.com/nodeca/js-yaml/commit/d90b6612a5a84385bdcb556c44578eac76dc0f6b](https://redirect.github.com/nodeca/js-yaml/commit/d90b6612a5a84385bdcb556c44578eac76dc0f6b) - [https://github.com/nodeca/js-yaml/releases/tag/3.15.2](https://redirect.github.com/nodeca/js-yaml/releases/tag/3.15.2) - [https://github.com/nodeca/js-yaml/releases/tag/4.3.2](https://redirect.github.com/nodeca/js-yaml/releases/tag/4.3.2) - [https://github.com/advisories/GHSA-2883-xcg3-v3hh](https://redirect.github.com/advisories/GHSA-2883-xcg3-v3hh) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-2883-xcg3-v3hh) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>nodeca/js-yaml (js-yaml)</summary> ### [`v4.3.2`](https://redirect.github.com/nodeca/js-yaml/compare/4.3.1...4.3.2) [Compare Source](https://redirect.github.com/nodeca/js-yaml/compare/4.3.1...4.3.2) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43OS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNzkuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
8d905a56e8 |
fix: do not expose the authenticated repository URL in EGITNOPERMISSION errors (#4283)
## Problem `EGITNOPERMISSION` interpolates `options.repositoryUrl` into the error `details`. By the time this error is thrown (`index.js`, after `verifyAuth` fails), `options.repositoryUrl` has been replaced with the result of `getGitAuthUrl()`, which can embed CI credentials (`GH_TOKEN`, `GITHUB_TOKEN`, `GL_TOKEN`, `BB_TOKEN`, …) as basic-auth in the URL. The existing masking covers most paths — terminal output goes through the `hookStd(hideSensitive(env))` hook, the CLI masks the inspected error before printing, and fail-plugin inputs are masked via `hideSensitiveValues` — but the thrown error object itself is rethrown **unmasked** to programmatic API consumers after `unhook()`. Any wrapper that catches the error and reports `error.details` elsewhere (PR comment, CI annotation, error tracker) would leak the token. ## Fix Use `options.originalRepositoryURL` — the URL as configured, saved before `getGitAuthUrl()` rewrites it — in the error details, falling back to `repositoryUrl` when it isn't set (e.g. when the error factory is invoked directly with a partial context). ## Testing - Added `test/definitions/errors.test.js` covering that the details contain the original URL and not the credential-bearing one, plus the fallback. - `npx ava test/definitions/` and `npm run lint:prettier` pass. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>v25.0.9 |
||
|
|
e176eb7a8b |
ci(action): update github/codeql-action action to v4.37.6 (#4282)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | patch | `v4.37.5` → `v4.37.6` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.37.6`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.6) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.5...v4.37.6) - Changed the default filepath for the new remote file address format that was introduced in CodeQL Action 4.37.0 / 3.37.0 to `.github/codeql-config.yml` to align it with the suggested path that is used elsewhere. [#​4070](https://redirect.github.com/github/codeql-action/pull/4070) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMS40IiwidXBkYXRlZEluVmVyIjoiNDQuMTEuNCIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
d27db1b86f |
chore(deps): update dependency js-yaml to v4.3.1 (#4279)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [js-yaml](https://redirect.github.com/nodeca/js-yaml) | [`4.3.0` → `4.3.1`](https://renovatebot.com/diffs/npm/js-yaml/4.3.0/4.3.1) |  |  | --- ### Release Notes <details> <summary>nodeca/js-yaml (js-yaml)</summary> ### [`v4.3.1`](https://redirect.github.com/nodeca/js-yaml/compare/4.3.0...4.3.1) [Compare Source](https://redirect.github.com/nodeca/js-yaml/compare/4.3.0...4.3.1) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
55beeac3fe |
ci(action): update github/codeql-action action to v4.37.5 (#4277)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | patch | `v4.37.4` → `v4.37.5` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.37.5`](https://redirect.github.com/github/codeql-action/compare/v4.37.4...v4.37.5) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.4...v4.37.5) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
7bf348df58 |
chore(deps): update dependency nock to v14.0.17 (#4275)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [nock](https://redirect.github.com/nock/nock) | [`14.0.16` → `14.0.17`](https://renovatebot.com/diffs/npm/nock/14.0.16/14.0.17) |  |  | --- ### Release Notes <details> <summary>nock/nock (nock)</summary> ### [`v14.0.17`](https://redirect.github.com/nock/nock/releases/tag/v14.0.17) [Compare Source](https://redirect.github.com/nock/nock/compare/v14.0.16...v14.0.17) ##### Bug Fixes - remove interceptor from scope.interceptors on nock.removeInterceptor ([#​2997](https://redirect.github.com/nock/nock/issues/2997)) ([1ee467c](https://redirect.github.com/nock/nock/commit/1ee467c68d601ddc22629d7a657061e6c27097c2)) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
2ec3ba29f2 |
chore(deps): update dependency mockserver-client to v7.5.0 (#4274)
> ℹ️ **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/) | |---|---|---|---| | [mockserver-client](http://mock-server.com) ([source](https://redirect.github.com/mock-server/mockserver-monorepo/tree/HEAD/mockserver-client-node)) | [`7.4.0` → `7.5.0`](https://renovatebot.com/diffs/npm/mockserver-client/7.4.0/7.5.0) |  |  | --- ### Release Notes <details> <summary>mock-server/mockserver-monorepo (mockserver-client)</summary> ### [`v7.5.0`](https://redirect.github.com/mock-server/mockserver-monorepo/blob/HEAD/changelog.md#750---2026-07-29) [Compare Source](https://redirect.github.com/mock-server/mockserver-monorepo/compare/fe29eedcd2fbf31c047176b117172026774034d6...d23b63077056bc3f6196620e7ce2362d7d043ea8) ##### 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 `<textarea>`, so nothing exercised the real editor's tokenisation, web-worker validation, or DOM. - **SOCKS4 CONNECT tunnelling is now proven end-to-end over a real socket.** A new socket-level integration test (`NettyHttpProxySOCKS4IntegrationTest`) performs a raw SOCKS4 CONNECT handshake against a bound MockServer targeting a loopback `EchoServer`, then sends an HTTP GET through the granted tunnel and asserts the EchoServer received the request and returned 200 (bytes relayed by `Socks4ConnectHandler`). Previously SOCKS4 was only exercised by an `EmbeddedChannel` unit test (`Socks4ProxyHandlerTest`, which asserts handler removal) while every real-socket proxy integration test used SOCKS5, so nothing drove the SOCKS4 relay path over the wire. - **Per-host forward-proxy client-certificate selection is now proven at a real TLS handshake.** A new integration test (`ForwardWithCustomClientCertificateByHostIntegrationTest`) configures `forwardProxyClientCertificatesByHost` to present two independent client certificates (each backed by its own CA) keyed by host, then forwards through MockServer to two secure upstream `EchoServer`s that each `REQUIRE` client auth and trust only ONE of the two client CAs. Because the host string is the cert-mapping key while the connection target is fixed independently by the forward port, the same upstream is reached under both host keys: the mapped cert is accepted (200) and the mismatched cert is rejected at the handshake (502). This makes the presented client certificate a load-bearing assertion, verified by a positive control (degrading the mapping to always present cert A flips host B's accepted case to 502). Previously `NettySslContextFactoryTest` asserted only `SslContext` identity/distinctness and the pure resolver -- nothing drove the per-host cert to an actual mTLS handshake. - **LLM streaming physics for Gemini, Ollama, and Bedrock are now proven over a real socket.** Streaming physics over the wire was previously e2e-tested only for Anthropic and OpenAI (both SSE); Gemini, Ollama, and Bedrock rested on self-derived golden JSONL plus codec unit tests, with no socket streaming e2e. Three new tests in `LlmAgentLoopE2eTest` serve a streaming `httpLlmResponse` for each provider, connect a real socket client, and assert both that the wire `Content-Type` is the provider's streaming media type (`text/event-stream` for Gemini SSE, `application/x-ndjson` for Ollama NDJSON, `application/vnd.amazon.eventstream` for Bedrock AWS event-stream binary framing) and that the text reconstructed by concatenating the streamed deltas — Gemini `candidates[].content.parts[].text`, Ollama `message.content`, and Bedrock's base64-wrapped Anthropic `text_delta` fragments decoded from the CRC32-validated binary event-stream messages — equals the completion text exactly. The Bedrock case de-chunks the HTTP/1.1 chunked body and decodes the binary framing end to end. - **The PHP client's fidelity harness now gates the TYPED model, not just raw replay.** The existing `RoundTripFidelityTest` deserialises each shared fixture with `Expectation::fromArray()`, which stores the decoded array verbatim in `rawData` and replays it unchanged -- so it records zero gaps for every fixture BY CONSTRUCTION and can never detect a field the typed builders (`HttpResponse`, `HttpForward`, `HttpError`, `HttpRequest`) fail to model. A new `TypedRoundTripFidelityTest` closes that tautology: for every shared fixture it reconstructs each action/matcher block THROUGH the typed model (reflection copies across only the properties each class declares, recursing into declared nested typed objects, then serialises via the class's own `toArray()`) and diffs the rebuilt structure back against the fixture -- the server-schema side of the contract -- so any server field the typed model drops surfaces as a concrete diff path derived from the corpus, never from the client's own key list. This immediately documented five real request-matcher gaps the raw harness hid (`dnsClass`/`dnsName`/`dnsType`, `pathParameters`, `protocol`, plus NottableString `method`/`path`), each pinned in a per-field gap ledger with a stale-entry ratchet, while the `httpResponse`/`httpForward`/`httpError` models are proven to cover their entire fixture surface. A positive-control test proves the gate fires when a typed builder drops a field it is supposed to carry (removing `statusCode` from `HttpResponse::toArray()` turns the suite red for every fixture carrying it, and green again on restore) -- the exact regression the raw-replay harness cannot catch. Shared comparator logic is extracted to `FidelityComparator`. - **The Go client's FORWARD and ERROR response actions are now proven over the wire.** New integration tests (`response_action_integration_test.go`) register a `httpForward` and a `httpError` (`dropConnection`) action via the Go client and drive real requests that assert the SERVER actually performs them: the forwarded request loops back through a match-once, higher-priority self-forward to a distinct upstream response body (needing no externally-reachable upstream, so it runs identically in the CI sibling-container harness and against a locally port-mapped server), and the error endpoint drops the connection at the transport level (no HTTP response) while a control endpoint on the same server still answers cleanly. Previously the Go client's response-action coverage was builder/JSON only -- no test drove a forward or error action to completion over a socket. - **Rust client wire tests proving the server actually enforces negation matchers and performs response actions.** The Rust integration suite previously only asserted control-plane serialization (`matcher_value_tests.rs`) and registered a forward expectation it never drove (`test_forward_expectation` "won't actually forward"), so nothing proved a running MockServer acted on either. Three new `#[ignore]`d integration tests drive a live server over the data plane via a dependency-free raw socket: `test_negation_matcher_enforced_over_wire` registers a `NottableString` negation (bare `"!foo"`, explicit `MatcherValue::not_literal`, and an escaped literal `"!foo"`) and asserts the server matches a non-`foo` value (200) while excluding `foo` (404) — and that an escaped `"!foo"` matches literally rather than as a negation; `test_forward_action_actually_forwards` registers a higher-priority run-once FORWARD that loops back to the server's own port plus a lower-priority fall-through RESPOND, and asserts the distinctive fall-through body is returned only if the forward genuinely executed (topology-independent — no external upstream); and `test_error_action_actually_returns_raw_bytes` registers an ERROR action and asserts the server writes the configured raw bytes back. Run in CI by the existing `rust-integration-test` step. - **Wire-level .NET client test coverage for NottableString header negation and for forward/error response actions.** The .NET integration suite asserted expectation *creation* but never proved the server honours what the client sends: there was no test that a `!foo` header matcher (`MatcherValue.NotLiteral`) is transmitted and enforced over the wire, nor that a registered forward or error action is actually performed. A new `WireBehaviorTests` drives real requests through a running MockServer (reached via the existing `MOCKSERVER_URL` harness) to prove: a "not foo" header matcher matches a non-`foo` request (200) and rejects a `foo` request (404); the escaped literal `MatcherValue.Literal("!foo")` matches only a header whose value really is `!foo`; a forward action is genuinely forwarded (the path is received twice — original plus the re-entered forward — not merely served directly); and an error action actually drops the connection (a transport failure, not an HTTP status). Each assertion was confirmed to redden when the corresponding client behaviour is degraded. - **Live-broker test coverage proving Kafka SASL credentials reach and are enforced by a real broker.** Kafka SASL/SSL security was only asserted at the property-map level (`KafkaMessagePublisherSecurityTest`) and every live-broker Kafka integration test used a plaintext bootstrap, so nothing proved the configured credentials actually authenticate against a broker. A new `KafkaSecurityLiveBrokerIntegrationTest` starts a Testcontainers Kafka whose external listener is `SASL_PLAINTEXT`/`PLAIN` with a broker-side JAAS config that knows a single credential, then drives MockServer's `KafkaMessagePublisher` with a `KafkaSecurity`: a correctly-credentialed publisher publishes successfully and the message is read back by a matching credentialed consumer, while a wrong-password publisher is rejected with an authentication exception (proving enforcement, not merely that plaintext works). Docker-gated so it SKIPS cleanly when Docker is unavailable. - **Credential-enforcement test coverage for MQTT security against a secured live broker.** MQTT `MqttSecurity` credentials were only asserted at the options-carrier unit level (`MqttSecurityOptionsTest`), while the sole live Mosquitto integration test ran an `allow_anonymous` plaintext broker — so nothing proved credentials are actually applied and enforced on the wire. A new `MqttTlsLiveBrokerIntegrationTest` drives MockServer's MQTT publisher against a Testcontainers Mosquitto broker configured with a `password_file` and `allow_anonymous false`: it asserts that a publisher wired with the correct `MqttSecurity` username/password authenticates and delivers a message to an authenticated subscriber, and that a publisher with the wrong password (and one with no credentials) is rejected by the broker at CONNECT. Docker-gated so it skips cleanly when Docker is unavailable. - **Live-broker test coverage for the AsyncAPI control-plane `load()` → publish-on-load path.** The control-plane's broker-connecting path (`createBrokerConnections` / `publishOnLoad`) was untested against a real broker — `AsyncApiControlPlaneImplTest` loads without a reachable broker (asserting `publishers=0`), and the endpoint IT covers only the broker-less endpoints. A new Docker-gated `AsyncApiControlPlaneLiveBrokerIntegrationTest` (Testcontainers Kafka) drives `load()` with a real `brokerConfig`, `publishOnLoad:true` and `consume:true`, then proves the control-plane genuinely connected and published by consuming the on-load message with a plain third-party Kafka client and asserting `status()` reports `publishers>0`, a subscriber, and the recorded round-tripped message. - **Over-the-wire test coverage for an LLM refusal preset served with a rate-limit quota.** The LLM refusal presets, provider-specific rate-limit headers, and stateful request-count quota were only asserted at the body-builder / handler-unit level; nothing drove them through a running server. A new `LlmRefusalQuotaRateLimitIntegrationTest` serves an `httpLlmResponse` configured with an Anthropic refusal preset and a 2-request quota, then asserts on the raw socket response that the first two requests return a `200` refusal envelope (`stop_reason:"refusal"`) carrying the `anthropic-ratelimit-requests-*` headers, and that the third (over-quota) request flips to a `429` `rate_limit_error` envelope with the exhausted rate-limit headers and `Retry-After`. ##### Fixed - **The `testcontainers-mockserver` (Python) port assertions no longer break against testcontainers 4.15.0, which keys `DockerContainer.ports` by `str(port)` rather than `int`.** `with_exposed_ports` now stores `self.ports[str(port)] = None` (4.15.0 types the attribute as `dict[str, Optional[int]]`), so the suite's `assert 1080 in container.ports` started failing with `assert 1080 in {'1080': None}` and took five tests — and the whole `MockServer Python` pipeline, and with it the umbrella `MockServer` build — red on `master`. The tests now read the exposed ports through a normaliser that parses each key to an `int` (tolerating a `"1080/tcp"` protocol suffix), so they assert the same thing under either key style. This also closes a latent false green: the `assert MOCKSERVER_PORT not in container.ports` check in `test_replaces_default_port` passed trivially once the keys became strings, and so would no longer have caught `with_server_port` failing to drop the previously exposed port. Only the tests changed — `MockServerContainer` itself was already correct, as `get_exposed_port` takes an `int` and normalises internally. `<blobStoreKeyPrefix>/<file name>` instead of under the writing machine's absolute local path, and a `blobStoreKeyPrefix` that does not end in a separator is now treated as a folder-style prefix instead of being glued straight onto the key (`mockserver` + `x.json` was `mockserverx.json` and is now `mockserver/x.json`). Anything persisted by an earlier version is stored under the OLD name and will NOT be restored after upgrading — the one-line migration is below.\*\* The blob key was the ABSOLUTE local `persistedExpectationsPath` (for example `/var/folders/.../persistedExpectations.json`) and the configured `blobStoreKeyPrefix` was concatenated onto it with plain string addition. With the prefix shape the documentation recommends — `blobStoreKeyPrefix="mockserver/"`, with a trailing separator — that composed `mockserver//var/folders/.../persistedExpectations.json`, and MinIO rejects the doubled `//` outright with HTTP 400, "Object name contains unsupported characters", so under that one configuration nothing was ever persisted and consequently nothing could be restored on restart. Under every other prefix shape the write SUCCEEDED and restore worked — a leading `/` is a legal byte in an S3 object name, and the read composed exactly the same name back — but the object was then named after the writing container's local filesystem layout, so a second instance that resolved `persistedExpectationsPath` to a different absolute path (started from a different working directory, or in a different container) looked under a different name and silently restored nothing. The key is now derived by the new shared `org.mockserver.state.BlobKeys` helper in `mockserver-core`: for every store other than `FilesystemBlobStore` the key is the FILE NAME of `persistedExpectationsPath` alone, and prefix and key are joined with exactly one separator, with any leading separator dropped and any repeated separators collapsed, so every prefix shape a user can configure — unset, `mockserver`, `mockserver/`, `/mockserver/` — now produces the same valid object name (`mockserver/persistedExpectations.json`). That normalisation is applied for all `put`/`get`/`list`/`delete` operations wherever `blobStoreKeyPrefix` is applied, so it renames EVERY blob key, not only the persisted-expectations document. `FilesystemBlobStore` is unaffected: it interprets the key as a file path, so it keeps the absolute path and writes exactly the file it always did. **Upgrading:** because the old key always embedded the absolute local path and the new key is the bare file name, the object name changes for every non-filesystem persistence user, under every prefix shape and on every platform — there is no configuration in which the old name is preserved. On the first start after upgrading, the restore looks under the new name, misses (logged at `INFO` with the name it looked for), and the instance starts with no restored expectations; the next expectation change then writes a fresh object under the new name and leaves the old one behind. To carry existing state across the upgrade, copy or rename the object once before starting the new version, for example `aws s3 mv s3://<bucket>/<prefix>/<old absolute path> s3://<bucket>/<prefix>/<file name>` — otherwise accept the miss and let the first expectation change re-create it. One long-standing footgun goes away with the change: restoring after a restart no longer requires the two instances to resolve `persistedExpectationsPath` to the same absolute path, only to the same file name. Deployments that must NOT share state within one bucket should give each its own `blobStoreKeyPrefix` (or its own file name). Proven by a Docker-gated MinIO round trip that writes and then reads back an expectation with a trailing-slash `blobStoreKeyPrefix` (the exact configuration that returned HTTP 400 before), a MinIO put/get/list/delete round trip across all four prefix shapes, and Docker-free unit coverage of the key composition and of the key the persistence layer derives. - **The configuration enforcement-evidence guard no longer certifies evidence it cannot see.** `ConfigurationEnforcementClassificationTest` records, for every risky configuration property, the `Class#method` test that proves an instance-set value changes observable behaviour. It validated those pointers by loading the class — but it runs in `mockserver-core`, so any pointer naming a test in a sibling module was silently skipped on `ClassNotFoundException`. That exempted precisely the most valuable evidence, the end-to-end Layer C pointers: renaming, moving or deleting the referenced test left a dangling pointer and the guard still passed green, for `maxRequestBodySize`, `maxResponseBodySize`, `wasmEnabled`, `redactSecretsInLog`, `clusterEnabled`, `dnsEnabled`, `grpcBidiStreamingEnabled`, `http3ConnectUdpEnabled` and `transparentProxyEnabled`. A class that cannot be loaded is now resolved by locating its `.java` source under any module's `src/test/java` and asserting the file declares both the class and the referenced method, so cross-module pointers are checked in a full reactor build and when only some modules are built. The guard fails closed: a pointer resolvable by neither route is now a failure naming the dangling pointer, never a silent skip. Anti-vacuity assertions in the spirit of the sibling `ConfigurationCallSiteGuardTest` keep the scan honest — the set of pointers resolved by source scan must match the declared cross-module ratchet exactly, `mockserver-netty` and `mockserver-state-infinispan` must both have contributed, and classpath resolution must still cover the bulk of the pointers — so a scan that resolves nothing cannot pass. Verified by degrading a real `mockserver-netty` test method name: the guard now fails with a message naming the dangling pointer, where the previous version passed green with the identical defect in place. - **gRPC trailing metadata is no longer silently dropped over HTTP/3.** Every trailer an expectation authored — `response().withTrailer("x-request-cost", "42")`, and the gRPC chaos profile's `customTrailers` — reached an HTTP/1.1 or HTTP/2 client but **never reached an HTTP/3 client at all**, in every branch of the HTTP/3 gRPC response path (with a body and body-less, and both with and without proto descriptors loaded). The same expectation therefore produced different trailing metadata depending only on which transport the client happened to use, and there was no error or warning anywhere to indicate the loss — a test asserting on trailing metadata over HTTP/3 simply saw nothing. The cause was that `Http3GrpcResponseWriter` builds its HTTP/3 frames by hand rather than through `MockServerHttpResponseToFullHttpResponse.mapResponseWithTrailers` (which is what carries trailers on the other transports), and `GrpcHttp3Adapter.buildTrailingHeadersFrame` / `buildTrailersOnlyFrame` populated only `grpc-status` and `grpc-message`; the response's own trailers were never read. They are now emitted on the terminal frame: on the trailing HEADERS frame when the response has a body, and folded into the Trailers-Only frame when it does not, which is the shape gRPC defines for that form (`HTTP-Status Content-Type Trailers`, where `Trailers` includes custom metadata) and leaves the framing unchanged — there is still exactly one terminal frame, written with `SHUTDOWN_OUTPUT`, so an added trailer cannot cost the response its end-of-stream marker the way it did on HTTP/2 before the fix above. A user-authored trailer cannot override or spoof the transport's own status: the new shared `GrpcResponseStatusResolver.passThroughTrailers` (the trailer twin of `passThroughHeaders`) excludes `grpc-status`, `grpc-message` and `grpc-status-name`, mirroring the exclusion the HTTP/2 path makes in `remainingTrailers`, and also excludes the connection-specific fields, `content-length`/`content-type` and pseudo-header names that RFC 9114 forbids in a trailer section. Trailer field names are lower-cased and CR/LF stripped from values before reaching the frame, because HTTP/3 field names must be lower-case and Netty's `DefaultHttp3Headers` rejects an upper-case one by throwing — so an expectation authoring `withTrailer("X-Request-Cost", …)` would otherwise have taken the client's entire response down rather than dropping a single field. Verified over the wire by two new tests in `Http3GrpcIntegrationTest` that drive a live in-JVM Netty QUIC client and read the metadata off the HEADERS frames it actually received, asserting which side each value arrived on (a trailer must not be folded into the initial headers, a response header must not be repeated as a trailer) and asserting the HEADERS-frame count so the metadata cannot arrive at the cost of correct framing, plus adapter-level coverage in `GrpcHttp3AdapterTest`. Positive control: neutering the trailer pass-through in production turns all seven new assertions red with the trailer absent. - **A FILE response body is now served verbatim (and templated) on every response path, and a FILE request body is now actually matched ([#​2450](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2450)).** A response whose body is a `FILE` (a `filePath` with no template engine) was previously read on the static response action only; the same FILE body returned from an object callback, a class callback, a response template, or a forward `responseOverride` reached the wire unread, emitting the file *path* string instead of the file *contents*. Materialisation now lives in a single shared `FileBodyMaterialiser` invoked from the two response-write funnels (`writeResponseActionResponse`, covering the static, object-callback, class-callback, response-template and SSE paths, and `writeForwardActionResponse`, covering the forward `responseOverride`), so all five producers — and the shared WAR/servlet path — serve the file contents. Templated FILE bodies (a `FileBody` carrying a Velocity/Mustache `templateType`) are rendered against the request on these paths too, not only verbatim ones; a text content type yields the decoded string and a binary or absent content type yields the raw bytes intact. A missing or unreadable file now produces a clean, logged `500` whose body does not leak the path, instead of a broken connection or the path string. Separately, a `FILE` body used for **request matching** had no case in `BodyMatcherBuilder`, so the body constraint was silently ignored (it matched any body); it now matches the request body against the exact file contents (string or binary). This resolves the earlier "static response only" caveat. - **A forward `responseOverride` that replaces the body is no longer truncated to the upstream `Content-Length`.** When a forwarded request's response is overridden with a new body, `HttpResponse.update()` replaced the body but kept the `Content-Length` inherited from the upstream response. A replacement body longer than the upstream body was therefore truncated on the wire (and a shorter one could over-run) — visible only to a real client, since every layer above the encoder held the full, correct response. `update()` now drops the inherited `Content-Length` whenever the override supplies a new body (or a `generateFromSchema`), unless the override itself sets an explicit `Content-Length` (which is still honoured verbatim), so the encoder recomputes the length from the actual body. This closes the residual on the forward-override path left by the FILE-body fix above. - **A gRPC error response carrying custom trailing metadata no longer loses its status.** On HTTP/2 a body-less gRPC response is collapsed into the gRPC Trailers-Only form, which moves `grpc-status` into the initial HEADERS frame and relies on that frame being end-of-stream. When the expectation also authored a custom trailer with `withTrailer(...)`, that trailer kept a separate trailing HEADERS frame alive, so the initial frame was no longer end-of-stream: a real client read it as ordinary headers (where `grpc-status` is ignored) and then found no status at all in the terminal frame, failing the call with `UNKNOWN: missing GRPC status`. In other words, adding a single trailer to an error response destroyed the error — the caller lost both the status code and the message. `GrpcToHttpResponseHandler.asTrailersOnlyIfHttp2` now skips the Trailers-Only collapse whenever any user-authored trailer remains, keeping `grpc-status`/`grpc-message` in the trailing HEADERS frame alongside the custom metadata, which is the correct shape in that case. The same fix covers the gRPC chaos fault path, which produced the byte-identical broken shape: a fault response configured with `customTrailers` emits them as real trailers alongside `grpc-status`/`grpc-message` on a body-less response, so a chaos-injected error over HTTP/2 also reached the client as `UNKNOWN: missing GRPC status` instead of the configured status. Found by the new real-client trailing-metadata coverage described under Added. - **gRPC-Web now re-frames matched-expectation responses correctly over a real HTTP/1.1 socket, and is covered by an over-the-wire integration test.** Every previous gRPC-Web test drove the handler through an `EmbeddedChannel` and set `x-grpc-web-content-type` directly on the response, so none exercised the actual mock-matching path: there the marker lives on the request only and was lost, and a matched expectation went back to a browser client as `application/grpc` with `grpc-status` in HTTP trailers a gRPC-Web client cannot read. The original request content-type is now retained in the per-stream `GrpcPendingRequests` record alongside the resolved service/method, so `GrpcToHttpResponseHandler` re-frames the response as gRPC-Web (length-prefixed message frame + a `0x80` trailer frame carrying `grpc-status` in the body, base64-encoded for the `-text` variant). A new `GrpcWebOverTheWireIntegrationTest` posts a real `application/grpc-web` and `application/grpc-web-text` framed request to a running server over a raw socket and asserts on the exact bytes a browser client would receive. - **The AsyncAPI control-plane HTTP endpoints now have an over-the-wire integration test.** `PUT /mockserver/asyncapi`, `GET /mockserver/asyncapi` and `PUT /mockserver/asyncapi/verify` were only exercised at the orchestrator/control-plane level, so a regression in the Netty → `HttpState` → `AsyncApiControlPlaneRegistry` routing or response wiring would not have been caught. A new `AsyncApiControlPlaneIntegrationTest` boots a real MockServer and drives all three endpoints over a raw socket without any live broker: it asserts the load response (`201`, `loaded:true`, channel count, zero publishers/subscribers), the status response (`200`, channels, counts, and the empty/unloaded case), and the broker-less verify verdict (`406` with the "at least 1 … found 0" failure detail) plus the blank-body `400`. - **A `StreamingBody` response delivered to a real HTTP/2 inbound client is now covered end-to-end.** `NettyResponseWriter.writeStreamingResponse` re-stamps the request's HTTP/2 stream id onto the streaming response head (the field is not part of the copied header multimap) and flushes each chunk as it arrives, but no test drove that path with a real HTTP/2 client — `Http2SseStreamingIntegrationTest` covered only the SSE sibling and explicitly noted the `StreamingBody` case was untested, while the existing streaming-relay tests drive an HTTP/1.1 inbound socket. A new `Http2StreamingBodyIntegrationTest` drives a real prior-knowledge h2c multiplex client through a `streamingResponsesEnabled` forward MockServer to an SSE upstream and asserts on the frames the client receives on its OWN request stream: both events arrive (proving the stream-id stamp — the [#​2419](https://redirect.github.com/mock-server/mockserver-monorepo/issues/2419) class), and the early event's DATA frame arrives promptly as one of at least two separate, in-order DATA frames rather than being buffered into one. Degrading the write path to buffer chunks until stream completion was verified to make the incremental-delivery assertion go red. - **PROXY-protocol destination resolution is now proven to drive transparent-proxy forwarding over a real socket.** `ProxyProtocolOriginalDestinationHandler` was only exercised via `EmbeddedChannel`, which asserts the handler sets the `REMOTE_SOCKET` channel attribute but never that this attribute actually chooses the forward target end-to-end. A new non-privileged loopback `ProxyProtocolForwardingIntegrationTest` runs MockServer with `transparentProxyEnabled=true` and no fixed remote, opens a raw socket, writes a valid PROXY v1 `TCP4` header naming a loopback `EchoServer` as the destination followed by a plain GET whose `Host` header points at an unrelated (closed) decoy port, and asserts the EchoServer reflects the request back — proving the PROXY-protocol `REMOTE_SOCKET`, and not the `Host` header, drives forwarding. The test needs no `NET_ADMIN`/privileged capability because the PROXY-protocol header is an application-level byte prefix. Verified as a genuine regression guard by a positive control: ignoring the PROXY-header destination turns the forwarding assertions RED, restoring it returns them GREEN. - **A FILE response body with no template engine now serves the file contents, not the file path ([#​2450](https://r > ✂ **Note** > > PR body was truncated to here. </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
d3b772477f |
chore(deps): update npm to v12.0.2 (#4273)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [npm](https://docs.npmjs.com/) ([source](https://redirect.github.com/npm/cli)) | [`12.0.1+sha512.2f94fd8bf600416416a934bfc59c4991e8bff7372ef7d842784e2a8b8d48c81555ee645069ddea73625fb8e92dc261feab0188fd5dab6c22fefd46316f5f9140` → `12.0.2`](https://renovatebot.com/diffs/npm/npm/12.0.1/12.0.2) |  |  | --- ### Release Notes <details> <summary>npm/cli (npm)</summary> ### [`v12.0.2`](https://redirect.github.com/npm/cli/blob/HEAD/CHANGELOG.md#1202-2026-07-27) [Compare Source](https://redirect.github.com/npm/cli/compare/v12.0.1...v12.0.2) ##### Bug Fixes - [`834408e`](https://redirect.github.com/npm/cli/commit/834408e8f0f2295d02205d8ff5d011c859835225) [#​9760](https://redirect.github.com/npm/cli/pull/9760) pack: honor min-release-age-exclude ([#​9760](https://redirect.github.com/npm/cli/issues/9760)) ([@​martinrrm](https://redirect.github.com/martinrrm), [@​Copilot](https://redirect.github.com/Copilot)) - [`ef6cfea`](https://redirect.github.com/npm/cli/commit/ef6cfeaae218d1177e29f4fd26c591d0a1b86a46) [#​9786](https://redirect.github.com/npm/cli/pull/9786) owner: use scoped registry for user lookup ([#​9786](https://redirect.github.com/npm/cli/issues/9786)) ([@​martinrrm](https://redirect.github.com/martinrrm), [@​Copilot](https://redirect.github.com/Copilot)) ##### Documentation - [`9e17dc0`](https://redirect.github.com/npm/cli/commit/9e17dc064782ca1a1fd7f549e5a2fc7903f7fe51) [#​9805](https://redirect.github.com/npm/cli/pull/9805) clarify npm 12 unknown-config breaking change in changelogs ([#​9805](https://redirect.github.com/npm/cli/issues/9805)) ([@​Hashim1999164](https://redirect.github.com/Hashim1999164)) ##### Chores - [`7b1f6c1`](https://redirect.github.com/npm/cli/commit/7b1f6c173d17b3bf30e45426f6df39473c6a1163) [#​9747](https://redirect.github.com/npm/cli/pull/9747) parse pack --json object output in node integration ([#​9747](https://redirect.github.com/npm/cli/issues/9747)) ([@​reggi](https://redirect.github.com/reggi), [@​Copilot](https://redirect.github.com/Copilot)) ##### Dependencies - [workspace](https://redirect.github.com/npm/cli/releases/tag/arborist-v10.0.2): `@npmcli/arborist@10.0.2` - [workspace](https://redirect.github.com/npm/cli/releases/tag/config-v11.0.1): `@npmcli/config@11.0.1` - [workspace](https://redirect.github.com/npm/cli/releases/tag/libnpmdiff-v9.0.2): `libnpmdiff@9.0.2` - [workspace](https://redirect.github.com/npm/cli/releases/tag/libnpmexec-v11.0.2): `libnpmexec@11.0.2` - [workspace](https://redirect.github.com/npm/cli/releases/tag/libnpmfund-v8.0.2): `libnpmfund@8.0.2` - [workspace](https://redirect.github.com/npm/cli/releases/tag/libnpmpack-v10.0.2): `libnpmpack@10.0.2` </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
514dc5f5ae |
chore(deps): update dependency npm-run-all2 to v9.0.3 (#4271)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [npm-run-all2](https://redirect.github.com/bcomnes/npm-run-all2) | [`9.0.2` → `9.0.3`](https://renovatebot.com/diffs/npm/npm-run-all2/9.0.2/9.0.3) |  |  | --- ### Release Notes <details> <summary>bcomnes/npm-run-all2 (npm-run-all2)</summary> ### [`v9.0.3`](https://redirect.github.com/bcomnes/npm-run-all2/blob/HEAD/CHANGELOG.md#v903) [Compare Source](https://redirect.github.com/bcomnes/npm-run-all2/compare/v9.0.2...v9.0.3) ##### Merged - Upgrade: Bump ansi-styles from 6.2.3 to 7.0.0 [`#244`](https://redirect.github.com/bcomnes/npm-run-all2/pull/244) - Upgrade: Bump zizmorcore/zizmor-action from 0.6.0 to 0.6.1 [`#243`](https://redirect.github.com/bcomnes/npm-run-all2/pull/243) - Upgrade: Bump zizmorcore/zizmor-action from 0.5.7 to 0.6.0 [`#242`](https://redirect.github.com/bcomnes/npm-run-all2/pull/242) - Upgrade: Bump actions/setup-node from 6 to 7 [`#241`](https://redirect.github.com/bcomnes/npm-run-all2/pull/241) - chore: update schema version in .knip.jsonc to v6 [`#237`](https://redirect.github.com/bcomnes/npm-run-all2/pull/237) - Upgrade: Bump [@​types/node](https://redirect.github.com/types/node) from 25.9.4 to 26.0.0 [`#239`](https://redirect.github.com/bcomnes/npm-run-all2/pull/239) - Upgrade: Bump actions/checkout from 6 to 7 [`#238`](https://redirect.github.com/bcomnes/npm-run-all2/pull/238) ##### Commits - Harden GitHub Actions workflows [`7f5fca6`](https://redirect.github.com/bcomnes/npm-run-all2/commit/7f5fca6de6a0b454458baf1e650b9535b689aa1d) - Remove obsolete shell-quote types [`d970668`](https://redirect.github.com/bcomnes/npm-run-all2/commit/d970668ba2c5a1c835df1d22c5f66a2abc507e9c) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
f25b71600d |
ci(action): update github/codeql-action action to v4.37.4 (#4270)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | patch | `v4.37.3` → `v4.37.4` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.37.4`](https://redirect.github.com/github/codeql-action/compare/v4.37.3...v4.37.4) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.3...v4.37.4) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zLjIiLCJ1cGRhdGVkSW5WZXIiOiI0NC4zLjIiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
1114416a5b |
chore: remove 'next version' badge from README (#4265)
Removed the 'next version' badge from README. |
||
|
|
8675f7fbb2 | chore(deps): update verdaccio/verdaccio docker tag to v6.9.0 (#4268) | ||
|
|
af1fa1cbc5 |
chore(deps): update dependency fs-extra to v11.4.0 (#4267)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [fs-extra](https://redirect.github.com/jprichardson/node-fs-extra) | [`11.3.6` → `11.4.0`](https://renovatebot.com/diffs/npm/fs-extra/11.3.6/11.4.0) |  |  | --- ### Release Notes <details> <summary>jprichardson/node-fs-extra (fs-extra)</summary> ### [`v11.4.0`](https://redirect.github.com/jprichardson/node-fs-extra/blob/HEAD/CHANGELOG.md#1140--2026-07-23) [Compare Source](https://redirect.github.com/jprichardson/node-fs-extra/compare/11.3.6...11.4.0) - Proper `EEXIST` error when trying to create a symlink and the dest already exists as a broken symlink ([#​925](https://redirect.github.com/jprichardson/node-fs-extra/issues/925), [#​1076](https://redirect.github.com/jprichardson/node-fs-extra/pull/1076)) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
e1a4833a18 |
chore(deps): update dependency publint to v0.3.22 (#4266)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [publint](https://publint.dev) ([source](https://redirect.github.com/publint/publint/tree/HEAD/packages/publint)) | [`0.3.21` → `0.3.22`](https://renovatebot.com/diffs/npm/publint/0.3.21/0.3.22) |  |  | --- ### Release Notes <details> <summary>publint/publint (publint)</summary> ### [`v0.3.22`](https://redirect.github.com/publint/publint/blob/HEAD/packages/publint/CHANGELOG.md#0322) ##### Patch Changes - [#​241](https://redirect.github.com/publint/publint/pull/241) [`7740a62`](https://redirect.github.com/publint/publint/commit/7740a62fe60cc874de25fe491793eaf2bfc11d9e) - Support npm v12 and pnpm v11 - [`cad0425`](https://redirect.github.com/publint/publint/commit/cad0425333aaa3c7a2dbca492477c80a7bd7fd09) - Relax git url regex for repository validation - [#​244](https://redirect.github.com/publint/publint/pull/244) [`393ac4d`](https://redirect.github.com/publint/publint/commit/393ac4d2fda4b26b8f921e021bf6efeab2849467) - Recognize more common internal files for the `USE_FILES` suggestion. - [#​242](https://redirect.github.com/publint/publint/pull/242) [`4a8dc75`](https://redirect.github.com/publint/publint/commit/4a8dc757f7928dd884c762c9315f6e99d8805917) - Refactor supported package manager handling from `@publint/pack` </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC4wIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
18b3e0dbcd |
build(deps-dev): bump fast-uri from 3.1.3 to 3.1.4 (#4262)
Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
8e8df2fa22 |
ci(action): update ossf/scorecard-action action to v2.4.4 (#4264)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [ossf/scorecard-action](https://redirect.github.com/ossf/scorecard-action) | action | patch | `v2.4.3` → `v2.4.4` | --- ### Release Notes <details> <summary>ossf/scorecard-action (ossf/scorecard-action)</summary> ### [`v2.4.4`](https://redirect.github.com/ossf/scorecard-action/releases/tag/v2.4.4) [Compare Source](https://redirect.github.com/ossf/scorecard-action/compare/v2.4.3...v2.4.4) #### What's Changed This update bumps the Scorecard version to the v5.5.0 release. For a complete list of changes, please refer to the [Scorecard v5.4.0 release notes](https://redirect.github.com/ossf/scorecard/releases/tag/v5.4.0) and the [Scorecard v5.5.0 release notes](https://redirect.github.com/ossf/scorecard/releases/tag/v5.5.0). - log POST failures instead of failing entire action by [@​spencerschrock](https://redirect.github.com/spencerschrock) in [#​1625](https://redirect.github.com/ossf/scorecard-action/pull/1625) **Full Changelog**: <https://github.com/ossf/scorecard-action/compare/v2.4.3...v2.4.4> </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4yIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
a546db2995 |
chore(deps): update dependency sinon to v22.1.0 (#4263)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [sinon](https://sinonjs.org/) ([source](https://redirect.github.com/sinonjs/sinon)) | [`22.0.0` → `22.1.0`](https://renovatebot.com/diffs/npm/sinon/22.0.0/22.1.0) |  |  | --- ### Release Notes <details> <summary>sinonjs/sinon (sinon)</summary> ### [`v22.1.0`](https://redirect.github.com/sinonjs/sinon/blob/HEAD/CHANGES.md#2210) [Compare Source](https://redirect.github.com/sinonjs/sinon/compare/v22.0.0...v22.1.0) - [`d36e921b`](https://redirect.github.com/sinonjs/sinon/commit/d36e921baf382598cfa9323cb672c87ce85e2ad5) fix: let returns override returnsArg (王胜) > Signed-off-by: 王胜 <2318857637@​qq.com> - [`40c4caa0`](https://redirect.github.com/sinonjs/sinon/commit/40c4caa0f47b8fb184319a8873bac616c3eef871) fix: align restoreObject docs test with idempotent behavior ([#​2745](https://redirect.github.com/sinonjs/sinon/issues/2745)) (Julia Miller) > restoreObject was made idempotent in [#​2737](https://redirect.github.com/sinonjs/sinon/issues/2737) — it no longer throws > for objects with no restorable methods. Updates the docs page > and its corresponding test to reflect this. - [`a68dac19`](https://redirect.github.com/sinonjs/sinon/commit/a68dac198c6d0d9ce797dc9178d0c57ea6455aab) fix: throw a clear error when throwArg index equals the argument count ([#​2743](https://redirect.github.com/sinonjs/sinon/issues/2743)) (spokodev) > - fix: throw a clear error when throwArg index equals the argument count > > spyCall.throwArg(pos) guarded with pos > this.args.length, so calling it > with pos equal to the number of recorded arguments slipped past the guard > and reached throw this.args\[pos], throwing undefined instead of the > intended TypeError. A thrown undefined cannot be inspected as an Error and > is reported by test frameworks as no exception thrown. > > Use >= to match ensureArgs in behavior.js and the sibling callArg helpers, > which already reject an out-of-range index with a clear error. - [`9ea504e3`](https://redirect.github.com/sinonjs/sinon/commit/9ea504e317e9a27c376a9740bc04ec75f699ed30) feat: make sinon.restoreObject idempotent ([#​2737](https://redirect.github.com/sinonjs/sinon/issues/2737)) (Ilia Choly) > Passing an object with no live fakes to restoreObject now restores > nothing instead of throwing, giving it symmetry with sinon.restore() > and sandbox.restore(). The strict "found no methods" check is retained > for spy(object) and stub(object), which now use a dedicated > walkObjectStrict export, while restoreObject uses the loose walkObject. > Passing a falsy value still throws. > > Fixes [#​2736](https://redirect.github.com/sinonjs/sinon/issues/2736) - [`4db4feff`](https://redirect.github.com/sinonjs/sinon/commit/4db4feffe19d3f117d46b9015b4890187a282cf0) fix: preserve fake undefined argument validation (Vishal Kumar Singh) - [`755a40d7`](https://redirect.github.com/sinonjs/sinon/commit/755a40d772b02a7ba7e9a1d465a5f26d486ebbdb) fix: isolate callId counter per sandbox for parallel test support (Vishal Kumar Singh) > The global callId counter in proxy-invoke.js caused calledImmediatelyBefore > and calledImmediatelyAfter to fail when tests run in parallel with separate > sandboxes. Each sandbox now maintains its own callId counter, passed through > the spy/stub/fake creation chain via a context object. > > Fixes [#​2472](https://redirect.github.com/sinonjs/sinon/issues/2472) *Released by Morgan Roderick on 2026-07-20.* </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4yIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
d86844e6cd |
ci(action): update github/codeql-action action to v4.37.3 (#4261)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | patch | `v4.37.2` → `v4.37.3` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.37.3`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.3) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.2...v4.37.3) No user facing changes. </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi40IiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
70f7e73c2b |
ci(action): update github/codeql-action action to v4.37.2 (#4260)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [github/codeql-action](https://redirect.github.com/github/codeql-action) | action | patch | `v4.37.1` → `v4.37.2` | --- ### Release Notes <details> <summary>github/codeql-action (github/codeql-action)</summary> ### [`v4.37.2`](https://redirect.github.com/github/codeql-action/releases/tag/v4.37.2) [Compare Source](https://redirect.github.com/github/codeql-action/compare/v4.37.1...v4.37.2) - The new address format for the `config-file` input that was introduced in CodeQL Action 4.37.0 is now enabled by default. In addition to the format described there, the `remote=` prefix can now be used to explicitly indicate that the input refers to a remote file. All previous input formats continue to be accepted as well. [#​4023](https://redirect.github.com/github/codeql-action/pull/4023) - The CodeQL Action can now make use of [configured private registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries) in Default Setup to retrieve CodeQL configuration files from remote repositories that require authentication. This will allow customers to store their CodeQL configuration in a single repository that can then be referenced by Default Setup workflows in other repositories. We expect to roll this and other, related changes out to everyone in July. [#​4007](https://redirect.github.com/github/codeql-action/pull/4007) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi40IiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
520482ddf6 |
ci(action): update actions/checkout action to v7.0.1 (#4259)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/checkout](https://redirect.github.com/actions/checkout) | action | patch | `v7.0.0` → `v7.0.1` | --- ### Release Notes <details> <summary>actions/checkout (actions/checkout)</summary> ### [`v7.0.1`](https://redirect.github.com/actions/checkout/blob/HEAD/CHANGELOG.md#v701) [Compare Source](https://redirect.github.com/actions/checkout/compare/v7.0.0...v7.0.1) - Bump github/codeql-action from 3 to 4 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2475](https://redirect.github.com/actions/checkout/pull/2475) - Bump actions/setup-node from 4 to 6 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2477](https://redirect.github.com/actions/checkout/pull/2477) - Bump docker/build-push-action from 6.5.0 to 7.2.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2478](https://redirect.github.com/actions/checkout/pull/2478) - Bump docker/login-action from 3.3.0 to 4.2.0 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2479](https://redirect.github.com/actions/checkout/pull/2479) - Bump actions/checkout from 6 to 7 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2488](https://redirect.github.com/actions/checkout/pull/2488) - Bump actions/upload-artifact from 4 to 7 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2476](https://redirect.github.com/actions/checkout/pull/2476) - eslint 9 by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2474](https://redirect.github.com/actions/checkout/pull/2474) - Bump the minor-actions-dependencies group with 2 updates by [@​dependabot](https://redirect.github.com/dependabot)\[bot] in [#​2499](https://redirect.github.com/actions/checkout/pull/2499) - skip running unsafe pr check if input is default by [@​aiqiaoy](https://redirect.github.com/aiqiaoy) in [#​2518](https://redirect.github.com/actions/checkout/pull/2518) - trim only ascii whitespace for branch by [@​aiqiaoy](https://redirect.github.com/aiqiaoy) in [#​2521](https://redirect.github.com/actions/checkout/pull/2521) - escape values passed to --unset by [@​aiqiaoy](https://redirect.github.com/aiqiaoy) in [#​2530](https://redirect.github.com/actions/checkout/pull/2530) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzIuNCIsInVwZGF0ZWRJblZlciI6IjQzLjI3Mi40IiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
e4e2e48823 | chore(deps): update verdaccio/verdaccio docker tag to v6.8.0 (#4248) | ||
|
|
3575bb8c92 |
chore(deps): update dependency c8 to v12 (#4255)
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [c8](https://redirect.github.com/bcoe/c8) | [`11.0.0` → `12.0.0`](https://renovatebot.com/diffs/npm/c8/11.0.0/12.0.0) |  |  | --- ### Release Notes <details> <summary>bcoe/c8 (c8)</summary> ### [`v12.0.0`](https://redirect.github.com/bcoe/c8/blob/HEAD/CHANGELOG.md#1200-2026-07-14) [Compare Source](https://redirect.github.com/bcoe/c8/compare/v11.0.0...v12.0.0) ##### ⚠ BREAKING CHANGES - yargs enforces a stricter range of Node versions ^20.19.0 || ^22.12.0 || >=23 ##### Features - update yargs to 18.x.x ([#​599](https://redirect.github.com/bcoe/c8/issues/599)) ([dc2d6c8](https://redirect.github.com/bcoe/c8/commit/dc2d6c81e0b82aad80ffcc38d78bd4a76665675e)) </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/semantic-release/semantic-release). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNjUuMSIsInVwZGF0ZWRJblZlciI6IjQzLjI2NS4xIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
1bfdc52976 |
fix: mask sensitive environment variables and improve commit handling (#4252)
This pull request strengthens security and reliability by ensuring that template strings used for branch names and tag formats are rendered without evaluating potentially unsafe code. It also expands the detection and masking of sensitive environment variables, and improves robustness in commit parsing. Comprehensive tests have been added to verify these changes. **Security improvements:** * All uses of the `template` function for branch names and tag formats now disable evaluation and escaping, preventing unintended code execution when rendering templates in `lib/branches/expand.js`, `lib/branches/get-tags.js`, `lib/utils.js`, and `lib/verify.js`. * The detection of sensitive environment variables in `lib/hide-sensitive.js` is expanded to include common names such as `key`, `auth`, and `webhook`, increasing the likelihood of masking secrets in logs. **Bug fixes and robustness:** * Commit parsing in `lib/git.js` now safely trims `message` and `gitTags` fields, even if they are `undefined`, preventing runtime errors. **Testing improvements:** * New and expanded tests confirm that template evaluation syntax is not executed in branch and tag formats, and that a wide range of sensitive environment variables are properly masked.v25.0.8 |
||
|
|
0a60004a6a |
fix: handle potential null values in commit message and gitTags trimming
Co-authored-by: alanturing881 <alanturing881@users.noreply.github.com> |
||
|
|
f121540e89 |
fix: prevent template evaluation syntax in branch expansion and tag formatting
Co-authored-by: alanturing881 <alanturing881@users.noreply.github.com> |
||
|
|
973d763c2e |
fix(hide-sensitive): mask key/auth/webhook env vars
Co-authored-by: alanturing881 <alanturing881@users.noreply.github.com> |
||
|
|
474e5a385d |
ci(action): update github/codeql-action action to v4.37.1 (#4254)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
fc9382cd42 | docs: fix issue template links (#4251) | ||
|
|
e34c52dd1d |
ci(action): update actions/setup-node action to v7 (#4250)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
8020ec65b8 |
ci(action): update actions/setup-node action to v6.5.0 (#4249)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
956baf4d6d |
chore(deps): update npm to v12.0.1 (#4247)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
c46dbdaeda |
fix: argument Injection via repositoryUrl in package.json (#4245)
Co-Authored-By: Abhijith S abh78i00@gmail.comv25.0.7 |
||
|
|
7abb56289a |
chore(deps): update npm to v12 (#4244)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
8b15865161 |
chore(deps): update dependency @types/node to v24.13.3 (#4243)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
8e28dd3d6c | fix: ensure encoded secrets get masked v25.0.6 | ||
|
|
f293647392 |
Merge commit from fork
* fix: ensure percent-encoded secrets get masked Co-authored-by: Gregor Martynus <39992+gr2m@users.noreply.github.com> * fix: mask secrets in the exact form url.format() embeds them in git URLs The authenticated repository URL is built with the legacy url.format(), which encodes the auth field like encodeURIComponent() except that ":" separators are kept as is. A GIT_CREDENTIALS value such as "user:abc@def-secret" therefore appears as "user:abc%40def-secret" in a failing git command, a form matched by neither the raw value, encodeURI(), nor encodeURIComponent() candidates, and leaked unmasked. Add the colon-preserving encoded form to the redaction candidates, assert the unit tests against URLs built the same way get-git-auth-url.js builds them, and add an integration test reproducing the leak end-to-end with a git remote on a closed loopback port. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Matt Travi <programmer@travi.org> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a973d20a0f |
ci(action): update github/codeql-action action to v4.37.0 (#4241)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |
||
|
|
c62136f5b1 |
chore(deps): update dependency mockserver-client to v7.4.0 (#4240)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> |