Читать 8 мин

Могут ли дубликаты экземпляров шлюза разделить историю аудита?

Дубликаты экземпляров шлюза могут создать конфликт полномочий и скрытую историю. Безопасно проверьте владение хранилищем, одобрения, отзывы и целостность аудита.

Могут ли дубликаты экземпляров шлюза разделить историю аудита?

Скопированный пакет приложения не является безобидным способом создать второй локальный шлюз. Это проверка того, сможет ли программа сохранить единый контроль над учетными данными, одобрениями, отзывами и доказательствами, когда macOS предъявляет ей двух правдоподобных претендентов.

Опасный сбой не всегда сопровождается падением. Падение заметно сразу. Более тихий вариант выглядит так: два процесса работают без видимых проблем, принимают запросы агента и оставляют достаточно свидетельств, чтобы успокоить человека, который их запустил. Затем изменение учетных данных, отзыв или разбор инцидента выявляет разделение: один процесс знал то, чего не знал другой.

Sallyport задуман как одно подписанное постоянно работающее приложение macOS в строке меню со встроенным ядром хранилища. Поэтому одновременный запуск стабильной, бета- и скопированной версий нужно считать преднамеренным тестом конкуренции и идентичности, а не обычным режимом работы. Тест должен дать узкий ответ: система отклоняет дубликат, безопасно координирует его или разрешает работу, сохраняя одно авторитетное хранилище и одну проверяемую историю?

Два пакета не означают автоматически две идентичности

Имя в Finder это самый слабый сигнал идентичности в таком эксперименте. Sallyport.app, Sallyport Beta.app и Sallyport Copy.app могут выглядеть для человека как три независимых приложения, хотя внутри пакетов у них будут один и тот же идентификатор пакета и одна и та же подпись.

Apple описывает идентификатор пакета как значение, которое macOS использует для идентификации приложения на уровне приложения. Материалы Apple о подписи кода объясняют, что designated requirement дает системе способ распознавать код как то же приложение после обновлений. Это полезные понятия, но ни одно из них не отвечает на главный вопрос. То, что macOS распознает приложения как одну идентичность, не доказывает, что два живых процесса безопасно владеют общим состоянием.

Сначала зафиксируйте, что именно вы запустили. Сделайте это до открытия хранилища, подключения агента или одобрения действий.

APP_A="/Applications/Sallyport.app"
APP_B="$HOME/Desktop/Sallyport Beta.app"

for app in "$APP_A" "$APP_B"; do
  echo "=== $app ==="
  plutil -p "$app/Contents/Info.plist" | grep -E 'CFBundleIdentifier|CFBundleShortVersionString|CFBundleVersion'
  codesign -dvv "$app" 2>&1 | grep -E 'Identifier=|TeamIdentifier=|Authority='
  codesign -d -r- "$app" 2>&1 | grep 'designated =>'
done

Важна общая форма вывода, а не точный текст:

=== /Applications/Sallyport.app ===
"CFBundleIdentifier" => "..."
"CFBundleShortVersionString" => "..."
Identifier=...
TeamIdentifier=...
designated => identifier "..." and anchor ...

Сохраните этот результат вместе с записью о тесте. Если два неповрежденных пакета сообщают один идентификатор и одно designated requirement, считайте их двумя копиями одной идентичности кода. Если значения различаются, считайте их отдельными идентичностями кода. Не подменяйте эти факты ярлыками «стабильная» и «бета».

Есть и второе различие, которое команды часто смешивают: идентичность кода не равна идентичности хранилища. От двух процессов с одинаковым designated requirement можно ожидать доступа к одному защищенному материалу. Процессы с разными требованиями могут получить разные системные разрешения. Ни один из этих вариантов не говорит, смогут ли они безопасно использовать зашифрованное хранилище или добавлять записи в цепочку аудита. Владение хранилищем нужно проверять отдельно.

Разделенная история аудита хуже неполного журнала

Неполный журнал сообщает, что часть доказательств отсутствует. Разделенный журнал может рассказать две внутренне согласованные истории, в каждой из которых не будет записей, хранящихся у другой стороны. Это замедляет разбор инцидента и может сделать отозванный сеанс действительным с точки зрения одного процесса.

После события журнал шлюза действий должен отвечать на конкретные вопросы:

  • Какой процесс агента запросил действие?
  • Какой процесс шлюза разрешил его или отказал?
  • Какая ссылка на учетные данные использовалась без раскрытия секрета?
  • Одобрил ли человек сеанс или отдельный вызов?
  • Произошел ли отзыв до действия или после него?

Если процессы A и B записывают независимые последовательности, каждая последовательность может проверяться сама по себе. Этого недостаточно. Проверка криптографической цепочки показывает, что записи внутри цепочки не были незаметно изменены. Она сама по себе не доказывает, что другой легитимный автор не начал отдельную цепочку в другом месте.

Поэтому важно различать защиту от подмены и полноту. Хеш-цепочка защищает связь между записями, которые присутствуют в этой цепочке. Для полноты нужны четкое правило владения, единая точка добавления записей или долговечное доказательство каждой принятой ветви и способа ее согласования. Если ошибиться, оператор успешно выполнит проверку и все равно пропустит половину действий.

Речь идет не только о журналах. Разделенная история аудита часто появляется вслед за разделенными полномочиями:

  • Один процесс считает хранилище заблокированным, а у другого остается открытый сеанс.
  • Один процесс отзывает запуск агента, а другой продолжает его принимать.
  • Один процесс записывает одобрение отдельного вызова, а другой не видит причины спрашивать.
  • Один процесс записывает окончательный результат действия, а другой только запрос.

Не оценивайте тест по тому, могут ли обе копии выполнить HTTP-вызов или команду SSH. Успешный вызов доказывает только наличие рабочего пути. Тест пройден, когда последующий проверяющий может восстановить полную историю действий и ему не приходится угадывать, у какой копии находилось недостающее состояние.

Определите правило владения до начала гонки

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

Для локальных копий шлюза есть три обоснованных варианта.

  1. Исключительное владение. Первый процесс владеет хранилищем и журналами. Поздние копии отказываются работать, переводят фокус на первое приложение или завершаются с понятным объяснением.
  2. Один активный процесс с передачей работы. При новом запуске приложение находит владельца и просит его выполнить нужную работу. Новый процесс сам не открывает хранилище, не одобряет действия и не добавляет записи.
  3. Согласованное владение несколькими процессами. Несколько процессов могут работать, но все используют продуманный протокол общего состояния, который сохраняет атомарность изменений хранилища и единый проверяемый порядок событий.

Первый вариант обычно проще всего анализировать для настольного приложения, хранящего важное состояние. Третий может быть допустим, но требует гораздо более серьезного доказательства корректности. «Они оба указывают на одну папку» это не протокол координации.

До теста составьте таблицу ожидаемых результатов. Каждый результат должен быть наблюдаемым.

| Условие | Ожидаемое поведение | Что сохранить |\n| --- | --- | --- |\n| Stable владеет открытым хранилищем | Beta отклоняется, передает работу или согласуется | состояние интерфейса, список процессов, ответ шлюза |\n| Stable владеет заблокированным хранилищем | Ни одна копия не выполняет действие до открытия границы хранилища | запись отклоненного запроса и локальное состояние |\n| У Stable есть одобренный сеанс агента | Новому процессу агента нужно отдельное решение по сеансу | записи одобрений с идентичностью процесса |\n| Для учетных данных включено одобрение каждого вызова | Каждый вызов запрашивает одобрение независимо от получившей его копии | по одной записи одобрения на попытку вызова |\n| В одном процессе запуск отозван | Ни один процесс не продолжает этот запуск | событие отзыва и отклоненный повторный вызов |\n| Обе копии одновременно запрашивают безопасное действие | История остается полной и проходит проверку | упорядоченные записи активности и результат проверки аудита |

Формулировка имеет значение. «Копии не должны конфликтовать» нельзя проверить. «Скопированный пакет не может вернуть успешный ответ после того, как существующий владелец отозвал тот же запуск агента» уже проверяемо.

Отдельно учитывайте поведение продукта и тестового стенда. Скрипт оболочки может случайно не допустить два запуска, но это не доказывает, что приложение предотвращает их. Обратный прокси может последовательно обрабатывать запросы, но это не доказывает, что локальное хранилище справляется с одновременными запросами. Стенд не должен исправлять ошибку, которую вы хотели найти.

Сначала запускайте неповрежденные копии

Чистый эксперимент начинается с неповрежденных пакетов приложений. Скопируйте пакет без изменения файлов внутри, поместите копии в разные обычные каталоги и зафиксируйте каждый путь. Изменение исполняемого файла или Info.plist сначала часто делает подпись недействительной, превращая эксперимент в тест проверки подписи.

TN3127 от Apple объясняет, почему эта граница важна: macOS использует designated requirements, чтобы определить, соответствует ли код установленной идентичности. Если изменение пакета нарушает проверку подписи, отказ может быть правильным, но он ничего не скажет о владении общим состоянием двумя действительными сборками.

Используйте небольшой лист запуска. В нем должны быть только наблюдаемые факты:

Test ID: duplicate-owner-01
Build A path: /Applications/Sallyport.app
Build B path: /Users/tester/Desktop/Sallyport Beta.app
Bundle IDs: [recorded value A] / [recorded value B]
Designated requirements: [recorded value A] / [recorded value B]
Launch order: A first, B second
Vault state before launch: locked
Agent process IDs: [record after start]
Expected contract: exclusive ownership

Запустите A, дождитесь состояния простоя и запустите B. Сразу запишите результат, не делая ничего другого. Отказ должен быть достаточно явным, чтобы оператор понимал, какой существующий процесс владеет состоянием. Тихое завершение создает обращения в поддержку и провоцирует повторные попытки, пока не возникнет гонка.

Проверяйте разделение процессов средствами операционной системы, а не по окнам приложения. Второе окно может принадлежать тому же процессу, а фоновый помощник способен создать второй процесс даже при одном видимом элементе в строке меню.

pgrep -alf 'Sallyport|sp mcp|sp-ssh'
ps -axo pid,ppid,start,command | grep -E 'Sallyport|sp mcp|sp-ssh' | grep -v grep

Считайте этот вывод артефактом временной шкалы. Сохраняйте его сразу после каждого этапа запуска. По возможности включайте идентификаторы родительских процессов. Они помогают понять, пришло ли второе действие от независимого процесса приложения, прокладки, запущенной агентом, или дочернего помощника.

Не используйте рабочие учетные данные. Направляйте HTTP-запросы к отдельной конечной точке с безопасным методом или контролируемому тестовому сервису. Для SSH используйте отдельную учетную запись с ограниченной командой или узел без доступа к рабочей среде. Вы проверяете владение процессами и поведение аудита. Разрушительная конечная точка не нужна.

У границы хранилища должен быть один видимый владелец

Повторно запрашивайте одобрение чувствительных ключей
Отметьте ключ для одобрения каждого вызова, если каждое отдельное использование должно требовать решения человека.

Граница хранилища абсолютна только тогда, когда к ней ведут все пути выполнения действий. Если один процесс остается открытым после того, как другой заблокировал хранилище, завершился или потерял доступ, слово «заблокировано» описывает окно, а не фактическое состояние системы.

Сначала проверьте эту последовательность на безопасном HTTP-действии:

  1. Запустите копию A с заблокированным хранилищем.
  2. Подключите один процесс агента через локальную оболочку MCP и попробуйте безопасное действие. Ожидайте отказа.
  3. Откройте A обычным способом, повторите действие и запишите успешный результат вместе с записью активности.
  4. Запустите копию B, пока A остается доступной. Пока не открывайте B.
  5. Попросите тот же процесс агента и новый процесс агента выполнить действие через доступный маршрут B, если он есть.
  6. Заблокируйте A или завершите ее, затем повторите запросы от обоих агентов.

Результат зависит от правила владения, но небезопасный случай легко описать: B выполняет действие, потому что сохранила или независимо получила полномочия, о которых человек не мог знать, заблокировав A.

Здесь часто не срабатывает совет «просто разделите открытое состояние, чтобы бета-версия не спрашивала снова». Так говорят, потому что повторная локальная аутентификация раздражает при разработке. Но это неправильно, если у общего состояния нет определенного владельца, четкого срока жизни и пути отзыва, который каждый процесс проверяет до выполнения действия. Удобство не стоит появления невидимого второго состояния разблокировки.

Модель хранилища с аппаратной защитой задает полезную границу теста. Пока хранилище заблокировано, агент должен получить отказ, а не заглушку секрета, частично подготовленный запрос или действие, поставленное в очередь и выполняющееся после разблокировки. Шлюз действий должен сам выполнить одобренное действие и вернуть результат. Он не должен передавать агенту учетные данные, пока человек разбирается с локальным состоянием.

Записывайте и ответ действия, и свидетельства в журнале. Отказ, исчезнувший из истории, сильно усложняет отладку. Еще хуже успешное действие без предшествующей записи об открытии или одобрении.

Одобрение сеанса должно быть связано с процессом, а не с ярлыком

Авторизация сеанса нужна, чтобы человек мог оценить конкретный запуск агента. Она теряет смысл, когда переходит от одного процесса к другому только потому, что у них похожие имена, один терминал или одна скопированная копия шлюза.

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

Проведите этот тест с двумя отдельными процессами агента. Не используйте один процесс оболочки и не называйте его двумя агентами.

# Terminal 1
sp mcp

# Terminal 2
sp mcp

Команды намеренно просты. Важно, что они запускаются из отдельных процессов агента в тестовом стенде, после чего каждый отправляет один безопасный вызов. Одобрите первый сеанс, а второй оставьте без ответа. Если в карточке одобрения видны сведения о процессе, сохраните показанные полномочия и сравните их с запущенным процессом.

Затем проверьте переходы:

  • Завершите одобренный процесс агента и запустите заменяющий процесс с той же командой.
  • Запустите или активируйте копию шлюза, пока первый сеанс остается одобренным.
  • Отзовите первый запуск в журнале сеансов.
  • Попросите оба процесса выполнить еще по одному безопасному запросу.

Правило простое: одобрение принадлежит запуску до его завершения, а отзыв везде прекращает полномочия этого запуска. Новый процесс не должен наследовать одобрение только потому, что выглядит знакомо. Копия шлюза не должна считать то же подключение агента разрешением обойти решение, которое потребовалось бы другой копии.

Не смешивайте одобрение сеанса с ключами для отдельных вызовов. Одобрение сеанса отвечает на вопрос, может ли этот процесс агента пользоваться шлюзом во время запуска. Ключ для отдельного вызова отвечает на вопрос, требуется ли новое решение человека для каждого использования конкретных учетных данных. Одно связано со сроком жизни вызывающей стороны, другое с чувствительностью учетных данных. Если смешать их в записях теста, результат будет прочитан неверно.

Одобрение каждого вызова выявляет скрытые пути дубликатов

Проверяйте доказательства после гонки
Проверяйте цепочку аудита офлайн по шифротексту с помощью sp audit verify, не открывая секреты.

Учетные данные, для которых требуется одобрение при каждом использовании, хорошо подходят для проверки дубликатов: программа должна отдельно учесть каждое действие. Возьмите отдельные тестовые учетные данные или SSH-узел, включите для них это правило и отправьте через два возможных пути одновременные безопасные запросы.

Вопрос не в том, получили ли вы два запроса на одобрение. Два запроса могут быть правильным результатом, а могут показывать, что обе копии создали независимые полномочия. Нужно проверить, есть ли у каждого завершенного действия соответствующее одобрение и может ли одна копия использовать одобрение другой.

Во время теста ведите небольшой журнал событий:

ВремяПроцесс шлюзаPID агентаID запросаРешение человекаРезультат
10:03:01A4128req-a1одобреноуспех
10:03:02B4194req-b1отклоненоотказ
10:03:04A4128req-a2одобреноуспех

Используйте идентификаторы запросов, созданные тестовой конечной точкой или стендом. Не полагайтесь на порядок появления окон. Планировщик рабочего стола может изменить порядок видимых запросов, а HTTP-ответ может прийти после более позднего запроса.

Плохой результат сначала часто выглядит аккуратно: запрос A одобрен в копии A, но затем копия B завершает запрос B без собственного одобрения. Это означает, что состояние одобрения пересекло границу без решения оператора. Обратный вариант тоже серьезен: B одобрена, но результат записан в поток активности A без объяснения, почему действовала A.

Повторите гонку после блокировки хранилища, завершения одной копии и отзыва первого запуска агента. Эти переходы выявляют устаревшее состояние в памяти. Самые показательные ошибки обычно появляются после изменения состояния, когда один процесс обновил свое представление, а другой еще нет.

Для проверки аудита нужны доказательства до и после

Отчет «журнал выглядел нормально» не является доказательством. Снимите исходное состояние, создайте контролируемый набор действий, выполните проверку после запуска и сравните ожидаемые записи с фактическими.

У описанной для этого шлюза архитектуры аудита есть важное преимущество: один зашифрованный журнал с хеш-цепочкой и запретом записи проецируется одновременно в журнал сеансов и журнал активности. Значит, эти журналы должны быть двумя представлениями одной истории, а не двумя независимо поддерживаемыми наборами записей, которые лишь похожи друг на друга.

Начните с пустого или четко ограниченного периода теста. Зафиксируйте время начала, затем создайте известную последовательность: отказ при заблокированном хранилище, действие в одобренном сеансе, одобренное действие с отдельным вызовом, отказ отдельного вызова, отзыв сеанса и отклоненное действие после отзыва. Последовательность должна быть достаточно короткой, чтобы учесть каждое событие.

После этого запустите офлайн-проверку:

sp audit verify

Сохраните полный вывод команды, включая ненулевой код завершения при ошибке. Для проверки цепочки шифротекста проверяющему не нужен доступ к хранилищу. Это позволяет расследователю проверить целостность, не открывая хранилище учетных данных, что особенно важно после неудачного теста с несколькими процессами.

Одной проверки недостаточно. Сравните три представления:

  1. Внешний журнал теста со всеми ID запросов и ожидаемыми результатами.
  2. Журнал сеансов с одобрениями, завершениями запусков и отзывами.
  3. Журнал активности с каждой попыткой действия и результатом.

Каждое событие внешнего журнала должно соответствовать нужному представлению журнала. Каждое событие журнала за ограниченный период теста должно иметь связь с тем, что вы намеренно создали. Проверяйте дополнительные записи, даже если цепочка проходит проверку. Неожиданное успешное действие может быть повтором, запросом из очереди или свидетельством того, что второй процесс оставался активным после предполагаемого завершения.

Если две независимые цепочки проходят проверку, считайте это нарушением полноты истории, если только документированная архитектура с несколькими процессами не записывает связь с родителем и детерминированное объединение. Не исправляйте это объединением экспортированных журналов после теста. Ручное объединение создает отчет, а не журнал аудита.

Восстановление определяет, станет ли ошибка дубликата инцидентом

Храните API-ключи в шлюзе
Sallyport сам выполняет HTTP-запросы и подставляет учетные данные, не передавая их агенту.

Нужно учитывать прерывания владения. Люди принудительно завершают бета-сборки. Ноутбуки засыпают. Тестовый стенд убивает процесс между одобрением и результатом действия. Приложение должно справляться с этим так, чтобы брошенный владелец не блокировал работу навсегда, а новый владелец не считал, что действия не было.

Проверьте как минимум четыре точки прерывания:

  • Убейте копию A после получения запроса, но до получения одобрения.
  • Убейте копию A после одобрения, но до завершения внешнего действия.
  • Убейте копию A после завершения действия, но до того, как результат станет виден агенту.
  • Сразу после каждого прерывания запустите копию B.

Для каждого случая заранее запишите безопасное правило восстановления. Например, B может отказаться работать, пока не установит, что A завершилась, и не восстановит долговечное состояние. Другой вариант: B продолжает работу только по зафиксированным записям аудита, а неопределенное действие помечает как неизвестное, не объявляя его успешным или неуспешным. Правило зависит от реализации, но гадать недопустимо.

Не скрывайте неопределенность. Внешняя система может завершить HTTP-запрос или команду SSH в тот момент, когда локальный процесс завершается. Если шлюз не может доказать, завершилась ли операция, это состояние неопределенности должно сохраниться в доказательствах. Повтор неизвестной записи может создать второе реальное действие. Притворство, будто первого действия не было, создает ложную историю аудита.

Здесь же нужно внимательно проверить мгновенный отзыв. Отзовите запуск агента, сразу завершите текущего владельца, запустите копию и повторите действие от имени этого агента. Если новый процесс считает отсутствие состояния в памяти новым сеансом, отзыв недостаточно долговечен. Отзыв, работающий только пока жив один процесс, нельзя надежно использовать при сбое.

Держите стабильные и бета-тесты отдельно, если общий доступ не является намеренным

Стабильные и бета-сборки легко запускают вместе, потому что обе полезны. Stable выполняет реальную работу, а Beta нуждается в реалистичной нагрузке. Если направить их к одному хранилищу и журналам без четкого правила совместимости, вы получите рабочие риски при наблюдаемости эксперимента.

Используйте один из двух вариантов. Более безопасный дает Beta отдельное тестовое хранилище, тестовые учетные данные, тестовых агентов и отдельный набор доказательств. Так можно проверить поведение Beta, не превращая экспериментальный процесс в часть рабочего журнала действий.

Более сложный вариант намеренно заставляет Stable и Beta использовать общее состояние. Выбирайте его, только если непрерывность между версиями сама является предметом теста. Проверяйте несовпадение версий в обоих направлениях: сначала состояние принадлежит Stable, затем запускается Beta; сначала состояние принадлежит Beta, затем запускается Stable; один процесс обновляется, пока другой остается открытым; один процесс откатывается после того, как другой записал новую историю. Для каждого перехода фиксируйте, был ли отказ, передача работы или координация.

Для Sallyport фиксированная последовательность решений задает полезные критерии приемки: граница хранилища остается абсолютной, новый процесс агента по умолчанию получает собственное одобрение сеанса, а учетные данные с одобрением каждого вызова по-прежнему требуют решения при каждом использовании. Реализация может выбрать исключительное владение или безопасную передачу работы, но не может незаметно ослабить эти ограничения ради удобства двух пакетов.

Завершите тест четким выводом, который сможет проверить другой инженер: какой процесс владел хранилищем, что произошло при появлении другой копии, пересекло ли какое-либо действие границу одобрения или отзыва и охватила ли одна офлайн-проверка все созданные события. Если ответ зависит от того, за каким окном вы следили, повторите тест. Доказательств пока недостаточно.

Вопросы и ответы

Безопасно ли запускать две копии локального шлюза действий с ИИ?

Считайте это тестом владения состоянием, а не проверкой внешнего вида. Запускайте копии только в изолированной тестовой среде, держите идентификаторы процессов и расположение хранилищ под контролем и выполняйте только безопасные действия. Тест пройден, если вы можете показать одно авторитетное хранилище и одну полную проверяемую историю созданных действий.

Должна ли бета-версия использовать хранилище стабильного приложения?

Бета-версия может совместно использовать идентификатор и хранилище со стабильной версией или быть полностью изолированной. Оба варианта допустимы, случайное смешение недопустимо. Если бета-версия может открыть рабочее хранилище или добавлять записи в рабочий журнал, зафиксируйте это правило и проверьте обновление, откат версии и возврат к предыдущей версии.

Создает ли переименование пакета приложения macOS отдельный экземпляр?

Переименование внешней папки .app не обязательно создает отдельную идентичность приложения в macOS. Перед выводами проверьте идентификатор пакета, данные подписи, путь к исполняемому файлу, идентификатор запущенного процесса и расположение хранилища. Копия пакета может по-прежнему распознаваться как то же подписанное приложение или быть отклонена из-за недействительной подписи.

Может ли подпись кода предотвратить разделение состояния хранилища?

Нет. Подписанный пакет сообщает macOS, кто создал и идентифицировал код, но не доказывает, что два работающих процесса правильно согласуют записи. Нужны явное владение, блокировка, восстановление после сбоев и тест аудита, который выявляет разветвление истории, а не только сбой.

Какие доказательства нужно собирать при тестировании дубликатов?

Нужен точный порядок событий: запуск процесса, попытка открыть хранилище, одобрение сеанса, запрос действия, результат, отзыв и завершение. Записывайте время, идентификаторы процессов, пути к исполняемым файлам и результат проверки аудита после каждого этапа. Если нельзя восстановить, какой процесс отвечал за каждое событие, доказательств недостаточно для оценки результата.

Можно ли тестировать дубликаты шлюза с рабочими API-ключами?

Не используйте рабочие учетные данные только потому, что приложение не передает секреты агенту. Возьмите отдельную тестовую конечную точку или SSH-узел, который принимает безопасный запрос вне рабочей среды. Цель теста состоит в проверке поведения шлюза, а не в выяснении, сможет ли случайная копия добраться до важной системы.

Что произойдет, если два процесса шлюза одновременно записывают события аудита?

Одновременная запись в журнал не означает автоматическую порчу данных, но до доказательства обратного это повод для проверки. Журнал с хеш-цепочкой должен иметь однозначного предшественника для каждой принятой записи либо четкий механизм регистрации нескольких авторов без сокрытия одной из ветвей. После гонки выполните офлайн-проверку и изучите порядок событий, а не доверяйте одному успешному ответу действия.

Могут ли два процесса агента использовать одно одобрение?

Одобрение сеанса должно быть связано с конкретным процессом агента, а не только с именем приложения, окном терминала или расплывчатым намерением пользователя. Запишите идентичность процесса, показанную при одобрении, и убедитесь, что второй процесс агента получает собственное решение. Иначе одно одобрение может распространиться на действия, которые человек не проверял.

Нужно ли изменять пакет приложения для тестирования дубликатов?

Начните с копий пакетов, а не с измененных пакетов. Изменение файлов внутри приложения может сделать подпись недействительной и превратить проверку дубликатов в тест обработки неподписанного кода. Сначала установите поведение на неповрежденных артефактах, а затем при необходимости проведите отдельный тест отказа из-за подписи.

Как должен выглядеть успешный тест дубликатов шлюза?

Правильный результат это явный отказ, передача работы одному процессу или согласованная архитектура общего состояния, которая сохраняет целостность хранилища и истории аудита. Неправильный результат это два внешне исправных процесса с разными представлениями о полномочиях или истории. Удобство не имеет значения, если оператор позже не может доказать, какой процесс выполнил действие.

Sallyport

Sallyport выполняет API-вызовы и SSH-команды за вашего ИИ-агента. Ключи остаются в локальном хранилище на вашем Mac; вы подтверждаете каждый запуск, и каждое действие попадает в запечатанный журнал.

© 2026 Sallyport · Открытый код по лицензии Apache-2.0 · Oleg Sotnikov