shreemaan-abhishek commented on code in PR #13842: URL: https://github.com/apache/apisix/pull/13842#discussion_r3819812552
########## CHANGELOG.md: ########## @@ -85,6 +86,183 @@ title: Changelog - [0.7.0](#070) - [0.6.0](#060) +## 3.18.0 + +**The changes marked with :warning: are not backward compatible.** + +### Change + +- :warning: change(debug): report executed plugins with phase in execution order. The `Apisix-Plugins` debug header now carries `name#phase` entries in execution order instead of a de-duplicated plugin-name list [#13710](https://github.com/apache/apisix/pull/13710) +- :warning: feat: bound request and response body buffering in plugins. `max_req_body_size` / `max_resp_body_size` (default 64 MiB) added to ~19 plugins; larger bodies are now rejected or truncated instead of being buffered without limit [#13705](https://github.com/apache/apisix/pull/13705) +- :warning: fix(batch-processor): bound the pending entries backlog by default. Every batch-processor logger now defaults `max_pending_entries` to 8192 and discards entries above it [#13826](https://github.com/apache/apisix/pull/13826) +- :warning: refactor(ai-aws-content-moderation): moderate decoded LLM content in the access phase. Priority moved from 1050 to 1031, the plugin now requires ai-proxy/ai-proxy-multi, moderates the extracted prompt instead of the raw body, and denies with `deny_code` (default 200) instead of 400 [#13647](https://github.com/apache/apisix/pull/13647) +- :warning: feat(ai-aliyun-content-moderation): role-aware `request_check_mode` and O(n) content chunking. Request moderation now covers the user role of the latest turn by default instead of every message in the body [#13598](https://github.com/apache/apisix/pull/13598) +- :warning: fix(sls-logger): verify the TLS certificate of the log server. New `ssl_verify` option, default `true` [#13785](https://github.com/apache/apisix/pull/13785) +- :warning: fix(openid-connect): enforce audience, issuer and required scopes. Bearer introspection fails closed when the discovery document is unavailable, `claim_validator.audience.match_with_client_id` now implies `required`, and `required_scopes` is enforced on session (authorization code) flows [#13829](https://github.com/apache/apisix/pull/13829) +- :warning: fix(admin): reject duplicate consumer authentication keys instead of silently accepting them [#13529](https://github.com/apache/apisix/pull/13529) +- :warning: perf(core): sanitize the `X-Forwarded-*` headers in the NGINX config. The `$var_x_forwarded_proto/host/port` variables are gone, and a trusted peer that sends no `X-Forwarded-Host`/`X-Forwarded-Port` now receives the APISIX-observed values instead of falling through to `$host`/`$server_port` [#13803](https://github.com/apache/apisix/pull/13803) Review Comment: Good catch, fixed in 9bce154a4 with your wording. Verified: `ngx_tpl.lua` still defines `$var_x_forwarded_host` and `$var_x_forwarded_port` as `map` outputs and feeds them to the `more_set_input_headers` directives; only `$var_x_forwarded_proto` is gone, replaced by `$scheme`. All three did leave the Lua-writable list in `core/ctx.lua`, which is what the entry now says. ########## CHANGELOG.md: ########## @@ -85,6 +86,183 @@ title: Changelog - [0.7.0](#070) - [0.6.0](#060) +## 3.18.0 + +**The changes marked with :warning: are not backward compatible.** + +### Change + +- :warning: change(debug): report executed plugins with phase in execution order. The `Apisix-Plugins` debug header now carries `name#phase` entries in execution order instead of a de-duplicated plugin-name list [#13710](https://github.com/apache/apisix/pull/13710) +- :warning: feat: bound request and response body buffering in plugins. `max_req_body_size` / `max_resp_body_size` (default 64 MiB) added to ~19 plugins; larger bodies are now rejected or truncated instead of being buffered without limit [#13705](https://github.com/apache/apisix/pull/13705) +- :warning: fix(batch-processor): bound the pending entries backlog by default. Every batch-processor logger now defaults `max_pending_entries` to 8192 and discards entries above it [#13826](https://github.com/apache/apisix/pull/13826) +- :warning: refactor(ai-aws-content-moderation): moderate decoded LLM content in the access phase. Priority moved from 1050 to 1031, the plugin now requires ai-proxy/ai-proxy-multi, moderates the extracted prompt instead of the raw body, and denies with `deny_code` (default 200) instead of 400 [#13647](https://github.com/apache/apisix/pull/13647) +- :warning: feat(ai-aliyun-content-moderation): role-aware `request_check_mode` and O(n) content chunking. Request moderation now covers the user role of the latest turn by default instead of every message in the body [#13598](https://github.com/apache/apisix/pull/13598) +- :warning: fix(sls-logger): verify the TLS certificate of the log server. New `ssl_verify` option, default `true` [#13785](https://github.com/apache/apisix/pull/13785) +- :warning: fix(openid-connect): enforce audience, issuer and required scopes. Bearer introspection fails closed when the discovery document is unavailable, `claim_validator.audience.match_with_client_id` now implies `required`, and `required_scopes` is enforced on session (authorization code) flows [#13829](https://github.com/apache/apisix/pull/13829) +- :warning: fix(admin): reject duplicate consumer authentication keys instead of silently accepting them [#13529](https://github.com/apache/apisix/pull/13529) +- :warning: perf(core): sanitize the `X-Forwarded-*` headers in the NGINX config. The `$var_x_forwarded_proto/host/port` variables are gone, and a trusted peer that sends no `X-Forwarded-Host`/`X-Forwarded-Port` now receives the APISIX-observed values instead of falling through to `$host`/`$server_port` [#13803](https://github.com/apache/apisix/pull/13803) + +### Core + +- feat: raise default sizes for non-evictable shared dicts: `prometheus-metrics` 15m/10m→128m, `nacos` 10m→64m, consul and kubernetes discovery `shared_size` 1m→64m, `tracing_buffer` 10m→32m [#13688](https://github.com/apache/apisix/pull/13688) +- chore(core): remove the dead `clean_handlers` mechanism. `core.config_util.add_clean_handler`, `cancel_clean_handler` and `fire_all_clean_handlers` no longer exist [#13761](https://github.com/apache/apisix/pull/13761) +- feat(ai-proxy): send LLM requests through `ngx_http_ffi_client`. New `plugin_attr.ai-proxy.http_client`, defaulting to the FFI client, which requires an APISIX-Runtime that ships `ngx_http_ffi_client` (set `lua-resty-http` to opt out) [#13778](https://github.com/apache/apisix/pull/13778) Review Comment: Keeping this one in Core, for the reason above. Every release repins `APISIX_RUNTIME` in `.requirements` (1.3.11 -> 1.3.16 this cycle), so "requires this release's runtime" would make most runtime-dependent work backward-incompatible and dilute the Change section. I have reworded the entry in 9bce154a4 to say the client ships with the runtime pinned by this release, and to name the `plugin_attr.ai-proxy.http_client: lua-resty-http` opt-out for hand-built runtimes without the module. ########## CHANGELOG.md: ########## @@ -85,6 +86,183 @@ title: Changelog - [0.7.0](#070) - [0.6.0](#060) +## 3.18.0 + +**The changes marked with :warning: are not backward compatible.** + +### Change + +- :warning: change(debug): report executed plugins with phase in execution order. The `Apisix-Plugins` debug header now carries `name#phase` entries in execution order instead of a de-duplicated plugin-name list [#13710](https://github.com/apache/apisix/pull/13710) +- :warning: feat: bound request and response body buffering in plugins. `max_req_body_size` / `max_resp_body_size` (default 64 MiB) added to ~19 plugins; larger bodies are now rejected or truncated instead of being buffered without limit [#13705](https://github.com/apache/apisix/pull/13705) +- :warning: fix(batch-processor): bound the pending entries backlog by default. Every batch-processor logger now defaults `max_pending_entries` to 8192 and discards entries above it [#13826](https://github.com/apache/apisix/pull/13826) +- :warning: refactor(ai-aws-content-moderation): moderate decoded LLM content in the access phase. Priority moved from 1050 to 1031, the plugin now requires ai-proxy/ai-proxy-multi, moderates the extracted prompt instead of the raw body, and denies with `deny_code` (default 200) instead of 400 [#13647](https://github.com/apache/apisix/pull/13647) +- :warning: feat(ai-aliyun-content-moderation): role-aware `request_check_mode` and O(n) content chunking. Request moderation now covers the user role of the latest turn by default instead of every message in the body [#13598](https://github.com/apache/apisix/pull/13598) +- :warning: fix(sls-logger): verify the TLS certificate of the log server. New `ssl_verify` option, default `true` [#13785](https://github.com/apache/apisix/pull/13785) +- :warning: fix(openid-connect): enforce audience, issuer and required scopes. Bearer introspection fails closed when the discovery document is unavailable, `claim_validator.audience.match_with_client_id` now implies `required`, and `required_scopes` is enforced on session (authorization code) flows [#13829](https://github.com/apache/apisix/pull/13829) +- :warning: fix(admin): reject duplicate consumer authentication keys instead of silently accepting them [#13529](https://github.com/apache/apisix/pull/13529) +- :warning: perf(core): sanitize the `X-Forwarded-*` headers in the NGINX config. The `$var_x_forwarded_proto/host/port` variables are gone, and a trusted peer that sends no `X-Forwarded-Host`/`X-Forwarded-Port` now receives the APISIX-observed values instead of falling through to `$host`/`$server_port` [#13803](https://github.com/apache/apisix/pull/13803) + +### Core + +- feat: raise default sizes for non-evictable shared dicts: `prometheus-metrics` 15m/10m→128m, `nacos` 10m→64m, consul and kubernetes discovery `shared_size` 1m→64m, `tracing_buffer` 10m→32m [#13688](https://github.com/apache/apisix/pull/13688) +- chore(core): remove the dead `clean_handlers` mechanism. `core.config_util.add_clean_handler`, `cancel_clean_handler` and `fire_all_clean_handlers` no longer exist [#13761](https://github.com/apache/apisix/pull/13761) +- feat(ai-proxy): send LLM requests through `ngx_http_ffi_client`. New `plugin_attr.ai-proxy.http_client`, defaulting to the FFI client, which requires an APISIX-Runtime that ships `ngx_http_ffi_client` (set `lua-resty-http` to opt out) [#13778](https://github.com/apache/apisix/pull/13778) +- feat: support per-port PROXY protocol for stream TCP proxy [#13561](https://github.com/apache/apisix/pull/13561) +- feat(stream): support `set_real_ip_from` to trust an inbound PROXY protocol header [#13700](https://github.com/apache/apisix/pull/13700) +- feat(stream): support upstream client certificate (mTLS) in the L4 proxy [#13596](https://github.com/apache/apisix/pull/13596) +- feat(router): add `match_uri_encoded_slash` to keep `%2F` in path parameters [#13626](https://github.com/apache/apisix/pull/13626) +- feat: add `max_post_args_readable_size` to bound `post_arg.*` body reads [#13601](https://github.com/apache/apisix/pull/13601) Review Comment: Agreed, moved to Change with :warning: in 9bce154a4, including the migration action (raise the value, or set it to `0`). Worth adding that this is reachable in a default install rather than only on tuned deployments: `client_max_body_size` defaults to `0` (unlimited), so a body above 64 MiB does reach route matching. ########## CHANGELOG.md: ########## @@ -85,6 +86,183 @@ title: Changelog - [0.7.0](#070) - [0.6.0](#060) +## 3.18.0 + +**The changes marked with :warning: are not backward compatible.** + +### Change + +- :warning: change(debug): report executed plugins with phase in execution order. The `Apisix-Plugins` debug header now carries `name#phase` entries in execution order instead of a de-duplicated plugin-name list [#13710](https://github.com/apache/apisix/pull/13710) +- :warning: feat: bound request and response body buffering in plugins. `max_req_body_size` / `max_resp_body_size` (default 64 MiB) added to ~19 plugins; larger bodies are now rejected or truncated instead of being buffered without limit [#13705](https://github.com/apache/apisix/pull/13705) +- :warning: fix(batch-processor): bound the pending entries backlog by default. Every batch-processor logger now defaults `max_pending_entries` to 8192 and discards entries above it [#13826](https://github.com/apache/apisix/pull/13826) +- :warning: refactor(ai-aws-content-moderation): moderate decoded LLM content in the access phase. Priority moved from 1050 to 1031, the plugin now requires ai-proxy/ai-proxy-multi, moderates the extracted prompt instead of the raw body, and denies with `deny_code` (default 200) instead of 400 [#13647](https://github.com/apache/apisix/pull/13647) +- :warning: feat(ai-aliyun-content-moderation): role-aware `request_check_mode` and O(n) content chunking. Request moderation now covers the user role of the latest turn by default instead of every message in the body [#13598](https://github.com/apache/apisix/pull/13598) +- :warning: fix(sls-logger): verify the TLS certificate of the log server. New `ssl_verify` option, default `true` [#13785](https://github.com/apache/apisix/pull/13785) +- :warning: fix(openid-connect): enforce audience, issuer and required scopes. Bearer introspection fails closed when the discovery document is unavailable, `claim_validator.audience.match_with_client_id` now implies `required`, and `required_scopes` is enforced on session (authorization code) flows [#13829](https://github.com/apache/apisix/pull/13829) +- :warning: fix(admin): reject duplicate consumer authentication keys instead of silently accepting them [#13529](https://github.com/apache/apisix/pull/13529) +- :warning: perf(core): sanitize the `X-Forwarded-*` headers in the NGINX config. The `$var_x_forwarded_proto/host/port` variables are gone, and a trusted peer that sends no `X-Forwarded-Host`/`X-Forwarded-Port` now receives the APISIX-observed values instead of falling through to `$host`/`$server_port` [#13803](https://github.com/apache/apisix/pull/13803) + +### Core + +- feat: raise default sizes for non-evictable shared dicts: `prometheus-metrics` 15m/10m→128m, `nacos` 10m→64m, consul and kubernetes discovery `shared_size` 1m→64m, `tracing_buffer` 10m→32m [#13688](https://github.com/apache/apisix/pull/13688) +- chore(core): remove the dead `clean_handlers` mechanism. `core.config_util.add_clean_handler`, `cancel_clean_handler` and `fire_all_clean_handlers` no longer exist [#13761](https://github.com/apache/apisix/pull/13761) +- feat(ai-proxy): send LLM requests through `ngx_http_ffi_client`. New `plugin_attr.ai-proxy.http_client`, defaulting to the FFI client, which requires an APISIX-Runtime that ships `ngx_http_ffi_client` (set `lua-resty-http` to opt out) [#13778](https://github.com/apache/apisix/pull/13778) +- feat: support per-port PROXY protocol for stream TCP proxy [#13561](https://github.com/apache/apisix/pull/13561) +- feat(stream): support `set_real_ip_from` to trust an inbound PROXY protocol header [#13700](https://github.com/apache/apisix/pull/13700) +- feat(stream): support upstream client certificate (mTLS) in the L4 proxy [#13596](https://github.com/apache/apisix/pull/13596) +- feat(router): add `match_uri_encoded_slash` to keep `%2F` in path parameters [#13626](https://github.com/apache/apisix/pull/13626) +- feat: add `max_post_args_readable_size` to bound `post_arg.*` body reads [#13601](https://github.com/apache/apisix/pull/13601) +- feat: support `http_method` and `http_req_body` in active health checks [#13726](https://github.com/apache/apisix/pull/13726) +- feat(data_encryption): support AES-256 keys in the encryption keyring [#13756](https://github.com/apache/apisix/pull/13756) +- refactor: decouple generic data encryption from `ssl.lua` [#13564](https://github.com/apache/apisix/pull/13564) +- perf(plugin): reuse the filtered global-rule plugin set across phases [#13779](https://github.com/apache/apisix/pull/13779) +- fix: keep the chash ring stable during health changes [#13532](https://github.com/apache/apisix/pull/13532) +- fix(balancer): keep least_conn load state across upstream scaling [#13666](https://github.com/apache/apisix/pull/13666) +- fix(balancer): separate the keepalive pool by referenced client cert [#13587](https://github.com/apache/apisix/pull/13587) +- fix(healthcheck): reuse the checker on node-only upstream changes instead of destroy-and-rebuild [#13629](https://github.com/apache/apisix/pull/13629) +- fix(healthcheck): probe domain nodes by the node domain, not the resolved IP [#13743](https://github.com/apache/apisix/pull/13743) +- fix(healthcheck): purge stale targets and release the periodic lock [#13627](https://github.com/apache/apisix/pull/13627) +- fix(healthcheck): guard `construct_upstream` in healthcheck timers [#13592](https://github.com/apache/apisix/pull/13592) +- fix(stream): initialize env and secret for TLS cert resolution [#12935](https://github.com/apache/apisix/pull/12935) +- fix: fetch secrets from the upstream ssl config [#13062](https://github.com/apache/apisix/pull/13062) +- fix: invalidate the secret LRU cache on `/secrets` changes [#13668](https://github.com/apache/apisix/pull/13668) +- fix(secret): log an error when a secret reference cannot be resolved [#13737](https://github.com/apache/apisix/pull/13737) +- fix: reject consumer auth when a secret reference fails to resolve [#13667](https://github.com/apache/apisix/pull/13667) +- fix: encode control characters in `$upstream_uri` to prevent CRLF injection [#13787](https://github.com/apache/apisix/pull/13787) +- fix: reset `X-Forwarded-For` only for untrusted sources under `trusted_addresses` [#13611](https://github.com/apache/apisix/pull/13611) +- fix: normalize the case of hosts carried on a service [#13781](https://github.com/apache/apisix/pull/13781) +- fix(plugin): preserve plugin-conf state across the consumer route merge [#13757](https://github.com/apache/apisix/pull/13757) +- fix(resource): support all plugin-bearing resource types in `fetch_latest_conf` [#13663](https://github.com/apache/apisix/pull/13663) +- fix(config_etcd): keep the previous value when a full reload gets invalid data [#13717](https://github.com/apache/apisix/pull/13717) +- fix(etcd): do not advance the watch revision on a timeout, and make the recovery reload cheap [#13721](https://github.com/apache/apisix/pull/13721) +- fix(json): make cjson instances inherit APISIX's cjson options [#13680](https://github.com/apache/apisix/pull/13680) +- fix(env): resolve the `os.getenv` prefix collision for `env` directives [#13595](https://github.com/apache/apisix/pull/13595) +- fix(cli): remove the stale key after resolving an env var in config keys [#12885](https://github.com/apache/apisix/pull/12885) +- fix(cli): quote `nginx_config.envs` entries so values with spaces work [#13713](https://github.com/apache/apisix/pull/13713) +- fix(admin): harden stream_route `superior_id` dependency checks [#13672](https://github.com/apache/apisix/pull/13672) +- fix(admin): encrypt only after successful validation [#13729](https://github.com/apache/apisix/pull/13729) +- fix(admin): encrypt the inline upstream client key of a stream route [#13833](https://github.com/apache/apisix/pull/13833) +- fix(admin): reconcile the plugins reload instead of trusting the broadcast [#13714](https://github.com/apache/apisix/pull/13714) +- fix(control): reconcile `/v1/plugins/reload` like the admin reload path [#13745](https://github.com/apache/apisix/pull/13745) +- fix(log-sanitize): return raw tables to avoid double `delay_encode` [#13605](https://github.com/apache/apisix/pull/13605) +- fix(dns): correct the `error()` call in dns client initialization [#13358](https://github.com/apache/apisix/pull/13358) +- fix: avoid 503 error after dns service temporary fail [#13137](https://github.com/apache/apisix/pull/13137) +- fix(cli): add IPv6 listen support for the PROXY protocol [#12859](https://github.com/apache/apisix/pull/12859) +- fix(upstream): use `cert` and `key` instead of stale `ok` in mTLS error checks [#13442](https://github.com/apache/apisix/pull/13442) +- fix(core.request): `set_header` must update the cached headers with a normalized key [#13517](https://github.com/apache/apisix/pull/13517) +- fix(admin): `encrypt_fields` get double-encrypted on every PATCH [#13525](https://github.com/apache/apisix/pull/13525) +- fix(plugin): ignore `plugin_metadata` of disabled or unknown plugins [#13514](https://github.com/apache/apisix/pull/13514) +- fix(xrpc): stream routes with xRPC protocols fail `check_schema` in HTTP workers when the Admin API is disabled [#13515](https://github.com/apache/apisix/pull/13515) +- fix(secret): aws secret manager fails when the secret name contains a slash [#13519](https://github.com/apache/apisix/pull/13519) +- fix(consul): one invalid node should not discard the remaining nodes of the service [#13513](https://github.com/apache/apisix/pull/13513) +- fix(nacos): declare the `nacos-stream` shared dict in the stream subsystem [#13541](https://github.com/apache/apisix/pull/13541) +- fix: redis connections with different database/credentials must not share a keepalive pool [#13516](https://github.com/apache/apisix/pull/13516) + +### Plugins + +- feat: add ai-cache plugin [#13578](https://github.com/apache/apisix/pull/13578) +- feat(ai-cache): add the semantic (L2) cache layer [#13632](https://github.com/apache/apisix/pull/13632) +- feat(ai-cache): add streaming support with format tagging [#13644](https://github.com/apache/apisix/pull/13644) +- feat: add ai-lakera-guard plugin [#13570](https://github.com/apache/apisix/pull/13570) +- feat(ai-lakera-guard): scan LLM responses (direction output/both, non-streaming and streaming) [#13606](https://github.com/apache/apisix/pull/13606) +- feat: add ldap-auth-advanced plugin [#13762](https://github.com/apache/apisix/pull/13762) Review Comment: Confirmed, and added as its own Change entry in 9bce154a4 while keeping the new plugin under Plugins. The mechanism: in `lua-resty-ldap` 0.1.0 the handshake read `conf.verify_ldap_host` (`init.lua:78`) while `ldap-auth` passes `tls_verify`, so the argument was always nil and `sslhandshake(true, host, nil)` verified nothing. 0.3.1 maps `ssl_verify = conf.tls_verify`, so the flag now takes effect. Scope is limited to deployments that explicitly set `tls_verify: true`, which are exactly the ones that believed verification was already on. ########## CHANGELOG.md: ########## @@ -85,6 +86,183 @@ title: Changelog - [0.7.0](#070) - [0.6.0](#060) +## 3.18.0 + +**The changes marked with :warning: are not backward compatible.** + +### Change + +- :warning: change(debug): report executed plugins with phase in execution order. The `Apisix-Plugins` debug header now carries `name#phase` entries in execution order instead of a de-duplicated plugin-name list [#13710](https://github.com/apache/apisix/pull/13710) +- :warning: feat: bound request and response body buffering in plugins. `max_req_body_size` / `max_resp_body_size` (default 64 MiB) added to ~19 plugins; larger bodies are now rejected or truncated instead of being buffered without limit [#13705](https://github.com/apache/apisix/pull/13705) +- :warning: fix(batch-processor): bound the pending entries backlog by default. Every batch-processor logger now defaults `max_pending_entries` to 8192 and discards entries above it [#13826](https://github.com/apache/apisix/pull/13826) +- :warning: refactor(ai-aws-content-moderation): moderate decoded LLM content in the access phase. Priority moved from 1050 to 1031, the plugin now requires ai-proxy/ai-proxy-multi, moderates the extracted prompt instead of the raw body, and denies with `deny_code` (default 200) instead of 400 [#13647](https://github.com/apache/apisix/pull/13647) +- :warning: feat(ai-aliyun-content-moderation): role-aware `request_check_mode` and O(n) content chunking. Request moderation now covers the user role of the latest turn by default instead of every message in the body [#13598](https://github.com/apache/apisix/pull/13598) +- :warning: fix(sls-logger): verify the TLS certificate of the log server. New `ssl_verify` option, default `true` [#13785](https://github.com/apache/apisix/pull/13785) +- :warning: fix(openid-connect): enforce audience, issuer and required scopes. Bearer introspection fails closed when the discovery document is unavailable, `claim_validator.audience.match_with_client_id` now implies `required`, and `required_scopes` is enforced on session (authorization code) flows [#13829](https://github.com/apache/apisix/pull/13829) +- :warning: fix(admin): reject duplicate consumer authentication keys instead of silently accepting them [#13529](https://github.com/apache/apisix/pull/13529) +- :warning: perf(core): sanitize the `X-Forwarded-*` headers in the NGINX config. The `$var_x_forwarded_proto/host/port` variables are gone, and a trusted peer that sends no `X-Forwarded-Host`/`X-Forwarded-Port` now receives the APISIX-observed values instead of falling through to `$host`/`$server_port` [#13803](https://github.com/apache/apisix/pull/13803) + +### Core + +- feat: raise default sizes for non-evictable shared dicts: `prometheus-metrics` 15m/10m→128m, `nacos` 10m→64m, consul and kubernetes discovery `shared_size` 1m→64m, `tracing_buffer` 10m→32m [#13688](https://github.com/apache/apisix/pull/13688) +- chore(core): remove the dead `clean_handlers` mechanism. `core.config_util.add_clean_handler`, `cancel_clean_handler` and `fire_all_clean_handlers` no longer exist [#13761](https://github.com/apache/apisix/pull/13761) +- feat(ai-proxy): send LLM requests through `ngx_http_ffi_client`. New `plugin_attr.ai-proxy.http_client`, defaulting to the FFI client, which requires an APISIX-Runtime that ships `ngx_http_ffi_client` (set `lua-resty-http` to opt out) [#13778](https://github.com/apache/apisix/pull/13778) +- feat: support per-port PROXY protocol for stream TCP proxy [#13561](https://github.com/apache/apisix/pull/13561) +- feat(stream): support `set_real_ip_from` to trust an inbound PROXY protocol header [#13700](https://github.com/apache/apisix/pull/13700) +- feat(stream): support upstream client certificate (mTLS) in the L4 proxy [#13596](https://github.com/apache/apisix/pull/13596) +- feat(router): add `match_uri_encoded_slash` to keep `%2F` in path parameters [#13626](https://github.com/apache/apisix/pull/13626) +- feat: add `max_post_args_readable_size` to bound `post_arg.*` body reads [#13601](https://github.com/apache/apisix/pull/13601) +- feat: support `http_method` and `http_req_body` in active health checks [#13726](https://github.com/apache/apisix/pull/13726) +- feat(data_encryption): support AES-256 keys in the encryption keyring [#13756](https://github.com/apache/apisix/pull/13756) +- refactor: decouple generic data encryption from `ssl.lua` [#13564](https://github.com/apache/apisix/pull/13564) +- perf(plugin): reuse the filtered global-rule plugin set across phases [#13779](https://github.com/apache/apisix/pull/13779) +- fix: keep the chash ring stable during health changes [#13532](https://github.com/apache/apisix/pull/13532) +- fix(balancer): keep least_conn load state across upstream scaling [#13666](https://github.com/apache/apisix/pull/13666) +- fix(balancer): separate the keepalive pool by referenced client cert [#13587](https://github.com/apache/apisix/pull/13587) +- fix(healthcheck): reuse the checker on node-only upstream changes instead of destroy-and-rebuild [#13629](https://github.com/apache/apisix/pull/13629) +- fix(healthcheck): probe domain nodes by the node domain, not the resolved IP [#13743](https://github.com/apache/apisix/pull/13743) +- fix(healthcheck): purge stale targets and release the periodic lock [#13627](https://github.com/apache/apisix/pull/13627) +- fix(healthcheck): guard `construct_upstream` in healthcheck timers [#13592](https://github.com/apache/apisix/pull/13592) +- fix(stream): initialize env and secret for TLS cert resolution [#12935](https://github.com/apache/apisix/pull/12935) +- fix: fetch secrets from the upstream ssl config [#13062](https://github.com/apache/apisix/pull/13062) +- fix: invalidate the secret LRU cache on `/secrets` changes [#13668](https://github.com/apache/apisix/pull/13668) +- fix(secret): log an error when a secret reference cannot be resolved [#13737](https://github.com/apache/apisix/pull/13737) +- fix: reject consumer auth when a secret reference fails to resolve [#13667](https://github.com/apache/apisix/pull/13667) +- fix: encode control characters in `$upstream_uri` to prevent CRLF injection [#13787](https://github.com/apache/apisix/pull/13787) +- fix: reset `X-Forwarded-For` only for untrusted sources under `trusted_addresses` [#13611](https://github.com/apache/apisix/pull/13611) +- fix: normalize the case of hosts carried on a service [#13781](https://github.com/apache/apisix/pull/13781) +- fix(plugin): preserve plugin-conf state across the consumer route merge [#13757](https://github.com/apache/apisix/pull/13757) +- fix(resource): support all plugin-bearing resource types in `fetch_latest_conf` [#13663](https://github.com/apache/apisix/pull/13663) +- fix(config_etcd): keep the previous value when a full reload gets invalid data [#13717](https://github.com/apache/apisix/pull/13717) +- fix(etcd): do not advance the watch revision on a timeout, and make the recovery reload cheap [#13721](https://github.com/apache/apisix/pull/13721) +- fix(json): make cjson instances inherit APISIX's cjson options [#13680](https://github.com/apache/apisix/pull/13680) +- fix(env): resolve the `os.getenv` prefix collision for `env` directives [#13595](https://github.com/apache/apisix/pull/13595) +- fix(cli): remove the stale key after resolving an env var in config keys [#12885](https://github.com/apache/apisix/pull/12885) +- fix(cli): quote `nginx_config.envs` entries so values with spaces work [#13713](https://github.com/apache/apisix/pull/13713) +- fix(admin): harden stream_route `superior_id` dependency checks [#13672](https://github.com/apache/apisix/pull/13672) +- fix(admin): encrypt only after successful validation [#13729](https://github.com/apache/apisix/pull/13729) +- fix(admin): encrypt the inline upstream client key of a stream route [#13833](https://github.com/apache/apisix/pull/13833) +- fix(admin): reconcile the plugins reload instead of trusting the broadcast [#13714](https://github.com/apache/apisix/pull/13714) +- fix(control): reconcile `/v1/plugins/reload` like the admin reload path [#13745](https://github.com/apache/apisix/pull/13745) +- fix(log-sanitize): return raw tables to avoid double `delay_encode` [#13605](https://github.com/apache/apisix/pull/13605) +- fix(dns): correct the `error()` call in dns client initialization [#13358](https://github.com/apache/apisix/pull/13358) +- fix: avoid 503 error after dns service temporary fail [#13137](https://github.com/apache/apisix/pull/13137) +- fix(cli): add IPv6 listen support for the PROXY protocol [#12859](https://github.com/apache/apisix/pull/12859) +- fix(upstream): use `cert` and `key` instead of stale `ok` in mTLS error checks [#13442](https://github.com/apache/apisix/pull/13442) +- fix(core.request): `set_header` must update the cached headers with a normalized key [#13517](https://github.com/apache/apisix/pull/13517) +- fix(admin): `encrypt_fields` get double-encrypted on every PATCH [#13525](https://github.com/apache/apisix/pull/13525) +- fix(plugin): ignore `plugin_metadata` of disabled or unknown plugins [#13514](https://github.com/apache/apisix/pull/13514) +- fix(xrpc): stream routes with xRPC protocols fail `check_schema` in HTTP workers when the Admin API is disabled [#13515](https://github.com/apache/apisix/pull/13515) +- fix(secret): aws secret manager fails when the secret name contains a slash [#13519](https://github.com/apache/apisix/pull/13519) +- fix(consul): one invalid node should not discard the remaining nodes of the service [#13513](https://github.com/apache/apisix/pull/13513) +- fix(nacos): declare the `nacos-stream` shared dict in the stream subsystem [#13541](https://github.com/apache/apisix/pull/13541) +- fix: redis connections with different database/credentials must not share a keepalive pool [#13516](https://github.com/apache/apisix/pull/13516) + +### Plugins + +- feat: add ai-cache plugin [#13578](https://github.com/apache/apisix/pull/13578) +- feat(ai-cache): add the semantic (L2) cache layer [#13632](https://github.com/apache/apisix/pull/13632) +- feat(ai-cache): add streaming support with format tagging [#13644](https://github.com/apache/apisix/pull/13644) +- feat: add ai-lakera-guard plugin [#13570](https://github.com/apache/apisix/pull/13570) +- feat(ai-lakera-guard): scan LLM responses (direction output/both, non-streaming and streaming) [#13606](https://github.com/apache/apisix/pull/13606) +- feat: add ldap-auth-advanced plugin [#13762](https://github.com/apache/apisix/pull/13762) +- feat(ai-proxy-multi): add the semantic load-balancing algorithm [#13676](https://github.com/apache/apisix/pull/13676) +- feat(ai-proxy): include AI observability vars in `llm_summary` [#13609](https://github.com/apache/apisix/pull/13609) +- feat(ai-rate-limiting): support the redis policy for shared counters [#13670](https://github.com/apache/apisix/pull/13670) +- feat(ai-aws-content-moderation): moderate LLM responses, including streams [#13735](https://github.com/apache/apisix/pull/13735) +- feat(ai-aws-content-moderation): add `request_check_roles` and `request_check_mode` [#13773](https://github.com/apache/apisix/pull/13773) +- feat(ai-aliyun-content-moderation): moderate system and tool role content [#13646](https://github.com/apache/apisix/pull/13646) +- feat(prometheus): add metrics for AI cache hits, misses, bypasses, and embedding latency [#13659](https://github.com/apache/apisix/pull/13659) +- feat(prometheus): stream active connections, termination status and bandwidth [#13796](https://github.com/apache/apisix/pull/13796) +- feat: add `log_format_extra` to enrich the default logger format [#13568](https://github.com/apache/apisix/pull/13568) +- feat(kafka-logger): add TLS support for Kafka brokers [#13607](https://github.com/apache/apisix/pull/13607) +- feat(elasticsearch-logger): encrypt the `headers` field at rest [#13612](https://github.com/apache/apisix/pull/13612) +- feat: encrypt `redis_password` and `sentinel_password` in limit-count, limit-req and limit-conn [#13624](https://github.com/apache/apisix/pull/13624) +- feat(proxy-rewrite): support multiple same-name headers in `headers.add`/`headers.set` [#13597](https://github.com/apache/apisix/pull/13597) +- feat(openid-connect): add the `set_raw_id_token_header` option [#13616](https://github.com/apache/apisix/pull/13616) +- feat(openid-connect): support PAR and DPoP client options [#13649](https://github.com/apache/apisix/pull/13649) +- feat(ldap-auth): add `hide_credentials` [#13832](https://github.com/apache/apisix/pull/13832) +- refactor(ai-providers): make the LLM request client ctx-free [#13699](https://github.com/apache/apisix/pull/13699) Review Comment: Agreed, recategorised as `fix(ai-request-rewrite)` in 9bce154a4 with the user impact described. One refinement to the wording: the pre-image copied every client header and then merged `ext_opts_headers` over them, so when the provider authenticates through the `Authorization` header the client's value was overwritten. `Cookie` and any other client headers (custom API keys, session tokens) leaked unconditionally, and `Authorization` leaked whenever the provider uses query-param, `api-key` or SigV4 auth. The entry is phrased to match that. ########## CHANGELOG.md: ########## @@ -85,6 +86,183 @@ title: Changelog - [0.7.0](#070) - [0.6.0](#060) +## 3.18.0 + +**The changes marked with :warning: are not backward compatible.** + +### Change + +- :warning: change(debug): report executed plugins with phase in execution order. The `Apisix-Plugins` debug header now carries `name#phase` entries in execution order instead of a de-duplicated plugin-name list [#13710](https://github.com/apache/apisix/pull/13710) +- :warning: feat: bound request and response body buffering in plugins. `max_req_body_size` / `max_resp_body_size` (default 64 MiB) added to ~19 plugins; larger bodies are now rejected or truncated instead of being buffered without limit [#13705](https://github.com/apache/apisix/pull/13705) +- :warning: fix(batch-processor): bound the pending entries backlog by default. Every batch-processor logger now defaults `max_pending_entries` to 8192 and discards entries above it [#13826](https://github.com/apache/apisix/pull/13826) +- :warning: refactor(ai-aws-content-moderation): moderate decoded LLM content in the access phase. Priority moved from 1050 to 1031, the plugin now requires ai-proxy/ai-proxy-multi, moderates the extracted prompt instead of the raw body, and denies with `deny_code` (default 200) instead of 400 [#13647](https://github.com/apache/apisix/pull/13647) +- :warning: feat(ai-aliyun-content-moderation): role-aware `request_check_mode` and O(n) content chunking. Request moderation now covers the user role of the latest turn by default instead of every message in the body [#13598](https://github.com/apache/apisix/pull/13598) +- :warning: fix(sls-logger): verify the TLS certificate of the log server. New `ssl_verify` option, default `true` [#13785](https://github.com/apache/apisix/pull/13785) +- :warning: fix(openid-connect): enforce audience, issuer and required scopes. Bearer introspection fails closed when the discovery document is unavailable, `claim_validator.audience.match_with_client_id` now implies `required`, and `required_scopes` is enforced on session (authorization code) flows [#13829](https://github.com/apache/apisix/pull/13829) +- :warning: fix(admin): reject duplicate consumer authentication keys instead of silently accepting them [#13529](https://github.com/apache/apisix/pull/13529) +- :warning: perf(core): sanitize the `X-Forwarded-*` headers in the NGINX config. The `$var_x_forwarded_proto/host/port` variables are gone, and a trusted peer that sends no `X-Forwarded-Host`/`X-Forwarded-Port` now receives the APISIX-observed values instead of falling through to `$host`/`$server_port` [#13803](https://github.com/apache/apisix/pull/13803) + +### Core + +- feat: raise default sizes for non-evictable shared dicts: `prometheus-metrics` 15m/10m→128m, `nacos` 10m→64m, consul and kubernetes discovery `shared_size` 1m→64m, `tracing_buffer` 10m→32m [#13688](https://github.com/apache/apisix/pull/13688) +- chore(core): remove the dead `clean_handlers` mechanism. `core.config_util.add_clean_handler`, `cancel_clean_handler` and `fire_all_clean_handlers` no longer exist [#13761](https://github.com/apache/apisix/pull/13761) +- feat(ai-proxy): send LLM requests through `ngx_http_ffi_client`. New `plugin_attr.ai-proxy.http_client`, defaulting to the FFI client, which requires an APISIX-Runtime that ships `ngx_http_ffi_client` (set `lua-resty-http` to opt out) [#13778](https://github.com/apache/apisix/pull/13778) +- feat: support per-port PROXY protocol for stream TCP proxy [#13561](https://github.com/apache/apisix/pull/13561) +- feat(stream): support `set_real_ip_from` to trust an inbound PROXY protocol header [#13700](https://github.com/apache/apisix/pull/13700) +- feat(stream): support upstream client certificate (mTLS) in the L4 proxy [#13596](https://github.com/apache/apisix/pull/13596) +- feat(router): add `match_uri_encoded_slash` to keep `%2F` in path parameters [#13626](https://github.com/apache/apisix/pull/13626) +- feat: add `max_post_args_readable_size` to bound `post_arg.*` body reads [#13601](https://github.com/apache/apisix/pull/13601) +- feat: support `http_method` and `http_req_body` in active health checks [#13726](https://github.com/apache/apisix/pull/13726) +- feat(data_encryption): support AES-256 keys in the encryption keyring [#13756](https://github.com/apache/apisix/pull/13756) +- refactor: decouple generic data encryption from `ssl.lua` [#13564](https://github.com/apache/apisix/pull/13564) +- perf(plugin): reuse the filtered global-rule plugin set across phases [#13779](https://github.com/apache/apisix/pull/13779) +- fix: keep the chash ring stable during health changes [#13532](https://github.com/apache/apisix/pull/13532) +- fix(balancer): keep least_conn load state across upstream scaling [#13666](https://github.com/apache/apisix/pull/13666) +- fix(balancer): separate the keepalive pool by referenced client cert [#13587](https://github.com/apache/apisix/pull/13587) +- fix(healthcheck): reuse the checker on node-only upstream changes instead of destroy-and-rebuild [#13629](https://github.com/apache/apisix/pull/13629) +- fix(healthcheck): probe domain nodes by the node domain, not the resolved IP [#13743](https://github.com/apache/apisix/pull/13743) +- fix(healthcheck): purge stale targets and release the periodic lock [#13627](https://github.com/apache/apisix/pull/13627) +- fix(healthcheck): guard `construct_upstream` in healthcheck timers [#13592](https://github.com/apache/apisix/pull/13592) +- fix(stream): initialize env and secret for TLS cert resolution [#12935](https://github.com/apache/apisix/pull/12935) +- fix: fetch secrets from the upstream ssl config [#13062](https://github.com/apache/apisix/pull/13062) +- fix: invalidate the secret LRU cache on `/secrets` changes [#13668](https://github.com/apache/apisix/pull/13668) +- fix(secret): log an error when a secret reference cannot be resolved [#13737](https://github.com/apache/apisix/pull/13737) +- fix: reject consumer auth when a secret reference fails to resolve [#13667](https://github.com/apache/apisix/pull/13667) +- fix: encode control characters in `$upstream_uri` to prevent CRLF injection [#13787](https://github.com/apache/apisix/pull/13787) +- fix: reset `X-Forwarded-For` only for untrusted sources under `trusted_addresses` [#13611](https://github.com/apache/apisix/pull/13611) +- fix: normalize the case of hosts carried on a service [#13781](https://github.com/apache/apisix/pull/13781) +- fix(plugin): preserve plugin-conf state across the consumer route merge [#13757](https://github.com/apache/apisix/pull/13757) +- fix(resource): support all plugin-bearing resource types in `fetch_latest_conf` [#13663](https://github.com/apache/apisix/pull/13663) +- fix(config_etcd): keep the previous value when a full reload gets invalid data [#13717](https://github.com/apache/apisix/pull/13717) +- fix(etcd): do not advance the watch revision on a timeout, and make the recovery reload cheap [#13721](https://github.com/apache/apisix/pull/13721) +- fix(json): make cjson instances inherit APISIX's cjson options [#13680](https://github.com/apache/apisix/pull/13680) +- fix(env): resolve the `os.getenv` prefix collision for `env` directives [#13595](https://github.com/apache/apisix/pull/13595) +- fix(cli): remove the stale key after resolving an env var in config keys [#12885](https://github.com/apache/apisix/pull/12885) +- fix(cli): quote `nginx_config.envs` entries so values with spaces work [#13713](https://github.com/apache/apisix/pull/13713) +- fix(admin): harden stream_route `superior_id` dependency checks [#13672](https://github.com/apache/apisix/pull/13672) +- fix(admin): encrypt only after successful validation [#13729](https://github.com/apache/apisix/pull/13729) +- fix(admin): encrypt the inline upstream client key of a stream route [#13833](https://github.com/apache/apisix/pull/13833) +- fix(admin): reconcile the plugins reload instead of trusting the broadcast [#13714](https://github.com/apache/apisix/pull/13714) +- fix(control): reconcile `/v1/plugins/reload` like the admin reload path [#13745](https://github.com/apache/apisix/pull/13745) +- fix(log-sanitize): return raw tables to avoid double `delay_encode` [#13605](https://github.com/apache/apisix/pull/13605) +- fix(dns): correct the `error()` call in dns client initialization [#13358](https://github.com/apache/apisix/pull/13358) +- fix: avoid 503 error after dns service temporary fail [#13137](https://github.com/apache/apisix/pull/13137) +- fix(cli): add IPv6 listen support for the PROXY protocol [#12859](https://github.com/apache/apisix/pull/12859) +- fix(upstream): use `cert` and `key` instead of stale `ok` in mTLS error checks [#13442](https://github.com/apache/apisix/pull/13442) +- fix(core.request): `set_header` must update the cached headers with a normalized key [#13517](https://github.com/apache/apisix/pull/13517) +- fix(admin): `encrypt_fields` get double-encrypted on every PATCH [#13525](https://github.com/apache/apisix/pull/13525) +- fix(plugin): ignore `plugin_metadata` of disabled or unknown plugins [#13514](https://github.com/apache/apisix/pull/13514) +- fix(xrpc): stream routes with xRPC protocols fail `check_schema` in HTTP workers when the Admin API is disabled [#13515](https://github.com/apache/apisix/pull/13515) +- fix(secret): aws secret manager fails when the secret name contains a slash [#13519](https://github.com/apache/apisix/pull/13519) +- fix(consul): one invalid node should not discard the remaining nodes of the service [#13513](https://github.com/apache/apisix/pull/13513) +- fix(nacos): declare the `nacos-stream` shared dict in the stream subsystem [#13541](https://github.com/apache/apisix/pull/13541) +- fix: redis connections with different database/credentials must not share a keepalive pool [#13516](https://github.com/apache/apisix/pull/13516) + +### Plugins + +- feat: add ai-cache plugin [#13578](https://github.com/apache/apisix/pull/13578) +- feat(ai-cache): add the semantic (L2) cache layer [#13632](https://github.com/apache/apisix/pull/13632) +- feat(ai-cache): add streaming support with format tagging [#13644](https://github.com/apache/apisix/pull/13644) +- feat: add ai-lakera-guard plugin [#13570](https://github.com/apache/apisix/pull/13570) +- feat(ai-lakera-guard): scan LLM responses (direction output/both, non-streaming and streaming) [#13606](https://github.com/apache/apisix/pull/13606) +- feat: add ldap-auth-advanced plugin [#13762](https://github.com/apache/apisix/pull/13762) +- feat(ai-proxy-multi): add the semantic load-balancing algorithm [#13676](https://github.com/apache/apisix/pull/13676) +- feat(ai-proxy): include AI observability vars in `llm_summary` [#13609](https://github.com/apache/apisix/pull/13609) +- feat(ai-rate-limiting): support the redis policy for shared counters [#13670](https://github.com/apache/apisix/pull/13670) +- feat(ai-aws-content-moderation): moderate LLM responses, including streams [#13735](https://github.com/apache/apisix/pull/13735) +- feat(ai-aws-content-moderation): add `request_check_roles` and `request_check_mode` [#13773](https://github.com/apache/apisix/pull/13773) +- feat(ai-aliyun-content-moderation): moderate system and tool role content [#13646](https://github.com/apache/apisix/pull/13646) +- feat(prometheus): add metrics for AI cache hits, misses, bypasses, and embedding latency [#13659](https://github.com/apache/apisix/pull/13659) +- feat(prometheus): stream active connections, termination status and bandwidth [#13796](https://github.com/apache/apisix/pull/13796) +- feat: add `log_format_extra` to enrich the default logger format [#13568](https://github.com/apache/apisix/pull/13568) +- feat(kafka-logger): add TLS support for Kafka brokers [#13607](https://github.com/apache/apisix/pull/13607) +- feat(elasticsearch-logger): encrypt the `headers` field at rest [#13612](https://github.com/apache/apisix/pull/13612) +- feat: encrypt `redis_password` and `sentinel_password` in limit-count, limit-req and limit-conn [#13624](https://github.com/apache/apisix/pull/13624) +- feat(proxy-rewrite): support multiple same-name headers in `headers.add`/`headers.set` [#13597](https://github.com/apache/apisix/pull/13597) +- feat(openid-connect): add the `set_raw_id_token_header` option [#13616](https://github.com/apache/apisix/pull/13616) +- feat(openid-connect): support PAR and DPoP client options [#13649](https://github.com/apache/apisix/pull/13649) +- feat(ldap-auth): add `hide_credentials` [#13832](https://github.com/apache/apisix/pull/13832) +- refactor(ai-providers): make the LLM request client ctx-free [#13699](https://github.com/apache/apisix/pull/13699) +- refactor(cas-auth): drop the unnecessary raw Cookie header fallback [#13635](https://github.com/apache/apisix/pull/13635) +- perf(zipkin): skip span tag construction for unsampled requests [#13656](https://github.com/apache/apisix/pull/13656) +- perf(datadog): reuse one UDP socket per batch and coalesce metrics [#13653](https://github.com/apache/apisix/pull/13653) +- perf(loggly): hoist the per-request closure out of the log phase [#13648](https://github.com/apache/apisix/pull/13648) Review Comment: Agreed, it is `fix(loggly)` now in 9bce154a4. Confirmed the mechanism: `handle_http_payload` was a module-level local assigned inside `_M.log` on every request, while `handle_log` resolved it at flush time, so a batch queued for one route could be sent with another route's token, tags and endpoint. The reduced per-request allocation is described as the secondary benefit. ########## CHANGELOG.md: ########## @@ -85,6 +86,183 @@ title: Changelog - [0.7.0](#070) - [0.6.0](#060) +## 3.18.0 + +**The changes marked with :warning: are not backward compatible.** + +### Change + +- :warning: change(debug): report executed plugins with phase in execution order. The `Apisix-Plugins` debug header now carries `name#phase` entries in execution order instead of a de-duplicated plugin-name list [#13710](https://github.com/apache/apisix/pull/13710) +- :warning: feat: bound request and response body buffering in plugins. `max_req_body_size` / `max_resp_body_size` (default 64 MiB) added to ~19 plugins; larger bodies are now rejected or truncated instead of being buffered without limit [#13705](https://github.com/apache/apisix/pull/13705) +- :warning: fix(batch-processor): bound the pending entries backlog by default. Every batch-processor logger now defaults `max_pending_entries` to 8192 and discards entries above it [#13826](https://github.com/apache/apisix/pull/13826) +- :warning: refactor(ai-aws-content-moderation): moderate decoded LLM content in the access phase. Priority moved from 1050 to 1031, the plugin now requires ai-proxy/ai-proxy-multi, moderates the extracted prompt instead of the raw body, and denies with `deny_code` (default 200) instead of 400 [#13647](https://github.com/apache/apisix/pull/13647) +- :warning: feat(ai-aliyun-content-moderation): role-aware `request_check_mode` and O(n) content chunking. Request moderation now covers the user role of the latest turn by default instead of every message in the body [#13598](https://github.com/apache/apisix/pull/13598) +- :warning: fix(sls-logger): verify the TLS certificate of the log server. New `ssl_verify` option, default `true` [#13785](https://github.com/apache/apisix/pull/13785) +- :warning: fix(openid-connect): enforce audience, issuer and required scopes. Bearer introspection fails closed when the discovery document is unavailable, `claim_validator.audience.match_with_client_id` now implies `required`, and `required_scopes` is enforced on session (authorization code) flows [#13829](https://github.com/apache/apisix/pull/13829) +- :warning: fix(admin): reject duplicate consumer authentication keys instead of silently accepting them [#13529](https://github.com/apache/apisix/pull/13529) +- :warning: perf(core): sanitize the `X-Forwarded-*` headers in the NGINX config. The `$var_x_forwarded_proto/host/port` variables are gone, and a trusted peer that sends no `X-Forwarded-Host`/`X-Forwarded-Port` now receives the APISIX-observed values instead of falling through to `$host`/`$server_port` [#13803](https://github.com/apache/apisix/pull/13803) + +### Core + +- feat: raise default sizes for non-evictable shared dicts: `prometheus-metrics` 15m/10m→128m, `nacos` 10m→64m, consul and kubernetes discovery `shared_size` 1m→64m, `tracing_buffer` 10m→32m [#13688](https://github.com/apache/apisix/pull/13688) +- chore(core): remove the dead `clean_handlers` mechanism. `core.config_util.add_clean_handler`, `cancel_clean_handler` and `fire_all_clean_handlers` no longer exist [#13761](https://github.com/apache/apisix/pull/13761) +- feat(ai-proxy): send LLM requests through `ngx_http_ffi_client`. New `plugin_attr.ai-proxy.http_client`, defaulting to the FFI client, which requires an APISIX-Runtime that ships `ngx_http_ffi_client` (set `lua-resty-http` to opt out) [#13778](https://github.com/apache/apisix/pull/13778) +- feat: support per-port PROXY protocol for stream TCP proxy [#13561](https://github.com/apache/apisix/pull/13561) +- feat(stream): support `set_real_ip_from` to trust an inbound PROXY protocol header [#13700](https://github.com/apache/apisix/pull/13700) +- feat(stream): support upstream client certificate (mTLS) in the L4 proxy [#13596](https://github.com/apache/apisix/pull/13596) +- feat(router): add `match_uri_encoded_slash` to keep `%2F` in path parameters [#13626](https://github.com/apache/apisix/pull/13626) +- feat: add `max_post_args_readable_size` to bound `post_arg.*` body reads [#13601](https://github.com/apache/apisix/pull/13601) +- feat: support `http_method` and `http_req_body` in active health checks [#13726](https://github.com/apache/apisix/pull/13726) +- feat(data_encryption): support AES-256 keys in the encryption keyring [#13756](https://github.com/apache/apisix/pull/13756) +- refactor: decouple generic data encryption from `ssl.lua` [#13564](https://github.com/apache/apisix/pull/13564) +- perf(plugin): reuse the filtered global-rule plugin set across phases [#13779](https://github.com/apache/apisix/pull/13779) +- fix: keep the chash ring stable during health changes [#13532](https://github.com/apache/apisix/pull/13532) +- fix(balancer): keep least_conn load state across upstream scaling [#13666](https://github.com/apache/apisix/pull/13666) +- fix(balancer): separate the keepalive pool by referenced client cert [#13587](https://github.com/apache/apisix/pull/13587) +- fix(healthcheck): reuse the checker on node-only upstream changes instead of destroy-and-rebuild [#13629](https://github.com/apache/apisix/pull/13629) +- fix(healthcheck): probe domain nodes by the node domain, not the resolved IP [#13743](https://github.com/apache/apisix/pull/13743) +- fix(healthcheck): purge stale targets and release the periodic lock [#13627](https://github.com/apache/apisix/pull/13627) +- fix(healthcheck): guard `construct_upstream` in healthcheck timers [#13592](https://github.com/apache/apisix/pull/13592) +- fix(stream): initialize env and secret for TLS cert resolution [#12935](https://github.com/apache/apisix/pull/12935) +- fix: fetch secrets from the upstream ssl config [#13062](https://github.com/apache/apisix/pull/13062) +- fix: invalidate the secret LRU cache on `/secrets` changes [#13668](https://github.com/apache/apisix/pull/13668) +- fix(secret): log an error when a secret reference cannot be resolved [#13737](https://github.com/apache/apisix/pull/13737) +- fix: reject consumer auth when a secret reference fails to resolve [#13667](https://github.com/apache/apisix/pull/13667) +- fix: encode control characters in `$upstream_uri` to prevent CRLF injection [#13787](https://github.com/apache/apisix/pull/13787) +- fix: reset `X-Forwarded-For` only for untrusted sources under `trusted_addresses` [#13611](https://github.com/apache/apisix/pull/13611) +- fix: normalize the case of hosts carried on a service [#13781](https://github.com/apache/apisix/pull/13781) +- fix(plugin): preserve plugin-conf state across the consumer route merge [#13757](https://github.com/apache/apisix/pull/13757) +- fix(resource): support all plugin-bearing resource types in `fetch_latest_conf` [#13663](https://github.com/apache/apisix/pull/13663) +- fix(config_etcd): keep the previous value when a full reload gets invalid data [#13717](https://github.com/apache/apisix/pull/13717) +- fix(etcd): do not advance the watch revision on a timeout, and make the recovery reload cheap [#13721](https://github.com/apache/apisix/pull/13721) +- fix(json): make cjson instances inherit APISIX's cjson options [#13680](https://github.com/apache/apisix/pull/13680) +- fix(env): resolve the `os.getenv` prefix collision for `env` directives [#13595](https://github.com/apache/apisix/pull/13595) +- fix(cli): remove the stale key after resolving an env var in config keys [#12885](https://github.com/apache/apisix/pull/12885) +- fix(cli): quote `nginx_config.envs` entries so values with spaces work [#13713](https://github.com/apache/apisix/pull/13713) +- fix(admin): harden stream_route `superior_id` dependency checks [#13672](https://github.com/apache/apisix/pull/13672) +- fix(admin): encrypt only after successful validation [#13729](https://github.com/apache/apisix/pull/13729) +- fix(admin): encrypt the inline upstream client key of a stream route [#13833](https://github.com/apache/apisix/pull/13833) +- fix(admin): reconcile the plugins reload instead of trusting the broadcast [#13714](https://github.com/apache/apisix/pull/13714) +- fix(control): reconcile `/v1/plugins/reload` like the admin reload path [#13745](https://github.com/apache/apisix/pull/13745) +- fix(log-sanitize): return raw tables to avoid double `delay_encode` [#13605](https://github.com/apache/apisix/pull/13605) +- fix(dns): correct the `error()` call in dns client initialization [#13358](https://github.com/apache/apisix/pull/13358) +- fix: avoid 503 error after dns service temporary fail [#13137](https://github.com/apache/apisix/pull/13137) +- fix(cli): add IPv6 listen support for the PROXY protocol [#12859](https://github.com/apache/apisix/pull/12859) +- fix(upstream): use `cert` and `key` instead of stale `ok` in mTLS error checks [#13442](https://github.com/apache/apisix/pull/13442) +- fix(core.request): `set_header` must update the cached headers with a normalized key [#13517](https://github.com/apache/apisix/pull/13517) +- fix(admin): `encrypt_fields` get double-encrypted on every PATCH [#13525](https://github.com/apache/apisix/pull/13525) +- fix(plugin): ignore `plugin_metadata` of disabled or unknown plugins [#13514](https://github.com/apache/apisix/pull/13514) +- fix(xrpc): stream routes with xRPC protocols fail `check_schema` in HTTP workers when the Admin API is disabled [#13515](https://github.com/apache/apisix/pull/13515) +- fix(secret): aws secret manager fails when the secret name contains a slash [#13519](https://github.com/apache/apisix/pull/13519) +- fix(consul): one invalid node should not discard the remaining nodes of the service [#13513](https://github.com/apache/apisix/pull/13513) +- fix(nacos): declare the `nacos-stream` shared dict in the stream subsystem [#13541](https://github.com/apache/apisix/pull/13541) +- fix: redis connections with different database/credentials must not share a keepalive pool [#13516](https://github.com/apache/apisix/pull/13516) + +### Plugins + +- feat: add ai-cache plugin [#13578](https://github.com/apache/apisix/pull/13578) +- feat(ai-cache): add the semantic (L2) cache layer [#13632](https://github.com/apache/apisix/pull/13632) +- feat(ai-cache): add streaming support with format tagging [#13644](https://github.com/apache/apisix/pull/13644) +- feat: add ai-lakera-guard plugin [#13570](https://github.com/apache/apisix/pull/13570) +- feat(ai-lakera-guard): scan LLM responses (direction output/both, non-streaming and streaming) [#13606](https://github.com/apache/apisix/pull/13606) +- feat: add ldap-auth-advanced plugin [#13762](https://github.com/apache/apisix/pull/13762) +- feat(ai-proxy-multi): add the semantic load-balancing algorithm [#13676](https://github.com/apache/apisix/pull/13676) +- feat(ai-proxy): include AI observability vars in `llm_summary` [#13609](https://github.com/apache/apisix/pull/13609) +- feat(ai-rate-limiting): support the redis policy for shared counters [#13670](https://github.com/apache/apisix/pull/13670) +- feat(ai-aws-content-moderation): moderate LLM responses, including streams [#13735](https://github.com/apache/apisix/pull/13735) +- feat(ai-aws-content-moderation): add `request_check_roles` and `request_check_mode` [#13773](https://github.com/apache/apisix/pull/13773) +- feat(ai-aliyun-content-moderation): moderate system and tool role content [#13646](https://github.com/apache/apisix/pull/13646) +- feat(prometheus): add metrics for AI cache hits, misses, bypasses, and embedding latency [#13659](https://github.com/apache/apisix/pull/13659) +- feat(prometheus): stream active connections, termination status and bandwidth [#13796](https://github.com/apache/apisix/pull/13796) +- feat: add `log_format_extra` to enrich the default logger format [#13568](https://github.com/apache/apisix/pull/13568) +- feat(kafka-logger): add TLS support for Kafka brokers [#13607](https://github.com/apache/apisix/pull/13607) +- feat(elasticsearch-logger): encrypt the `headers` field at rest [#13612](https://github.com/apache/apisix/pull/13612) +- feat: encrypt `redis_password` and `sentinel_password` in limit-count, limit-req and limit-conn [#13624](https://github.com/apache/apisix/pull/13624) +- feat(proxy-rewrite): support multiple same-name headers in `headers.add`/`headers.set` [#13597](https://github.com/apache/apisix/pull/13597) +- feat(openid-connect): add the `set_raw_id_token_header` option [#13616](https://github.com/apache/apisix/pull/13616) +- feat(openid-connect): support PAR and DPoP client options [#13649](https://github.com/apache/apisix/pull/13649) +- feat(ldap-auth): add `hide_credentials` [#13832](https://github.com/apache/apisix/pull/13832) +- refactor(ai-providers): make the LLM request client ctx-free [#13699](https://github.com/apache/apisix/pull/13699) +- refactor(cas-auth): drop the unnecessary raw Cookie header fallback [#13635](https://github.com/apache/apisix/pull/13635) +- perf(zipkin): skip span tag construction for unsampled requests [#13656](https://github.com/apache/apisix/pull/13656) +- perf(datadog): reuse one UDP socket per batch and coalesce metrics [#13653](https://github.com/apache/apisix/pull/13653) +- perf(loggly): hoist the per-request closure out of the log phase [#13648](https://github.com/apache/apisix/pull/13648) +- fix(ai-proxy): preserve the upstream 429/5xx error response body [#13565](https://github.com/apache/apisix/pull/13565) +- fix(ai-proxy): drop `tool_choice` without tools and stop hanging the Anthropic stream [#13583](https://github.com/apache/apisix/pull/13583) +- fix(ai-proxy): do not abort the Anthropic response on bad `tool_call` arguments [#13599](https://github.com/apache/apisix/pull/13599) +- fix(ai-proxy): correct the Anthropic Messages to OpenAI Chat request conversion [#13674](https://github.com/apache/apisix/pull/13674) +- fix(ai-proxy): report error-path latency vars in milliseconds [#13711](https://github.com/apache/apisix/pull/13711) +- fix(ai-proxy-multi): keep the client request body intact across fallback retries [#13793](https://github.com/apache/apisix/pull/13793) +- fix(ai-protocols): flatten structured message content in the protocol layer [#13634](https://github.com/apache/apisix/pull/13634) +- fix(ai-cache): preserve non-text content in the exact key and bypass L2 [#13654](https://github.com/apache/apisix/pull/13654) +- fix(ai-lakera-guard): update alert mode behavior with the `fail_open` option [#13622](https://github.com/apache/apisix/pull/13622) +- fix(ai-content-moderation): validate that `deny_code` is a valid HTTP status [#13692](https://github.com/apache/apisix/pull/13692) +- fix(ai-content-moderation): stop re-counting converted chunks in realtime batches [#13765](https://github.com/apache/apisix/pull/13765) +- fix(ai-content-moderation): moderate the OpenAI `developer` role [#13780](https://github.com/apache/apisix/pull/13780) +- fix(ai-aws-content-moderation): respect Comprehend's segment limits and reuse the client [#13767](https://github.com/apache/apisix/pull/13767) +- fix(ai-aliyun-content-moderation): return nil instead of `ngx.OK` in `lua_body_filter` [#13623](https://github.com/apache/apisix/pull/13623) +- fix(limit-count): make the sliding-window limiter check-and-increment atomic [#13574](https://github.com/apache/apisix/pull/13574) +- fix(limit-count): `commit()` must report the window-weighted remaining [#13704](https://github.com/apache/apisix/pull/13704) +- fix(limit-count): validate variable-resolved `count`/`time_window` bounds [#13573](https://github.com/apache/apisix/pull/13573) +- fix(limit-count): upgrade the redis-cluster library so NOSCRIPT is not treated as a node failure [#13579](https://github.com/apache/apisix/pull/13579) +- fix(limit-conn): isolate the counter per workflow action via the `_vid` key [#13591](https://github.com/apache/apisix/pull/13591) +- fix(limit-conn): use the parent resource key for consumer isolation [#13600](https://github.com/apache/apisix/pull/13600) +- fix(redis-schema): copy policy schemas instead of mutating shared tables [#13555](https://github.com/apache/apisix/pull/13555) +- fix(graphql-limit-count): measure each fragment once when computing query depth [#13809](https://github.com/apache/apisix/pull/13809) +- fix(key-auth): propagate the real auth error to the multi-auth orchestrator [#13693](https://github.com/apache/apisix/pull/13693) +- fix(basic-auth): validate `anonymous_consumer` against the schema [#13682](https://github.com/apache/apisix/pull/13682) +- fix(hmac-auth): pass ctx when hiding the Authorization header [#13820](https://github.com/apache/apisix/pull/13820) +- fix(ldap-auth): key the consumer lookup on the escaped bind DN [#13805](https://github.com/apache/apisix/pull/13805) Review Comment: Agreed, moved to Change in 9bce154a4 with the escaped-DN migration example. Scope note for upgraders: only usernames containing RFC 4514 structural characters change key, since the library escapes the RDN value and returns the canonical bind DN that the plugin now keys the consumer lookup on. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
