Скрипт нейросети за ночь пометил 5 700 документов в рабочей базе 1С: где были двери и как их закрыть
Иван Недомолков · Dərc edilib:
Утром ко мне пришёл главбух: в 1С “появились” товары, которые не продаются и не выпускаются пять лет. Остатки сдвинулись на миллиардные суммы. На почте ждал вопрос, зачем я снял с проведения документы 2021-2022 годов.
Я ничего не снимал. Снимал скрипт, который написал Claude Code и который планировщик заданий Windows запускал каждый час под моей учётной записью. За ночь он пометил на удаление 5 700 документов перемещений, и когда я открыл журнал, он продолжал.
Эту историю я уже рассказал как есть, с эмоциями. Здесь другой разрез: где в цепочке были двери, через которые агент получил право писать в рабочую базу, и чем каждую закрыть. Двери у всех примерно одинаковые, поэтому разбор пригодится любому, кто пускает нейросеть к своей 1С.
Сначала масштаб: чего стоила одна ночь
| Что | Как было |
|---|---|
| Документов помечено на удаление | 5 700 за ночь, начиная с 2021 года |
| Остатки | сдвинулись на миллиардные суммы, товары пятилетней давности “вернулись” |
| Заказы | около 500 заказов с маркетплейсов и сайта на несуществующие товары по старым ценам, все в отмену |
| База | заблокирована до обеда, бухгалтерия и офис не работали |
| Соседние системы | кривые остатки уехали в WMS и мобильные приложения |
| Восстановление | база открыта после обеда, сверка и выравнивание остатков всю следующую ночь |
Отдельной строкой объяснения со службой безопасности, что это сбой системы, а не план разграбить компанию. К разбору подключились генеральный директор и всё руководство, в магазинах был хаос из-за остатков.
Контекст, без которого цифры не читаются. Основная база около 5 ТБ, около тысячи сеансов в день, больше 500 регламентных заданий. Вокруг неё другие базы на 1С и не только, связанные обменами, сервисами и брокерами сообщений. Доступ у разработчиков широкий, бюрократии почти нет. Поэтому одна ошибка в одной базе за ночь разошлась по всему контуру.
Цепочка: пять шагов, каждый выглядел разумно
Ни один шаг по отдельности не был безумием. Опасной оказалась их сумма.
| Шаг | Как выглядело | Что открылось на деле |
|---|---|---|
| 1. Временное задание на пару дней: создавать перемещения по другим условиям параллельно штатному регламентному | обычная разовая задача | второй источник документов в рабочей базе |
2. Скрипт пишет агент и ходит в базу через execute_code | быстро, проверено на ходу | агент получил запись в рабочую базу |
| 3. Два задания дали пару дублей, агент предложил помечать дубли на удаление, я согласился | мелкая уборка | скрипт получил право помечать чужие документы |
| 4. Попросили запускать каждый час, агент в режиме Bypass permission сам создал задание в планировщике | автоматизация за минуту | скрипт работает без человека, под моей учёткой |
| 5. Дубли определяются по документу-основанию | логичный признак | у перемещений основание либо внутренний заказ, либо пустое |
Пятый шаг и есть ошибка в коде. Пустая ссылка в основании стоит у тысяч перемещений. Для условия “одинаковое основание” все они оказались дублями друг друга, и скрипт начал последовательно помечать их, с 2021 года.
Как выглядит такая ошибка в запросе
Исходный скрипт я не показываю. Ниже схема той же логики на условных именах, чтобы ловушку было видно глазами:
// Схема ошибки: "дубли" ищутся по совпадению основания
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Док.Основание КАК Основание,
| КОЛИЧЕСТВО(Док.Ссылка) КАК Документов
|ИЗ
| Документ.ПеремещениеТоваров КАК Док
|ГДЕ
| НЕ Док.ПометкаУдаления
|СГРУППИРОВАТЬ ПО
| Док.Основание
|ИМЕЮЩИЕ
| КОЛИЧЕСТВО(Док.Ссылка) > 1";
// Все перемещения без основания попадают в одну группу
// с пустой ссылкой, и вся группа считается "дублями".
Минимальная защита в самом запросе: пустое основание в поиск дублей не берём.
|ГДЕ
| НЕ Док.ПометкаУдаления
| И Док.Основание <> ЗНАЧЕНИЕ(Документ.ВнутреннийЗаказ.ПустаяСсылка)
Только этого мало. Условие в запросе защищает от одной ошибки, а от следующей не защитит. Двери ниже закрывают целый класс.
Дверь 1. Агенту доступна запись в рабочую базу
Самая большая дверь, и закрывается она первой. После аварии все записи агентов в рабочие базы запрещены: им оставлен только метод чтения, отдельный execute_code_ro, и доработаны права доступа. Просьба “не пиши в рабочую базу” в файле памяти агента тоже добавлена, но это второй рубеж: инструкцию модель может не учесть, а метод без записи ей не обойти.
Как сделать чтение технически без записи, мы разбирали отдельно: исполнение кода агента в транзакции с гарантированным откатом и запрос нейросети с правами того пользователя, который спросил. Второй вариант собран в расширение, его описание на странице права спросившего для нейросети.
Дверь 2. Скрипт работает от имени человека
Скрипт ходил в базу под моей учёткой, поэтому утром вопрос пришёл ко мне, а журнал показывал меня. Разобраться помог журнал регистрации, который у нас лежит в ClickHouse: виновник нашёлся по логам быстро, и список пострадавших документов был виден сразу.
Вывод для себя такой: всё, что запускается без человека, должно быть видно в журнале отдельно от людей. Если журнал регистрации у вас большой и искать в нём больно, посмотрите, как мы разбираем журнал регистрации нейросетью: там же про то, как отдать модели снимок журнала, а не миллионы строк.
Дверь 3. Планировщик без ревизии
Задание на запуск каждый час агент создал сам, без вопросов, потому что работал в режиме Bypass permission. Таких заданий на рабочих машинах разработчика может накопиться много, и никто не помнит, что каждое делает.
После аварии я прошёл все планировщики на своих трёх ПК и удалил всё лишнее. Отдельный риск, который я заметил: если у подписки кончаются лимиты, агент может не дописать скрипт. А недописанный скрипт, поставленный в планировщик, будет запускаться с каждым срабатыванием.
Дверь 4. Массовая запись никого не будит
Скрипт работал всю ночь, и первым об этом узнал главный бухгалтер утром. Теперь настроены алерты в Telegram: если какая-то учётная запись за полчаса записала сотни документов или элементов справочников, я узнаю об этом сразу. Это та же идея, что у любого мониторинга: порог по скорости изменений вместо разбора последствий.
Дверь 5. Права шире, чем нужно
Права доступа после аварии тоже доработаны. При культуре “фул доступ на всё” любая ошибка любого скрипта, человеческого или машинного, имеет радиус всей базы и соседних систем. Сузить права до задачи дешевле, чем одна такая ночь.
Чек-лист перед тем, как пустить агента к рабочей базе
- Агенту доступен только метод чтения. Запись запрещена на стороне базы, не только инструкцией.
- Разовые скрипты с записью идут на копию. В рабочую базу их переносит человек и запускает сам.
- Условия отбора для массовых операций проверяются на пустые ссылки и пустые значения.
- Всё, что запускается по расписанию, работает под отдельной учёткой и видно в журнале.
- Режим, в котором агент действует без подтверждений, не включается для задач с доступом к рабочей базе.
- Планировщики на рабочих машинах проходят ревизию, временные задания удаляются по окончании.
- Есть алерт на массовую запись: N документов за M минут от одной учётки.
- Журнал регистрации позволяет за минуты найти, кто и что изменил.
Агенты при этом никуда не денутся. С ними разработка у меня ускорилась в разы, и писать всё руками я уже не вернусь. Вопрос только в том, где проходит граница между “агент подсказал” и “агент сделал сам в рабочей базе”.
Если вы подключаете нейросеть к своей 1С и хотите, чтобы граница чтения и записи стояла в коде, а не в договорённостях, это часть нашего обслуживания баз 1С. Начать можно с вопроса в WhatsApp, по описанию вашей схемы скажем, где у неё двери.