Безопасное тестирование MCP-инструментов с фиктивными учётными данными
Тестирование MCP-инструментов с фиктивными учётными данными и одноразовыми аккаунтами помогает проверить сценарии успеха, отказа, тайм-аута и очистки без риска для рабочей среды.

Безопасное тестирование MCP-инструментов требует большего, чем заменить рабочий токен строкой TEST_TOKEN. Инструмент может разобрать фиктивное значение, вернуть вежливое сообщение об успехе и всё равно впервые столкнуться с реальной границей прав, отказом в подтверждении, медленным провайдером или частично выполненной записью.
Тестовая среда должна одновременно доказывать две вещи: инструмент отправляет нужный запрос и не может создать реальное последствие в рабочей среде, если тест пойдёт не так. Одноразовые аккаунты и фиктивные учётные данные решают разные части этой задачи. Считайте их отдельными средствами контроля.
Фиктивные учётные данные проверяют разбор, а не полномочия
Фиктивные учётные данные доказывают только то, что инструмент правильно обрабатывает значение в нужном формате. Они не доказывают, что провайдер принимает эти данные, что у них есть нужные области доступа или что отозванное значение корректно отклоняется.
Разницу часто упускают, потому что все непроизводственные секреты называют фиктивными. На деле есть три разных варианта:
- Синтетическая строка существует только в локальной заглушке. Она нигде не может пройти аутентификацию.
- Тестовые учётные данные проходят аутентификацию у реального провайдера, но только внутри одноразового тенанта или проекта.
- Ограниченные рабочие учётные данные могут пройти аутентификацию в рабочей среде, даже если область доступа кажется небольшой.
Первый вариант подходит для модульных тестов и тестов контрактов. Второй, для интеграционных тестов. Третьему не место в автоматизированном наборе тестов агентов. Если учётные данные позволяют прочитать запись о рабочем клиенте, защищаемая граница уже нарушена.
Фиктивные значения должны напоминать формат, который реально получает ваш код. Если API-клиент отклоняет токены без префикса или минимальной длины, используйте синтетическое значение, проходящее локальную проверку. Не копируйте настоящий токен с изменением одного символа. Разработчики вставляют фикстуры в трекеры задач, вывод терминала и чаты. Почти настоящий секрет создаёт весь риск обращения с секретом, но не даёт пользы для тестирования.
Полезная фикстура называет полномочия, которых у неё нет. Например, stub_token_no_network говорит больше, чем token123. Ссылка на тестовые учётные данные вроде billing_test_writer показывает, что реальное значение получает агент не сам, а хранилище секретов. Сохраняйте ссылку неизменной и при необходимости меняйте лежащие за ней тестовые данные.
Не путайте успешный мок с авторизацией. Когда заглушка возвращает 200, она принимает любой контракт, который вы в неё заложили. Это полезное свидетельство о формировании собственного запроса, но оно ничего не говорит о модели областей доступа провайдера.
Разделяйте некорректный ввод, отказ и операционный сбой
Для неправильного аргумента, запрещённого действия и неисправной зависимости агенту нужны разные инструкции. Если MCP-инструмент превращает всё это в request failed, агент будет повторять действия, которые нужно остановить, и бросать действия, которые можно исправить.
Используйте небольшой набор категорий и сохраняйте его в результате инструмента. Я использую пять классов:
- Ошибка проверки: агент передал неправильный или неполный аргумент. Агент может исправить вызов.
- Ошибка аутентификации: учётные данные отсутствуют, просрочены, имеют неправильный формат или отозваны. Повтор того же вызова не поможет.
- Отказ в авторизации: личность прошла аутентификацию, но у неё нет права, либо человек отклонил подтверждение. Агент не должен искать обход границы.
- Конфликт: запрос корректен, но его нельзя применить к текущему состоянию ресурса. Сначала агенту может понадобиться получить актуальное состояние.
- Операционный сбой: тайм-аут, ошибка соединения, ограничение частоты или сбой провайдера. Повтор может иметь смысл, если действие безопасно повторять.
HTTP задаёт знакомые части этого разделения. RFC 9110 описывает 401 Unauthorized как запрос аутентификации, несмотря на исторически сбивающее с толку название, а 403 Forbidden, как отказ выполнить запрос. Провайдер может использовать эти коды неточно, поэтому проверяйте также тело ответа и документированные коды ошибок. Не стройте поведение агента только на коде статуса.
Результат инструмента Model Context Protocol поддерживает флаг isError вместе с содержимым. Используйте его, когда вызов инструмента завершился ошибкой, но помещайте практическую категорию в текст или структурированное содержимое, которое ожидает клиент. Ошибка транспортного уровня JSON-RPC и ошибка уровня инструмента тоже различаются. Оставляйте ошибки JSON-RPC для некорректных протокольных запросов или недоступных методов. Если инструмент выполнился, но внешнее действие завершилось ошибкой или было отклонено, возвращайте обычный результат tools/call с isError: true.
Такая форма ответа даёт агенту конкретные инструкции:
{
"jsonrpc": "2.0",
"id": 42,
"result": {
"content": [
{
"type": "text",
"text": "authorization_rejected: identity billing_test_writer cannot create invoices in tenant test-acme. Request a role change or stop."
}
],
"isError": true
}
}
Не включайте в этот результат bearer-токен, заголовок авторизации, полный исходящий запрос или необработанную ошибку провайдера. Сообщения об ошибках попадают в контекст агента, а значит, могут сохраняться в системах, которыми вы не управляете. Ошибка должна содержать достаточно сведений для выбора действия, но не превращаться в криминалистический дамп.
Для одноразовых аккаунтов нужна жёсткая граница
Одноразовый аккаунт безопасен только тогда, когда у него нет пути к рабочим ресурсам. Отдельный адрес электронной почты и метка test такую границу не создают.
Начните с самого сильного средства изоляции, которое предлагает провайдер. Это может быть отдельная организация, тенант, облачный проект, база данных или самостоятельный экземпляр. Поместите тестовый аккаунт внутрь этой единицы и проверьте, что он не может перейти в рабочую через идентификатор, общую роль или значение конфигурации по умолчанию.
Затем выдайте аккаунту права, необходимые для конкретного теста, и ничего больше. Если инструмент создаёт счета в тестах, тестовой личности нужны права создавать и просматривать тестовые счета. Ей не нужны права экспорта, доступ администратора или доступ к общей платёжной конфигурации. Широкие тестовые права популярны, потому что ускоряют настройку. Одновременно они скрывают, какие полномочия действительно нужны инструменту.
Используйте явную метку тестового запуска для каждого ресурса, который создаёт набор тестов. Помещайте её в поддерживаемое поле метаданных, описание, тег или имя. Метка делает очистку безопаснее и помогает узнавать оставшиеся тестовые артефакты. Не удаляйте всё, что случайно оказалось в тестовом тенанте. Другой разработчик может воспроизводить там ошибку.
Минимальная конфигурация может выглядеть так:
run_id: mcp-it-20250308-7f3c
account: [email protected]
allowed_tenant: test-acme
resource_prefix: mcp-it-20250308-7f3c-
cleanup_after_minutes: 90
Конфигурация предотвращает обычную, но дорогую ошибку: тестовый запуск обращается не к тому тенанту, потому что переменная окружения из оболочки разработчика имеет приоритет над проверенной конфигурацией. Перед созданием чего-либо код настройки должен получить текущую идентичность тенанта и сравнить её с allowed_tenant. Если значения различаются, остановитесь до первой записи.
Одноразовый не значит анонимный или бесхозный. Назначьте владельца, запишите способ выдачи учётных данных и задайте намеренный срок действия. Забытая тестовая личность всё равно остаётся личностью с доступом.
Стройте контракты вокруг наблюдаемых запросов
Хороший тест контракта проверяет запрос, который отправляет инструмент, результат, который он возвращает, и сведения, которые он отказывается раскрывать. Недостаточно проверить только факт вызова функции.
Поставьте локальную HTTP-заглушку перед клиентом и заставьте её проверять метод, путь, заголовки, параметры запроса и тело. Заглушка должна отклонять неожиданные поля. Снисходительные моки приучают инструмент отправлять случайные аргументы, пока реальный провайдер не отклонит их.
Для инструмента create_invoice сфокусированный тест может отправить такой вызов:
{
"jsonrpc": "2.0",
"id": 42,
"method": "tools/call",
"params": {
"name": "create_invoice",
"arguments": {
"tenant": "test-acme",
"customer_id": "cus_mcp_it_7f3c",
"amount_cents": 500,
"currency": "USD"
}
}
}
Заглушка должна ожидать POST /v1/invoices, проверять, что заголовок авторизации содержит синтетическое тестовое значение, и подтверждать наличие метки запуска в запросе. Она может вернуть фиксированный идентификатор вроде inv_mcp_it_001. Результат MCP должен раскрывать идентификатор и статус счета, но никогда не повторять заголовок авторизации.
Для каждого чувствительного поля запроса напишите хотя бы одно отрицательное утверждение контракта. Если схема может допустить поле authorization, base_url, account_id или tenant, переданное вызывающей стороной, отправьте его. Убедитесь, что инструмент отклоняет или игнорирует значения, способные перенаправить действие в другой аккаунт. Многие утечки учётных данных начинаются с безобидного на вид обходного пути для пользовательской конечной точки.
Проверяйте сериализацию запроса на уровне значимых байтов. Провайдер может различать пропущенные поля и null, пустые строки и отсутствующие значения, числа и числовые строки. Агент создаёт неожиданные формы аргументов, особенно когда описание инструмента не указывает единицы измерения. Если провайдер ожидает минимальные денежные единицы, схема должна говорить amount_cents, а не amount.
Тесты контрактов также подходят для проверки гигиены журналов. Перехватите структурированное событие журнала и убедитесь, что оно содержит ссылку на учётные данные или скрытую метку, но не сам синтетический секрет. Фиктивный секрет становится реальной проблемой раскрытия, когда разработчики привыкают печатать его повсюду.
Проверяйте права матрицей, а не только успешным сценарием
Одна разрешённая тестовая личность не показывает, правильно ли инструмент обрабатывает права. Нужны несколько личностей с намеренно различающимися правами и набор случаев с явно указанным ожидаемым результатом.
Держите матрицу достаточно небольшой, чтобы её можно было поддерживать. Для инструмента записи обычно полезны такие случаи:
| Состояние личности | Запрошенное действие | Ожидаемый результат |
|---|---|---|
| writer в тестовом тенанте | создать помеченную запись | успех |
| reader в тестовом тенанте | создать помеченную запись | отказ в авторизации |
| writer в другом тестовом тенанте | создать запись в целевом тенанте | отказ в авторизации |
| отозванные учётные данные | просмотреть помеченные записи | ошибка аутентификации |
| просроченные учётные данные | создать помеченную запись | ошибка аутентификации |
Эта матрица выявляет распространённый дефект: инструмент проверяет наличие токена, но не проверяет, какой тенант на самом деле представляет токен. Успешный сценарий проходит, потому что writer имеет широкие права. Ошибка появляется, когда агент получает идентификатор тенанта в задаче, а клиент принимает его, не связывая с выбранными учётными данными.
По возможности запускайте каждый случай матрицы против реального одноразового провайдера. Поведение провайдера в отношении унаследованных ролей, стандартных областей доступа и отложенного отзыва часто отличается от документации. Изолируйте случаи. Если один тест повышает роль, отсутствие которой ожидает другой, параллельные запуски создают ошибки, похожие на проблемы авторизации.
Не создавайте запрещённые ответы только в заглушке и не считайте набор завершённым. Заглушка подтверждает, что преобразователь ошибок распознаёт 403. Реальная тестовая личность подтверждает, что выдача учётных данных, настройка провайдера и маршрутизация инструмента действительно приводят к отказу.
Есть полезное исключение: ответы провайдера, которые нельзя надёжно вызвать, например некорректный JSON или неправильный тип содержимого. Такие случаи принадлежат заглушке. Важна не чистота подхода, а понимание того, какие сведения даёт каждый тест.
Для записей план очистки нужен до тестового кода
Для каждого инструмента, меняющего состояние, заранее решите, как тест удалит или нейтрализует это состояние. Если вы не можете описать очистку, выберите другую цель или операцию.
Отдавайте предпочтение операциям, создающим записи внутри короткоживущего тестового проекта. Избегайте тестовых вызовов, которые отправляют почту, списывают деньги с карты, меняют общий секрет, запускают развёртывание или связываются с реальной третьей стороной. Песочница провайдера всё ещё может отправлять webhook на endpoint, который вы настроили несколько лет назад. Проверяйте все сопутствующие эффекты, а не только название API.
Используйте уникальную метку запуска и выполняйте очистку в блоке finally или его аналоге. Очистка должна справляться с ресурсом, который не был создан, с ресурсом, созданным дважды после повтора, и с частично настроенным аккаунтом. Идемпотентная очистка экономит время, когда тест прерывается на этапе подготовки.
Вот отказ, который стоит проверить. Инструмент отправляет запрос создания. Провайдер создаёт запись, но разрывает соединение до возврата ответа. Агент видит операционный сбой и повторяет запрос. Без значения идемпотентности повтор создаёт дубликат. Без метки запуска очистка не может безопасно найти обе записи.
Добавляйте в запрос создания значение идемпотентности, полученное из идентификатора запуска и логического действия, а не из попытки передачи. Первая попытка и повтор должны использовать одно значение. Затем проверьте разрыв ответа с помощью заглушки, которая записывает первый запрос, закрывает соединение и возвращает успех, когда получает то же значение идемпотентности снова. Убедитесь, что на стороне провайдера осталась одна запись.
Если провайдер не поддерживает идемпотентность, перед повтором записи инструмент должен выполнить поиск по уникальной внешней ссылке. При параллельной работе этот подход может привести к гонке, поэтому зафиксируйте оставшийся риск. Не повторяйте молча денежные операции или необратимые записи только потому, что общий HTTP-клиент считает POST повторяемым.
Тайм-ауты и ограничения частоты выявляют плохое поведение агента
Инструмент может правильно обрабатывать успех и 403, но всё равно создавать ущерб, когда зависимость замедляется. Агент склонен повторять запросы, пытаясь завершить задачу. Инструмент должен давать ему ограниченный и честный ответ.
Проверьте тайм-аут соединения до отправки запроса на сервер, тайм-аут ответа после получения запроса сервером и ответ провайдера 429. Это разные случаи. В первом обычно не возникает побочного эффекта. Во втором сервер мог завершить запись. Ответ 429 может содержать указание повторить запрос, но используйте его только при наличии документации провайдера и сохраняйте его смысл.
Задайте короткие тестовые тайм-ауты, чтобы набор оставался удобным, но не подменяйте ими рабочие значения в коде. Передавайте часы или конфигурацию транспорта через зависимости. Жёстко заданный тайм-аут в две секунды, удобный для теста, превратится в сбой после развёртывания.
Утверждения должны проверять поведение, видимое агенту, а не только HTTP-клиент. Для ограничения частоты возвращайте операционный сбой с названием провайдера и указанием, разрешён ли повтор после задержки. Для тайм-аута ответа после записи сообщайте, что результат неизвестен, и просите найти операцию по значению идемпотентности или внешней ссылке. Простой статус ошибки в этом случае провоцирует дублирование записей.
Не проверяйте повторы только счётчиком. Записывайте, использовал ли повтор то же значение идемпотентности, подождал ли он нужное время и остановился ли после заданного лимита. Цикл повторов, который в итоге завершается, всё равно может создать всплеск запросов, исчерпать небольшой тестовый тенант и скрыть настоящую ошибку.
Отказ в подтверждении не должен менять цель
Если человек может подтверждать действия агента, проверьте путь отказа на endpoint, где побочный эффект будет очевиден. Надпись «отклонено» на экране не доказывает, что слой выполнения остановился.
Настройте одноразовую цель со счётчиком, помеченной записью или списком тестовых событий только для добавления. Запустите процесс агента, вызовите инструмент и отклоните сеанс или вызов. Затем запросите цель напрямую с отдельной тестовой личностью. Ожидаемое количество не изменилось.
Этот тест выявляет ошибку порядка действий: инструмент начинает исходящий запрос, а затем просит подтверждение, пока ждёт ответ. В демонстрации такой поток может выглядеть нормально, если провайдер медленный. Но смысл подтверждения теряется. Решение об авторизации должно быть принято до того, как диспетчер действий откроет сетевое соединение или запустит SSH-помощник.
Проверьте отдельно новый процесс агента и второй вызов в том же процессе. Для систем, выдающих авторизацию на один запуск, это разные гарантии безопасности. Проверьте также процесс с идентичностью подписи, отличающейся от ожидаемой. В запросе подтверждения должно быть достаточно сведений об источнике, чтобы человек мог отличить нужного агента от произвольного локального процесса.
В локальном процессе для Mac Sallyport хранит API- и SSH-учётные данные в зашифрованном хранилище и может требовать подтверждение для каждого нового запуска агента или каждого использования выбранных учётных данных. Проверяйте эти средства контроля на одноразовых endpoint, а не используйте их как повод пропустить тесты прав у провайдера.
Для SSH нужен тестовый объект, который можно выбросить
SSH добавляет сценарии сбоев, скрытые в примерах HTTP: проверку узла, экранирование команд, наследование окружения, поведение удалённой оболочки и файлы, оставшиеся после разрыва соединения. Никогда не направляйте автоматизированные SSH-тесты агентов на рабочую станцию разработчика или общий административный хост.
Создайте контролируемую тестовую машину или короткоживущую виртуальную машину с отдельной учётной записью. Домашний каталог должен быть пустым, набор команд, по возможности, ограниченным, а доступ к другим системам и их учётным данным отсутствовать. Используйте отдельный тестовый SSH-ключ и удаляйте его после завершения среды.
Проверьте аргументы команд, на которых ломается наивное построение командной строки. Тестируйте пробелы, кавычки, символы новой строки, пути, начинающиеся с дефиса, и данные, похожие на синтаксис оболочки. Инструмент должен передавать аргументы удалённой команде, не склеивая пользовательские значения в строку оболочки. Если удалённый интерфейс принимает только текст оболочки, ограничьте допустимую грамматику команд и отклоняйте всё остальное.
Безопасный тест может попросить цель создать файл с именем, содержащим метку запуска, а затем прочитать именно этот файл. В тесте отказа запросите путь за пределами разрешённого каталога тестового аккаунта и ожидайте отказа цели. В операционном тесте разорвите SSH-соединение после запуска команды, а затем проверьте, продолжил ли работать удалённый процесс.
Собирайте код завершения, ограниченный стандартный вывод и ограниченный вывод ошибок. Не возвращайте агенту неограниченный вывод команды. Большие результаты занимают контекст, а вывод команд часто содержит значения конфигурации, которые не должны покидать хост.
Свидетельства аудита должны связывать вызов агента с побочным эффектом
После сбоя теста нужно понять, вызвал ли инструмент действие, получил ли его провайдер и удалена ли запись при очистке. Набор строк в консоли надёжно на эти вопросы не отвечает.
Назначайте каждому тестовому запуску один идентификатор и переносите его в MCP-запрос, журнал инструмента, метаданные провайдера и журнал очистки. Не помещайте учётные данные в этот идентификатор. Полезная запись свидетельств содержит имя инструмента, категорию действия, ссылку на учётные данные, целевой тенант, идентификатор корреляции запроса, категорию результата и идентификатор возвращённого ресурса.
Храните записи сеансов агента отдельно от записей действий. Сеанс показывает, какой процесс и когда выполнил запуск и когда его отозвали. Запись действия показывает, какой внешний вызов произошёл. Связь по идентификатору корреляции делает тест отказа проверяемым: можно показать, что агент попытался выполнить действие, авторизация его отклонила, а соответствующей внешней записи действия нет.
Защита от изменений важна, когда результаты тестов используются для проверки новой границы инструмента. Sallyport создаёт журналы сеансов и активности из зашифрованного журнала аудита, связанного хешами, а sp audit verify может проверить эту цепочку офлайн без ключа хранилища. Это не заменяет журналы провайдера, но даёт локальным тестам способ обнаружить изменённую историю действий.
Не превращайте вывод аудита в место утечки секретов. Записывайте ссылки на учётные данные и скрытые атрибуты, а затем проверяйте эти правила тестами. Журнал аудита должен помогать восстановить ход действия, но не становиться самым простым местом для кражи доступа, благодаря которому оно было выполнено.
Кандидат на выпуск получает рабочий доступ постепенно
Инструмент должен проходить всё более реалистичные границы: локальные синтетические заглушки, реальный одноразовый провайдер, отклонённые и просроченные личности, внедрение сбоев и тест подтверждения человеком, если оно используется в процессе. Переход сразу в рабочую среду из-за отличий песочницы приводит к тому, что команды впервые проверяют безопасность под давлением.
Держите короткий набор выпуска, который запускается при каждом изменении, и более глубокий набор, который реже создаёт одноразовые ресурсы. Короткий набор должен проверять схему инструмента, формирование запросов, скрытие данных и типичные сбои. Глубокий набор должен проверять реальные области доступа, жизненный цикл очистки, отзыв и изоляцию цели.
Прежде чем разрешить новому действию работать в рабочей среде, изучите свидетельства намеренно отклонённого вызова и намеренно неоднозначного тайм-аута записи. Эти случаи показывают, уважает ли инструмент границу и говорит ли агенту правду, когда провайдер мог выполнить действие. Успешные сценарии легко подготовить. Именно сценарии отказа и неопределённости показывают, будет ли доступ к рабочей среде контролируемым или безрассудным.
Вопросы и ответы
Можно ли тестировать MCP-инструменты с реальным аккаунтом и ограниченными правами?
Используйте отдельный тенант, проект или рабочее пространство, у которого нет доступа к рабочим данным и платежам. Создайте в нём пользователей только для тестов, небольшие квоты и права, соответствующие сценарию. Фиктивный токен внутри рабочего тенанта всё равно даёт доступ к рабочей среде.
Доказывает ли ответ 403, что MCP-инструмент безопасен?
Нет. Отклонённый запрос показывает, что один путь авторизации при текущих условиях запретил одно действие. Нужны также тесты для некорректных аргументов, просроченных учётных данных, отозванного доступа, сбоев провайдера, ограничений частоты и отказа в подтверждении, если в процессе участвует человек.
Как должны выглядеть фиктивные API-учётные данные?
Фиктивные учётные данные должны иметь тот же формат, который ожидают инструмент и библиотека клиента, но проходить аутентификацию только в одноразовом сервисе или локальной заглушке. Не добавляйте в фикстуры префиксы рабочих токенов, материал для подписи или скопированные значения учётных данных. Фикстуры нужно считать кодом, который однажды может попасть в журналы или отчёты об ошибках.
Как MCP-инструмент должен сообщать о просроченных учётных данных?
Инструмент должен возвращать структурированную ошибку инструмента и сообщать агенту, может ли он исправить запрос, повторить его позже или остановиться. Для просроченного токена укажите, что аутентификация не пройдена и требуется повторная авторизация. Не возвращайте значение учётных данных, полный заголовок авторизации или ответ провайдера, содержащий эти данные.
Использовать ли для тестов MCP-инструмента моки или реальный тестовый аккаунт?
Используйте детерминированную локальную заглушку для точных тестов контрактов запросов и ошибок, а затем запускайте небольшой набор тестов против реального одноразового сервиса. Заглушки делают проверки тайм-аутов и некорректных ответов воспроизводимыми. Одноразовые аккаунты выявляют то, что вы забыли учесть в заглушке: реальную пагинацию, поведение областей доступа и проверки провайдера.
Как безопасно проверить отозванный API-токен?
Вызовите endpoint отзыва, если провайдер его предоставляет, а затем повторите тот же вызов инструмента с той же ссылкой на учётные данные. Ожидаемый результат, это понятный отказ в аутентификации или авторизации, а не незаметный успех из кеша. Проверьте также восстановление с помощью новых одноразовых учётных данных.
Как очищать одноразовые аккаунты после интеграционного теста?
Добавьте уникальный идентификатор запуска в каждую одноразовую запись и удаляйте записи по этому идентификатору во время очистки. Очистка должна справляться с частичной настройкой, поскольку неудачные тесты часто оставляют самые запутанные остатки. Включите автоматическое истечение срока у провайдера, если такая возможность есть, но не полагайтесь только на неё.
Можно ли безопасно тестировать MCP-инструменты, запускающие SSH-команды?
Да, если целевая машина находится под вашим контролем, а SSH-аккаунт не имеет маршрута к рабочим системам. Используйте отдельный тестовый ключ, ограниченную учётную запись и команды, вывод которых безопасно собирать. Не тестируйте с обычным SSH-ключом инженера, даже если цель кажется безвредной.
Как тестировать подтверждение человеком действий агента?
Проверьте границу действия напрямую. Отправьте один запрос инструмента от ожидаемого процесса агента, отклоните сеанс или отдельный вызов, а затем убедитесь, что внешняя система не получила запрос. Видимый отказ полезен, но доказательством служит отсутствие побочного эффекта.
Можно ли добавлять фиктивные учётные данные в тестовый репозиторий?
В репозитории должны храниться только синтетические короткоживущие фикстуры, которые не могут авторизовать реальный сервис. Сканеры секретов полезны, но они не определяют, может ли токен попасть в рабочую среду. Надёжное решение архитектурное: рабочие учётные данные никогда не должны участвовать в тестовой среде.