Перейти к основному содержанию

Обзор

Роль — это набор разрешений: какие объекты приложение может читать или изменять, какие поля оно может видеть и какие возможности платформенного уровня оно может использовать. Функции логики и фронтенд‑компоненты каждого приложения наследуют разрешения роли, помеченной с помощью defineApplicationRole() (см. раздел Роль функции по умолчанию ниже).
src/roles/restricted-company-role.ts
SystemPermissionFlag.USER_APPS и SystemPermissionFlag.WORKSPACE_APPS доступны в twenty-sdk начиная с версии 2.54; в более ранних версиях они называются CONNECTED_ACCOUNTS и APPLICATIONS. Старые имена являются устаревшими псевдонимами для тех же флагов, и роль содержит каждый флаг только один раз. Перечисление SystemPermissionFlag, например с помощью Object.keys, по-прежнему включает старые имена. API также сообщает об этих флагах под их старыми ключами, например в currentUserWorkspace.permissionFlags.

Безопасность на уровне строк

Для разрешений на уровне строк требуется план Organization или выше — см. тарифы. Что происходит при использовании плана без соответствующего права, описано в примечаниях в конце этого раздела. Разрешения на объекты и поля определяют, к каким объектам и полям у роли есть доступ. Предикаты прав доступа на уровне строк заходят дальше и определяют, какие записи роль может видеть и с которыми может работать — например, для роли самообслуживания, где каждый внешний пользователь видит только свои собственные записи. Объявляйте предикаты с помощью rowLevelPermissionPredicates в роли. Как и остальная часть манифеста, каждый предикат имеет свой собственный universalIdentifier и ссылается на объект и поле по их universalIdentifier, operand, а также (необязательно) поле workspaceMember, значение которого подставляется во время выполнения запроса — чтобы вы могли выразить: “отношение владельца записи является текущим участником рабочей области”:
src/roles/partner-role.ts
Поскольку предикаты поставляются в манифесте, они создаются, обновляются и удаляются вместе с ролью при каждой установке и обновлении — не требуется отдельный шаг после установки для поддержания синхронизации.

Комбинирование предикатов с группами

По умолчанию предикаты роли комбинируются с помощью AND. Чтобы комбинировать некоторые из них с помощью OR (или вкладывать логику), объявите запись rowLevelPermissionPredicateGroups и укажите на неё каждый предикат через predicateGroupUniversalIdentifier. Эта роль позволяет партнёру видеть сделку, которая либо принадлежит ему, либо по которой он является контактным лицом:
src/roles/partner-opportunities-role.ts
Заметки:
  • Присвойте каждому предикату и группе стабильный universalIdentifier (любой uuid) — он служит ключом сущности между обновлениями, а предикаты ссылаются на группы по нему.
  • Предикаты могут ссылаться на объекты и поля, принадлежащие вашему приложению, или на стандартные объекты и поля Twenty.
  • Безопасность на уровне строк применяется к рабочим пространствам на плане Organization или выше. В других планах предикаты, объявленные в манифесте приложения, по-прежнему синхронизируются, но не применяются.
  • API метаданных здесь ведёт себя иначе, чем манифест: без соответствующего права upsertRowLevelPermissionPredicates отклоняется с ошибкой ROW_LEVEL_PERMISSION_FEATURE_DISABLED вместо синхронизации. Следовательно, рабочее пространство на плане, который не включает безопасность на уровне строк, не может создавать предикаты вне манифеста приложения, даже несмотря на то, что поле rowLevelPermissionPredicates присутствует в типе Role при интроспекции схемы.

Роль функции по умолчанию

Когда вы создаёте новое приложение с помощью шаблона, CLI создаёт файл роли по умолчанию, объявленный с помощью defineApplicationRole():
src/roles/default-role.ts
defineApplicationRole() — это тонкая обёртка вокруг defineRole(), которая помечает ту роль, которая используется как роль приложения по умолчанию во время установки. Проверка идентична defineRole, но конвейер сборки автоматически подключает его universalIdentifier к полю defaultRoleUniversalIdentifier манифеста приложения — поэтому вам не нужно ссылаться на него из defineApplication самостоятельно. Заметки:
  • Допускается ровно один вызов defineApplicationRole(...) на приложение — сборка манифеста завершится с ошибкой, если будет найдено более одного.
  • Используйте defineRole() (а не defineApplicationRole()) для любых дополнительных ролей, которые ставятся вместе с вашим приложением.
  • Явная установка defaultRoleUniversalIdentifier в defineApplication() всё ещё поддерживается для обратной совместимости, но считается устаревшей по сравнению с defineApplicationRole(). Он также может указывать роль, которую ваше приложение не определяет, например встроенную роль по умолчанию пользовательского приложения рабочего пространства, сохраняемую командой twenty app pull; в таком случае сборка не может проверить эту роль, поэтому она должна существовать в целевом рабочем пространстве.
  • Роль, которую можно назначать участникам рабочего пространства или ключам API (canBeAssignedToUsers или canBeAssignedToApiKeys, оба значения true, если они не указаны), является пользовательской ролью и требует план Organization или выше: на других планах установка отклоняется. Оставьте оба значения false для ролей, от имени которых работают только ваше приложение и его агенты.

Роли агентов

Роль приложения — это то, что рабочее пространство проверяет при установке вашего приложения, поэтому она должна охватывать всё, что может делать само приложение. Любая роль, которую вы назначаете агенту через roleUniversalIdentifier в defineAgent(), не должна предоставлять больше прав, чем роль приложения: никаких действий с объектами, доступа к полям, флагов разрешений или областей действия на уровне строк, которых нет у роли приложения. Если это не так, сборка завершается с ошибкой, в которой перечислены избыточные предоставленные права. Роли, которые ваше приложение предоставляет для участников рабочего пространства или ключей API, не подпадают под это правило, поскольку приложение никогда не запускается с ними. Для проверки необходима роль приложения в исходном коде вашего приложения, поэтому она пропускается, когда роль по умолчанию определена в другом месте.

Лучшие практики

  • Начните с сгенерированной роли и постепенно ограничивайте её — роль по умолчанию предоставляет широкий доступ на чтение, что редко подходит для продакшена.
  • Замените objectPermissions и fieldPermissions на точные объекты и поля, которые действительно нужны вашим функциям.
  • permissionFlagUniversalIdentifiers управляют доступом к возможностям на уровне платформы. Сведите их к минимуму.
  • Флаг разрешения, объявляемый вашим приложением с помощью definePermissionFlag(), имеет permissionType: 'tool' (по умолчанию) для возможности, которая может быть предоставлена агенту или пользователю, и 'settings' для флага, открывающего область настроек.
  • Смотрите рабочий пример: examples/hello-world/src/roles/default-role.ts.