Представьте дизайнера-фрилансера Лену. Вы пригласили её в проект «Редизайн сайта», создали ей учётную запись, она вошла и увидела свои задачи. Всё хорошо. Но с этого момента Лена — зарегистрированный пользователь всей системы, а не только одного проекта. И для каждого другого проекта у неё есть какой-то статус. Если она в нём не участник, система относит её к Non-member. Что именно этот статус ей даёт, зависит от одного свойства чужого проекта, и о нём стоит подумать до приглашения, а не после.

Эта статья — про то, как устроить доступ внешних исполнителей в OpenProject так, чтобы человек видел ровно тот проект, ради которого его позвали. Мы разберём разницу между учётной записью и ролью, роль публичности проекта, схему из трёх пользователей и двух проектов, три пути, которыми чужие данные могут просочиться (задачи, поиск, прямые ссылки), и аккуратное завершение сотрудничества.

Две разные вещи: учётная запись и роль в проекте

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

Из этого следует практическая вещь. Роль — не свойство человека, а свойство пары «человек + проект». Лена не «подрядчик вообще». Она, например, «исполнитель» в проекте A и вообще не участвует в проекте B. Поэтому разумно мыслить не списком людей, а таблицей пересечений: строки — люди, столбцы — проекты, в ячейках — роли или их отсутствие.

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

Публичный и закрытый проект: кому что видно на самом деле

Теперь главный поворот. В документации сказано: роль Non-member применяется к зарегистрированным пользователям вне состава проекта, но только если проект публичный. А роль Anonymous связана с публичным проектом и разрешённым доступом без входа в систему. Здесь легко запутаться, поэтому разложим по трём наблюдателям.

  • Участник проекта получает права своей проектной роли.
  • Зарегистрированный пользователь, не входящий в проект — это Non-member. Его права определяются одноимённой ролью, но лишь для публичного проекта. Если проект закрытый, эта роль к нему не применяется, и проект для такого пользователя не должен быть доступен.
  • Посетитель без входа — Anonymous. Его права тоже имеют смысл только для публичного проекта, и только в рамках того, что разрешено этой роли.

Отсюда понятная логика выбора. Если проект содержит что-то, что подрядчик из соседней истории видеть не должен, делайте его закрытым, и тогда права Non-member его не затрагивают. Если проект публичный, то для него значимы права Non-member и Anonymous, и вам придётся проверить, что настроено в этих ролях. Поэтому проверка начинается не с проекта, а с двух встроенных ролей: что им разрешено сейчас? Не нужно угадывать: откройте их в разделе ролей и посмотрите список отмеченных разрешений. Если там отмечено просмотр задач, значит, любой зарегистрированный внешний человек сможет читать задачи всех публичных проектов.

Разберём это на матрице из статьи. Допустим, проект A «Редизайн сайта» публичный, а в роли Non-member отмечен просмотр задач. Тогда Артём, который в A не участвует, но зарегистрирован в системе, получит право читать задачи A: его статус Non-member для публичного проекта работает по описанию ролей OpenProject. Если сделать A закрытым, та же настройка роли Non-member к нему уже не применяется. Получается, что одна галочка в роли и один переключатель публичности вместе определяют результат, и смотреть нужно на обе вещи сразу.

Есть и вторая оговорка про Anonymous. Эта роль имеет смысл только для публичного проекта, поэтому публичность проекта стоит считать решением с двумя адресатами: зарегистрированными посторонними и теми, кто вообще не входил в систему. Прежде чем отметить проект публичным ради удобства, спросите себя, готовы ли вы показать его содержимое обеим группам в объёме, который разрешён их ролям.

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

Матрица: три пользователя, два проекта

Возьмём условный пример. Есть два проекта: «Редизайн сайта» (проект A, внешний, с участием подрядчиков) и «Финансовая модель» (проект B, внутренний). Три пользователя: сотрудник Игорь, дизайнер Лена и разработчик Артём. Лена и Артём — внешние. Вот целевая картина.

Целевая матрица доступа: кто в каком проекте и с какой ролью
ПользовательПроект A «Редизайн сайта»Проект B «Финансовая модель»
Игорь (сотрудник)Участник, внутренняя рольУчастник, внутренняя роль
Лена (подрядчик)Участник, роль «Подрядчик»Не участник; проект закрыт, значит, права Non-member не применяются
Артём (подрядчик)Не участникНе участник; проект закрыт

Обратите внимание на среднюю строку. Лена в проекте B не участник, но она зарегистрирована в системе, и именно из-за этого её статус там Non-member. Что она увидит, определяет публичность проекта B. Закрытый проект — и роль Non-member к нему не применяется. Поэтому правило для матрицы такое: ячейка «не участник» безопасна только тогда, когда проект закрытый, либо когда вы проверили права Non-member и они вас устраивают.

Полезно прочитать матрицу по столбцам, а не только по строкам. Столбец проекта B: Игорь участник, Лена и Артём нет. Если B закрыт, у проекта ровно один круг читателей, и он совпадает со списком участников. Столбец проекта A: участвуют Игорь и Лена, а Артём числится посторонним. Здесь круг читателей зависит от публичности A. Если A закрыт, Артём не видит ничего. Если A публичный, Артём получает ровно то, что отмечено в роли Non-member.

Поэтому перед выдачей доступа можно задать каждому проекту два вопроса. Первый: кого я вижу в списке участников. Второй: что получит человек, которого в этом списке нет. Если на второй вопрос ответ «ничего», проект закрыт, и такая ячейка в матрице действительно безопасна. Если ответ другой, его нужно записать рядом с матрицей, иначе через месяц никто не вспомнит, почему Артём читает чужие задачи.

Теперь усложним: через месяц Лену нужно подключить и к проекту B, но только для одной узкой задачи, скажем, оформить презентацию для инвесторов. Здесь работает свойство ролей из документации: у одного человека разные роли в разных проектах. В проекте A у Лены остаётся «Подрядчик» с правом править задачи, а в проекте B ей можно назначить более узкую роль, например с правом просмотра и комментирования. Это отдельная роль, созданная под этот случай, а не расширение прав в проекте A. Так вы не получаете сквозного «суперподрядчика», а получаете две независимые записи в таблице пересечений.

Одна Лена, две роли
ПроектРоль ЛеныЧто это означает по замыслу
A «Редизайн сайта»ПодрядчикРаботает с задачами, пишет комментарии
B «Финансовая модель»Наблюдатель (узкая роль, придумана вами)Видит только то, что разрешено роли; остальные проекты ей по-прежнему недоступны

Названия ролей здесь условные: в OpenProject вы сами задаёте их и набор разрешений. Главное — не копировать роль «как у сотрудника» только потому, что так быстрее.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации Россия, США, Франция и Великобритания. Оплата картой РФ и по СБП.

АРЕНДОВАТЬ СЕРВЕР

Три пользовательских пути, которые надо проверить отдельно

Настроить роли и проверить, что доступа нет, — не одно и то же. Утечки редко происходят через ту дверь, которую вы закрывали. Поэтому проверка делается глазами внешнего пользователя, по нескольким независимым путям. Лучше завести тестовую учётную запись с ролью подрядчика (или войти в приватном окне под реальным подрядчиком с его согласия) и пройтись по ним по очереди.

Путь первый: списки и задачи

Войдите под подрядчиком и посмотрите, какие проекты он видит в списке проектов и в выпадающем меню навигации. Для матрицы выше Артём не должен видеть ни A, ни B. Лена должна видеть A и, при добавлении, B. Затем проверьте глобальные представления задач, если они есть в вашей установке: список «назначено мне», общий список рабочих пакетов, сохранённые запросы. Смысл проверки — убедиться, что задачи проекта, где человек не участник, не появляются в сводных видах. Документация ролей утверждает связь Non-member с публичностью, но не заменяет эксперимент: именно в сводных видах ошибка в настройках публичности проявляется заметнее всего.

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

Ожидания для проверки списков (проект B закрыт)
Под кем входимПроект AПроект B
ИгорьВиден, он участникВиден, он участник
ЛенаВиден, роль «Подрядчик»Не виден, пока её не добавили
АртёмЗависит от публичности A и прав Non-memberНе виден, проект закрыт

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

Путь второй: поиск

Поиск — это отдельный сценарий, потому что пользователь вводит слово, а не идёт по навигации. Заведите в закрытом проекте задачу с узнаваемым словом, которого нет больше нигде, скажем «Фиолетовый-Барсук-42». Затем под подрядчиком, который в этом проекте не участвует, выполните глобальный поиск по этому слову. Ожидаемый результат — пустая выдача. Если в выдаче что-то появилось, значит, либо проект публичный, либо права Non-member шире, чем вы думали. Проверьте и обратный случай: подрядчик-участник должен находить слово в своём проекте, иначе у него недостаточно прав на просмотр.

Путь третий: прямые ссылки

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

Отдельно стоит сказать про файлы. Поучительный пример даёт другой продукт: в документации BookStack по безопасности описано, что изображения по умолчанию размещаются с публичным доступом, что локальные вложения по умолчанию находятся за слоем авторизации приложения, а для хранилища S3 доступ зависит от настроек S3. Там же отмечено, что непредсказуемое имя картинки усложняет угадывание адреса, но не заменяет проверку прав пользователя. Это описание BookStack, а не OpenProject, и переносить его механику на вложения OpenProject нельзя. Но урок общий: красивая длинная ссылка не равна проверке прав. Поэтому для OpenProject сделайте собственный опыт: загрузите вложение в задачу закрытого проекта, скопируйте адрес вложения и откройте его без входа и под неучастником. Результат проверки на вашей установке и есть ответ; предположения о хранилище здесь не заменят наблюдения. Если вы выносите файлы во внешнее хранилище, проверьте его настройки доступа отдельно от прав в OpenProject.

Письма и уведомления: чужие данные в почтовом ящике

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

Когда подрядчик ушёл: завершить доступ, но сохранить историю

Работа закончилась. Есть два соблазна: удалить пользователя, чтобы «всё было чисто», или оставить всё как есть, чтобы не трогать. Первое рискует потерей контекста: в задачах, комментариях и журнале изменений остаются следы работы человека, и они полезны. Второе оставляет открытую дверь. Золотая середина: отозвать возможность действовать, но не стирать след.

Порядок можно выстроить так.

  1. Переназначьте открытые задачи. Всё, что назначено на подрядчика и ещё не закрыто, передайте сотруднику или закройте. Иначе в проекте останутся задачи с исполнителем, который уже не отвечает.
  2. Уберите членство в проекте. Откройте список участников проекта и удалите Лену из A (и из B, если она там была). Из матрицы исчезает её строка в этом проекте.
  3. Заблокируйте учётную запись или оставьте её без членств. Возможности администрирования пользователей смотрите в разделе пользователей вашей установки: нужно именно прекратить вход или лишить прав, а не стирать профиль. Что будет с отображением имени в старых записях при каждом варианте, проверьте на тестовом пользователе, а не по памяти.
  4. Повторите три пути проверки. Под тестовой учётной записью с теми же признаками убедитесь, что поиск, списки и прямые ссылки уже не открывают то, что открывали. Ревизия после отзыва — тот же эксперимент, что и при выдаче доступа, только с обратным ожидаемым результатом.
  5. Отдельно просмотрите внешние места. Если задачи или файлы пересылались вне системы, например, через хранилище или общие ссылки в другом сервисе, отзыв членства в OpenProject их не закроет. Это нужно сделать там, где они лежат.

После такой процедуры имя подрядчика остаётся в истории задач как автор решений, а ключи от дверей — нет. Через полгода, когда кто-то спросит, почему в макете именно такой отступ, ответ найдётся в комментарии Лены.

Где всё это живёт и сколько ему нужно ресурсов

Схема ролей не зависит от сервера, но от него зависит, насколько спокойно вы можете проверять всё это на настоящей копии системы. Если вы хотите держать OpenProject на собственном сервере, а не в чужом облаке, подойдёт VPS MAATRIX: в публичном предложении указаны NVMe-диски, процессоры AMD EPYC и root-доступ, а локации перечислены как UK, US, RU и FR. Тарифная линейка начинается с Ba (1 vCPU, 2 ГБ RAM, 40 ГБ NVMe) и идёт через Uab (2 vCPU, 4 ГБ, 80 ГБ), Heka (4 vCPU, 8 ГБ, 160 ГБ), Maat (8 vCPU, 16 ГБ, 240 ГБ) до Djed (16 vCPU, 32 ГБ, 320 ГБ). Это заявленные ресурсы сервера, а не обещание, сколько одновременных пользователей выдержит ваша установка: нагрузку нужно мерить на своих данных. Оплата возможна картой РФ и через СБП, а VPS создаётся автоматически через пару минут после оплаты.

Для темы доступа подрядчиков отдельный сервер даёт одно практическое удобство: вы можете развернуть второй, тестовый экземпляр, завести там копию структуры ролей и проектов и безопасно проверять матрицу, не трогая рабочих исполнителей. Про сам процесс установки читайте в статье как установить и настроить OpenProject на VPS.

Что остаётся подрядчику

Вернёмся к Лене. После всей настройки её учётная запись по-прежнему существует в системе, и в любом проекте у неё есть формальный статус. Но этот статус теперь пуст: закрытые проекты не открывают Non-member ничего, права Non-member в публичных проектах вы просмотрели и они вас устраивают, поиск по чужим словам возвращает пустоту, а чужая прямая ссылка упирается в отказ. Остаётся один проект «Редизайн сайта», роль «Подрядчик» и набор действий: смотреть свои задачи, обсуждать, отчитываться. Ровно то, ради чего её пригласили, и ничего сверх этого.