Skip to content
This repository was archived by the owner on Apr 24, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions src/fairvisor/loop_detector.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,23 @@ local function _is_positive_integer(value)
return type(value) == "number" and value > 0 and floor(value) == value
end

local function _append_sorted_key_values(parts, values, scratch_keys)
if type(values) ~= "table" or next(values) == nil then
local function _append_sorted_key_values(parts, kv, scratch_keys)
if type(kv) ~= "table" or next(kv) == nil then
return
end

while #scratch_keys > 0 do
scratch_keys[#scratch_keys] = nil
for i = 1, #scratch_keys do
scratch_keys[i] = nil
end
for key in pairs(values) do

for key in pairs(kv) do
scratch_keys[#scratch_keys + 1] = key
end
table_sort(scratch_keys)

for i = 1, #scratch_keys do
local key = scratch_keys[i]
parts[#parts + 1] = tostring(key) .. "=" .. tostring(values[key])
parts[#parts + 1] = tostring(key) .. "=" .. tostring(kv[key])
end
end

Expand Down Expand Up @@ -110,9 +111,10 @@ function _M.validate_config(config)
end

function _M.build_fingerprint(method, path, query_params, body_hash, limit_key_values)
while #_parts > 0 do
_parts[#_parts] = nil
for i = 1, #_parts do
_parts[i] = nil
end

_parts[1] = tostring(method or "")
_parts[2] = tostring(path or "")

Expand Down
7 changes: 4 additions & 3 deletions src/fairvisor/rule_engine.lua
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,10 @@ end

local function _build_decision_from_loop(loop_result, policy_id)
local action = "reject"
if loop_result.allowed == true or loop_result.action == "warn" then
local loop_action = loop_result and loop_result.action
if loop_result.allowed == true or loop_action == "warn" then
action = "allow"
elseif loop_result.action == "throttle" then
elseif loop_action == "throttle" then
action = "throttle"
end

Expand Down Expand Up @@ -707,7 +708,7 @@ function _M.evaluate(request_context, bundle)
if loop_cfg and loop_cfg.enabled then
local fingerprint = _call(
_loop_detector.build_fingerprint,
"",
0,
request_context and request_context.method,
request_context and request_context.path,
request_context and request_context.query_params,
Expand Down
Loading