The Lua settings preprocessing was removing groups_disabled, groups_enabled,
symbols_disabled, and symbols_enabled fields from settings objects after
converting them to individual symbol lists. However, the C++ runtime code
(rspamd_symcache_process_settings) also needs these fields to mark symbols
as enabled/disabled in the runtime state.
Background:
- June 2019: Lua preprocessing added, removed fields to 'avoid clash'
- April 2022: C++ runtime process_settings() added, which reads these fields
- The two mechanisms were never properly synchronized
How settings work:
1. Lua preprocessing (at config load): Converts groups_* to symbol lists,
registers via rspamd_config:register_settings_id(), creates settings_elt
with allowed/forbidden symbol IDs for enforcement
2. C++ runtime (when settings applied): Reads task->settings UCL object,
processes groups_*/symbols_* fields to mark symbols as finished/not_started
in the runtime state for optimization
The issue:
When settings are applied via task:set_settings(cached.settings.apply),
the Lua table is converted to UCL and stored in task->settings. If the
groups_* fields were removed by preprocessing, process_settings() cannot
find them, so symbols don't get marked as disabled in runtime state.
The fix:
Don't remove these fields. Both mechanisms work complementarily:
- Settings element: Enforcement (checks allowed/forbidden IDs per symbol)
- Runtime processing: Optimization (marks symbols as finished to skip them)
This is safe because:
- The preprocessing still builds correct allowed/forbidden symbol lists
- The runtime processing reads the same fields and applies them correctly
- No conflict occurs - they work on different aspects (enforcement vs state)
Note: This affects settings IDs (static settings), not dynamic settings
applied directly via Settings={} header, which never went through the
removal step.
rspamd_config:register_settings_id(set.name, enabled_symbols, disabled_symbols)
- -- Remove to avoid clash
- s.symbols_disabled = nil
- s.symbols_enabled = nil
- s.groups_enabled = nil
- s.groups_disabled = nil
+ -- Note: we do NOT remove groups_*/symbols_* here anymore, as the C++ runtime
+ -- needs them for processing settings when they are applied to tasks.
+ -- The preprocessing above builds the allowed/forbidden symbol lists for the
+ -- settings element, but the runtime also needs to mark symbols as disabled/enabled.
end
-- We now iterate over all symbols and check for allowed_ids/forbidden_ids