diff --git a/doc/group_isolation_plan.txt b/doc/group_isolation_plan.txt index 1cc5e87f2..c3502e78a 100644 --- a/doc/group_isolation_plan.txt +++ b/doc/group_isolation_plan.txt @@ -391,19 +391,141 @@ tests/logs/test_chat_group_isolation.log. Общий ./check.sh:240/240, proxy9/ group_id заказа остаётся прежним, даже если повтор пришёл через другую разрешённую группу. - dm_custody_store при точном повторе отвечает через новую группу/source, но сохранённые group_id/supernode не меняются. Фоновая обработка использует старые поля. - - dm_media_holders имеет ключ (id,node_id), без группы. Повторное назначение того же M - через B нельзя считать новым только заменой проверки допуска: оно пересекается с прежним A. - - mb_scope/dm_media_scope пока недостаточно проверяют admitted/source/self и третьего участника; - простое усиление этих условий остановит старые задания, но не даст корректного пересогласования. + - dm_media_holders имеет ключ (id,node_id), без идентификатора попытки. Разные попытки + назначения того же M не различаются; смена группы сама по себе новой попыткой не является. + - mb_scope/dm_media_scope недостаточно проверяют admitted/source/self и смешивают допуск + транспортной пары с требованием общей группы автора/получателя/S/M. Нужны отдельные + предметные проверки и выбор маршрута по паре узлов согласно уточнению пользователя ниже. -Предлагаемый следующий этап: - 1. Разделить идентичность неизменяемого файла (UUID/body hash) и контекст задания хранения. - Явно определить атомарную замену group/supernode при новом допустимом PUT/STORE. - Сохранить первоначальные TTL/политику удаления; смена маршрута не продлевает хранение. - 2. Связать holder и его ACK/DELETE/EXPIRED с конкретным назначением и группой, чтобы поздний - ответ A не изменял действующее назначение B; согласовать это с одной физической копией M. - 3. Добавить общий свежий допуск, проверки всех ролей/участников и отмену заданий/проб; - завершение custody worker проверяет актуальное назначение перед публикацией результата. - 4. Проверить реальными A–S–B/M: отзыв только одной группы, новый заказ через другую, - тот же UUID/M, поздние ответы, перезапуск, прежний TTL и сохранность локальной истории. -Изменения mailbox/custody остановлены на этой границе по правилу AGENTS о логических несоответствиях. +Архитектура следующего этапа — проект, ещё не реализация. +Уточнение пользователя: при хранении и передаче личных сообщений/вложений конкретная +CHAT-группа не закрепляется. Можно использовать любую доступную общую группу непосредственных +отправителя и получателя пакета; значение имеют их личности и права на объект. +Это заменяет прежнее предложение связывать назначение хранения с группой. +MEMBER_FILES остаётся файловым сервисом конкретной группы; UTUN в эту доработку не входит. + +1. Три независимые сущности. + - Личный объект: подписанное сообщение, UUID вложения, hash полного тела, автор и стороны + беседы. Существующие правила DEVICE/GROUPS и снимок адресатов сообщения сохраняются. + - Назначение хранения: координатор S просит выбранное хранилище M сохранить этот объект. + assignment_id создаётся S и сохраняется до отправки STORE; привязан к S, M и точному телу. + Повтор, рестарт и смена маршрута сохраняют assignment_id. Другой M или новая попытка + после окончательного отказа получают новый assignment_id. Не вводим отдельную эпоху группы. + - Активный сетевой обмен: peer, выбранная сейчас группа, router session/transfer/probe ID. + Только этот слой содержит обязательную привязку к группе. Ответ может прийти другой группой. + +2. Маршрут выбирается для каждой пары отдельно. + Автор -> S, S -> M, M -> автор, S -> получатель и M -> получатель могут использовать + разные группы. Не требуем группу, в которой одновременно состоят все четыре узла. + Перед каждой новой отправкой выбирается доступная общая CHAT-группа self/peer; + приём, очередь, повтор и callback проверяют свежий topo_group_chat_allowed этой пары. + Подпись router обязательна для DM_MAILBOX/DM_MEDIA, в том числе header-only controls. + Роль и объектное право проверяются отдельно от выбора сетевого пути. + + Роли supernode/storage нужны для выбора и допуска обслуживающего узла к новой работе. + Источник этих сведений — актуальные подписанные строки участников допущенных общих групп + проверяющей стороны и проверяемого узла; роль не обязана находиться в группе текущего пакета. + Строка из чужой группы, source!=0, deleted или admitted!=1 полномочий не даёт. + Смена маршрута не заменяет обслуживающий узел и не отменяет уже принятую им копию. + Сохранённое назначение разрешает учитывать его результаты и завершать его после изменения + роли; оно не даёт права создавать другие назначения или обращаться к групповым API. + + PUT принимается от автора точного подписанного сообщения, адресованного указанному получателю. + DELIVER/OFFER проверяют личность отправителя, предметные полномочия и подписанное тело. + Выдача файла проверяет право конкретного устройства/стороны беседы либо допустимого storage; + членство в транспортной группе и знание UUID сами по себе доступа к файлу не дают. + HAVE, передача файла и квитанции используют те же предметные правила, что основной запрос. + Квитанция получателя подтверждает точное тело и подписанта из снимка адресатов. + Локальное совмещение S=M вызывает те же предметные проверки без искусственного сетевого self-сеанса. + +3. Постоянное состояние не содержит обязательного group_id. + Удалить group_id из контракта личных pending, receipts, sources, jobs и custody. + Не переносить его в новый ключ и не делать из него сохранённое разрешение на доступ. + При необходимости последний удачный маршрут можно кешировать только как необязательную + runtime-подсказку: после рестарта всё находится по node_id, перед использованием допуск проверяется. + Текстовый mailbox сохраняет существующий ключ сообщения и точное тело; нового assignment_id + для текста не нужно. Повтор через другую группу не создаёт сообщение заново и не отменяет receipt. + + На S существующий список dm_media_holders превращается в список назначений: + assignment_id, file_id, M, состояние/ответ, подтверждённые expires и delete_on_open. + Координатор dm_media_jobs ссылается на текущее назначение, прежние назначения сохраняются + до окончательного разрешения. Поля статуса не дублировать без необходимости в обеих таблицах. + На M dm_custody описывает одну физическую копию: точное тело/hash, состояние, первоначальный + deadline и политику удаления. Поля единственного supernode/group_id из копии убираются. + Отдельный список обращений M: (S, assignment_id), file_id/body_hash, принято или отказано. + Принятые обращения нескольких S могут ссылаться на одну копию; ответы адресуются каждому S. + В каждый момент на M для этой копии работает не более одной загрузки/проверки/очистки. + +4. Идемпотентный STORE и точные ответы. + STORE и относящиеся к нему RESERVED/STORED/REJECT/DELETE_ACK/EXPIRED несут assignment_id + и file_id. Стороны S/M берутся из проверенной личности отправителя и локальной записи, + тело/hash неизменно закреплены в назначении. Совпадения одного UUID или группы недостаточно. + Повтор принятого STORE возвращает текущее состояние той же копии и прежние TTL/политику. + Окончательный отказ, например по квоте, сохраняется для этого assignment_id до ответа; + его повтор не превращается в принятие. Реальная новая попытка использует новый ID. + Неавторизованный запрос не создаёт запись назначения и не меняет состояние файла. + При конфликте ID/тела/M, SQL-ошибке или неудачном commit успешный ответ не отправляется. + + Поздний ответ изменяет только найденное назначение. Изменение текущего назначения возможно + только при совпадении assignment_id; ответ прежнего M не сбрасывает нового M. + RESERVED после STORED не откатывает готовность; терминальное назначение не оживает от STORED. + Ответ той же операции через другую разрешённую группу принимается как обычный ответ. + Даже запоздалый ответ старой группы допустим, если её текущий допуск не отозван. + Если допуск отозван, пакет отвергается до изменения durable состояния. + +5. Физическая копия и факты о файле. + Состояния копии M: RESERVED -> READY -> REMOVING -> REMOVED; удаление возможно и из RESERVED. + Первый успешный резерв на данном M фиксирует абсолютный expires и delete_on_open. + Повтор, другой маршрут, ещё один S и перезапуск не продлевают этот срок и не меняют политику. + После удаления сохраняется существующий tombstone по UUID/hash; поздний STORE не возрождает копию. + Это срок конкретной копии на M; не вводим несуществующий сейчас общий TTL для всех хранилищ. + + RECEIPT/TAKEN — подписанные факты о файле, не о маршруте и не об assignment_id. + DELETE переносит эти факты; сам координатор не получает права произвольно удалить общую копию. + M проверяет факты и первоначальную политику: открытие получателем либо загрузка всеми + адресатами стороны получателя из исходного снимка. Ещё одно обращение S не меняет этот снимок. + Сначала commit REMOVING, затем отмена передачи и удаление на диске, затем tombstone и ACK. + ACK адресуется конкретному обращению; остальные координаторы также получают конечный результат. + Минимальные терминальные записи нужны для повторов после рестарта; очистка не должна допускать replay. + + Разделить EXPIRED назначения S--M и сообщение конечному получателю о недоступности источника. + Второе относится к file_id/body_hash и конкретному holder, не делает весь личный файл удалённым. + Позднее исчезновение M1 не отменяет источник M2, готовую локальную копию или получение оригинала. + +6. Отзыв группы и фоновые операции. + Отзыв закрывает только сетевые операции этой группы, включая очереди, probes и waiters. + Общий ETCP и другая допущенная группа продолжают работать. Сохранённое сообщение, назначение + и готовая копия остаются. Недоступность пути не означает REJECT/EXPIRED/доставку. + Планировщик выбирает другой допустимый маршрут для того же peer и того же assignment_id. + Незавершённая FILE_TRANSFER получает новый transfer ID; это не новое назначение хранения. + При отсутствии пути работа ждёт, а первоначальный срок хранения продолжает идти. + + Worker занят локальным файлом, не выбранной группой; он не обращается к сети/SQLite. + Уже полученные байты можно проверить локально независимо от исчезновения сетевого маршрута. + Callback в uasync проверяет актуальность объекта, состояние удаления и deadline перед READY. + Начатая дисковая команда может закончиться; результат не возвращается по отозванному маршруту. + Новая сетевая работа требует нового допуска. Терминальное состояние копии не отменяется + поздним callback; cleanup разрешён и после потери доступа. Перезапуск не запускает второй + worker для тех же путей до завершения/отмены первого. Локальная история и готовые файлы сохраняются. + +7. Этапы реализации и обязательные проверки. + I. Отделить предметный допуск от маршрута в DM_MAILBOX/DM_MEDIA и выборе источников. + Убрать постоянную привязку к группе; роли искать независимо от группы пакета. + Проверить текстовый mailbox и прямое вложение через разные группы без общей группы всех узлов. + Одного этого этапа недостаточно для объявления custody изолированным. + II. Ввести assignment_id, список обращений на M и транзакционные переходы; изменить wire + и схему вместе, без слоя обратной совместимости. Развести статус назначения и источника. + Проверить дубли STORE, отказ/новую попытку, два S/один M, поздние ответы и SQL rollback. + III. Довести revalidate/callback/retry/cleanup; проверить сетевой стенд и весь ./check.sh. + Стенд: A/S/M/B соединены разными попарными группами, общей для всех нет; вторая группа + одной пары отзывается при живом ETCP. Прежнее назначение завершается через оставшийся путь. + Также: отзыв self, роли и третьего участника; отсутствие любого пути; поздние controls/DATA; + старый M после выбора нового; restart между commit/отправкой; прежний TTL; worker при удалении; + отказ в чужой группе до записи в БД/lookup/выдачи файла; сохранность MEMBER_FILES и локальной истории. + Диагностика каждого значимого перехода: file_id, assignment_id, self/peer, выбранная группа, + предыдущее/новое состояние, deadline и точная причина отказа/отмены. Пауза логируется при + изменении состояния, а не на каждом тике. Ошибки БД/диска/протокола не замалчиваются. + +Это архитектурный план по чтению кода и уточнению пользователя. Изменения mailbox/custody +и новые проверки из пунктов 1--7 ещё не реализованы; прежние результаты 65/65 и 240/240 +относятся только к описанным выше завершённым доработкам FILE_TRANSFER и прямого DM. diff --git a/doc/tasks.md b/doc/tasks.md index d5885cf57..0795e205b 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -45,8 +45,13 @@ Воспроизведены усечение файла до отказа, незакрытая операция и запись DM через отозванную живую сессию. Сетевой стенд65/65; test_dm_media17 фаз PASS, allocations0->0. Общий ./check.sh:240/240, proxy9/9, burst/load PASS (199с), /tmp/chat-personal-isolation-check.log. - Следующая граница mailbox/custody: повтор через B отвечает в B, но сохраняет старое назначение A; - усиление допуска требует атомарного пересогласования и защиты от поздних ответов A. Схема — в конце плана. + Следующая граница mailbox/custody: постоянные group_id/supernode смешивают маршрут и хранение. + По уточнению пользователя личные объекты передаются через любую доступную общую группу пары узлов; + общей группы автора/получателя/S/M не требуется. Назначение хранения сохраняется при смене маршрута. + Проект решения: предметные права отдельно от маршрута, assignment_id для точных ответов, + одна копия M и отдельные обращения S, неизменные TTL/политика, попарный выбор пути и отзыв сетевой работы. + Подробная схема и три этапа — в конце плана. Пока подготовлена только архитектура; + mailbox/custody не изменены, новые сценарии не запускались. Прежний 240/240 не подтверждает этот проект. Подмена источника, raw JOIN/invite, личные DM и оставшиеся сервисы ещё не закрыты общей гарантией; точная граница проверок — раздел 5 плана. План исправления и критерии по четырём этапам: [group_isolation_plan.txt](group_isolation_plan.txt).