bizprocdesigner 26.600.0: публикация схемы сверяет права с шаблоном, внешние ИИ-агенты получили REST v3

2 мин чтения Устаревших API: 1

Обновление безопасности

Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.

В bizprocdesigner 26.600.0 публикация схемы проверяет права по типу документа самого шаблона. До этого пользователь с правом создавать процессы для одного типа документа мог опубликовать схему поверх шаблона другого типа, а по ответу контроллера понять, существует ли шаблон с нужным ID. Вендор не упомянул в описании второе крупное изменение, выключенное по умолчанию подключение внешнего ИИ-агента (Claude Code, Codex или любого другого) к конкретному шаблону через REST v3 и временный вебхук.

Обновитесь, чтобы закрыть перезапись чужих шаблонов

Дыра была в publicateAction() и publicateDraftAction() контроллера Bitrix\BizprocDesigner\Infrastructure\Controller\Diagram. Права проверялись только по documentTypeSigned из запроса (метод prepareDiagramData), а templateId брался из того же JSON и с типом документа шаблона не сверялся. Разработчики Битрикса в комментариях к исправлению называют обе проблемы: «cross-type overwrite» и «existence/type oracle».

Теперь право CreateWorkflow проверяется по типу документа целевого шаблона, этим занимается новый приватный canWriteTemplate(). Несуществующий шаблон для пользователя без прав администратора выглядит так же, как чужой, причём и при публикации, и в getAction() (через getTemplateData()).

До обновления контроллер отдавал эти ошибки через getError() с кодом 0, и удалённый шаблон от чужого отличался только текстом сообщения. Теперь у них есть коды ACCESS_DENIED и TEMPLATE_NOT_FOUND, и по TEMPLATE_NOT_FOUND редактор показывает экран удалённого шаблона. Обычный пользователь этот код не получит, на несуществующий ID ему придёт ACCESS_DENIED. В getAction() и публикации ошибки доступа теперь идут через getCodedError(). Новые действия агента отдают их через getError() с кодом 0 и сообщают TEMPLATE_NOT_FOUND любому пользователю.

Если у вас есть свой контроллер или сервис, который меняет шаблон бизнес-процесса по ID из запроса, проверяйте права тем же способом, по типу документа из записи шаблона:

        <?php declare(strict_types=1);

namespace Vendor\Module\Application\Service;

use Bitrix\Bizproc\Workflow\Template\Entity\WorkflowTemplateTable;
use Bitrix\Main\Error;
use Bitrix\Main\Loader;
use Bitrix\Main\Result;

final class TemplateWriteGuard
{
    public function check(int $templateId, int $userId): Result
    {
        Loader::requireModule('bizproc');

        $template = WorkflowTemplateTable::getRow([
            'select' => ['MODULE_ID', 'ENTITY', 'DOCUMENT_TYPE'],
            'filter' => ['=ID' => $templateId],
        ]);

        // тип документа берём из записи шаблона, documentType из запроса здесь не участвует
        $allowed = $template !== null && \CBPDocument::canUserOperateDocumentType(
            \CBPCanUserOperateOperation::CreateWorkflow,
            $userId,
            [$template['MODULE_ID'], $template['ENTITY'], $template['DOCUMENT_TYPE']],
        );

        $result = new Result();
        if (!$allowed) {
            // один ответ на «нет шаблона» и «нет прав», чтобы перебор ID не выдавал чужие шаблоны
            $result->addError(new Error('Access denied', 'ACCESS_DENIED'));
        }

        return $result;
    }
}

    

Передавайте properties в ActionDictionaryEntryDto по имени

В конструктор Bitrix\BizprocDesigner\Infrastructure\Dto\Activity\Complex\ActionDictionaryEntryDto добавили ?string $group = null перед ?array $properties. Если вы передавали properties четвёртым позиционным аргументом, массив теперь уйдёт в $group и вызов упадёт с TypeError, потому что массив в ?string не проходит даже без strict_types. С именованными аргументами порядок параметров перестаёт иметь значение:

        <?php declare(strict_types=1);

use Bitrix\BizprocDesigner\Infrastructure\Dto\Activity\Complex\ActionDictionaryEntryDto;

$entry = new ActionDictionaryEntryDto(
    id: 'vendor_send_invoice',
    title: 'Отправить счёт',
    handlesDocument: true,
    properties: $properties,
);

    

Заберите все найденные элементы из _all

Фильтр в комплексной ноде (Internal\Command\Activity\Complex\ConvertRuleCommand) раньше регистрировал одно возвращаемое свойство <filterId>, и флаг Multiple у него копировался из свойства документа. Теперь свойств два. <filterId> всегда идёт с Multiple => false и подписью «— первый найденный», у нового <filterId>_all стоят Multiple => true и подпись «— все найденные». Там, где результат фильтра нужен списком, берите <filterId>_all.

В том же ConvertRuleCommand к порту теперь подключаются все rule-входы. Раньше подключался только первый, в коде так и было написано: /* temporary only first input activity */. Когда на порту несколько правил, inputNames[порт] становится массивом, когда одно, остаётся строкой. Код, который читает inputNames, должен понимать оба варианта.

Пройдитесь по остальным несовместимостям

Почти все они в пространствах Internal и Infrastructure. Если вы на них опирались:

  • У Diagram::getAction() удалён параметр ?string $editBlock вместе с веткой //todo: proto, которая подменяла граф дочерними активити выбранного блока. Шаблон компонента bizprocdesigner.editor больше не передаёт в приложение initEditBlock из $_GET['editBlock'].
  • Diagram::updateTemplateAction() при ошибке UpdateWorkflowTemplateCommand возвращает null и ошибки. Раньше он отдавал ->run()->getData() без проверки результата.
  • Internal\Entity\Block::toArray() отдаёт порты плоским списком через Bitrix\Bizproc\Activity\Dto\NodePorts::fromArray()->toArray(), группировки {input, output} больше нет.
  • AiAvailabilityService, DocumentFieldService и DocumentAccessService из lib/Internal/Integration/AiAssistant/Service/ стали final, DocumentAccessService ещё и readonly, а LastWorkflowService из final стал final readonly. У DocumentFieldService убран конструктор, семантический поиск создаётся лениво.
  • Internal\Integration\AiAssistant\Entity\Draft стал final, а с публичных свойств его конструктора сняли readonly, объект стал изменяемым. У Validator\SaveWorkflowValidator readonly переехал со свойств на класс, свойства по-прежнему только для чтения.

Остальные изменения сигнатур добавляют необязательные параметры в конец списка и старые вызовы не ломают. Например, у Activity::getNodeFilterMetadataAction() появился bool $includeRelatedEntityTypes = false для фильтрации по связям. Отдельно NodeCatalogItemDtoFactory::makeDefaultSettingsByType() из private static стал public static.

Не вызывайте InstallEvents() у bizprocdesigner

Из класса bizprocdesigner в install/index.php удалили собственные InstallEvents() и UnInstallEvents(), которые регистрировали pull OnGetDependentModule и main OnAfterRegisterModule. Обработчики теперь описаны в install/migrations/events.php, где к ним добавился rest OnRestServiceBuildDescription. InstallDB() и UnInstallDB() вызывают installMigrations() и uninstallMigrations($dropTables) с учётом savedata, прямой вызов \CAgent::RemoveModuleAgents('bizprocdesigner') из удаления модуля убрали.

Одноимённые методы остались у базового CModule, и они пустые. Скрипт, который чинил обработчики через CModule::CreateModuleObject('bizprocdesigner')->InstallEvents(), отработает без ошибок и ничего не зарегистрирует. Сверять и восстанавливать обработчики теперь нужно по списку из install/migrations/events.php, при установке его применяет CModule::installMigrations() из InstallDB().

Новых таблиц и полей нет. Остальное про установку:

  • install/migrations/agents.php регистрирует AgentTokenGardenerAgent::execute с интервалом 86400, isPeriod=false и execDelay=3600;
  • install/updater.php при обновлении регистрирует только обработчик rest OnRestServiceBuildDescription на \Bitrix\BizprocDesigner\RestService;
  • появился migration_config.json с installDirectoriesMapping для components, js и tools;
  • новые опции модуля: external_ai_agent_available (N), expression_builder_available (N) и agent_token_ttl (86400 секунд, значение не больше нуля сбрасывается на 86400).

Подключите к шаблону Claude Code или Codex

У шаблона в редакторе появилась кнопка подключения агента (shared/ui/connect-agent-button/). За ней стоят действия Diagram::connectAgentAction, revokeAgentAction, regenerateAgentAction и agentStatusAction с параметром int $templateId, из JS они вызываются как bizprocdesigner.v2.Diagram.*. Ответ connect и regenerate содержит connectUrl вида /rest/api/<user>/<token>/bizprocdesigner.agent.connect?templateId=… и готовые команды запуска commands.claude, commands.codex и commands.universal.

Дальше агент работает с REST v3 в scope bizprocdesigner. Контроллеры лежат в lib/Infrastructure/Rest/Controller/, методы такие:

  • bizprocdesigner.agent.connect отдаёт агенту инструкцию в markdown;
  • bizprocdesigner.catalog.list возвращает типы блоков или схему настроек блока с defaultValues пресета;
  • bizprocdesigner.document.fields возвращает поля документа, а если в Configuration задан semantic_search.url, ищет по ним семантически;
  • bizprocdesigner.template.list, .get и .validate читают шаблон и проверяют граф без сохранения;
  • bizprocdesigner.template.draft.push валидирует граф, сохраняет черновик и через pull отправляет его в открытый редактор.

Публикует шаблон пользователь сам, метода публикации у агента нет.

Токен агента выпускает AgentWebhookService. Это System-вебхук модуля rest, созданный через CreateSystemIncomingWebhookCommand, с атрибутами bizprocdesigner=Y, template_id и expire_at. Живёт он agent_token_ttl секунд, по умолчанию сутки. Перевыпуск идёт под блокировкой bizprocdesigner:agent_token:{user}:{template}, и новый токен создаётся раньше, чем отключаются старые. Раз в сутки AgentTokenGardenerAgent отключает просроченные токены, а отключённые токены удаляет совсем, когда с последнего использования или создания прошло больше 7 дней.

Токен привязан к одному шаблону, поэтому bizprocdesigner.template.list возвращает только его. Привязку AbstractAgentRestController::resolveAndAuthorize() проверяет до поиска шаблона, чтобы по разнице между 404 и 403 нельзя было узнать о чужих шаблонах. Граф от агента ограничен: AgentBlocksValidator::MAX_BLOCKS = 256, AgentConnectionsValidator::MAX_CONNECTIONS = 512. В комментариях это названо «DoS guard», потому что раскладка полиномиальна по числу блоков.

По комментариям в AgentTokenGuard.php и AbstractAgentRestController.php, цепочка авторизации REST кеширует валидность токена до суток, и отозванный или просроченный токен может пройти транспортную авторизацию. Поэтому AgentTokenGuard перечитывает токен через IncomingWebhookRepository на каждый вызов. Если ваш модуль отдаёт данные по вебхуку и вы рассчитываете, что его отключение сразу закроет доступ, проверяйте токен в контроллере так же.

Включается всё опцией external_ai_agent_available, по умолчанию N:

        <?php declare(strict_types=1);

use Bitrix\Main\Config\Option;

Option::set('bizprocdesigner', 'external_ai_agent_available', 'Y');
// срок жизни токена агента в секундах, 0 и меньше модуль заменит на 86400
Option::set('bizprocdesigner', 'agent_token_ttl', '3600');

    

Кроме опции, Feature::isExternalAiAgentAccessible() проверяет через ServiceLocator AiAgentsFeature и RegionAvailabilityService, а фильтр AiAvailabilityFilter у REST-методов требует модуль aiassistant и «реального» пользователя. В «Управлении сайтом» модуля aiassistant нет, значит, все REST-методы агента там ответят AccessDenied. При этом Diagram::authorizeAgentTemplate() в контроллере редактора наличие aiassistant не проверяет.

Сверьте правила комплексных нод с каталогом

ValidateSingleRuleCommand теперь сверяет тип конструкции и activityData.Type с каталогом ноды. Правило с недоступным блоком получит ошибку ERR-BLOCK-NOT-AVAILABLE, вторая базовая конструкция на ноду получит ERR-BASE-SETTINGS-DUPLICATE. Сам каталог допустимых блоков и действий отдаёт новый Complex::getCapabilityCatalogAction(ActivityData, array $documentType) в виде CapabilityCatalogResponseDto и AvailableBlocksDto.

Базовая конструкция — это новый ConstructionType::BASE_SETTINGS ('base-settings') с Rule\BaseSettingsExpressionDto. Без actionId её свойства вливаются в саму ноду, и такая конструкция на ноду может быть только одна. С actionId она превращается в дочернюю активити. Ещё правила получили именованные группы (RuleDto::$groupTitle), а NodeCatalogItemDto знает про relationsAvailable и подложку (contentBlock, contentBlockProducer, contentBlockConsumer через Bitrix\Bizproc\Activity\ContentBlockResolver). SaveCommandHandler записывает в активити ключ ContentBlock. Каталог фильтрует группы через Bitrix\Bizproc\Public\Service\ActivityGroup\GroupVisibilityServiceInterface, если тот зарегистрирован в ServiceLocator.

В JS редактора появились таблицы данных ноды со слиянием двух источников по ключу и группировкой с итогами SUM/COUNT/AVG/MIN/MAX (features/data-view-editor/), конструктор выражений с функциями, калькулятором и модификаторами, текст и файлы в подложке. Таблицы данных читают опцию bizproc dataview_enabled, конструктор выражений закрыт expression_builder_available, и об обоих вендор не пишет. Включены ли функции, фронт проверяет через Feature.isAvailable() из расширения bizprocdesigner.feature с кодами dataTables, externalAiAgent и expressionBuilder. Новый Feature.isLocked() возвращает true только для externalAiAgent, когда опция включена, а тариф или регион агента не пускают.

Мелочи и находки

  • Команды для Claude Code и Codex лежат прямо в языковом файле lang/ru/lib/Infrastructure/Controller/Diagram.php. Команда для Claude начинается с claude "Выполни в терминале: curl -s '#URL#'… и запрещает агенту встроенный WebFetch, потому что «запрос должен идти с твоей машины». Команда для Codex даже в русском файле написана по-английски.
  • Инструкция из bizprocdesigner.agent.connect — это фраза BIZPROCDESIGNER_AGENT_CONNECT_INSTRUCTION, промпт с форматом графа, портами oN/iN, замыканием циклов ForEach/While и порядком работы get → validate → draft.push. Отдельно агента предупреждают, что validate и draft.push полностью заменяют граф. Английской версии фразы в релизе нет, build() в этом случае берёт 'ru'.
  • ActivityVisibilityFilter прячет от ИИ старые контейнеры: IfElseActivity, ParallelActivity, StateMachineWorkflowActivity, ListenActivity, EventDrivenActivity и ещё семь. По комментарию, конвертер не умеет разложить их на ноды с портами, и структура «молча потерялась бы».
  • Порт возврата цикла распознаётся по заголовку '->>' (BlockTypeDetail::LOOPBACK_PORT_TITLE). У ForEach это вход i1, у While маркер стоит на выходе.
  • LegacyAgentTokenMigratorAgent должен отключать «старые» User-токены со scope ровно [bizprocdesigner], которые выдавал «former AgentWebhookService». Но AgentWebhookService в bus появился только в этом релизе, а сам агент нигде не регистрируется, его нет ни в install/migrations/agents.php, ни в install/updater.php.
  • Контроллер Activity передаёт третий аргумент $includeRelatedEntityTypes в $className::getNodeFilterMetadata(), хотя в интерфейсе Bitrix\Bizproc\Public\Activity\Interface\NodeFilterMetadataProvider на этом коммите (bizproc 26.1200.0) параметров по-прежнему два.
  • Ссылка >>> OPEN NODE DESIGNER <<< в bizproc.workflow.edit теперь показывается для любого шаблона, раньше только для StateMachineWorkflowActivity. С константой Bitrix\Bizproc\Dev\ENV каталог получает группу dev с захардкоженным заголовком 'В разработке'.
  • В комментариях встречаются ссылки на внутренние спецификации «DTO-01…DTO-04» и «ADR invariant». Докблок lib/Internal/Entity/AgentPortDefault.php написан по-русски, остальной код по-английски.
  • VERSION_DATE в install/version.php пошла назад. У 26.600.0 там 2026-07-02 10:14:00, у предыдущей 26.550.0 было 2026-08-07 09:34:35.

Что делать

  1. Обновите модуль, если схемы в редакторе публикуют пользователи без прав администратора.
  2. Если ваш код разбирает ошибки контроллера Diagram по тексту, переведите его на коды ACCESS_DENIED и TEMPLATE_NOT_FOUND и учтите, что обычный пользователь TEMPLATE_NOT_FOUND не получает.
  3. Найдите new ActionDictionaryEntryDto( и переведите вызовы на именованные аргументы.
  4. Проверьте схемы, где результат фильтра комплексной ноды используется как список, и переключите их на <filterId>_all.
  5. Уберите вызовы InstallEvents() у модуля bizprocdesigner из своих скриптов восстановления и сверяйте обработчики по install/migrations/events.php.

Устаревшие и удалённые API в этой версии

Символ Статус Чем заменять
Bitrix\BizprocDesigner\Infrastructure\Controller\Diagram::getAction($editBlock) Удалено Bitrix\BizprocDesigner\Infrastructure\Controller\Diagram::getAction()

Читайте дальше

bizprocdesigner 26.550.0: кода нет, переводы догнали выборку CRM из 26.500.0

В релизе сменился только номер версии в `version.php` и приехали языковые файлы de/en/kz. Логика PHP и JS не менялась, API, схема БД и deprecated-пометки на месте, обновляться можно не глядя. По коду в эталоне, выборка элементов CRM по фильтру, секция «Name and description» в настройках ноды и заглу...

2 мин

bizprocdesigner 26.500.0: фильтр ноды приехал выключенным

Крупный UI-релиз редактора схем плюс новый тип конструкции — фильтр ноды. Ломающих изменений нет: все правки контроллера и DTO совместимы со старыми вызовами. Главное, что стоит знать заранее: фича спрятана за опцией и по умолчанию выключена.

3 мин
voximplant 26.800.0 Ломающее Свежее

Voximplant 26.800.0: attachRecord и finish отказывают локальным адресам, searchCrmEntities отдаёт один лид

В voximplant 26.800.0 у четырёх REST-методов внешней телефонии поменялось поведение, хотя сигнатуры остались прежними. `telephony.externalCall.attachRecord` и `telephony.externalCall.finish` с `RECORD_URL` больше не скачивают записи с приватных адресов и не ходят через прокси. `searchCrmEntities` от...

4 мин
timeman 26.100.0 Ломающее Свежее

Timeman 26.100.0: время считается по IANA-зоне сотрудника, у CTimeManEntry и REST другие значения

С timeman 26.100.0 учёт рабочего времени берёт зону сотрудника из IANA-идентификатора в `b_user.TIME_ZONE` и считает смещение UTC на момент каждого события, с переходами на летнее и зимнее время. Форматы полей и ответов остались прежними, поменялись значения: `TIME_START`, `TIME_FINISH` и `DURATION`...

3 мин
Мы используем файлы cookie для улучшения работы сайта. Продолжая использовать сайт, вы соглашаетесь с нашей политикой конфиденциальности.
AI Домовой

AI Домовой История

на связи

пишет…
Нет истории чатов
AI Домовой

Нужна авторизация

Войдите, чтобы задавать вопросы AI Домовому.

Войти