bizproc 26.1500.0–26.1700.0: закрыты дыры в правах, lib/ на PSR-4, задания выполняются пачкой
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
В БУС пришли три версии bizproc: 26.1500.0, 26.1600.0 и 26.1700.0. Каждая закрывает дыры в правах, последняя ещё и доступ к чужим файлам через задания, так что обновляйтесь. После обновления проверьте код, который подключает файлы модуля по путям, интеграции, которые передают в задания ID файлов, и доступ сотрудников к процессам инфоблоков. И решите, оставлять ли новый дизайнер, он теперь включён по умолчанию. Прошлый разбор модуля — bizproc 26.1450.0.
Новое
Выполняйте задания пачкой (26.1600.0)
Ajax-действие bizproc.task.doCollection применяет одно решение к нескольким заданиям. Оно принимает только POST и до 50 заданий за вызов. Задания выполняются по очереди без общей транзакции, по каждому приходит статус done, not_found, access_denied или error. На нём построено групповое действие «Выполнить задания» в bizproc.user.processes.
С 26.1700.0 значение файлового поля пачкой не передать. Задание, чьё файловое поле есть в общем запросе, получает ошибку TASK_FILE_FIELD_NOT_SHARED, остальные выполняются как обычно.
// taskRequest повторяет то, что отправляет кнопка задания.
// У «Утверждения документа» кнопки называются approve и nonapprove.
async function approveTasks(taskIds, comment)
{
const response = await BX.ajax.runAction('bizproc.task.doCollection', {
data: {
taskIds,
taskRequest: { approve: 'Y', fields: { task_comment: comment } },
},
});
const { results, doneCount } = response.data;
results
.filter((item) => item.status !== 'done')
.forEach((item) => console.warn(item.taskId, item.status, item.errors));
return doneCount;
}
approveTasks([101, 102, 103], 'Согласовано пачкой')
.then((doneCount) => console.log(`Выполнено: ${doneCount}`))
.catch((response) => console.error(response.errors)); // например, больше 50 заданий
Ходите во внешние API из процесса (26.1700.0)
Нода «Исходящий вебхук с ответом» (CBPOutgoingWebHookActivity) отправляет GET, POST, PUT, PATCH или DELETE и отдаёт следующим нодам ResponseBody, ResponseCode, ResponseHeaders, IsTransportError и ErrorMessage. Таймаут до 30 секунд, ответ до 1 МБ, редирект считается ошибкой. В каталоге нода появится после bizproc:outgoing_webhook_node_available=Y.
Запросы нода шлёт через Bitrix\Bizproc\Activity\Http\PublicAddressHttpClient, наследника Main\Web\HttpClient с защитой от SSRF. Он пускает только на публичные IPv4, отклоняет IPv6 и 100.64.0.0/10, а setPrivateIp() у него всегда ставит false. Дополнительные запрещённые диапазоны берутся из опции bizproc:outgoing_request_denied_ranges. Клиент пригодится своему действию или роботу, которому URL задаёт пользователь:
<?php declare(strict_types=1);
use Bitrix\Bizproc\Activity\Http\PublicAddressHttpClient;
use Bitrix\Main\Loader;
Loader::requireModule('bizproc');
function fetchExternalJson(string $url): ?array
{
$client = (new PublicAddressHttpClient(['redirect' => false, 'socketTimeout' => 5, 'streamTimeout' => 10]))
->setDeadline(15)
->setHeadersLengthMax(64 * 1024);
$body = $client->get($url);
if ($body === false) {
// PRIVATE_IP, DENIED_IP или обычная сетевая ошибка
AddMessage2Log(implode('; ', $client->getError()), 'bizproc');
return null;
}
$data = json_decode($body, true);
return is_array($data) ? $data : null;
}
Работайте над шаблоном вместе
Журнал изменений шаблона (26.1500.0) записывает, кто правил схему (человек, ИИ или система) и откуда пришла правка: из редактора, от Марты, от внешнего агента или от системы. Ленту отдаёт WorkflowTemplateHistoryService::getChangeEvents() с проверкой доступа. Записи хранятся 90 дней.
В 26.1600.0 появились заметки на схеме с упоминаниями через @ и блокировка редактирования шаблона на 10 минут (WorkflowTemplateLockService). С флагом useEditConflictGuard черновик сохраняется с проверкой ревизии, и если его успел изменить кто-то другой, сервис ответит DRAFT_REVISION_CONFLICT. Заметки и блокировка включаются опциями template_notes_available и template_edit_lock_available модуля bizprocdesigner, по умолчанию обе N.
В 26.1700.0 за опцией process_data_enabled появились «Данные процесса»: в шаблоне, созданном при включённой опции, стартовые параметры копируются в одноимённые переменные.
Триггер и API для своих действий
- Триггер «Сотрудник уволен» (
EmployeeDismissalTrigger, 26.1500.0) срабатывает по событиюintranet:onAfterUserFireи передаёт в процессuserId,firedAt,nameиlastName. BaseType\ValueRule(26.1500.0): ограниченияMin,MaxиMaxLengthв настройках поля под ключомValueRule. Целые и строки проверяют по ним значение из формы.CBPTrackingService::writeForced()(26.1700.0) пишет в журнал процесса в обход пропускаемых типов и без обрезки по размеру.BaseType\Date::internalizeValue()(26.1700.0) принимает['value' => '…', 'tz' => 'Europe/Moscow'], безtzберёт пояс текущего пользователя.CBPActivity(26.1500.0) получил точки расширения для внешних ИИ-агентов:getAiPassthroughSettingNames(),getAiRestrictedSettingNames()иgetAiEnforcedSettingValues()решают, что агент переносит как есть, что только копирует из опубликованного шаблона и что выставляет сам.
Что сломается
Проверьте пути и регистр классов (26.1500.0)
Каталог lib/ перевели на PSR-4: 260 файлов переименованы в CamelCase, например lib/basetype/inttype.php стал lib/BaseType/IntType.php. Классы и namespace прежние. Упадёт require по старому пути, а на регистрозависимой ФС ещё и обращение к классу с неверным регистром вроде Bitrix\Bizproc\Basetype\Inttype: файла в нижнем регистре, который загрузчик искал вторым, больше нет. Старые ajax-действия вида bizproc.task.do работают через карту контроллеров в autoload.php. Пути в своём коде найдёт grep:
grep -rn "modules/bizproc/lib/" local/ bitrix/php_interface/
Сверьте вызовы API
CBPWorkflowTemplateLoader::setShowInTimelineBeforeUpdate(array &$fields, ?string $templateType, int $id)(26.1500.0) получил обязательный$id. Наследник загрузчика со старой сигнатурой упадёт с фатальной ошибкой.Api\Service\WorkflowTemplateService::saveTemplate()иsaveTemplateDraft()(26.1500.0) пропускают только белый список полей и молча отбрасываютTYPE,SYSTEM_CODE,ACTIVE,CREATED_BYиUPDATED_BY.PROPERTY_VALUEвGlobalConstTableиGlobalVarTable(26.1700.0) десериализуется по белому списку: даты и время изBaseType\ValueиMain\Type,\DateTime,\DateTimeZone. Объекты других классов станут__PHP_Incomplete_Class.Public\Provider\TemplateAccessProvider::getEntityFilter()(26.1500.0) при опцииaccess_rights_own_templates=Yи праве «свои шаблоны» возвращаетConditionTreeпод ключомSCOPE_CONDITION_KEY. Его место вQuery::where(), в массивfilterон не ляжет. По умолчанию опция выключена. Код, готовый к обоим вариантам:
<?php declare(strict_types=1);
use Bitrix\Bizproc\Public\Provider\TemplateAccessProvider;
use Bitrix\Bizproc\Workflow\Template\Entity\WorkflowTemplateTable;
use Bitrix\Main\Engine\CurrentUser;
use Bitrix\Main\Loader;
Loader::requireModule('bizproc');
$filter = (new TemplateAccessProvider())->getEntityFilter((int)CurrentUser::get()->getId());
$scope = $filter[TemplateAccessProvider::SCOPE_CONDITION_KEY] ?? null;
unset($filter[TemplateAccessProvider::SCOPE_CONDITION_KEY]);
$query = WorkflowTemplateTable::query()
->setSelect(['ID', 'NAME'])
->setFilter($filter);
if ($scope !== null) {
$query->where($scope);
}
$templates = $query->fetchAll();
Решите, нужен ли новый дизайнер (26.1700.0)
Новый дизайнер БП включён по умолчанию. Опцию designer_v2 заменил флаг Bitrix\Bizproc\Public\Feature\Designer\DesignerV2Flag, а фоновая задача переписывает опцию под его значение. Где дизайнер не включали, он включится, и designer_v2 станет Y. Вернуть старое поведение можно так, синхронизация потом запишет N:
<?php declare(strict_types=1);
use Bitrix\Bizproc\Public\Feature\Designer\DesignerV2Flag;
use Bitrix\Main\Config\Feature;
use Bitrix\Main\Loader;
Loader::requireModule('bizproc');
Feature::disable(DesignerV2Flag::class);
Не подставляйте ID файлов в задания (26.1700.0)
Файловые поля «Запроса дополнительной информации» принимают только ID, который уже стоит в поле, пришёл из загрузчика этого поля или сохранён текущим запросом. Остальные ID молча отбрасываются. Интеграция, которая закрывает задание через bizproc.task.do или REST bizproc.task.complete с ID существующего файла, файл не прикрепит. В REST передавайте содержимое файла.
В карточке задания вместо <input type="file"> теперь виджет загрузки bizproc.task.file-field. Кастомные шаблоны карточки и JS, которые ищут file input, его не найдут.
Проверьте права, роботов и ноды
CBPVirtualDocument::canUserOperateDocumentType() (26.1600.0) для нестатусных процессов на виртуальных документах (bizproc.wizards, инфоблоки type_*) спрашивает права инфоблока. Раньше почти любая операция разрешалась всем, теперь сотрудники без прав на инфоблок потеряют доступ.
Нода нового дизайнера, у которой не нашёлся документ из контекста, пропускается с записью «Действие пропущено: не удалось определить документ» (26.1600.0). Раньше действие, включая удаление, выполнялось над документом процесса.
Автором изменений от роботов теперь пишется сотрудник, сменивший статус, а CBPSetFieldActivity при пустом ModifiedBy пишет запустившего процесс (26.1500.0). У Automation\Engine\Runtime::runDocumentStatus() и onDocumentStatusChanged() появился необязательный ?int $initiatorUserId, наследник со старой сигнатурой несовместим.
Что увидят пользователи
Список шаблонов bizproc.template.processes (26.1600.0) перешёл на фильтр bizproc_template_processes_filter_v2, сохранённые настройки фильтра пропадут. По умолчанию стоит новый пресет «Мои», и страница открывается только со своими шаблонами.
Описания шаблонов в списках запуска и в админке выводятся простым текстом, HTML не рендерится (26.1500.0). Скопированные шаблоны bizproc.wizards.start, bizproc.workflow.start и bizproc.template.processes этого не получат.
Что закрыто
- 26.1500.0: запуск смарт-скриптов без права на тип документа; XSS в описании шаблона в
bizproc.wizards.start; подменаTYPE,SYSTEM_CODEи авторства при сохранении шаблона; поиск хранилища по коду через LIKE, который мог попасть в чужое хранилище; копирование чужого ИИ-агента без права на редактирование. - 26.1600.0: удаление процесса в
bizproc.workflow.instancesбез прав администратора; выдача глобальных переменных и констант черезbizproc.globalfield.reloadбез прав; доступ к виртуальным документам и действия над чужим документом при битом контексте ноды. - 26.1700.0: файловые поля заданий принимали ID любого файла портала, загрузчик файлов заданий не проверял исполнителя,
unserializeглобальных констант ничем не ограничивался.
БД
b_bp_workflow_template_change(26.1500.0): колонкиAUTHOR_TYPE,AI_TOOL,INITIATOR_USER_ID,REQUEST_SOURCE,CHANGES,CHANGES_SUMMARYиHAS_SNAPSHOT. АгентTemplateChangeCleanupAgentраз в сутки удаляет записи старше 90 дней (template_change_retention_days), записи со снимком версии остаются.- 26.1600.0: колонка
b_bp_workflow_template_draft.REVISION, таблицыb_bp_workflow_template_lock,b_bp_workflow_template_noteиb_bp_workflow_template_note_message. Удаление шаблона чистит его блокировки и заметки. - 26.1700.0: таблица фрагментов схемы
b_bp_workflow_template_fragment, ORMWorkflow\Template\Fragment\Entity\TemplateFragmentTable.