fix(config): lua 5.1 compatibility and multi-tenant validation

- Replace goto statements with if-not pattern for Lua 5.1 compatibility
- Validate mail config only for API keys with mail:send permissions
- Safe display of API key info for monitoring keys without mail config
- Fix health check SMTP detection for new config structure
- Multi-tenant system tested and working on port 7811

Fixes multi-tenant config parsing, validation, and health checks.
Related to DAW/furt#89
This commit is contained in:
michael 2025-08-28 19:53:30 +02:00
parent a5db9a633f
commit 8ec401930c
4 changed files with 75 additions and 49 deletions

View file

@ -1,6 +1,7 @@
-- src/config_parser.lua
-- nginx-style configuration parser for Multi-Tenant setup
-- Dragons@Work Digital Sovereignty Project
-- Lua 5.1 compatible (no goto statements)
local ConfigParser = {}
@ -26,53 +27,48 @@ function ConfigParser.parse_file(config_path)
-- Skip empty lines and comments
line = line:match("^%s*(.-)%s*$") -- trim whitespace
if line == "" or line:match("^#") then
goto continue
end
-- Section headers: [section] or [api_key "keyname"]
local section_match = line:match("^%[([^%]]+)%]$")
if section_match then
if section_match:match("^api_key") then
-- Extract API key from [api_key "keyname"]
local key_name = section_match:match('^api_key%s+"([^"]+)"$')
if not key_name then
error(string.format("Invalid api_key section at line %d: %s", line_number, line))
if not (line == "" or line:match("^#")) then
-- Section headers: [section] or [api_key "keyname"]
local section_match = line:match("^%[([^%]]+)%]$")
if section_match then
if section_match:match("^api_key") then
-- Extract API key from [api_key "keyname"]
local key_name = section_match:match('^api_key%s+"([^"]+)"$')
if not key_name then
error(string.format("Invalid api_key section at line %d: %s", line_number, line))
end
current_api_key = key_name
current_section = "api_key"
config.api_keys[key_name] = {}
else
current_section = section_match
current_api_key = nil
if not config[current_section] then
config[current_section] = {}
end
end
current_api_key = key_name
current_section = "api_key"
config.api_keys[key_name] = {}
else
current_section = section_match
current_api_key = nil
if not config[current_section] then
config[current_section] = {}
-- Key-value pairs: key = value
local key, value = line:match("^([^=]+)=(.+)$")
if key and value then
key = key:match("^%s*(.-)%s*$") -- trim
value = value:match("^%s*(.-)%s*$") -- trim
-- Remove quotes from value if present
value = value:match('^"(.*)"$') or value
if current_section == "api_key" and current_api_key then
ConfigParser.set_api_key_value(config.api_keys[current_api_key], key, value)
elseif current_section then
ConfigParser.set_config_value(config[current_section], key, value)
else
error(string.format("Key-value pair outside section at line %d: %s", line_number, line))
end
else
error(string.format("Invalid line format at line %d: %s", line_number, line))
end
end
goto continue
end
-- Key-value pairs: key = value
local key, value = line:match("^([^=]+)=(.+)$")
if key and value then
key = key:match("^%s*(.-)%s*$") -- trim
value = value:match("^%s*(.-)%s*$") -- trim
-- Remove quotes from value if present
value = value:match('^"(.*)"$') or value
if current_section == "api_key" and current_api_key then
ConfigParser.set_api_key_value(config.api_keys[current_api_key], key, value)
elseif current_section then
ConfigParser.set_config_value(config[current_section], key, value)
else
error(string.format("Key-value pair outside section at line %d: %s", line_number, line))
end
else
error(string.format("Invalid line format at line %d: %s", line_number, line))
end
::continue::
end
file:close()
@ -163,13 +159,25 @@ function ConfigParser.validate_config(config)
key_config.allowed_ips = {} -- no IP restrictions
end
-- Validate mail configuration
if not key_config.mail_to then
error("API key '" .. key_name .. "' missing mail_to")
-- Validate mail configuration only if API key has mail:send permission
local has_mail_permission = false
if key_config.permissions then
for _, perm in ipairs(key_config.permissions) do
if perm == "mail:send" or perm == "*" then
has_mail_permission = true
break
end
end
end
if not key_config.mail_from then
error("API key '" .. key_name .. "' missing mail_from")
if has_mail_permission then
if not key_config.mail_to then
error("API key '" .. key_name .. "' missing mail_to")
end
if not key_config.mail_from then
error("API key '" .. key_name .. "' missing mail_from")
end
end
end

View file

@ -285,7 +285,7 @@ server:add_route("GET", "/health", function(request, server)
timestamp = os.time(),
source = version_info.source,
features = {
smtp_configured = config.mail and config.mail.username ~= nil,
smtp_configured = config.smtp_default and config.smtp_default.host ~= nil,
auth_enabled = true,
rate_limiting = true,
merkwerk_integrated = version_info.source == "merkwerk"