feat(modules): log who started a module operation - #1099
Conversation
Enabling or disabling a module over REST left no trace in system/messages, so answering "who turned this module off" meant digging through nginx/access.log. ModulesManagementProcessor now forwards the REST sessionContext into startModuleOperation() and writes one audit line right after the journal claim succeeds — rejected (409) attempts are not recorded as operations that ran. The line covers install and uninstall as well, since they share the same entry point. Context is JSON-encoded to keep crafted user names from forging fields, matching the pattern in WorkerCallEvents/DeleteCDR. Initiator resolution: JWT callers log their user name, raw API-Key callers log `api` plus the token id, localhost and internal calls log `system`. For a batch update the context is stored in the batch state, so every module enqueued by UpdateAllModulesAction keeps the attribution of the admin who started it. Uses LOG_WARNING deliberately: the logger threshold is core.logsLevel (4 by default) and a LOG_NOTICE line never reaches system/messages.
|
Уточнение по проверкам. Проверено на стенде 172.16.32.85 end-to-end: одиночные enable/disable через REST пишут строку с корректным инициатором ( Батч-путь ( |
|
Батч-путь подтверждён на стенде 172.16.32.85 — «Обновить все» из веб-интерфейса:
|
Включение и выключение модуля через REST не оставляло следа в
system/messages— «кто выключил модуль» приходилось восстанавливать поnginx/access.log. Добавлена одна строка аудита на операцию.Как устроено
ModulesManagementProcessor::callBack()читает$request['sessionContext'](штатный конверт, документирован вPBXCoreREST/CLAUDE.md) и прокидывает его вstartModuleOperation(). Строка пишется после успешного claim в журнале, поэтому отклонённые (409) попытки не выглядят как выполненные операции.Пример:
api+tokenId; localhost и внутренние вызовы —system.reasonлогируется для disable, чтобы отличатьDISABLED_BY_USERотDISABLED_BY_LICENSEи срабатывания crash-loop-вотчдога.reasonTextнамеренно не логируется — туда попадает текст исключения.UpdateAllModulesAction, сохраняет атрибуцию администратора, а не пишется какsystem.WorkerCallEvents/DeleteCDR.php.LOG_WARNING, а неLOG_NOTICE: порог логгера —core.logsLevel(по умолчанию 4), строка уровня NOTICE вsystem/messagesне попадает вовсе (проверено эмпирически).Побочный эффект: ту же строку получают install и uninstall — они идут через ту же точку входа. Это улучшение, но упоминаю явно, чтобы не выглядело расширением области.
Проверено на стенде 172.16.32.85
{"operation":"disable","module":"ModuleCdrTags","user":"system","ip":"local","reason":"DISABLED_BY_USER",...}{"operation":"enable","module":"ModuleCdrTags","user":"admin","ip":"127.0.0.1",...}updateAllвызван с новой сигнатурой (без реального обновления модулей) — TypeError нет; сам enqueue батча end-to-end не прогонялся, чтобы не тянуть пакеты на стенд.Что осталось непокрытым (осознанно)
useLegacyInstallPipeline()(аварийный переключатель на один релиз) минуютstartModuleOperation()и ничего не пишут. У enable/disable легаси-ветки нет.PbxExtensionUtils::forceDisableModule()(несовместимая версия, битыйmodule.json) логируется только при неудаче — это отдельный след, вне области REST-аудита.WorkerSafeScriptsCoreперед отключением, дублировать не стал.