chore: release 3.19.0 - #13976
chore: release 3.19.0#13976shreemaan-abhishek wants to merge 4 commits into
Conversation
| - fix(control): always report healthcheck nodes as a JSON array, so `nodes` and the top-level list of `/v1/healthcheck` are `[]` instead of `{}` when empty [#13891](https://github.com/apache/apisix/pull/13891) | ||
| - fix(plugin): align unavailable plugin handling: reject unknown plugin names before persistence, keep data-plane loading tolerant of them, and warn when one is skipped [#13928](https://github.com/apache/apisix/pull/13928) | ||
| - fix: preserve servlet upstream URI boundaries by encoding the original path before proxying when servlet-style normalization is enabled [#13914](https://github.com/apache/apisix/pull/13914) | ||
| - feat: label WebSocket sessions with `request_type=websocket`. A request answered with `101 Switching Protocols` is reported as `websocket` instead of `traditional_http` in `apisix_http_status`, `apisix_http_latency` and `apisix_bandwidth`, so a session can be kept out of latency queries [#13909](https://github.com/apache/apisix/pull/13909) |
There was a problem hiding this comment.
This should be marked as backward-incompatible and moved into Change (grouped with #13915). For existing enable_websocket routes, apisix_http_status, apisix_http_latency, and apisix_bandwidth series for successful 101 responses change request_type from traditional_http to websocket. PromQL selectors, recording rules, dashboards, and alerts that filter on the old value can silently lose WebSocket traffic after upgrade. Please scope the wording to the enable_websocket/NGINX proxy path: the new ws/wss content path does not run http_header_filter_phase, where this label is assigned.
| - feat: chaitin-waf response logging through `log_resp`, `resp_body_size` and `extra_ignored_content_types`, reported asynchronously after the response has been handed back to the client [#13763](https://github.com/apache/apisix/pull/13763) | ||
| - feat(ai-proxy-multi): let configured HTTP statuses trigger a fallback via `fallback_http_statuses` [#13852](https://github.com/apache/apisix/pull/13852) | ||
| - feat(saml-auth): add the lua-resty-saml 0.2.6 validation options `idp_issuers`, `sp_acs_url`, `sp_audiences`, `clock_skew`, `replay_dict` and `replay_ttl` [#13964](https://github.com/apache/apisix/pull/13964) | ||
| - fix(redis): send the TLS SNI and add `redis_server_name`, so a Redis behind a name-routed TLS front works with `redis_ssl: true`; the SNI is skipped for an IP literal host [#13938](https://github.com/apache/apisix/pull/13938) |
There was a problem hiding this comment.
This has a backward-incompatible case that should be called out in Change: for the single-node policy: redis path, when redis_ssl_verify: true, the landed code now passes redis_host (or redis_server_name) as server_name, so hostname verification becomes effective. An existing DNS alias not covered by the Redis certificate now fails with a certificate-host mismatch. The migration is to set redis_server_name to the certificate identity or replace the certificate; disabling verification is only an insecure compatibility fallback. This does not describe the Redis Cluster or Sentinel paths, and SNI is skipped only when the configured host/server-name value itself is an IP literal.
| - fix(ai-providers): encode the Vertex AI model path segment [#13872](https://github.com/apache/apisix/pull/13872) | ||
| - fix(ai-cache): key the passthrough protocol on the client method, path and query, so two upstream endpoints no longer collide on one cache entry [#13887](https://github.com/apache/apisix/pull/13887) | ||
| - fix(ai-aliyun-content-moderation): report final results without usage [#13922](https://github.com/apache/apisix/pull/13922) | ||
| - fix(feishu-auth, dingtalk-auth): bind the authorization code to the session that started the login. A random `state` is appended to the `redirect_uri` redirect and required back on the callback, so a code obtained elsewhere is no longer accepted on any session. Whatever serves `redirect_uri` has to pass `state` on to the identity provider; the header code path (`X-Feishu-Code` / `X-DingTalk-Code`) is unchanged [#13806](https://github.com/apache/apisix/pull/13806) |
There was a problem hiding this comment.
This should be marked backward-incompatible and moved into Change. Existing browser flows that only forward the authorization code now return 401 Invalid state; the application serving redirect_uri must forward the generated state to the IdP and preserve it on the callback. The header-code paths remain compatible.
| - fix(ai-cache): key the passthrough protocol on the client method, path and query, so two upstream endpoints no longer collide on one cache entry [#13887](https://github.com/apache/apisix/pull/13887) | ||
| - fix(ai-aliyun-content-moderation): report final results without usage [#13922](https://github.com/apache/apisix/pull/13922) | ||
| - fix(feishu-auth, dingtalk-auth): bind the authorization code to the session that started the login. A random `state` is appended to the `redirect_uri` redirect and required back on the callback, so a code obtained elsewhere is no longer accepted on any session. Whatever serves `redirect_uri` has to pass `state` on to the identity provider; the header code path (`X-Feishu-Code` / `X-DingTalk-Code`) is unchanged [#13806](https://github.com/apache/apisix/pull/13806) | ||
| - fix(jwe-decrypt): accept JWE tokens that authenticate the protected header, as RFC 7516 requires, and reject an unsupported `alg` or `enc` [#13889](https://github.com/apache/apisix/pull/13889) |
There was a problem hiding this comment.
Please split the compatibility-sensitive part into Change (or mark this entry with :warning:). Tokens that previously decrypted while explicitly declaring an unsupported alg or enc now return 400. Legacy no-AAD tokens and headers that omit those fields remain accepted, but token generators that emit misleading values must change to alg: dir and enc: A256GCM.
| - fix(etcd): do not block writes when the deployment role cannot be read [#13885](https://github.com/apache/apisix/pull/13885) | ||
| - fix(standalone): stop aborting stream connections before the first config arrives [#13855](https://github.com/apache/apisix/pull/13855) | ||
| - fix(standalone): harden the declarative configuration paths: validate the shape of the request body instead of 500ing, log the parser error rather than the body (which can carry credentials and private keys), check a stream route's `superior_id` self reference during validation, and guard null deployment sections in the CLI [#13886](https://github.com/apache/apisix/pull/13886) | ||
| - fix(control): always report healthcheck nodes as a JSON array, so `nodes` and the top-level list of `/v1/healthcheck` are `[]` instead of `{}` when empty [#13891](https://github.com/apache/apisix/pull/13891) |
There was a problem hiding this comment.
This changes the JSON type of an existing Control API response from object to array when empty ({} to []). That is the correct contract, but strict clients or deserializers can still break on upgrade. Please mark it compatibility-sensitive in Change, or explicitly explain why this API shape correction is exempt from the warning policy.
|
|
||
| ### Change | ||
|
|
||
| - :warning: feat(upstream): verify the upstream certificate against configurable CAs. `upstream.tls.verify` was only read by the `kafka` scheme and is now honoured for `https` and `grpcs` as well, so an upstream that already carried `verify: true` starts rejecting a certificate it cannot validate; `tls.ca_certs` picks the trust anchors per upstream [#13863](https://github.com/apache/apisix/pull/13863) |
There was a problem hiding this comment.
Please also mention the Runtime dependency for this breaking change. The new behavior calls resty.apisix.upstream.set_ssl_verify and set_ssl_trusted_store; an older/custom Runtime that lacks either API returns 503 (need to build APISIX-Runtime...) before certificate validation. The 3.19 release tree pins APISIX Runtime 1.3.18, so official 3.19 packages are covered, but custom builds need the equivalent APIs.
|
|
||
| - :warning: feat(upstream): verify the upstream certificate against configurable CAs. `upstream.tls.verify` was only read by the `kafka` scheme and is now honoured for `https` and `grpcs` as well, so an upstream that already carried `verify: true` starts rejecting a certificate it cannot validate; `tls.ca_certs` picks the trust anchors per upstream [#13863](https://github.com/apache/apisix/pull/13863) | ||
| - :warning: fix(openid-connect): validate the introspection issuer. With an explicit `claim_validator.issuer.valid_issuers`, a successful remote introspection response must now carry a string `iss` matching one of them, or the request is rejected with 401; omit the allowlist to keep the previous behavior [#13916](https://github.com/apache/apisix/pull/13916) | ||
| - :warning: fix(batch-requests): bound aggregated response bodies. New `max_response_body_size` (1 MiB) and `max_response_body_size_total` (10 MiB) plugin metadata; a pipeline above either limit now returns 502 instead of the full aggregate [#13906](https://github.com/apache/apisix/pull/13906) |
There was a problem hiding this comment.
The new limits are global plugin metadata written through /apisix/admin/plugin_metadata/batch-requests, not route-level fields. Also, the merged docs/en/latest/plugins/batch-requests.md and Chinese counterpart still omit max_response_body_size and max_response_body_size_total from the Metadata table and configuration example. Please add the two fields so operators can act on this breaking change without relying on the changelog alone.
| - feat(stream): match a stream route by several SNIs through the new `snis` field, mutually exclusive with `sni` [#13911](https://github.com/apache/apisix/pull/13911) | ||
| - feat(websocket): add the `ws`/`wss` upstream scheme, which proxies frames through APISIX itself and exposes the `ws_handshake`, `ws_client_frame`, `ws_upstream_frame` and `ws_close` plugin phases plus the `core.websocket` API [#13939](https://github.com/apache/apisix/pull/13939) | ||
| - feat(upstream): slow start for newly observed upstream nodes via `warm_up_conf` [#13941](https://github.com/apache/apisix/pull/13941) | ||
| - feat: improve API-driven standalone update reliability: workers report a per-entity configuration digest, `PUT /apisix/admin/configs` accepts a `wait` parameter and answers 200 once every worker has loaded the configuration (202 otherwise), and the shdict format carries the digest outside the JSON [#13904](https://github.com/apache/apisix/pull/13904) |
There was a problem hiding this comment.
“Per-entity configuration digest” is misleading here. The implementation writes the same target X-Digest under each tracked resource-type key (routes, services, and so on) for every worker/subsystem; it does not compute a separate digest for each resource object. Consider “workers report application of the configuration digest for each tracked resource type.”
| ### Plugins | ||
|
|
||
| - feat: add the `openapi-to-mcp` plugin, serving an HTTP API to MCP clients from its OpenAPI document over Streamable HTTP and HTTP+SSE [#13942](https://github.com/apache/apisix/pull/13942) | ||
| - feat(websocket): add the `websocket-proxy` plugin to customize proxy behaviors, starting with `client_max_payload_len` / `upstream_max_payload_len` for `ws`/`wss` upstreams [#13972](https://github.com/apache/apisix/pull/13972) |
There was a problem hiding this comment.
The implementation and PR rationale define these values as the maximum size of a single WebSocket frame, but the plugin schema and parts of docs/en/latest/plugins/websocket-proxy.md call them a message limit. Because fragmented messages can span multiple frames, please standardize the documentation on “frame” (and update the Chinese page) before the release notes rely on this behavior.
Description
Release 3.19.0.
This PR:
3.19.0section toCHANGELOG.md(and its Table of Contents entry), covering all PRs merged since therelease/3.18branch was cut. Backward-incompatible changes are grouped under Change and marked with3.19.0inapisix/core/version.luaanddocs/{en,zh}/latest/config.json.ci/check_changelog_prs.tsIGNORE_PRSwith changes that are not user-facing: CI-only work whosefix(ci)subject prefix dodges the docs/chore/test/ci type filter (fix(ci): unbreak CI under pnpm 12 #13921, fix(ci): stop rerun_flaky_tests from turning unparsable failures into a pass #13923).APISIX_DASHBOARD_COMMITin.requirementstofa2fd0f(currentapisix-dashboardmaster).APISIX_RUNTIMEis already at1.3.18, so it is unchanged.Breaking changes (see the
Changesection)Only changes that break an existing configuration or stored state on upgrade, with no adjustment made, are listed here.
Checklist
Changesection)