Skip to content

Commit bc41d7d

Browse files
committed
feat(plugins) validate PRIORITY and VERSION metadata
1 parent 279d2c7 commit bc41d7d

File tree

21 files changed

+196
-45
lines changed

21 files changed

+196
-45
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,17 @@
101101

102102
- The PDK is no longer versioned
103103
[#8585](https://github.com/Kong/kong/pull/8585)
104+
- Plugins MUST now have a valid `PRIORITY` (integer) and `VERSION` ("x.y.z" format)
105+
field in their `handler.lua` file, otherwise the plugin will fail to load.
106+
[#8836](https://github.com/Kong/kong/pull/8836)
104107

105108
#### Plugins
106109

107110
- The HTTP-log plugin `headers` field now only takes a single string per header name,
108111
where it previously took an array of values
109112
[#6992](https://github.com/Kong/kong/pull/6992)
113+
- The pre-functions plugin changed priority from `+inf` to `1000000`.
114+
[#8836](https://github.com/Kong/kong/pull/8836)
110115

111116
### Deprecations
112117

kong/api/routes/kong.lua

+1-7
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,9 @@ return {
9393

9494
local available_plugins = {}
9595
for name in pairs(singletons.configuration.loaded_plugins) do
96-
local pr = kong.db.plugins.handlers[name].PRIORITY
97-
if pr ~= nil then
98-
if type(pr) ~= "number" or math.abs(pr) == math.huge then
99-
pr = tostring(pr)
100-
end
101-
end
10296
available_plugins[name] = {
10397
version = kong.db.plugins.handlers[name].VERSION,
104-
priority = pr,
98+
priority = kong.db.plugins.handlers[name].PRIORITY,
10599
}
106100
end
107101

kong/db/dao/plugins.lua

+64-19
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ local DAO = require "kong.db.dao"
44
local plugin_loader = require "kong.db.schema.plugin_loader"
55
local reports = require "kong.reports"
66
local plugin_servers = require "kong.runloop.plugin_servers"
7-
7+
local version = require "version"
88

99
local Plugins = {}
1010

@@ -126,31 +126,76 @@ local function implements(plugin, method)
126126
end
127127

128128

129-
local function load_plugin_handler(plugin)
130-
-- NOTE: no version _G.kong (nor PDK) in plugins main chunk
129+
local load_plugin_handler do
131130

132-
local plugin_handler = "kong.plugins." .. plugin .. ".handler"
133-
local ok, handler = utils.load_module_if_exists(plugin_handler)
134-
if not ok then
135-
ok, handler = plugin_servers.load_plugin(plugin)
136-
if type(handler) == "table" then
137-
handler._go = true
131+
local function valid_priority(prio)
132+
if type(prio) ~= "number" or
133+
prio == (0/0) or -- NaN
134+
math.abs(prio) == math.huge or
135+
math.floor(prio) ~= prio then
136+
return false
138137
end
138+
return true
139139
end
140140

141-
if not ok then
142-
return nil, plugin .. " plugin is enabled but not installed;\n" .. handler
143-
end
141+
-- Returns the cleaned version string, only x.y.z part
142+
local function valid_version(v)
143+
if type(v) ~= "string" then
144+
return false
145+
end
146+
local vparsed = version(v)
147+
if not vparsed or vparsed[4] ~= nil then
148+
return false
149+
end
144150

145-
if implements(handler, "response") and
146-
(implements(handler, "header_filter") or implements(handler, "body_filter"))
147-
then
148-
return nil, fmt(
149-
"Plugin %q can't be loaded because it implements both `response` " ..
150-
"and `header_filter` or `body_filter` methods.\n", plugin)
151+
return tostring(vparsed)
151152
end
152153

153-
return handler
154+
155+
function load_plugin_handler(plugin)
156+
-- NOTE: no version _G.kong (nor PDK) in plugins main chunk
157+
158+
local plugin_handler = "kong.plugins." .. plugin .. ".handler"
159+
local ok, handler = utils.load_module_if_exists(plugin_handler)
160+
if not ok then
161+
ok, handler = plugin_servers.load_plugin(plugin)
162+
if type(handler) == "table" then
163+
handler._go = true
164+
end
165+
end
166+
167+
if not ok then
168+
return nil, plugin .. " plugin is enabled but not installed;\n" .. handler
169+
end
170+
171+
if type(handler) == "table" then
172+
173+
if not valid_priority(handler.PRIORITY) then
174+
return nil, fmt(
175+
"Plugin %q cannot be loaded because its PRIORITY field is not " ..
176+
"a valid integer number, got: %q.\n", plugin, tostring(handler.PRIORITY))
177+
end
178+
179+
local v = valid_version(handler.VERSION)
180+
if v then
181+
handler.VERSION = v -- update to cleaned version string
182+
else
183+
return nil, fmt(
184+
"Plugin %q cannot be loaded because its VERSION field does not " ..
185+
"follow the \"x.y.z\" format, got: %q.\n", plugin, tostring(handler.VERSION))
186+
end
187+
end
188+
189+
if implements(handler, "response") and
190+
(implements(handler, "header_filter") or implements(handler, "body_filter"))
191+
then
192+
return nil, fmt(
193+
"Plugin %q can't be loaded because it implements both `response` " ..
194+
"and `header_filter` or `body_filter` methods.\n", plugin)
195+
end
196+
197+
return handler
198+
end
154199
end
155200

156201

kong/plugins/pre-function/handler.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
return require("kong.plugins.pre-function._handler")(math.huge)
1+
return require("kong.plugins.pre-function._handler")(1000000)

spec/02-integration/03-db/03-plugins_spec.lua

+95-2
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ for _, strategy in helpers.each_strategy() do
193193
local ok, err = db.plugins:load_plugin_schemas({
194194
["plugin-with-custom-dao"] = true,
195195
})
196-
assert.truthy(ok)
197196
assert.is_nil(err)
197+
assert.truthy(ok)
198198

199199
assert.same("I was implemented for " .. strategy, db.custom_dao:custom_method())
200200
end)
@@ -215,12 +215,105 @@ for _, strategy in helpers.each_strategy() do
215215
assert.match("failed converting legacy schema for legacy-plugin-bad", err, 1, true)
216216
end)
217217

218+
describe("with bad PRIORITY fails; ", function()
219+
setup(function()
220+
local schema = {}
221+
package.loaded["kong.plugins.NaN_priority.schema"] = schema
222+
package.loaded["kong.plugins.NaN_priority.handler"] = { PRIORITY = 0/0, VERSION = "1.0" }
223+
package.loaded["kong.plugins.huge_negative.schema"] = schema
224+
package.loaded["kong.plugins.huge_negative.handler"] = { PRIORITY = -math.huge, VERSION = "1.0" }
225+
package.loaded["kong.plugins.string_priority.schema"] = schema
226+
package.loaded["kong.plugins.string_priority.handler"] = { PRIORITY = "abc", VERSION = "1.0" }
227+
end)
228+
229+
teardown(function()
230+
package.loaded["kong.plugins.NaN_priority.schema"] = nil
231+
package.loaded["kong.plugins.NaN_priority.handler"] = nil
232+
package.loaded["kong.plugins.huge_negative.schema"] = nil
233+
package.loaded["kong.plugins.huge_negative.handler"] = nil
234+
package.loaded["kong.plugins.string_priority.schema"] = nil
235+
package.loaded["kong.plugins.string_priority.handler"] = nil
236+
end)
237+
238+
it("NaN", function()
239+
local ok, err = db.plugins:load_plugin_schemas({
240+
["NaN_priority"] = true,
241+
})
242+
assert.falsy(ok)
243+
assert.match('Plugin "NaN_priority" cannot be loaded because its PRIORITY field is not a valid integer number, got: "nan"', err, 1, true)
244+
end)
245+
246+
it("-math.huge", function()
247+
local ok, err = db.plugins:load_plugin_schemas({
248+
["huge_negative"] = true,
249+
})
250+
assert.falsy(ok)
251+
assert.match('Plugin "huge_negative" cannot be loaded because its PRIORITY field is not a valid integer number, got: "-inf"', err, 1, true)
252+
end)
253+
254+
it("string", function()
255+
local ok, err = db.plugins:load_plugin_schemas({
256+
["string_priority"] = true,
257+
})
258+
assert.falsy(ok)
259+
assert.match('Plugin "string_priority" cannot be loaded because its PRIORITY field is not a valid integer number, got: "abc"', err, 1, true)
260+
end)
261+
262+
end)
263+
264+
describe("with bad VERSION fails; ", function()
265+
setup(function()
266+
local schema = {}
267+
package.loaded["kong.plugins.no_version.schema"] = schema
268+
package.loaded["kong.plugins.no_version.handler"] = { PRIORITY = 1000, VERSION = nil }
269+
package.loaded["kong.plugins.too_many.schema"] = schema
270+
package.loaded["kong.plugins.too_many.handler"] = { PRIORITY = 1000, VERSION = "1.0.0.0" }
271+
package.loaded["kong.plugins.number.schema"] = schema
272+
package.loaded["kong.plugins.number.handler"] = { PRIORITY = 1000, VERSION = 123 }
273+
end)
274+
275+
teardown(function()
276+
package.loaded["kong.plugins.no_version.schema"] = nil
277+
package.loaded["kong.plugins.no_version.handler"] = nil
278+
package.loaded["kong.plugins.too_many.schema"] = nil
279+
package.loaded["kong.plugins.too_many.handler"] = nil
280+
package.loaded["kong.plugins.number.schema"] = nil
281+
package.loaded["kong.plugins.number.handler"] = nil
282+
end)
283+
284+
it("without version", function()
285+
local ok, err = db.plugins:load_plugin_schemas({
286+
["no_version"] = true,
287+
})
288+
assert.falsy(ok)
289+
assert.match('Plugin "no_version" cannot be loaded because its VERSION field does not follow the "x.y.z" format, got: "nil"', err, 1, true)
290+
end)
291+
292+
it("too many components", function()
293+
local ok, err = db.plugins:load_plugin_schemas({
294+
["too_many"] = true,
295+
})
296+
assert.falsy(ok)
297+
assert.match('Plugin "too_many" cannot be loaded because its VERSION field does not follow the "x.y.z" format, got: "1.0.0.0"', err, 1, true)
298+
end)
299+
300+
it("number", function()
301+
local ok, err = db.plugins:load_plugin_schemas({
302+
["number"] = true,
303+
})
304+
assert.falsy(ok)
305+
assert.match('Plugin "number" cannot be loaded because its VERSION field does not follow the "x.y.z" format, got: "123"', err, 1, true)
306+
end)
307+
308+
end)
309+
310+
218311
it("succeeds with good plugins", function()
219312
local ok, err = db.plugins:load_plugin_schemas({
220313
["legacy-plugin-good"] = true,
221314
})
222-
assert.truthy(ok)
223315
assert.is_nil(err)
316+
assert.truthy(ok)
224317

225318
local foo = {
226319
required = false,
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
return {}
1+
return {
2+
PRIORITY = 1000,
3+
VERSION = "1.0",
4+
}

spec/fixtures/custom_plugins/kong/plugins/ctx-tests-response/handler.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ end
191191

192192

193193
local CtxTests = {
194-
PRIORITY = -math.huge
194+
PRIORITY = -1000000,
195+
VERSION = "1.0",
195196
}
196197

197198

spec/fixtures/custom_plugins/kong/plugins/ctx-tests/handler.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ end
199199

200200

201201
local CtxTests = {
202-
PRIORITY = -math.huge
202+
PRIORITY = -1000000,
203+
VERSION = "1.0",
203204
}
204205

205206

spec/fixtures/custom_plugins/kong/plugins/enable-buffering-response/handler.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ local kong = kong
33

44

55
local EnableBuffering = {
6-
PRIORITY = math.huge
6+
PRIORITY = 1000000,
7+
VERSION = "1.0",
78
}
89

910

spec/fixtures/custom_plugins/kong/plugins/enable-buffering/handler.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ local kong = kong
33

44

55
local EnableBuffering = {
6-
PRIORITY = math.huge
6+
PRIORITY = 1000000,
7+
VERSION = "1.0",
78
}
89

910

spec/fixtures/custom_plugins/kong/plugins/error-generator-last/handler.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ local error = error
44
local ErrorGeneratorLastHandler = {}
55

66

7-
ErrorGeneratorLastHandler.PRIORITY = -math.huge
8-
7+
ErrorGeneratorLastHandler.PRIORITY = -1000000
8+
ErrorGeneratorLastHandler.VERSION = "1.0"
99

1010
function ErrorGeneratorLastHandler:init_worker()
1111
end

spec/fixtures/custom_plugins/kong/plugins/error-generator/handler.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ local error = error
33

44
local ErrorGeneratorHandler = {
55
VERSION = "0.1-t",
6-
PRIORITY = math.huge,
6+
PRIORITY = 1000000,
77
}
88

99

@@ -60,4 +60,5 @@ function ErrorGeneratorHandler:log(conf)
6060
end
6161

6262

63+
6364
return ErrorGeneratorHandler

spec/fixtures/custom_plugins/kong/plugins/error-handler-log/handler.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ local ErrorHandlerLog = {}
66

77

88
ErrorHandlerLog.PRIORITY = 1000
9-
9+
ErrorHandlerLog.VERSION = "1.0"
1010

1111
local function register(phase)
1212
local ws_id = ngx.ctx.workspace or kong.default_workspace
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
return {
2-
PRIORITY = 1
2+
PRIORITY = 1,
3+
VERSION = "1.0",
34
}

spec/fixtures/custom_plugins/kong/plugins/init-worker-lua-error/handler.lua

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local InitWorkerLuaError = {}
22

33

44
InitWorkerLuaError.PRIORITY = 1000
5+
InitWorkerLuaError.VERSION = "1.0"
56

67

78
function InitWorkerLuaError:init_worker(conf)

spec/fixtures/custom_plugins/kong/plugins/invalidations/handler.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ local counts = {}
66

77

88
local Invalidations = {
9-
PRIORITY = 0
9+
PRIORITY = 0,
10+
VERSION = "1.0",
1011
}
1112

1213

spec/fixtures/custom_plugins/kong/plugins/reports-api/handler.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
local ReportsApiHandler = {
2-
PRIORITY = 1000
2+
PRIORITY = 1000,
3+
VERSION = "1.0",
34
}
45

56
function ReportsApiHandler:preread()

spec/fixtures/custom_plugins/kong/plugins/short-circuit/handler.lua

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ local init_worker_called = false
1111

1212
local ShortCircuitHandler = {
1313
VERSION = "0.1-t",
14-
PRIORITY = math.huge,
14+
PRIORITY = 1000000,
1515
}
1616

1717

@@ -45,5 +45,4 @@ function ShortCircuitHandler:preread(conf)
4545
return exit(conf.status)
4646
end
4747

48-
4948
return ShortCircuitHandler
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

22
return {
33
PRIORITY = 1000,
4+
VERSION = "1.0",
45
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
return {
2-
PRIORITY = 1
2+
PRIORITY = 1,
3+
VERSION = "1.0",
34
}

0 commit comments

Comments
 (0)