This is an automated email from the ASF dual-hosted git repository.
shreemaan-abhishek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new e1053faa7 fix(opa): apply send_headers_upstream for headers absent
from OPA response (#13433)
e1053faa7 is described below
commit e1053faa7c501bd9ba835f7fa6ab30be02d200f7
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Tue Jun 2 14:22:10 2026 +0800
fix(opa): apply send_headers_upstream for headers absent from OPA response
(#13433)
---
apisix/plugins/opa.lua | 14 ++++++---
t/plugin/opa3.t | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+), 5 deletions(-)
diff --git a/apisix/plugins/opa.lua b/apisix/plugins/opa.lua
index 0475529f0..790ef5f1a 100644
--- a/apisix/plugins/opa.lua
+++ b/apisix/plugins/opa.lua
@@ -137,13 +137,17 @@ function _M.access(conf, ctx)
end
return status_code, reason
- else if result.headers and conf.send_headers_upstream then
+ else if conf.send_headers_upstream then
+ local headers = result.headers or {}
+ -- set headers from the OPA response, clearing any client-supplied
+ -- values for configured headers not present in the OPA response
for _, name in ipairs(conf.send_headers_upstream) do
- local value = result.headers[name]
- if value then
- core.request.set_header(ctx, name, value)
- end
+ local value = headers[name]
+ -- if value is nil, the client header's value will be removed if
it exists
+ core.request.set_header(ctx, name, value)
end
+ -- discard cached request headers so downstream readers observe the
update
+ ctx.headers = nil
end
end
end
diff --git a/t/plugin/opa3.t b/t/plugin/opa3.t
new file mode 100644
index 000000000..17f348626
--- /dev/null
+++ b/t/plugin/opa3.t
@@ -0,0 +1,84 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ if (!defined $block->request) {
+ $block->set_value("request", "GET /t");
+ }
+});
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: setup route with send_headers_upstream
+--- config
+ location /t {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "plugins": {
+ "opa": {
+ "host": "http://127.0.0.1:8181",
+ "policy": "example",
+ "send_headers_upstream": ["X-Foo"]
+ },
+ "serverless-post-function": {
+ "phase": "access",
+ "functions": [
+ "return function(conf, ctx) local core =
require(\"apisix.core\"); core.response.exit(200, core.request.headers(ctx));
end"
+ ]
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/echo"
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.say(body)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 2: client-supplied send_headers_upstream entry is cleared when OPA
response omits it
+--- request
+GET /echo
+--- more_headers
+X-Foo: client-value
+--- error_code: 200
+--- response_body_unlike eval
+qr/x-foo/