@objectstack/plugin-security 9.10.0 → 9.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/translations/en.objects.generated.ts","../src/translations/zh-CN.objects.generated.ts","../src/translations/ja-JP.objects.generated.ts","../src/translations/es-ES.objects.generated.ts","../src/translations/index.ts","../src/permission-evaluator.ts","../src/rls-compiler.ts","../src/field-masker.ts","../src/errors.ts","../src/bootstrap-platform-admin.ts","../src/claim-seed-ownership.ts","../src/auto-org-admin-grant.ts","../src/objects/sys-role.object.ts","../src/objects/sys-permission-set.object.ts","../src/objects/sys-user-permission-set.object.ts","../src/objects/sys-role-permission-set.object.ts","../src/objects/default-permission-sets.ts","../src/manifest.ts","../src/security-plugin.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'en'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const enObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"Role\",\n pluralLabel: \"Roles\",\n description: \"Role definitions for RBAC access control\",\n fields: {\n label: {\n label: \"Display Name\"\n },\n name: {\n label: \"API Name\",\n help: \"Unique machine name for the role (e.g. admin, editor, viewer)\"\n },\n description: {\n label: \"Description\"\n },\n permissions: {\n label: \"Permissions\",\n help: \"JSON-serialized array of permission strings\"\n },\n active: {\n label: \"Active\"\n },\n is_default: {\n label: \"Default Role\",\n help: \"Automatically assigned to new users\"\n },\n id: {\n label: \"Role ID\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\"\n },\n default_roles: {\n label: \"Default\"\n },\n custom: {\n label: \"Custom\"\n },\n all_roles: {\n label: \"All\"\n }\n },\n _actions: {\n activate_role: {\n label: \"Activate Role\",\n successMessage: \"Role activated\"\n },\n deactivate_role: {\n label: \"Deactivate Role\",\n confirmText: \"Deactivate this role? Users with the role keep their assignment but the role stops granting permissions until re-activated.\",\n successMessage: \"Role deactivated\"\n },\n set_default_role: {\n label: \"Set as Default\",\n confirmText: \"Make this the default role for new users? Existing users are unaffected.\",\n successMessage: \"Default role updated\"\n },\n clone_role: {\n label: \"Clone Role\",\n successMessage: \"Role cloned\"\n }\n }\n },\n sys_permission_set: {\n label: \"Permission Set\",\n pluralLabel: \"Permission Sets\",\n description: \"Named permission groupings for fine-grained access control\",\n fields: {\n label: {\n label: \"Display Name\"\n },\n name: {\n label: \"API Name\",\n help: \"Unique machine name for the permission set\"\n },\n description: {\n label: \"Description\"\n },\n object_permissions: {\n label: \"Object Permissions\",\n help: \"JSON-serialized object-level CRUD permissions\"\n },\n field_permissions: {\n label: \"Field Permissions\",\n help: \"JSON-serialized field-level read/write permissions\"\n },\n system_permissions: {\n label: \"System Permissions\",\n help: \"JSON-serialized array of system capability names (e.g. [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"Row-Level Security\",\n help: \"JSON-serialized array of row-level security policies (USING/CHECK clauses)\"\n },\n tab_permissions: {\n label: \"Tab Permissions\",\n help: \"JSON-serialized map of app tab visibility (visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"Active\"\n },\n id: {\n label: \"Permission Set ID\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\"\n },\n inactive: {\n label: \"Inactive\"\n },\n all_permsets: {\n label: \"All\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"Activate\",\n successMessage: \"Permission set activated\"\n },\n deactivate_permission_set: {\n label: \"Deactivate\",\n confirmText: \"Deactivate this permission set? Existing assignments stay in place but stop granting access until re-activated.\",\n successMessage: \"Permission set deactivated\"\n },\n clone_permission_set: {\n label: \"Clone\",\n successMessage: \"Permission set cloned\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"User Permission Set\",\n pluralLabel: \"User Permission Sets\",\n description: \"Direct assignment of a permission set to a user (optionally scoped to an organization).\",\n fields: {\n id: {\n label: \"Assignment ID\",\n help: \"UUID of the assignment.\"\n },\n user_id: {\n label: \"User\",\n help: \"Foreign key to sys_user.\"\n },\n permission_set_id: {\n label: \"Permission Set\",\n help: \"Foreign key to sys_permission_set.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Optional organization scope. NULL = applies in every org context.\"\n },\n granted_by: {\n label: \"Granted By\",\n help: \"User who granted this permission set.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"Role Permission Set\",\n pluralLabel: \"Role Permission Sets\",\n description: \"Binds a permission set to a role.\",\n fields: {\n id: {\n label: \"Binding ID\",\n help: \"UUID of the role-permission-set binding.\"\n },\n role_id: {\n label: \"Role\",\n help: \"Foreign key to sys_role.\"\n },\n permission_set_id: {\n label: \"Permission Set\",\n help: \"Foreign key to sys_permission_set.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'zh-CN'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const zhCNObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"角色\",\n pluralLabel: \"角色\",\n description: \"用于 RBAC 访问控制的角色定义\",\n fields: {\n label: {\n label: \"显示名称\"\n },\n name: {\n label: \"API 名称\",\n help: \"角色的唯一机器名称(例如 admin、editor、viewer)\"\n },\n description: {\n label: \"描述\"\n },\n permissions: {\n label: \"权限\",\n help: \"权限字符串数组的 JSON 序列化内容\"\n },\n active: {\n label: \"启用\"\n },\n is_default: {\n label: \"默认角色\",\n help: \"自动分配给新用户\"\n },\n id: {\n label: \"角色 ID\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n active: {\n label: \"启用\"\n },\n default_roles: {\n label: \"默认\"\n },\n custom: {\n label: \"自定义\"\n },\n all_roles: {\n label: \"全部\"\n }\n },\n _actions: {\n activate_role: {\n label: \"激活角色\",\n successMessage: \"角色已激活\"\n },\n deactivate_role: {\n label: \"停用角色\",\n confirmText: \"确定要停用此角色吗?拥有该角色的用户仍保留其分配,但在重新激活之前该角色将不再授予权限。\",\n successMessage: \"角色已停用\"\n },\n set_default_role: {\n label: \"设为默认\",\n confirmText: \"将此角色设为新用户的默认角色吗?现有用户不受影响。\",\n successMessage: \"已更新默认角色\"\n },\n clone_role: {\n label: \"克隆角色\",\n successMessage: \"已克隆角色\"\n }\n }\n },\n sys_permission_set: {\n label: \"权限集\",\n pluralLabel: \"权限集\",\n description: \"用于精细化访问控制的命名权限分组\",\n fields: {\n label: {\n label: \"显示名称\"\n },\n name: {\n label: \"API 名称\",\n help: \"权限集的唯一机器名称\"\n },\n description: {\n label: \"描述\"\n },\n object_permissions: {\n label: \"对象权限\",\n help: \"对象级 CRUD 权限的 JSON 序列化内容\"\n },\n field_permissions: {\n label: \"字段权限\",\n help: \"字段级读写权限的 JSON 序列化内容\"\n },\n system_permissions: {\n label: \"系统权限\",\n help: \"系统能力名称的 JSON 序列化数组(例如 [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"行级安全\",\n help: \"行级安全策略的 JSON 序列化数组(USING/CHECK 子句)\"\n },\n tab_permissions: {\n label: \"标签页权限\",\n help: \"应用标签页可见性的 JSON 序列化映射(visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"启用\"\n },\n id: {\n label: \"权限集 ID\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n active: {\n label: \"启用\"\n },\n inactive: {\n label: \"停用\"\n },\n all_permsets: {\n label: \"全部\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"激活\",\n successMessage: \"权限集已激活\"\n },\n deactivate_permission_set: {\n label: \"停用\",\n confirmText: \"确定要停用此权限集吗?现有分配仍将保留,但在重新激活之前将不再授予访问权限。\",\n successMessage: \"权限集已停用\"\n },\n clone_permission_set: {\n label: \"克隆\",\n successMessage: \"已克隆权限集\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"用户权限集\",\n pluralLabel: \"用户权限集\",\n description: \"将权限集直接分配给用户(可按组织范围限定)。\",\n fields: {\n id: {\n label: \"分配 ID\",\n help: \"该分配记录的 UUID。\"\n },\n user_id: {\n label: \"用户\",\n help: \"指向 sys_user 的外键。\"\n },\n permission_set_id: {\n label: \"权限集\",\n help: \"指向 sys_permission_set 的外键。\"\n },\n organization_id: {\n label: \"组织\",\n help: \"可选的组织范围。NULL = 在所有组织上下文中都生效。\"\n },\n granted_by: {\n label: \"授权人\",\n help: \"授予该权限集的用户。\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"角色权限集\",\n pluralLabel: \"角色权限集\",\n description: \"将权限集绑定到角色。\",\n fields: {\n id: {\n label: \"绑定 ID\",\n help: \"角色-权限集绑定记录的 UUID。\"\n },\n role_id: {\n label: \"角色\",\n help: \"指向 sys_role 的外键。\"\n },\n permission_set_id: {\n label: \"权限集\",\n help: \"指向 sys_permission_set 的外键。\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'ja-JP'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const jaJPObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"ロール\",\n pluralLabel: \"ロール\",\n description: \"RBAC アクセス制御のためのロール定義\",\n fields: {\n label: {\n label: \"表示名\"\n },\n name: {\n label: \"API 名\",\n help: \"ロールの一意の機械名(例: admin、editor、viewer)\"\n },\n description: {\n label: \"説明\"\n },\n permissions: {\n label: \"権限\",\n help: \"権限文字列の JSON シリアライズ配列\"\n },\n active: {\n label: \"有効\"\n },\n is_default: {\n label: \"デフォルトロール\",\n help: \"新規ユーザーに自動的に割り当てられます\"\n },\n id: {\n label: \"ロール ID\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n },\n _views: {\n active: {\n label: \"有効\"\n },\n default_roles: {\n label: \"デフォルト\"\n },\n custom: {\n label: \"カスタム\"\n },\n all_roles: {\n label: \"すべて\"\n }\n },\n _actions: {\n activate_role: {\n label: \"ロールを有効化\",\n successMessage: \"ロールが有効化されました\"\n },\n deactivate_role: {\n label: \"ロールを無効化\",\n confirmText: \"このロールを無効化しますか?このロールを持つユーザーの割り当ては維持されますが、再度有効化するまで権限の付与は停止されます。\",\n successMessage: \"ロールが無効化されました\"\n },\n set_default_role: {\n label: \"デフォルトに設定\",\n confirmText: \"このロールを新規ユーザーのデフォルトロールにしますか?既存のユーザーには影響しません。\",\n successMessage: \"デフォルトロールを更新しました\"\n },\n clone_role: {\n label: \"ロールを複製\",\n successMessage: \"ロールを複製しました\"\n }\n }\n },\n sys_permission_set: {\n label: \"権限セット\",\n pluralLabel: \"権限セット\",\n description: \"細かいアクセス制御のための権限グループ\",\n fields: {\n label: {\n label: \"表示名\"\n },\n name: {\n label: \"API 名\",\n help: \"権限セットの一意の機械名\"\n },\n description: {\n label: \"説明\"\n },\n object_permissions: {\n label: \"オブジェクト権限\",\n help: \"JSON シリアライズされたオブジェクトレベルの CRUD 権限\"\n },\n field_permissions: {\n label: \"フィールド権限\",\n help: \"JSON シリアライズされたフィールドレベルの読み取り/書き込み権限\"\n },\n system_permissions: {\n label: \"システム権限\",\n help: \"システムケーパビリティ名のJSONシリアライズ配列(例: [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"行レベルセキュリティ\",\n help: \"行レベルセキュリティポリシーのJSONシリアライズ配列(USING/CHECK 句)\"\n },\n tab_permissions: {\n label: \"タブ権限\",\n help: \"アプリのタブ表示のJSONシリアライズマップ(visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"有効\"\n },\n id: {\n label: \"権限セット ID\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n },\n _views: {\n active: {\n label: \"有効\"\n },\n inactive: {\n label: \"無効\"\n },\n all_permsets: {\n label: \"すべて\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"有効化\",\n successMessage: \"権限セットが有効化されました\"\n },\n deactivate_permission_set: {\n label: \"無効化\",\n confirmText: \"この権限セットを無効化しますか?既存の割り当ては維持されますが、再度有効化するまでアクセスの付与は停止されます。\",\n successMessage: \"権限セットが無効化されました\"\n },\n clone_permission_set: {\n label: \"複製\",\n successMessage: \"権限セットを複製しました\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"ユーザー権限セット\",\n pluralLabel: \"ユーザー権限セット\",\n description: \"ユーザーへの権限セットの直接割り当て(組織スコープ可能)。\",\n fields: {\n id: {\n label: \"割り当て ID\",\n help: \"割り当ての UUID。\"\n },\n user_id: {\n label: \"ユーザー\",\n help: \"sys_user への外部キー。\"\n },\n permission_set_id: {\n label: \"権限セット\",\n help: \"sys_permission_set への外部キー。\"\n },\n organization_id: {\n label: \"組織\",\n help: \"オプションの組織スコープ。NULL = すべての組織コンテキストで適用。\"\n },\n granted_by: {\n label: \"付与者\",\n help: \"この権限セットを付与したユーザー。\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"ロール権限セット\",\n pluralLabel: \"ロール権限セット\",\n description: \"権限セットをロールにバインドします。\",\n fields: {\n id: {\n label: \"バインド ID\",\n help: \"ロール権限セットバインドの UUID。\"\n },\n role_id: {\n label: \"ロール\",\n help: \"sys_role への外部キー。\"\n },\n permission_set_id: {\n label: \"権限セット\",\n help: \"sys_permission_set への外部キー。\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'es-ES'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const esESObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"Rol\",\n pluralLabel: \"Roles\",\n description: \"Definiciones de rol para el control de acceso RBAC\",\n fields: {\n label: {\n label: \"Nombre visible\"\n },\n name: {\n label: \"Nombre de API\",\n help: \"Nombre técnico único del rol (p. ej. admin, editor, viewer).\"\n },\n description: {\n label: \"Descripción\"\n },\n permissions: {\n label: \"Permisos\",\n help: \"Matriz serializada en JSON de cadenas de permisos.\"\n },\n active: {\n label: \"Activo\"\n },\n is_default: {\n label: \"Rol predeterminado\",\n help: \"Se asigna automáticamente a los nuevos usuarios.\"\n },\n id: {\n label: \"ID de rol\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n },\n _views: {\n active: {\n label: \"Activo\"\n },\n default_roles: {\n label: \"Predeterminado\"\n },\n custom: {\n label: \"Personalizado\"\n },\n all_roles: {\n label: \"Todos\"\n }\n },\n _actions: {\n activate_role: {\n label: \"Activar rol\",\n successMessage: \"Rol activado\"\n },\n deactivate_role: {\n label: \"Desactivar rol\",\n confirmText: \"¿Desactivar este rol? Los usuarios con el rol conservan su asignación, pero el rol deja de otorgar permisos hasta que se vuelva a activar.\",\n successMessage: \"Rol desactivado\"\n },\n set_default_role: {\n label: \"Establecer como predeterminado\",\n confirmText: \"¿Convertir este en el rol predeterminado para los nuevos usuarios? Los usuarios existentes no se ven afectados.\",\n successMessage: \"Rol predeterminado actualizado\"\n },\n clone_role: {\n label: \"Clonar rol\",\n successMessage: \"Rol clonado\"\n }\n }\n },\n sys_permission_set: {\n label: \"Conjunto de permisos\",\n pluralLabel: \"Conjuntos de permisos\",\n description: \"Agrupaciones de permisos con nombre para un control de acceso detallado\",\n fields: {\n label: {\n label: \"Nombre visible\"\n },\n name: {\n label: \"Nombre de API\",\n help: \"Nombre técnico único del conjunto de permisos.\"\n },\n description: {\n label: \"Descripción\"\n },\n object_permissions: {\n label: \"Permisos de objeto\",\n help: \"Permisos CRUD a nivel de objeto serializados en JSON.\"\n },\n field_permissions: {\n label: \"Permisos de campo\",\n help: \"Permisos de lectura/escritura a nivel de campo serializados en JSON.\"\n },\n system_permissions: {\n label: \"Permisos del sistema\",\n help: \"Array serializado en JSON de nombres de capacidades del sistema (p. ej. [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"Seguridad a nivel de fila\",\n help: \"Array serializado en JSON de políticas de seguridad a nivel de fila (cláusulas USING/CHECK)\"\n },\n tab_permissions: {\n label: \"Permisos de pestañas\",\n help: \"Mapa serializado en JSON de la visibilidad de las pestañas de la app (visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"Activo\"\n },\n id: {\n label: \"ID de conjunto de permisos\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n },\n _views: {\n active: {\n label: \"Activo\"\n },\n inactive: {\n label: \"Inactivo\"\n },\n all_permsets: {\n label: \"Todos\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"Activar\",\n successMessage: \"Conjunto de permisos activado\"\n },\n deactivate_permission_set: {\n label: \"Desactivar\",\n confirmText: \"¿Desactivar este conjunto de permisos? Las asignaciones existentes se mantienen, pero dejan de otorgar acceso hasta que se vuelva a activar.\",\n successMessage: \"Conjunto de permisos desactivado\"\n },\n clone_permission_set: {\n label: \"Clonar\",\n successMessage: \"Conjunto de permisos clonado\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"Conjunto de permisos de usuario\",\n pluralLabel: \"Conjuntos de permisos de usuario\",\n description: \"Asignación directa de un conjunto de permisos a un usuario (opcionalmente con ámbito de organización).\",\n fields: {\n id: {\n label: \"ID de asignación\",\n help: \"UUID de la asignación.\"\n },\n user_id: {\n label: \"Usuario\",\n help: \"Clave foránea a sys_user.\"\n },\n permission_set_id: {\n label: \"Conjunto de permisos\",\n help: \"Clave foránea a sys_permission_set.\"\n },\n organization_id: {\n label: \"Organización\",\n help: \"Ámbito de organización opcional. NULL = se aplica en cualquier contexto de organización.\"\n },\n granted_by: {\n label: \"Concedido por\",\n help: \"Usuario que concedió este conjunto de permisos.\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"Conjunto de permisos de rol\",\n pluralLabel: \"Conjuntos de permisos de rol\",\n description: \"Vincula un conjunto de permisos a un rol.\",\n fields: {\n id: {\n label: \"ID de vinculación\",\n help: \"UUID de la vinculación rol-conjunto de permisos.\"\n },\n role_id: {\n label: \"Rol\",\n help: \"Clave foránea a sys_role.\"\n },\n permission_set_id: {\n label: \"Conjunto de permisos\",\n help: \"Clave foránea a sys_permission_set.\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n }\n }\n};\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * SecurityTranslations — i18n bundle owned by this plugin (ADR-0029 D8).\n *\n * Object label/field/view/action translations for the sys_* objects this\n * plugin owns. Loaded at runtime via the plugin's `kernel:ready` hook\n * (`i18n.loadTranslations`). Regenerate with `os i18n extract` against\n * `scripts/i18n-extract.config.ts`.\n */\n\nimport type { TranslationBundle } from '@objectstack/spec/system';\nimport { enObjects } from './en.objects.generated.js';\nimport { zhCNObjects } from './zh-CN.objects.generated.js';\nimport { jaJPObjects } from './ja-JP.objects.generated.js';\nimport { esESObjects } from './es-ES.objects.generated.js';\n\nexport const SecurityTranslations: TranslationBundle = {\n en: { objects: enObjects },\n 'zh-CN': { objects: zhCNObjects },\n 'ja-JP': { objects: jaJPObjects },\n 'es-ES': { objects: esESObjects },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { PermissionSet, ObjectPermission, FieldPermission } from '@objectstack/spec/security';\n\n/**\n * Operation type mapping to permission checks\n */\nconst OPERATION_TO_PERMISSION: Record<string, keyof ObjectPermission> = {\n find: 'allowRead',\n findOne: 'allowRead',\n count: 'allowRead',\n aggregate: 'allowRead',\n insert: 'allowCreate',\n update: 'allowEdit',\n delete: 'allowDelete',\n};\n\n/**\n * Destructive operation class — operations that must FAIL CLOSED when they are\n * not mapped to a concrete permission key. See ADR-0049: an unrecognised\n * destructive operation (e.g. a future `transfer`/`restore`/`purge` added\n * without a matching `OPERATION_TO_PERMISSION` entry, gated by the spec's\n * `allowTransfer`/`allowRestore`/`allowPurge` bits) must be DENIED rather than\n * silently allowed by the default-allow fallthrough. Non-destructive unknown\n * operations retain default-allow so custom read-side operations are not broken.\n */\nconst DESTRUCTIVE_OPERATIONS = new Set<string>(['transfer', 'restore', 'purge']);\n\n/**\n * PermissionEvaluator\n * \n * Runtime evaluator for PermissionSet definitions.\n * Resolves aggregated permissions from roles to concrete allow/deny decisions.\n */\nexport class PermissionEvaluator {\n /**\n * Check if an operation is allowed on an object for the given permission sets.\n * Uses \"most permissive\" merging: if ANY permission set allows, it's allowed.\n */\n checkObjectPermission(\n operation: string,\n objectName: string,\n permissionSets: PermissionSet[]\n ): boolean {\n const permKey = OPERATION_TO_PERMISSION[operation];\n if (!permKey) {\n // Fail CLOSED for the destructive operation class (ADR-0049): an\n // unrecognised destructive op must be denied, never silently allowed.\n // Other unknown operations are allowed by default.\n return !DESTRUCTIVE_OPERATIONS.has(operation);\n }\n\n for (const ps of permissionSets) {\n // Honour the `'*'` wildcard sentinel — admin permission sets typically\n // grant blanket access via a single `objects: { '*': … }` entry rather\n // than enumerating every system object.\n const objPerm = ps.objects?.[objectName] ?? ps.objects?.['*'];\n if (objPerm) {\n // Check if modifyAllRecords is set (super-user bypass for write ops)\n if (['allowEdit', 'allowDelete'].includes(permKey) && objPerm.modifyAllRecords) {\n return true;\n }\n // Check if viewAllRecords is set (super-user bypass for read ops)\n if (permKey === 'allowRead' && (objPerm.viewAllRecords || objPerm.modifyAllRecords)) {\n return true;\n }\n // Check the specific permission\n if (objPerm[permKey]) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Get the merged field permissions for an object.\n * Returns a map of field names to their effective permissions.\n * Uses \"most permissive\" merging.\n */\n getFieldPermissions(\n objectName: string,\n permissionSets: PermissionSet[]\n ): Record<string, FieldPermission> {\n const result: Record<string, FieldPermission> = {};\n\n for (const ps of permissionSets) {\n if (!ps.fields) continue;\n\n for (const [key, perm] of Object.entries(ps.fields)) {\n // Field keys are in format: \"object_name.field_name\"\n if (!key.startsWith(`${objectName}.`)) continue;\n const fieldName = key.substring(objectName.length + 1);\n\n if (!result[fieldName]) {\n result[fieldName] = { readable: false, editable: false };\n }\n\n // Most permissive merge\n if (perm.readable) result[fieldName].readable = true;\n if (perm.editable) result[fieldName].editable = true;\n }\n }\n\n return result;\n }\n\n /**\n * Resolve permission sets for a list of identifier names from metadata.\n *\n * Identifiers are matched to `PermissionSet.name`. The names may be\n * either role names (when `sys_role.name` is reused as a permission set\n * name — common for default admin/member/viewer roles) or explicit\n * permission set names supplied through `ExecutionContext.permissions[]`\n * (resolved by `resolveExecutionContext` from `sys_user_permission_set`\n * and `sys_role_permission_set`).\n *\n * Async because the underlying metadata service exposes `list()` as a\n * Promise — synchronous iteration would silently yield zero results\n * (the historical SecurityPlugin behaviour, masking all enforcement).\n *\n * `bootstrapPermissionSets` is a fallback list of plugin-owned permission\n * sets (typically the platform defaults: admin_full_access /\n * member_default / viewer_readonly) that are registered via\n * `manifest.register({ permissions })` but do not currently propagate\n * into the metadata service's `list()` index. Without this fallback,\n * SecurityPlugin would never resolve the defaults and all enforcement\n * would be silently disabled for authenticated requests.\n */\n async resolvePermissionSets(\n identifiers: string[],\n metadataService: any,\n bootstrapPermissionSets: PermissionSet[] = [],\n /**\n * Optional async loader for permission set names that aren't found in\n * metadata or bootstrap. Lets callers query user-defined permission\n * sets persisted in `sys_permission_set`. Failures are swallowed.\n */\n dbLoader?: (unresolved: string[]) => Promise<PermissionSet[]>\n ): Promise<PermissionSet[]> {\n if (identifiers.length === 0) return [];\n\n const result: PermissionSet[] = [];\n const seen = new Set<string>();\n\n // Get all permission sets from metadata. Support both async (Manager) and\n // sync (test stub) implementations of `list`.\n let allPermSets: any = [];\n try {\n const listed = metadataService?.list?.('permission')\n ?? metadataService?.list?.('permissions')\n ?? [];\n allPermSets = typeof (listed as any)?.then === 'function' ? await listed : listed;\n } catch {\n allPermSets = [];\n }\n if (!Array.isArray(allPermSets)) allPermSets = [];\n\n const wanted = new Set(identifiers);\n for (const ps of allPermSets) {\n if (wanted.has(ps.name) && !seen.has(ps.name)) {\n seen.add(ps.name);\n result.push(ps);\n }\n }\n\n // Fallback: any wanted name not yet matched is sourced from the\n // bootstrap list (plugin-owned defaults). Avoids silent failure when\n // permission sets are registered via `manifest.register` but the\n // metadata service hasn't indexed them.\n for (const ps of bootstrapPermissionSets) {\n if (wanted.has(ps.name) && !seen.has(ps.name)) {\n seen.add(ps.name);\n result.push(ps);\n }\n }\n\n // Last-resort: query user-defined permission sets from the database.\n // Without this, custom permission sets (created via the admin UI as\n // `sys_permission_set` rows) would be silently ignored both for CRUD\n // enforcement and for field-level masking.\n if (dbLoader) {\n const unresolved = identifiers.filter((n) => !seen.has(n));\n if (unresolved.length > 0) {\n try {\n const dbRows = await dbLoader(unresolved);\n for (const ps of dbRows ?? []) {\n if (ps?.name && !seen.has(ps.name)) {\n seen.add(ps.name);\n result.push(ps);\n }\n }\n } catch {\n // Swallow — the request shouldn't fail just because the DB\n // lookup is unavailable.\n }\n }\n }\n\n return result;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { RowLevelSecurityPolicy } from '@objectstack/spec/security';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\n\n/**\n * RLS User Context\n * Variables available for RLS expression evaluation.\n */\ninterface RLSUserContext {\n id?: string;\n /**\n * Active organization id for the request. RLS expressions reference\n * this as `current_user.organization_id`. Sourced from\n * `ExecutionContext.tenantId` (the runtime keeps the abstract\n * \"tenant\" name, but at the data/RLS layer the canonical column is\n * `organization_id` — see better-auth's organization plugin).\n */\n organization_id?: string;\n roles?: string[];\n /**\n * IDs of all users that share the active organization with the\n * current user (incl. self). Pre-resolved by the runtime so RLS can\n * scope identity tables like `sys_user` via\n * `id IN (current_user.org_user_ids)` without needing subquery\n * support in the compiler. This is the one well-known membership set;\n * arbitrary §7.3.1 sets arrive via `ExecutionContext.rlsMembership`\n * and are merged in under their own keys (see {@link RLSCompiler.compileFilter}).\n */\n org_user_ids?: string[];\n [key: string]: unknown;\n}\n\n/**\n * Sentinel filter used when applicable RLS policies exist but none can\n * be compiled against the current execution context (typically because a\n * required `current_user.*` variable is missing — e.g. the user has no\n * active organization). The filter compares `id` against a non-printable\n * UUID-shaped string that no real record will ever carry, so the upstream\n * SQL layer naturally returns zero rows without raising an error. This\n * gives us **fail-closed** semantics for select/update/delete on tables\n * that the user is not entitled to see, without forcing every caller to\n * handle a thrown `PermissionDeniedError` for what is conceptually an\n * empty result set.\n *\n * Exposed for the SecurityPlugin's optional short-circuit path and for\n * tests; see {@link RLSCompiler.compileFilter}.\n */\nexport const RLS_DENY_FILTER: Record<string, unknown> = Object.freeze({\n id: '__rls_deny__:00000000-0000-0000-0000-000000000000',\n});\n\n/**\n * RLSCompiler\n * \n * Compiles Row-Level Security policy expressions into query filters.\n * Converts `using` / `check` expressions into ObjectQL-compatible filter conditions.\n */\nexport class RLSCompiler {\n /**\n * Compile RLS policies into a query filter for the given user context.\n * Multiple policies for the same object/operation are OR-combined (any match allows access).\n *\n * Return-value semantics:\n * - `null` → no policies applicable → caller applies no RLS filter.\n * - non-null → caller AND's it onto the existing where clause.\n * - {@link RLS_DENY_FILTER} → policies were defined but none could be\n * compiled (e.g. wildcard `tenant_isolation` against a user with no\n * active organization). The caller must treat this as \"deny by\n * default\" — its `id` comparison naturally yields zero rows on\n * select/update/delete, which is the safe fail-closed answer.\n */\n compileFilter(\n policies: RowLevelSecurityPolicy[],\n executionContext?: ExecutionContext\n ): Record<string, unknown> | null {\n if (policies.length === 0) return null;\n\n const userCtx: RLSUserContext = {\n id: executionContext?.userId,\n organization_id: executionContext?.tenantId,\n roles: executionContext?.roles,\n org_user_ids: (executionContext as any)?.org_user_ids,\n };\n\n // §7.3.1 dynamic membership: the runtime pre-resolves arbitrary\n // set-membership (team members, territory accounts, shared records)\n // into `ExecutionContext.rlsMembership`. Merge each set under its key\n // so `field IN (current_user.<key>)` resolves without subquery support.\n // Arrays only; a missing/empty set still fails closed downstream.\n // We never let a membership key clobber the named fields above.\n const membership = (executionContext as any)?.rlsMembership;\n if (membership && typeof membership === 'object') {\n for (const [key, value] of Object.entries(membership)) {\n if (Array.isArray(value) && userCtx[key] === undefined) {\n userCtx[key] = value;\n }\n }\n }\n\n const filters: Record<string, unknown>[] = [];\n\n for (const policy of policies) {\n if (!policy.using) continue;\n const filter = this.compileExpression(policy.using, userCtx);\n if (filter) {\n filters.push(filter);\n }\n }\n\n if (filters.length === 0) {\n // Policies *were* applicable but every one of them depended on a\n // `current_user.*` variable that wasn't populated (or used an\n // expression we couldn't compile). Fail closed — return a sentinel\n // filter that matches no rows. This prevents the \"user without an\n // active org sees every tenant's data\" class of bug.\n return RLS_DENY_FILTER;\n }\n if (filters.length === 1) return filters[0];\n\n // Multiple policies: OR-combine (any policy allows access)\n return { $or: filters };\n }\n\n /**\n * Compile a single RLS expression into a query filter.\n *\n * This reference compiler recognizes exactly four forms — anything else\n * returns `null` and (via {@link compileFilter}) fails closed:\n * - `field = current_user.property` → `{ field: <value> }`\n * - `field = 'literal_value'` → `{ field: 'literal_value' }`\n * - `field IN (current_user.array)` → `{ field: { $in: [...] } }`\n * (the array may be a §7.3.1 pre-resolved membership set)\n * - `1 = 1` → `{}` (always-true / no restriction)\n *\n * There is intentionally no support for subqueries, `LIKE`/`ILIKE`,\n * regex, `ANY`/`ALL`, `AND`/`OR`/`NOT`, or `NULL` checks — express those\n * needs as a `current_user.*` property the runtime pre-resolves instead.\n */\n compileExpression(\n expression: string,\n userCtx: RLSUserContext\n ): Record<string, unknown> | null {\n if (!expression) return null;\n\n // Always-true literal: \"1 = 1\" → no restriction (match every row).\n // Lets RLS.allowAllPolicy ('1 = 1' for privileged roles) grant access\n // instead of silently failing closed. An empty filter AND's onto the\n // caller's where clause as a no-op.\n if (/^\\s*1\\s*=\\s*1\\s*$/.test(expression)) {\n return {};\n }\n\n // Handle simple equality: \"field = current_user.property\"\n const eqMatch = expression.match(/^\\s*(\\w+)\\s*=\\s*current_user\\.(\\w+)\\s*$/);\n if (eqMatch) {\n const [, field, prop] = eqMatch;\n const value = userCtx[prop];\n // Skip when the user-context value is missing (undefined or null).\n // A `null` `organization_id` means \"no active organization\" — applying\n // the filter as `organization_id IS NULL` would silently expose every\n // un-tenanted row across tenants and break system tables that lack the\n // column entirely. Treating null as \"skip this policy\" makes the\n // tenant_isolation rule safely opt-out for users without an active org\n // while still applying when one is set.\n if (value === undefined || value === null) return null;\n return { [field]: value };\n }\n\n // Handle literal equality: \"field = 'value'\"\n const litMatch = expression.match(/^\\s*(\\w+)\\s*=\\s*'([^']*)'\\s*$/);\n if (litMatch) {\n const [, field, value] = litMatch;\n return { [field]: value };\n }\n\n // Handle IN: \"field IN (current_user.array_property)\"\n const inMatch = expression.match(/^\\s*(\\w+)\\s+IN\\s+\\(\\s*current_user\\.(\\w+)\\s*\\)\\s*$/i);\n if (inMatch) {\n const [, field, prop] = inMatch;\n const value = userCtx[prop];\n if (!Array.isArray(value) || value.length === 0) return null;\n return { [field]: { $in: value } };\n }\n\n // Unsupported expression: return null (no additional RLS filter applied).\n // Note: callers should treat absence of RLS policies as \"allow all\" only when\n // no policies are defined. If policies exist but cannot be compiled, the caller\n // may want to deny access as a safety measure.\n return null;\n }\n\n /**\n * Get applicable RLS policies for a given object and operation.\n */\n getApplicablePolicies(\n objectName: string,\n operation: string,\n allPolicies: RowLevelSecurityPolicy[]\n ): RowLevelSecurityPolicy[] {\n // Map engine operation to RLS operation type\n const rlsOp = this.mapOperationToRLS(operation);\n\n return allPolicies.filter(policy => {\n // Check object match\n if (policy.object !== objectName && policy.object !== '*') return false;\n\n // Check operation match\n if (policy.operation === 'all') return true;\n if (policy.operation === rlsOp) return true;\n\n return false;\n });\n }\n\n private mapOperationToRLS(operation: string): string {\n switch (operation) {\n case 'find':\n case 'findOne':\n case 'count':\n case 'aggregate':\n return 'select';\n case 'insert':\n return 'insert';\n case 'update':\n return 'update';\n case 'delete':\n return 'delete';\n default:\n return 'select';\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { FieldPermission } from '@objectstack/spec/security';\n\n/**\n * FieldMasker\n * \n * Applies field-level security by stripping restricted fields from query results.\n */\nexport class FieldMasker {\n /**\n * Mask fields in query results based on field permissions.\n * Removes fields that the user does not have read access to.\n */\n maskResults(\n results: any | any[],\n fieldPermissions: Record<string, FieldPermission>,\n _objectName: string\n ): any | any[] {\n // If no field permissions defined, return results as-is\n if (Object.keys(fieldPermissions).length === 0) return results;\n\n // Get list of non-readable fields\n const hiddenFields = Object.entries(fieldPermissions)\n .filter(([, perm]) => !perm.readable)\n .map(([field]) => field);\n\n if (hiddenFields.length === 0) return results;\n\n if (Array.isArray(results)) {\n return results.map(record => this.maskRecord(record, hiddenFields));\n }\n\n return this.maskRecord(results, hiddenFields);\n }\n\n /**\n * Get non-editable fields for use in write operations.\n * Returns a list of field names that should be stripped from incoming data.\n */\n getNonEditableFields(\n fieldPermissions: Record<string, FieldPermission>\n ): string[] {\n return Object.entries(fieldPermissions)\n .filter(([, perm]) => !perm.editable)\n .map(([field]) => field);\n }\n\n /**\n * Strip non-editable fields from write data.\n */\n stripNonEditableFields(\n data: Record<string, any>,\n fieldPermissions: Record<string, FieldPermission>\n ): Record<string, any> {\n const nonEditable = this.getNonEditableFields(fieldPermissions);\n if (nonEditable.length === 0) return data;\n\n const result = { ...data };\n for (const field of nonEditable) {\n delete result[field];\n }\n return result;\n }\n\n /**\n * Detect which fields in the caller's write payload would touch a\n * field they are not allowed to edit. Returns the set of offending\n * field names (no duplicates, sorted for stable error messages).\n *\n * Used by the security middleware on insert/update to fail-closed\n * with an explicit 403 rather than silently dropping fields — a\n * silent drop hides the security boundary from honest clients\n * (their update partially \"doesn't save\") and gives an attacker no\n * negative signal that the field exists. Throwing makes the\n * boundary observable in both directions.\n *\n * `data` may be a single record or an array of records (bulk insert);\n * either way the returned list is the union across all rows.\n *\n * Fields without a permission entry pass through — permission sets\n * are an allow-list at the field level only for fields they\n * explicitly enumerate. Most objects do not declare per-field rules\n * and remain fully editable.\n */\n detectForbiddenWrites(\n data: Record<string, any> | Record<string, any>[],\n fieldPermissions: Record<string, FieldPermission>\n ): string[] {\n if (Object.keys(fieldPermissions).length === 0) return [];\n const nonEditable = new Set(this.getNonEditableFields(fieldPermissions));\n if (nonEditable.size === 0) return [];\n\n const offenders = new Set<string>();\n const rows = Array.isArray(data) ? data : [data];\n for (const row of rows) {\n if (!row || typeof row !== 'object') continue;\n for (const field of Object.keys(row)) {\n if (nonEditable.has(field)) offenders.add(field);\n }\n }\n return Array.from(offenders).sort();\n }\n\n private maskRecord(record: any, hiddenFields: string[]): any {\n if (!record || typeof record !== 'object') return record;\n\n const result = { ...record };\n for (const field of hiddenFields) {\n delete result[field];\n }\n return result;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Typed sentinel error thrown by `SecurityPlugin` when an operation is\n * denied. Caught by `@objectstack/runtime`'s HTTP dispatcher and translated\n * to HTTP 403.\n */\nexport class PermissionDeniedError extends Error {\n readonly code = 'PERMISSION_DENIED';\n readonly statusCode = 403;\n readonly details?: Record<string, unknown>;\n constructor(message: string, details?: Record<string, unknown>) {\n super(message);\n this.name = 'PermissionDeniedError';\n this.details = details;\n }\n}\n\nexport function isPermissionDeniedError(e: unknown): e is PermissionDeniedError {\n if (!e || typeof e !== 'object') return false;\n const anyE = e as any;\n return (\n anyE.name === 'PermissionDeniedError' ||\n anyE.code === 'PERMISSION_DENIED' ||\n (typeof anyE.message === 'string' && anyE.message.startsWith('[Security] Access denied'))\n );\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * bootstrapPlatformAdmin — first-boot platform admin promotion.\n *\n * Two responsibilities, both idempotent and run on `kernel:ready`:\n *\n * 1. **Seed `sys_permission_set` rows** for each `defaultPermissionSets`\n * entry (admin_full_access / member_default / viewer_readonly).\n *\n * 2. **Promote the first registered user to platform admin** by\n * inserting a `sys_user_permission_set` row that points at\n * `admin_full_access` with `organization_id = NULL` (= cross-tenant).\n * If a platform admin already exists, this is a no-op forever.\n *\n * The \"create a Default Organization for the freshly-promoted admin\"\n * behavior moved to `@objectstack/plugin-org-scoping` (see\n * `ensureDefaultOrganization`). Install that plugin to get\n * multi-tenant bootstrap.\n */\n\nimport type { PermissionSet } from '@objectstack/spec/security';\nimport { SystemUserId } from '@objectstack/spec/system';\nimport { claimSeedOwnership } from './claim-seed-ownership.js';\n\ninterface BootstrapOptions {\n /** Logger from PluginContext. */\n logger?: {\n info: (message: string, meta?: Record<string, any>) => void;\n warn: (message: string, meta?: Record<string, any>) => void;\n };\n}\n\nconst SYSTEM_CTX = { isSystem: true };\n\nasync function tryFind(ql: any, object: string, where: any, limit = 100): Promise<any[]> {\n try {\n const rows = await ql.find(object, { where, limit }, { context: SYSTEM_CTX });\n return Array.isArray(rows) ? rows : [];\n } catch {\n return [];\n }\n}\n\nasync function tryInsert(ql: any, object: string, data: any): Promise<any | null> {\n try {\n return await ql.insert(object, data, { context: SYSTEM_CTX });\n } catch {\n return null;\n }\n}\n\nfunction genId(prefix: string): string {\n const rand = Math.random().toString(36).slice(2, 10);\n const ts = Date.now().toString(36);\n return `${prefix}_${ts}${rand}`;\n}\n\n/**\n * Persist seed permission sets and promote the first registered user to\n * platform admin. Safe to call multiple times.\n */\nexport async function bootstrapPlatformAdmin(\n ql: any,\n bootstrapPermissionSets: PermissionSet[],\n options: BootstrapOptions = {},\n): Promise<{\n seeded: number;\n adminPromoted: boolean;\n reason?: string;\n /** Count of seeded rows re-owned to the freshly-promoted admin. */\n ownershipClaimed?: number;\n}> {\n const logger = options.logger;\n if (!ql || typeof ql.find !== 'function' || typeof ql.insert !== 'function') {\n return { seeded: 0, adminPromoted: false, reason: 'objectql_unavailable' };\n }\n\n // 1. Seed permission set rows.\n const seeded: Record<string, string> = {};\n for (const ps of bootstrapPermissionSets) {\n if (!ps.name) continue;\n const existing = await tryFind(ql, 'sys_permission_set', { name: ps.name }, 1);\n if (existing.length > 0 && existing[0].id) {\n seeded[ps.name] = existing[0].id;\n continue;\n }\n const id = genId('ps');\n const created = await tryInsert(ql, 'sys_permission_set', {\n id,\n name: ps.name,\n label: ps.label ?? ps.name,\n // `description` is not part of the typed PermissionSet shape (name/label\n // only); read it defensively so a runtime-provided description still\n // persists without tripping the dts typecheck.\n description: (ps as any).description ?? null,\n object_permissions: JSON.stringify(ps.objects ?? {}),\n field_permissions: JSON.stringify(ps.fields ?? {}),\n // Persist the remaining permset facets so the runtime resolver\n // (rest-server.ts / resolve-execution-context.ts) can hydrate\n // them back into ExecutionContext.systemPermissions etc. Without\n // these the platform-admin promotion grants the right LINK row\n // but the permission set itself carries no capabilities, so\n // `setup.access` / `studio.access` never reach the app filter\n // and the Setup app is invisible even to admin_full_access.\n system_permissions: JSON.stringify(ps.systemPermissions ?? []),\n row_level_security: JSON.stringify(ps.rowLevelSecurity ?? []),\n tab_permissions: JSON.stringify(ps.tabPermissions ?? {}),\n active: true,\n });\n if (created?.id) seeded[ps.name] = created.id;\n else if (created) seeded[ps.name] = id;\n }\n\n const seededCount = Object.keys(seeded).length;\n\n // 2. First-user platform admin promotion.\n const adminPsId = seeded['admin_full_access'];\n if (!adminPsId) {\n return { seeded: seededCount, adminPromoted: false, reason: 'admin_permission_set_missing' };\n }\n\n const existingAdminLinks = await tryFind(\n ql,\n 'sys_user_permission_set',\n { permission_set_id: adminPsId },\n 50,\n );\n // A platform admin \"already exists\" only if a *human* holds the\n // cross-tenant grant. The seed-data owner `usr_system` (provisioned by\n // the SeedLoader, see runtime/app-plugin.ts `ensureSeedIdentity`) must\n // never count — otherwise a DB where it was wrongly promoted would block\n // every real admin forever. Ignoring it here makes the bootstrap\n // self-healing on restart.\n if (existingAdminLinks.some((r) => !r.organization_id && r.user_id !== SystemUserId.SYSTEM)) {\n return { seeded: seededCount, adminPromoted: false, reason: 'already_have_admin' };\n }\n\n const allUsers = await tryFind(ql, 'sys_user', {}, 50);\n // Exclude the non-loginable system service account. It is created during\n // seed loading — *before* the first human sign-up — so without this filter\n // it is the earliest user and steals the platform-admin promotion, leaving\n // the real admin login without `setup.access` / `studio.access` (Setup and\n // Studio then stay invisible even though login succeeds).\n const humanUsers = allUsers.filter(\n (u) => u.id !== SystemUserId.SYSTEM && u.role !== 'system',\n );\n if (humanUsers.length === 0) {\n logger?.info?.('[security] no human users yet — first sign-up will be promoted to platform admin');\n return { seeded: seededCount, adminPromoted: false, reason: 'no_users' };\n }\n const sorted = [...humanUsers].sort((a, b) => {\n const ta = a.created_at ? new Date(a.created_at).getTime() : 0;\n const tb = b.created_at ? new Date(b.created_at).getTime() : 0;\n return ta - tb;\n });\n const target = sorted[0];\n\n const inserted = await tryInsert(ql, 'sys_user_permission_set', {\n id: genId('ups'),\n user_id: target.id,\n permission_set_id: adminPsId,\n organization_id: null,\n granted_by: null,\n });\n if (!inserted) {\n logger?.warn?.(`[security] failed to grant admin_full_access to first user ${target.email ?? target.id}`);\n return { seeded: seededCount, adminPromoted: false, reason: 'insert_failed' };\n }\n logger?.info?.(`[security] first user promoted to platform admin: ${target.email ?? target.id}`);\n\n // Hand seeded business records (owner_id NULL / usr_system) to the freshly\n // promoted admin so owner-keyed UX works out of the box. Best-effort and\n // idempotent — failures here must not undo the promotion above.\n let ownershipClaimed = 0;\n try {\n const claims = await claimSeedOwnership(ql, target.id, { logger });\n ownershipClaimed = claims.reduce((s, c) => s + c.count, 0);\n } catch (e) {\n logger?.warn?.('[security] seed ownership handoff failed', { error: (e as Error).message });\n }\n\n return { seeded: seededCount, adminPromoted: true, ownershipClaimed };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * claimSeedOwnership — hand seeded business records to the first platform admin.\n *\n * Seed data is loaded during app-plugin `start()`, which runs BEFORE any human\n * user exists (the login admin is minted later, on `kernel:ready`). So seeded\n * rows land with `owner_id = NULL` (the author left it unset — the correct,\n * mistake-proof default) or `owner_id = usr_system` (the deterministic seed\n * identity bound to `os.user`). Either way the record is owned by nobody a\n * human can log in as, so owner-keyed UX — \"My\" views, owner reports, owner\n * notifications — is empty out of the box.\n *\n * This helper runs **once**, right after `bootstrapPlatformAdmin` promotes the\n * first human user to platform admin, and transfers ownership of those orphan\n * rows to that admin. It is the ownership twin of org-scoping's\n * `claimOrphanOrgRows` (which back-fills `organization_id`): walk every\n * user-authored object that declares the canonical `owner_id` column, and\n * re-own the rows that no human owns yet.\n *\n * Mistake-proof by construction: authors write plain seed records (no\n * `owner_id`), and the platform — not the author — performs the handoff. There\n * is nothing to remember and nothing to mistype.\n *\n * Idempotent: only NULL / `usr_system`-owned rows are touched, so once a real\n * admin owns them a re-run is a no-op. `managedBy` and `sys_*` tables are\n * skipped (their ownership, if any, is platform-controlled).\n */\n\nimport type { ServiceObject } from '@objectstack/spec/data';\nimport { SystemUserId } from '@objectstack/spec/system';\n\ninterface ClaimOwnershipOptions {\n logger?: {\n info: (message: string, meta?: Record<string, any>) => void;\n warn: (message: string, meta?: Record<string, any>) => void;\n };\n}\n\nconst SYSTEM_CTX = { isSystem: true };\n\nfunction hasOwnerField(schema: ServiceObject): boolean {\n const fields: any = (schema as any)?.fields;\n if (!fields) return false;\n if (Array.isArray(fields)) {\n return fields.some((f) => f?.name === 'owner_id');\n }\n return Object.prototype.hasOwnProperty.call(fields, 'owner_id');\n}\n\n/**\n * Re-own every orphan seed row (owner_id NULL or usr_system) to `adminUserId`.\n *\n * Walks `ql.registry.getAllObjects()`, filters to schemas that\n * (a) are not `managedBy` (skip sys_/auth/platform tables),\n * (b) are not `sys_*`-namespaced,\n * (c) declare an `owner_id` field,\n * and updates the unowned rows as `isSystem`. Returns a per-object summary.\n */\nexport async function claimSeedOwnership(\n ql: any,\n adminUserId: string,\n options: ClaimOwnershipOptions = {},\n): Promise<{ object: string; count: number }[]> {\n const logger = options.logger;\n if (!adminUserId || adminUserId === SystemUserId.SYSTEM) return [];\n if (!ql || typeof ql.update !== 'function' || typeof ql.find !== 'function') {\n return [];\n }\n const registry = (ql as any).registry;\n if (!registry || typeof registry.getAllObjects !== 'function') {\n logger?.warn?.('[security] claimSeedOwnership: registry unavailable');\n return [];\n }\n\n const schemas: ServiceObject[] = registry.getAllObjects();\n const results: { object: string; count: number }[] = [];\n\n for (const schema of schemas) {\n if (!schema?.name) continue;\n if ((schema as any).managedBy) continue;\n if (schema.name.startsWith('sys_')) continue;\n if (!hasOwnerField(schema)) continue;\n\n try {\n // Unowned = owner_id NULL (author left it unset) OR usr_system (seed\n // identity). Two narrow scans keep the where-clauses driver-portable\n // instead of relying on an OR/IN predicate.\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const where of [{ owner_id: null }, { owner_id: SystemUserId.SYSTEM }]) {\n const rows = await ql.find(\n schema.name,\n { where, limit: 10_000, fields: ['id'] },\n { context: SYSTEM_CTX },\n );\n const list: any[] = Array.isArray(rows)\n ? rows\n : Array.isArray(rows?.records)\n ? rows.records\n : [];\n for (const r of list) {\n if (r?.id && !seen.has(r.id)) {\n seen.add(r.id);\n ids.push(r.id);\n }\n }\n }\n if (ids.length === 0) continue;\n\n let updated = 0;\n for (const id of ids) {\n try {\n await ql.update(\n schema.name,\n { id, owner_id: adminUserId },\n { context: SYSTEM_CTX },\n );\n updated += 1;\n } catch (e) {\n logger?.warn?.(`[security] claimSeedOwnership failed for ${schema.name}:${id}`, {\n error: (e as Error).message,\n });\n }\n }\n if (updated > 0) results.push({ object: schema.name, count: updated });\n } catch (e) {\n logger?.warn?.(`[security] claimSeedOwnership scan failed for ${schema.name}`, {\n error: (e as Error).message,\n });\n }\n }\n\n if (results.length > 0) {\n const total = results.reduce((s, r) => s + r.count, 0);\n logger?.info?.(`[security] handed ${total} seeded record(s) to first admin ${adminUserId}`, {\n breakdown: results,\n });\n }\n return results;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-grant `organization_admin` to org owners/admins.\n *\n * For every `sys_member` row whose `role` contains `owner` or `admin`,\n * ensure a `sys_user_permission_set` row exists that links the user to\n * the `organization_admin` permission set scoped to that organization.\n * For members whose role no longer qualifies (demotion or membership\n * removal), revoke the matching scoped grant.\n *\n * Lifecycle hookup (wired from `security-plugin.ts`):\n *\n * - after `sys_member` insert → reconcile (user_id, organization_id)\n * - after `sys_member` update → reconcile both old and new owner pair\n * - after `sys_member` delete → reconcile to revoke\n * - on `kernel:ready` → backfill across every existing member\n *\n * All operations are idempotent and failure-isolated so a missing\n * permission-set row, schema drift, or a stale row never blocks the\n * underlying `sys_member` mutation.\n *\n * **Why this isn't done by the better-auth org plugin directly:**\n * better-auth does not know about ObjectStack permission sets — it\n * only stores membership roles. Translating \"owner/admin role on this\n * org\" into \"owns the `organization_admin` permission set scoped to\n * this org\" is platform metadata policy and belongs here, alongside\n * `bootstrapPlatformAdmin` (which does the analogous thing for\n * platform admins).\n *\n * **Anti-escalation:** `organization_admin` itself (declared in\n * `platform-objects/src/security/default-permission-sets.ts`) is\n * deliberately read-only on the global RBAC tables\n * (`sys_permission_set`, `sys_user_permission_set`, `sys_role`, …),\n * so a freshly-granted org admin cannot rebind themselves to\n * `admin_full_access`.\n */\n\nconst SYSTEM_CTX = { isSystem: true } as const;\nconst PERMISSION_SET_NAME = 'organization_admin';\n\ninterface MaybeLogger {\n info?: (message: string, meta?: Record<string, any>) => void;\n warn?: (message: string, meta?: Record<string, any>) => void;\n debug?: (message: string, meta?: Record<string, any>) => void;\n}\n\nfunction genId(prefix: string): string {\n const rand = Math.random().toString(36).slice(2, 10);\n const ts = Date.now().toString(36);\n return `${prefix}_${ts}${rand}`;\n}\n\nasync function tryFind(ql: any, object: string, where: any, limit = 50): Promise<any[]> {\n try {\n const rows = await ql.find(object, { where, limit }, { context: SYSTEM_CTX });\n return Array.isArray(rows) ? rows : Array.isArray(rows?.records) ? rows.records : [];\n } catch {\n return [];\n }\n}\n\nasync function tryInsert(ql: any, object: string, data: any): Promise<any | null> {\n try {\n return await ql.insert(object, data, { context: SYSTEM_CTX });\n } catch {\n return null;\n }\n}\n\nasync function tryDelete(ql: any, object: string, id: string): Promise<boolean> {\n try {\n await ql.delete(object, id, { context: SYSTEM_CTX });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse a better-auth `sys_member.role` value into a lower-cased role\n * list. better-auth stores either a single role (`\"owner\"`) or a\n * comma-separated list (`\"owner,admin\"`).\n */\nfunction parseRoles(raw: unknown): string[] {\n if (typeof raw !== 'string') return [];\n return raw\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => s.length > 0);\n}\n\nfunction isAdminRole(raw: unknown): boolean {\n const roles = parseRoles(raw);\n return roles.includes('owner') || roles.includes('admin');\n}\n\n/**\n * Resolve the `sys_permission_set.id` for `organization_admin`. Cached\n * across calls per ObjectQL instance via a WeakMap so repeated\n * reconciliations do not re-query.\n */\nconst permissionSetIdCache = new WeakMap<object, string>();\n\nasync function resolvePermissionSetId(ql: any): Promise<string | null> {\n const cached = permissionSetIdCache.get(ql);\n if (cached) return cached;\n const rows = await tryFind(ql, 'sys_permission_set', { name: PERMISSION_SET_NAME }, 1);\n const id = rows[0]?.id;\n if (typeof id === 'string' && id.length > 0) {\n permissionSetIdCache.set(ql, id);\n return id;\n }\n return null;\n}\n\n/**\n * Ensure (or revoke) the org-scoped `organization_admin` grant for\n * `(userId, orgId)` based on the current `sys_member` rows.\n *\n * - If ANY membership row for the pair carries an owner/admin role,\n * ensure exactly one `sys_user_permission_set` row exists.\n * - Else, remove every `sys_user_permission_set` row that links the\n * pair to `organization_admin` (handles demotion and membership\n * removal symmetrically).\n *\n * Returns a structured report for observability. Never throws.\n */\nexport async function reconcileOrgAdminGrant(\n ql: any,\n userId: string,\n orgId: string,\n options: { logger?: MaybeLogger } = {},\n): Promise<{\n action: 'granted' | 'revoked' | 'noop' | 'skipped';\n reason?: string;\n}> {\n const logger = options.logger;\n if (!ql || typeof ql.find !== 'function' || typeof ql.insert !== 'function') {\n return { action: 'skipped', reason: 'objectql_unavailable' };\n }\n if (!userId || !orgId) {\n return { action: 'skipped', reason: 'missing_keys' };\n }\n\n const permSetId = await resolvePermissionSetId(ql);\n if (!permSetId) {\n // organization_admin permission set isn't seeded yet (boot ordering)\n // — caller can retry later (e.g. via kernel:ready backfill).\n return { action: 'skipped', reason: 'permission_set_missing' };\n }\n\n // 1. Determine whether the user currently holds an admin-grade role\n // in this org. Better-auth allows multiple membership rows per\n // pair under some edge cases (legacy data) — any qualifying row\n // is enough.\n const memberships = await tryFind(\n ql,\n 'sys_member',\n { user_id: userId, organization_id: orgId },\n 10,\n );\n const shouldGrant = memberships.some((m: any) => isAdminRole(m?.role));\n\n // 2. Look at existing grants for this exact pair.\n const existingGrants = await tryFind(\n ql,\n 'sys_user_permission_set',\n { user_id: userId, organization_id: orgId, permission_set_id: permSetId },\n 5,\n );\n\n if (shouldGrant) {\n if (existingGrants.length > 0) {\n // Deduplicate stale duplicates if any slipped through.\n for (const extra of existingGrants.slice(1)) {\n if (extra?.id) await tryDelete(ql, 'sys_user_permission_set', String(extra.id));\n }\n return { action: 'noop' };\n }\n const created = await tryInsert(ql, 'sys_user_permission_set', {\n id: genId('ups'),\n user_id: userId,\n permission_set_id: permSetId,\n organization_id: orgId,\n granted_by: null,\n });\n if (created) {\n logger?.info?.('[security] granted organization_admin', { userId, orgId });\n return { action: 'granted' };\n }\n return { action: 'skipped', reason: 'insert_failed' };\n }\n\n // shouldGrant === false → revoke any pre-existing scoped grant.\n if (existingGrants.length === 0) {\n return { action: 'noop' };\n }\n let removed = 0;\n for (const row of existingGrants) {\n if (row?.id && (await tryDelete(ql, 'sys_user_permission_set', String(row.id)))) {\n removed += 1;\n }\n }\n if (removed > 0) {\n logger?.info?.('[security] revoked organization_admin', { userId, orgId, removed });\n return { action: 'revoked' };\n }\n return { action: 'skipped', reason: 'delete_failed' };\n}\n\n/**\n * Reconcile every `(user_id, organization_id)` pair that has at least\n * one `sys_member` row. Used by `kernel:ready` to backfill grants for\n * memberships that pre-date this feature, and as a safety net after\n * the platform admin bootstrap auto-creates the default organization.\n */\nexport async function backfillOrgAdminGrants(\n ql: any,\n options: { logger?: MaybeLogger; limit?: number } = {},\n): Promise<{ scanned: number; granted: number; revoked: number; skipped: number }> {\n const logger = options.logger;\n const limit = options.limit ?? 5000;\n const summary = { scanned: 0, granted: 0, revoked: 0, skipped: 0 };\n if (!ql || typeof ql.find !== 'function') return summary;\n\n const permSetId = await resolvePermissionSetId(ql);\n if (!permSetId) {\n logger?.debug?.('[security] organization_admin backfill skipped — permission set missing');\n return summary;\n }\n\n const members = await tryFind(ql, 'sys_member', {}, limit);\n // De-duplicate by (user_id, organization_id) pair — a user with two\n // membership rows (e.g. legacy duplicates) only needs one reconcile.\n const seen = new Set<string>();\n for (const m of members) {\n const userId = String(m?.user_id ?? '');\n const orgId = String(m?.organization_id ?? '');\n if (!userId || !orgId) continue;\n const key = `${userId}|${orgId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n summary.scanned += 1;\n const res = await reconcileOrgAdminGrant(ql, userId, orgId, { logger });\n if (res.action === 'granted') summary.granted += 1;\n else if (res.action === 'revoked') summary.revoked += 1;\n else if (res.action === 'skipped') summary.skipped += 1;\n }\n\n // Also revoke any organization_admin grant pointing at a (user, org)\n // pair with NO membership row left (orphaned grants from deletes\n // that fired before this hook existed).\n const allGrants = await tryFind(\n ql,\n 'sys_user_permission_set',\n { permission_set_id: permSetId },\n limit,\n );\n for (const g of allGrants) {\n const userId = String(g?.user_id ?? '');\n const orgId = String(g?.organization_id ?? '');\n if (!userId || !orgId) continue;\n const key = `${userId}|${orgId}`;\n if (seen.has(key)) continue;\n const res = await reconcileOrgAdminGrant(ql, userId, orgId, { logger });\n if (res.action === 'revoked') summary.revoked += 1;\n }\n\n logger?.info?.('[security] organization_admin backfill complete', summary);\n return summary;\n}\n\n/**\n * Extract (user_id, organization_id) candidate pairs from a\n * `sys_member` ObjectQL middleware context. Returns both the\n * pre-change and post-change pair so callers can reconcile each.\n */\nexport function extractMemberPairs(opCtx: any): Array<{ userId: string; orgId: string }> {\n const out = new Map<string, { userId: string; orgId: string }>();\n const add = (userId: unknown, orgId: unknown) => {\n if (typeof userId === 'string' && typeof orgId === 'string' && userId && orgId) {\n out.set(`${userId}|${orgId}`, { userId, orgId });\n }\n };\n // Post-write payload — most common case.\n add(opCtx?.result?.user_id, opCtx?.result?.organization_id);\n // Update payloads carry the new values in `data` and the prior row\n // in `before` (driver-dependent). We reconcile BOTH so a member\n // moved from org A to org B (or user changed) is handled.\n add(opCtx?.data?.user_id, opCtx?.data?.organization_id);\n add(opCtx?.before?.user_id, opCtx?.before?.organization_id);\n // For deletes the affected row is sometimes only in `existing`.\n add(opCtx?.existing?.user_id, opCtx?.existing?.organization_id);\n return Array.from(out.values());\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_role — System Role Object\n *\n * RBAC role definition for the ObjectStack platform.\n * Roles group permissions and are assigned to users or members.\n *\n * @namespace sys\n */\nexport const SysRole = ObjectSchema.create({\n name: 'sys_role',\n label: 'Role',\n pluralLabel: 'Roles',\n icon: 'shield',\n isSystem: true,\n managedBy: 'config',\n // ADR-0010 §3.7 — RBAC primitive; tenants may add custom rows\n // (created via UI / API) but the schema itself is locked.\n protection: {\n lock: 'no-overlay',\n reason: 'RBAC schema is platform-defined — see ADR-0010.',\n docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',\n },\n description: 'Role definitions for RBAC access control',\n displayNameField: 'label',\n titleFormat: '{label}',\n compactLayout: ['label', 'name', 'active', 'is_default'],\n\n // Custom actions — system roles drive RBAC and are edited rarely but\n // require the four high-frequency sysadmin affordances every IdP\n // (Salesforce, ServiceNow, Okta) ships: activate/deactivate (lifecycle\n // without losing assignments), mark default (auto-assign to new users),\n // and clone (template for new roles). All operations hit the generic\n // data CRUD endpoint exposed by `apiEnabled` — no custom server route\n // required because `managedBy: 'config'` allows direct mutation.\n actions: [\n {\n name: 'activate_role',\n label: 'Activate Role',\n icon: 'circle-check',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_role/{id}',\n bodyExtra: { active: true },\n successMessage: 'Role activated',\n refreshAfter: true,\n },\n {\n name: 'deactivate_role',\n label: 'Deactivate Role',\n icon: 'circle-off',\n variant: 'danger',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_role/{id}',\n bodyExtra: { active: false },\n confirmText: 'Deactivate this role? Users with the role keep their assignment but the role stops granting permissions until re-activated.',\n successMessage: 'Role deactivated',\n refreshAfter: true,\n },\n {\n name: 'set_default_role',\n label: 'Set as Default',\n icon: 'star',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_role/{id}',\n bodyExtra: { is_default: true },\n confirmText: 'Make this the default role for new users? Existing users are unaffected.',\n successMessage: 'Default role updated',\n refreshAfter: true,\n },\n {\n // Clone — POST a new sys_role row pre-filled from the source. The\n // dialog asks only for the new API name / label so the operator\n // can rename atomically; permissions JSON is copied wholesale via\n // defaultFromRow.\n name: 'clone_role',\n label: 'Clone Role',\n icon: 'copy',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'POST',\n target: '/api/v1/data/sys_role',\n bodyExtra: { is_default: false, active: true },\n successMessage: 'Role cloned',\n refreshAfter: true,\n params: [\n { name: 'label', label: 'New Display Name', type: 'text', required: true },\n { name: 'name', label: 'New API Name', type: 'text', required: true, helpText: 'Unique snake_case machine name' },\n { field: 'description', defaultFromRow: true },\n { field: 'permissions', defaultFromRow: true },\n ],\n },\n ],\n\n listViews: {\n active: {\n type: 'grid',\n name: 'active',\n label: 'Active',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'is_default', 'updated_at'],\n filter: [{ field: 'active', operator: 'equals', value: true }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n default_roles: {\n type: 'grid',\n name: 'default_roles',\n label: 'Default',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'description', 'active'],\n filter: [{ field: 'is_default', operator: 'equals', value: true }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n custom: {\n type: 'grid',\n name: 'custom',\n label: 'Custom',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'active', 'updated_at'],\n filter: [{ field: 'is_default', operator: 'equals', value: false }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n all_roles: {\n type: 'grid',\n name: 'all_roles',\n label: 'All',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'active', 'is_default', 'updated_at'],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n },\n\n fields: {\n // ── Identity ─────────────────────────────────────────────────\n label: Field.text({\n label: 'Display Name',\n required: true,\n searchable: true,\n maxLength: 255,\n group: 'Identity',\n }),\n\n name: Field.text({\n label: 'API Name',\n required: true,\n searchable: true,\n maxLength: 100,\n description: 'Unique machine name for the role (e.g. admin, editor, viewer)',\n group: 'Identity',\n }),\n\n description: Field.textarea({\n label: 'Description',\n required: false,\n group: 'Identity',\n }),\n\n // ── Configuration ────────────────────────────────────────────\n permissions: Field.textarea({\n label: 'Permissions',\n required: false,\n description: 'JSON-serialized array of permission strings',\n group: 'Configuration',\n }),\n\n // ── Status ───────────────────────────────────────────────────\n active: Field.boolean({\n label: 'Active',\n defaultValue: true,\n group: 'Status',\n }),\n\n is_default: Field.boolean({\n label: 'Default Role',\n defaultValue: false,\n description: 'Automatically assigned to new users',\n group: 'Status',\n }),\n\n // ── System ───────────────────────────────────────────────────\n id: Field.text({\n label: 'Role ID',\n required: true,\n readonly: true,\n group: 'System',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['name'], unique: true },\n { fields: ['active'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_permission_set — System Permission Set Object\n *\n * Named groupings of fine-grained permissions.\n * Permission sets can be assigned to roles or directly to users\n * for granular access control.\n *\n * @namespace sys\n */\nexport const SysPermissionSet = ObjectSchema.create({\n name: 'sys_permission_set',\n label: 'Permission Set',\n pluralLabel: 'Permission Sets',\n icon: 'lock',\n isSystem: true,\n managedBy: 'config',\n // ADR-0010 §3.7 — RBAC primitive; tenants may add custom rows\n // (created via UI / API) but the schema itself is locked.\n protection: {\n lock: 'no-overlay',\n reason: 'RBAC schema is platform-defined — see ADR-0010.',\n docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',\n },\n description: 'Named permission groupings for fine-grained access control',\n displayNameField: 'label',\n titleFormat: '{label}',\n compactLayout: ['label', 'name', 'active'],\n\n // Custom actions — permission sets are templates assigned to roles or\n // users (via sys_role_permission_set / sys_user_permission_set). The\n // sysadmin operations that don't live on the parent-detail tabs are\n // lifecycle (activate/deactivate without losing assignments) and\n // clone (build a new permset by tweaking an existing one). Both hit\n // the generic data CRUD endpoint — managedBy: 'config' permits it.\n actions: [\n {\n name: 'activate_permission_set',\n label: 'Activate',\n icon: 'circle-check',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_permission_set/{id}',\n bodyExtra: { active: true },\n successMessage: 'Permission set activated',\n refreshAfter: true,\n },\n {\n name: 'deactivate_permission_set',\n label: 'Deactivate',\n icon: 'circle-off',\n variant: 'danger',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_permission_set/{id}',\n bodyExtra: { active: false },\n confirmText: 'Deactivate this permission set? Existing assignments stay in place but stop granting access until re-activated.',\n successMessage: 'Permission set deactivated',\n refreshAfter: true,\n },\n {\n name: 'clone_permission_set',\n label: 'Clone',\n icon: 'copy',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'POST',\n target: '/api/v1/data/sys_permission_set',\n bodyExtra: { active: true },\n successMessage: 'Permission set cloned',\n refreshAfter: true,\n params: [\n { name: 'label', label: 'New Display Name', type: 'text', required: true },\n { name: 'name', label: 'New API Name', type: 'text', required: true, helpText: 'Unique snake_case machine name' },\n { field: 'description', defaultFromRow: true },\n { field: 'object_permissions', defaultFromRow: true },\n { field: 'field_permissions', defaultFromRow: true },\n ],\n },\n ],\n\n listViews: {\n active: {\n type: 'grid',\n name: 'active',\n label: 'Active',\n data: { provider: 'object', object: 'sys_permission_set' },\n columns: ['label', 'name', 'description', 'updated_at'],\n filter: [{ field: 'active', operator: 'equals', value: true }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n inactive: {\n type: 'grid',\n name: 'inactive',\n label: 'Inactive',\n data: { provider: 'object', object: 'sys_permission_set' },\n columns: ['label', 'name', 'updated_at'],\n filter: [{ field: 'active', operator: 'equals', value: false }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n all_permsets: {\n type: 'grid',\n name: 'all_permsets',\n label: 'All',\n data: { provider: 'object', object: 'sys_permission_set' },\n columns: ['label', 'name', 'active', 'updated_at'],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n },\n\n fields: {\n // ── Identity ─────────────────────────────────────────────────\n label: Field.text({\n label: 'Display Name',\n required: true,\n searchable: true,\n maxLength: 255,\n group: 'Identity',\n }),\n\n name: Field.text({\n label: 'API Name',\n required: true,\n searchable: true,\n maxLength: 100,\n description: 'Unique machine name for the permission set',\n group: 'Identity',\n }),\n\n description: Field.textarea({\n label: 'Description',\n required: false,\n group: 'Identity',\n }),\n\n // ── Permissions ──────────────────────────────────────────────\n object_permissions: Field.textarea({\n label: 'Object Permissions',\n required: false,\n description: 'JSON-serialized object-level CRUD permissions',\n group: 'Permissions',\n }),\n\n field_permissions: Field.textarea({\n label: 'Field Permissions',\n required: false,\n description: 'JSON-serialized field-level read/write permissions',\n group: 'Permissions',\n }),\n\n system_permissions: Field.textarea({\n label: 'System Permissions',\n required: false,\n description: 'JSON-serialized array of system capability names (e.g. [\"setup.access\",\"studio.access\",\"manage_users\"])',\n group: 'Permissions',\n }),\n\n row_level_security: Field.textarea({\n label: 'Row-Level Security',\n required: false,\n description: 'JSON-serialized array of row-level security policies (USING/CHECK clauses)',\n group: 'Permissions',\n }),\n\n tab_permissions: Field.textarea({\n label: 'Tab Permissions',\n required: false,\n description: 'JSON-serialized map of app tab visibility (visible | hidden | default_on | default_off)',\n group: 'Permissions',\n }),\n\n // ── Status ───────────────────────────────────────────────────\n active: Field.boolean({\n label: 'Active',\n defaultValue: true,\n group: 'Status',\n }),\n\n // ── System ───────────────────────────────────────────────────\n id: Field.text({\n label: 'Permission Set ID',\n required: true,\n readonly: true,\n group: 'System',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['name'], unique: true },\n { fields: ['active'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_user_permission_set — User ↔ PermissionSet assignment.\n *\n * Salesforce-style additive permission grant: a user may be assigned any\n * number of `sys_permission_set` rows, optionally scoped to a specific\n * organization. The runtime resolver (`resolveExecutionContext` in\n * `@objectstack/runtime`) reads this table when building the per-request\n * `ExecutionContext.permissions[]`.\n *\n * Uniqueness is `(user_id, permission_set_id, organization_id)` so the\n * same permission set can be granted independently in each org context\n * the user belongs to.\n *\n * @namespace sys\n */\nexport const SysUserPermissionSet = ObjectSchema.create({\n name: 'sys_user_permission_set',\n label: 'User Permission Set',\n pluralLabel: 'User Permission Sets',\n icon: 'user-check',\n isSystem: true,\n managedBy: 'system',\n description: 'Direct assignment of a permission set to a user (optionally scoped to an organization).',\n titleFormat: '{user_id} → {permission_set_id}',\n compactLayout: ['user_id', 'permission_set_id', 'organization_id'],\n\n fields: {\n id: Field.text({\n label: 'Assignment ID',\n required: true,\n readonly: true,\n description: 'UUID of the assignment.',\n }),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n required: true,\n description: 'Foreign key to sys_user.',\n }),\n\n permission_set_id: Field.lookup('sys_permission_set', {\n label: 'Permission Set',\n required: true,\n description: 'Foreign key to sys_permission_set.',\n }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n description: 'Optional organization scope. NULL = applies in every org context.',\n }),\n\n granted_by: Field.lookup('sys_user', {\n label: 'Granted By',\n required: false,\n description: 'User who granted this permission set.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['user_id', 'permission_set_id', 'organization_id'], unique: true },\n { fields: ['user_id'] },\n { fields: ['organization_id'] },\n { fields: ['permission_set_id'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_role_permission_set — Role ↔ PermissionSet binding.\n *\n * Allows administrators to compose a `sys_role` from one or more\n * `sys_permission_set` rows. At request time, the runtime resolver\n * (`resolveExecutionContext`) collects every permission set bound to\n * the user's roles via this table and injects their names into\n * `ExecutionContext.permissions[]` for downstream RBAC evaluation.\n *\n * @namespace sys\n */\nexport const SysRolePermissionSet = ObjectSchema.create({\n name: 'sys_role_permission_set',\n label: 'Role Permission Set',\n pluralLabel: 'Role Permission Sets',\n icon: 'shield-plus',\n isSystem: true,\n managedBy: 'system',\n description: 'Binds a permission set to a role.',\n titleFormat: '{role_id} → {permission_set_id}',\n compactLayout: ['role_id', 'permission_set_id'],\n\n fields: {\n id: Field.text({\n label: 'Binding ID',\n required: true,\n readonly: true,\n description: 'UUID of the role-permission-set binding.',\n }),\n\n role_id: Field.lookup('sys_role', {\n label: 'Role',\n required: true,\n description: 'Foreign key to sys_role.',\n }),\n\n permission_set_id: Field.lookup('sys_permission_set', {\n label: 'Permission Set',\n required: true,\n description: 'Foreign key to sys_permission_set.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['role_id', 'permission_set_id'], unique: true },\n { fields: ['role_id'] },\n { fields: ['permission_set_id'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { PermissionSetSchema, type PermissionSet } from '@objectstack/spec/security';\n\n/**\n * Identity tables managed by the better-auth plugin (see\n * `packages/platform-objects/src/identity/`). Mutations to these tables\n * MUST flow through the better-auth API endpoints (sign-up, password\n * reset, organization invite/remove-member, api-key/create, …) rather\n * than the generic CRUD pipeline so that password hashing, token\n * signing, email verification, invitation flows and scope hashing all\n * fire correctly.\n *\n * The default member/viewer permission sets therefore explicitly DENY\n * `allowCreate / allowEdit / allowDelete` on these objects while still\n * permitting reads (subject to the rest of the RLS chain). Admin\n * permission sets keep their `*` wildcard so they can rescue data\n * directly when needed.\n *\n * Each entry mirrors the `managedBy: 'better-auth'` flag declared on\n * the corresponding object schema in `packages/platform-objects/src/identity/`.\n */\nconst BETTER_AUTH_MANAGED_OBJECTS = [\n 'sys_user',\n 'sys_account',\n 'sys_session',\n 'sys_organization',\n 'sys_member',\n 'sys_invitation',\n 'sys_team',\n 'sys_team_member',\n 'sys_api_key',\n 'sys_two_factor',\n 'sys_verification',\n 'sys_jwks',\n 'sys_device_code',\n 'sys_oauth_application',\n 'sys_oauth_access_token',\n 'sys_oauth_refresh_token',\n 'sys_oauth_consent',\n] as const;\n\nconst denyWritesOnManagedObjects = (): Record<string, {\n allowRead: boolean;\n allowCreate: boolean;\n allowEdit: boolean;\n allowDelete: boolean;\n}> => Object.fromEntries(\n BETTER_AUTH_MANAGED_OBJECTS.map((name) => [\n name,\n { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n ]),\n);\n\n/**\n * Default permission sets seeded by the platform.\n *\n * These are referenced by name (`admin_full_access`, `member_default`,\n * `viewer_readonly`) from `sys_role_permission_set` rows or assigned\n * directly to users via `sys_user_permission_set`.\n *\n * The runtime SecurityPlugin reads these via the metadata service when a\n * permission set name appears in the request `ExecutionContext.permissions[]`.\n *\n * Each entry is run through `PermissionSetSchema.parse(...)` so Zod fills\n * in the boolean/`priority`/`enabled` defaults — keeping the literal\n * source readable while still satisfying the strict output type.\n *\n * `objects: { '*': … }` uses the wildcard sentinel honoured by\n * `PermissionEvaluator` — admins do not need an explicit row per object.\n * Per-object entries fully override the wildcard for that object (see\n * `PermissionEvaluator.checkObjectPermission` — lookup, not merge).\n *\n * RLS policies use the canonical `current_user.*` placeholders compiled\n * by `RLSCompiler`. The active organization is exposed under\n * `current_user.organization_id` (sourced from\n * `ExecutionContext.tenantId` at request time) — there is no rewrite\n * step or `tenantField` indirection in SecurityPlugin. Schemas with a\n * different physical tenant column should fork these defaults.\n */\nexport const defaultPermissionSets: PermissionSet[] = [\n PermissionSetSchema.parse({\n name: 'admin_full_access',\n label: 'Administrator — Full Access',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: true,\n allowEdit: true,\n allowDelete: true,\n viewAllRecords: true,\n modifyAllRecords: true,\n },\n },\n systemPermissions: [\n 'manage_users',\n 'manage_metadata',\n 'manage_platform_settings',\n 'setup.access',\n 'studio.access',\n ],\n }),\n // ── Organization Administrator ──────────────────────────────────────\n //\n // Third tier between platform admin (`admin_full_access`) and rank-and-file\n // member. Lives at the *organization* scope: full CRUD on business\n // objects within their org (governed by `tenant_isolation` RLS), plus\n // `setup.access` so the Setup app shell is reachable.\n //\n // **Deliberately withheld** vs `admin_full_access`:\n // - `studio.access` — schema-design surfaces are platform-level (a\n // tenant cannot mutate the shared metadata) and Studio is hidden.\n // - `manage_metadata` — same reasoning.\n // - `manage_platform_settings` — global settings manifests\n // (mail / storage / AI / knowledge) and platform-only Setup pages\n // (sharing rules, audit logs, OAuth apps, JWKS, …) require this\n // and are hidden / 403'd for org admins. Tenant-scoped manifests\n // (`branding`, `feature_flags`) keep using `setup.access` so org\n // admins CAN configure their own org's branding.\n //\n // **Anti-escalation**: writes to the global RBAC tables\n // (`sys_role`, `sys_permission_set`, `sys_role_permission_set`,\n // `sys_user_permission_set`, `sys_user_role`) are denied. Allowing\n // them would let an org admin bind `admin_full_access` (which has no\n // RLS) to themselves and break out of tenant isolation. Reads are\n // permitted so the Roles / Permission Sets nav entries still render.\n //\n // Auto-granted to every `sys_member` whose role contains `owner` or\n // `admin` by `plugin-security/src/auto-org-admin-grant.ts`.\n PermissionSetSchema.parse({\n name: 'organization_admin',\n label: 'Organization Administrator',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: true,\n allowEdit: true,\n allowDelete: true,\n viewAllRecords: true,\n modifyAllRecords: true,\n },\n // Identity tables — go through better-auth endpoints (invite,\n // accept, remove-member, transfer, …) rather than raw CRUD.\n ...denyWritesOnManagedObjects(),\n // RBAC tables — read-only to prevent privilege escalation.\n sys_role: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_permission_set: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_role_permission_set: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_user_permission_set: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_user_role: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n },\n systemPermissions: ['manage_org_users', 'setup.access'],\n rowLevelSecurity: [\n {\n name: 'tenant_isolation',\n object: '*',\n operation: 'all',\n using: 'organization_id = current_user.organization_id',\n },\n // ── better-auth system tables that lack `organization_id` and would\n // otherwise be denied by the wildcard policy. Same self-only\n // carve-outs as `member_default` — an org admin does not get to\n // inspect cross-tenant identity rows.\n {\n name: 'sys_organization_self',\n object: 'sys_organization',\n operation: 'all',\n using: 'id = current_user.organization_id',\n },\n {\n name: 'sys_user_self',\n object: 'sys_user',\n operation: 'select',\n using: 'id = current_user.id',\n },\n {\n name: 'sys_user_org_members',\n object: 'sys_user',\n operation: 'select',\n using: 'id IN (current_user.org_user_ids)',\n },\n {\n name: 'sys_session_self',\n object: 'sys_session',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_account_self',\n object: 'sys_account',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_team_member_self',\n object: 'sys_team_member',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_two_factor_self',\n object: 'sys_two_factor',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_user_preference_self',\n object: 'sys_user_preference',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_api_key_self',\n object: 'sys_api_key',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_device_code_self',\n object: 'sys_device_code',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_access_token_self',\n object: 'sys_oauth_access_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_refresh_token_self',\n object: 'sys_oauth_refresh_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_consent_self',\n object: 'sys_oauth_consent',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n // OAuth applications a user has registered themselves (self-service\n // developer flow exposed in the Account app's Developer section).\n // `sys_oauth_application` has no `organization_id` so the wildcard\n // `tenant_isolation` policy would otherwise deny every row.\n {\n name: 'sys_oauth_application_self',\n object: 'sys_oauth_application',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n // Org-scoped visibility for organization-owned identity-adjacent\n // tables. Org admins may inspect their own org's invitations and\n // memberships (read; writes still flow through better-auth).\n {\n name: 'sys_member_org',\n object: 'sys_member',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n {\n name: 'sys_invitation_org',\n object: 'sys_invitation',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n {\n name: 'sys_team_org',\n object: 'sys_team',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n ],\n }),\n PermissionSetSchema.parse({\n name: 'member_default',\n label: 'Member — Standard Access',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: true,\n allowEdit: true,\n allowDelete: true,\n },\n // Identity tables are managed by better-auth — no direct writes.\n ...denyWritesOnManagedObjects(),\n },\n rowLevelSecurity: [\n {\n name: 'tenant_isolation',\n object: '*',\n operation: 'all',\n using: 'organization_id = current_user.organization_id',\n },\n // Owner-scoped writes/deletes for rank-and-file members: you may modify\n // and delete the records you created, not other users'. Keyed on\n // `created_by` — the column the engine stamps on EVERY record — rather\n // than `owner_id`, which author-defined objects almost never declare. The\n // old `owner_id` key referenced a missing column on real objects, so\n // `computeRlsFilter` dropped the policy and the scoping silently no-op'd\n // (any member could edit/delete any record — #1985). These policies are\n // ENFORCED on writes via the security middleware's pre-image check (a\n // by-id update/delete never builds an RLS `where`, so the predicate is\n // verified against the target row before the mutation). Objects that\n // model transferable ownership with a dedicated owner field should\n // override these with a per-object policy.\n {\n name: 'owner_only_writes',\n object: '*',\n operation: 'update',\n using: 'created_by = current_user.id',\n },\n {\n name: 'owner_only_deletes',\n object: '*',\n operation: 'delete',\n using: 'created_by = current_user.id',\n },\n // ── better-auth system tables that lack `organization_id` and would\n // otherwise be left unprotected by the wildcard rule above. ────\n //\n // The security plugin's RLS injector treats wildcard policies that\n // target a missing field as `RLS_DENY_FILTER` (zero rows) unless a\n // per-object policy contributes an alternate match. Each `*_self`\n // policy below restores per-user visibility on a better-auth table\n // that has `user_id` but no `organization_id`. Tables without\n // `user_id` (`sys_verification`, `sys_jwks`, empty `sys_passkey`)\n // stay DENY for non-admins by design — only platform admins (via\n // `admin_full_access`, which has no RLS) should inspect them.\n {\n name: 'sys_organization_self',\n object: 'sys_organization',\n operation: 'all',\n using: 'id = current_user.organization_id',\n },\n {\n name: 'sys_user_self',\n object: 'sys_user',\n operation: 'select',\n using: 'id = current_user.id',\n },\n // Org collaborators: members can see other users in the same\n // organization. Without this, owner/assignee lookups, @-mention\n // suggestions, reviewer pickers and team-roster surfaces all\n // collapse to just the current user. `org_user_ids` is\n // pre-resolved by runtime/resolve-execution-context from\n // `sys_member` for the active organization. Sensitive credential\n // tables (`sys_account`, `sys_session`, `sys_api_key`, …) keep\n // their stricter self-only carve-outs above.\n {\n name: 'sys_user_org_members',\n object: 'sys_user',\n operation: 'select',\n using: 'id IN (current_user.org_user_ids)',\n },\n {\n name: 'sys_session_self',\n object: 'sys_session',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_account_self',\n object: 'sys_account',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_team_member_self',\n object: 'sys_team_member',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_two_factor_self',\n object: 'sys_two_factor',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_user_preference_self',\n object: 'sys_user_preference',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_api_key_self',\n object: 'sys_api_key',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_device_code_self',\n object: 'sys_device_code',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_access_token_self',\n object: 'sys_oauth_access_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_refresh_token_self',\n object: 'sys_oauth_refresh_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_consent_self',\n object: 'sys_oauth_consent',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n // OAuth applications a user has registered themselves (Account →\n // Developer → OAuth Applications). `sys_oauth_application` has no\n // `organization_id`, so without this carve-out the wildcard\n // `tenant_isolation` policy returns zero rows even for the owner.\n {\n name: 'sys_oauth_application_self',\n object: 'sys_oauth_application',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n ],\n }),\n PermissionSetSchema.parse({\n name: 'viewer_readonly',\n label: 'Viewer — Read-Only',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: false,\n allowEdit: false,\n allowDelete: false,\n },\n // Belt-and-suspenders: explicit deny on managed objects even though\n // the wildcard already denies — keeps the policy readable when\n // future relaxations might widen the wildcard.\n ...denyWritesOnManagedObjects(),\n },\n rowLevelSecurity: [\n {\n name: 'tenant_isolation',\n object: '*',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n {\n name: 'sys_organization_self',\n object: 'sys_organization',\n operation: 'select',\n using: 'id = current_user.organization_id',\n },\n {\n name: 'sys_user_self',\n object: 'sys_user',\n operation: 'select',\n using: 'id = current_user.id',\n },\n // Org collaborators (read-only): see `sys_user_org_members` in\n // `member_default` for rationale.\n {\n name: 'sys_user_org_members',\n object: 'sys_user',\n operation: 'select',\n using: 'id IN (current_user.org_user_ids)',\n },\n {\n name: 'sys_session_self',\n object: 'sys_session',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_account_self',\n object: 'sys_account',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_team_member_self',\n object: 'sys_team_member',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_two_factor_self',\n object: 'sys_two_factor',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_user_preference_self',\n object: 'sys_user_preference',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_api_key_self',\n object: 'sys_api_key',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_device_code_self',\n object: 'sys_device_code',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_access_token_self',\n object: 'sys_oauth_access_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_refresh_token_self',\n object: 'sys_oauth_refresh_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_consent_self',\n object: 'sys_oauth_consent',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n ],\n }),\n];\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Canonical plugin-security manifest source.\n *\n * Both `objectstack.config.ts` (compile-time) and `security-plugin.ts`\n * (runtime `manifest.register`) import from this file so the two\n * registration paths cannot drift (D7).\n */\n\nimport {\n SysPermissionSet,\n SysRole,\n SysUserPermissionSet,\n SysRolePermissionSet,\n defaultPermissionSets,\n} from './objects/index.js';\n\nexport const SECURITY_PLUGIN_ID = 'com.objectstack.plugin-security';\nexport const SECURITY_PLUGIN_VERSION = '1.0.0';\n\n/** Security objects owned by plugin-security. */\nexport const securityObjects = [\n SysRole,\n SysPermissionSet,\n SysUserPermissionSet,\n SysRolePermissionSet,\n];\n\n/** Default platform permission sets (admin / member / viewer). */\nexport const securityDefaultPermissionSets = defaultPermissionSets;\n\n/** Manifest header shared by compile-time config and runtime registration. */\nexport const securityPluginManifestHeader = {\n id: SECURITY_PLUGIN_ID,\n namespace: 'sys',\n version: SECURITY_PLUGIN_VERSION,\n type: 'plugin' as const,\n scope: 'system' as const,\n defaultDatasource: 'cloud',\n name: 'Security Plugin',\n description: 'RBAC roles and permission sets for ObjectStack (Role, PermissionSet)',\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport type { PermissionSet, RowLevelSecurityPolicy } from '@objectstack/spec/security';\nimport { PermissionEvaluator } from './permission-evaluator.js';\nimport { RLSCompiler, RLS_DENY_FILTER } from './rls-compiler.js';\nimport { FieldMasker } from './field-masker.js';\nimport { PermissionDeniedError } from './errors.js';\nimport { bootstrapPlatformAdmin } from './bootstrap-platform-admin.js';\nimport {\n backfillOrgAdminGrants,\n extractMemberPairs,\n reconcileOrgAdminGrant,\n} from './auto-org-admin-grant.js';\nimport {\n securityObjects,\n securityDefaultPermissionSets,\n securityPluginManifestHeader,\n} from './manifest.js';\n\nexport interface SecurityPluginOptions {\n /**\n * Additional permission sets to register with the metadata service on\n * plugin start. Defaults to {@link securityDefaultPermissionSets}\n * (admin_full_access / member_default / viewer_readonly).\n */\n defaultPermissionSets?: PermissionSet[];\n /**\n * Permission set name applied as an implicit baseline whenever an\n * authenticated request has no resolved permission sets (and no roles\n * that map to one). This guarantees baseline tenant/owner RLS for\n * every logged-in user even before an admin assigns explicit\n * profiles. Set to `null` to disable.\n *\n * @default 'member_default'\n */\n fallbackPermissionSet?: string | null;\n}\n\n/**\n * SecurityPlugin\n *\n * Provides RBAC, Row-Level Security, and Field-Level Security runtime.\n * Registers as an engine middleware on the ObjectQL engine.\n *\n * This plugin is fully optional — without it, the system operates\n * without permission checks (same as current behavior).\n *\n * **Multi-tenant Organization scoping is provided by the separate\n * `@objectstack/plugin-org-scoping` package** (auto-stamps\n * `organization_id` on insert, per-org seed replay, default-org\n * bootstrap). When that plugin is installed, SecurityPlugin detects\n * it via `getService('org-scoping')` and keeps the wildcard\n * `current_user.organization_id` RLS policies that ship with the\n * default permission sets. Without it, those policies are stripped so\n * single-tenant deployments don't pay the field-existence safety-net\n * cost on every find.\n *\n * Dependencies:\n * - objectql service (ObjectQL engine with middleware support)\n * - metadata service (MetadataFacade for reading permission sets and RLS policies)\n */\nexport class SecurityPlugin implements Plugin {\n name = 'com.objectstack.security';\n type = 'standard';\n version = '1.0.0';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private permissionEvaluator = new PermissionEvaluator();\n private rlsCompiler = new RLSCompiler();\n private fieldMasker = new FieldMasker();\n private readonly bootstrapPermissionSets: PermissionSet[];\n private readonly fallbackPermissionSet: string | null;\n /**\n * Runtime probe — set in `start()` from\n * `ctx.getService('org-scoping')`. When `false`, wildcard RLS\n * policies that reference `current_user.organization_id` are\n * stripped from the per-request policy set (saves the\n * field-existence safety net cost on every find in single-tenant\n * deployments). When `true`, the policies apply normally.\n */\n private orgScopingEnabled = false;\n /**\n * Per-object field-name cache. Populated lazily from the metadata\n * service / ObjectQL registry on first access per object. Schemas are\n * effectively immutable for the lifetime of the kernel today (hot\n * reload tears the kernel down), so we don't bother with\n * invalidation — a kernel restart drops the cache.\n */\n private readonly fieldNamesCache = new Map<string, Set<string> | null>();\n /**\n * Per-object cache of tenancy opt-out. `true` means the schema\n * explicitly disabled multi-tenancy (`tenancy.enabled === false` or\n * `systemFields.tenant === false`). Wildcard policies that target\n * the conventional tenant column (`organization_id`) are treated as\n * *not applicable* on these tables instead of triggering the\n * field-missing deny sentinel — without this, every read of a\n * cross-org catalog (e.g. `sys_package`, the Marketplace) returns\n * zero rows.\n */\n private readonly tenancyDisabledCache = new Map<string, boolean>();\n /**\n * Service handles captured in `start()` so the request-time RLS resolution\n * (used by BOTH the engine middleware and the public {@link getReadFilter}\n * service method) shares one code path. `null` until `start()` wires them.\n */\n private metadata: any = null;\n private ql: any = null;\n private dbLoader?: (names: string[]) => Promise<PermissionSet[]>;\n private logger: { info?: (...a: any[]) => void; warn?: (...a: any[]) => void; error?: (...a: any[]) => void } = {};\n\n constructor(options: SecurityPluginOptions = {}) {\n this.bootstrapPermissionSets =\n options.defaultPermissionSets ?? securityDefaultPermissionSets;\n this.fallbackPermissionSet =\n options.fallbackPermissionSet === undefined\n ? 'member_default'\n : options.fallbackPermissionSet;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Initializing Security Plugin...');\n\n // Register security services\n ctx.registerService('security.permissions', this.permissionEvaluator);\n ctx.registerService('security.rls', this.rlsCompiler);\n ctx.registerService('security.fieldMasker', this.fieldMasker);\n // Bootstrap permission sets (admin_full_access, member_default,\n // viewer_readonly by default) — exposed as a service so other\n // plugins (e.g. plugin-hono-server's /me/permissions endpoint)\n // can pass them as the fallback list to\n // `PermissionEvaluator.resolvePermissionSets` without re-importing\n // the platform-objects package directly.\n ctx.registerService('security.bootstrapPermissionSets', this.bootstrapPermissionSets);\n ctx.registerService('security.fallbackPermissionSet', this.fallbackPermissionSet);\n\n ctx.getService<{ register(m: any): void }>('manifest').register({\n ...securityPluginManifestHeader,\n objects: securityObjects,\n // Permission sets ride along on the manifest so the metadata service\n // can resolve them by name when SecurityPlugin middleware queries\n // `metadata.list('permissions')`.\n permissions: this.bootstrapPermissionSets,\n // ADR-0029 D7 — contribute the RBAC entries into the Setup app's\n // `group_access_control` slot. This plugin owns these objects (K2), so it\n // ships their menu too; when the plugin is absent the entries don't appear.\n navigationContributions: [\n {\n app: 'setup',\n group: 'group_access_control',\n priority: 100,\n items: [\n { id: 'nav_roles', type: 'object', label: 'Roles', objectName: 'sys_role', icon: 'shield-check' },\n { id: 'nav_permission_sets', type: 'object', label: 'Permission Sets', objectName: 'sys_permission_set', icon: 'lock' },\n ],\n },\n ],\n });\n\n // ADR-0029 D8 — contribute this plugin's object translations to the i18n\n // service on kernel:ready (the i18n plugin may register after this one).\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', async () => {\n try {\n const i18n = ctx.getService<any>('i18n');\n if (i18n && typeof i18n.loadTranslations === 'function') {\n const { SecurityTranslations } = await import('./translations/index.js');\n for (const [locale, data] of Object.entries(SecurityTranslations)) {\n i18n.loadTranslations(locale, data as Record<string, unknown>);\n }\n }\n } catch { /* i18n optional */ }\n });\n }\n\n ctx.logger.info('Security Plugin initialized', {\n defaultPermissionSets: this.bootstrapPermissionSets.map((p) => p.name),\n });\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Starting Security Plugin...');\n\n // Get required services\n let ql: any;\n let metadata: any;\n\n try {\n ql = ctx.getService('objectql');\n metadata = ctx.getService('metadata');\n } catch (e) {\n ctx.logger.warn('ObjectQL or metadata service not available, security middleware not registered');\n return;\n }\n\n if (!ql || typeof ql.registerMiddleware !== 'function') {\n ctx.logger.warn('ObjectQL engine does not support middleware, security middleware not registered');\n return;\n }\n\n // Capture handles so the request-time RLS resolution is shared by the\n // engine middleware AND the public getReadFilter service method.\n this.metadata = metadata;\n this.ql = ql;\n this.logger = ctx.logger;\n\n // Probe for OrgScopingPlugin presence. When registered, its\n // `init()` exposes itself as the `org-scoping` service. We capture\n // the boolean once at start time (plugin DI graph is static after\n // start) and let `collectRLSPolicies` consult it on every request.\n try {\n const orgScoping = ctx.getService('org-scoping');\n this.orgScopingEnabled = !!orgScoping;\n } catch {\n this.orgScopingEnabled = false;\n }\n if (this.orgScopingEnabled) {\n ctx.logger.info(\n '[security] org-scoping plugin detected — wildcard `organization_id` RLS policies will apply',\n );\n } else {\n ctx.logger.info(\n '[security] org-scoping plugin not present — wildcard `organization_id` RLS policies will be stripped (single-tenant mode)',\n );\n }\n\n // Construct a dbLoader once that lets resolvePermissionSets\n // surface user-defined permission sets from `sys_permission_set`\n // (created via the admin UI) in addition to plugin-registered\n // ones. Uses `isSystem` to bypass tenant RLS.\n const dbLoader = ql\n ? async (names: string[]) => {\n let rows: any;\n try {\n rows = await ql.find(\n 'sys_permission_set',\n { where: { name: { $in: names } }, limit: names.length },\n { context: { isSystem: true } },\n );\n } catch {\n rows = [];\n }\n const list = Array.isArray(rows) ? rows : rows?.records ?? [];\n return list.map((r: any) => ({\n name: r.name,\n label: r.label,\n objects: typeof r.object_permissions === 'string'\n ? JSON.parse(r.object_permissions || '{}')\n : r.object_permissions ?? {},\n fields: typeof r.field_permissions === 'string'\n ? JSON.parse(r.field_permissions || '{}')\n : r.field_permissions ?? {},\n }));\n }\n : undefined;\n this.dbLoader = dbLoader;\n\n // ADR-0021 D-C — expose the per-request READ scope as a reusable service.\n // The analytics raw-SQL path (which bypasses this engine middleware)\n // auto-bridges to `getService('security').getReadFilter(object, context)`\n // to enforce tenant/RLS on every base + joined object. We register the\n // service only once the metadata/ql/dbLoader handles are wired (above), so\n // a degraded start never exposes a half-initialised resolver.\n try {\n ctx.registerService('security', {\n getReadFilter: (object: string, context?: any) => this.getReadFilter(object, context),\n });\n ctx.logger.info('[security] registered \"security\" service (getReadFilter) for raw-SQL RLS bridging');\n } catch (e) {\n ctx.logger.warn?.('[security] failed to register \"security\" service', {\n error: (e as Error).message,\n });\n }\n\n // Register security middleware\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n // System operations bypass security\n if (opCtx.context?.isSystem) {\n return next();\n }\n\n const roles = opCtx.context?.roles ?? [];\n const explicitPermissionSets = opCtx.context?.permissions ?? [];\n\n // Skip security checks if no roles AND no explicit permission sets\n // AND no userId (anonymous/unauthenticated). The auth middleware\n // should handle authentication separately.\n if (\n roles.length === 0 &&\n explicitPermissionSets.length === 0 &&\n !opCtx.context?.userId\n ) {\n return next();\n }\n\n // 1. Resolve permission sets from BOTH role names and explicit\n // permission set names attached to the execution context. The\n // resolution (incl. the implicit + post-resolution baseline\n // fallback) is shared with the public getReadFilter service via\n // resolvePermissionSetsForContext — keeping the find-path RLS and\n // the analytics raw-SQL RLS provably in lock-step.\n let permissionSets: PermissionSet[] = [];\n try {\n permissionSets = await this.resolvePermissionSetsForContext(opCtx.context);\n } catch (e) {\n // Fail CLOSED. A permission-resolution failure must DENY the request,\n // never bypass the checks (that would let a degraded metadata service\n // expose every tenant's data). System/bootstrap operations already\n // short-circuited above (`opCtx.context?.isSystem`), so reaching here\n // means an authenticated user request whose RBAC/RLS could not be\n // resolved — deny it and alert.\n ctx.logger.error(\n `[security] permission resolution failed for operation '${opCtx.operation}' on ` +\n `object '${opCtx.object}' (user ${opCtx.context?.userId ?? 'unknown'}) — ` +\n `denying request (fail-closed)`,\n e instanceof Error ? e : new Error(String(e)),\n );\n throw new PermissionDeniedError(\n `[Security] Access denied: permission subsystem unavailable for ` +\n `operation '${opCtx.operation}' on object '${opCtx.object}'`,\n );\n }\n\n // 2. CRUD permission check\n if (permissionSets.length > 0) {\n const allowed = this.permissionEvaluator.checkObjectPermission(\n opCtx.operation,\n opCtx.object,\n permissionSets\n );\n\n if (!allowed) {\n throw new PermissionDeniedError(\n `[Security] Access denied: operation '${opCtx.operation}' on object '${opCtx.object}' ` +\n `is not permitted for roles [${roles.join(', ')}]`,\n { operation: opCtx.operation, object: opCtx.object, roles, permissionSets: explicitPermissionSets },\n );\n }\n }\n\n // 2.7. Row-level WRITE authorization (pre-image check).\n //\n // RLS is injected as a `where` filter on the read path (step 3, via\n // `opCtx.ast`), but a single-id update/delete goes straight to\n // `driver.update(object, id, …)` / `driver.delete(object, id)` — it builds\n // no `ast`, so the row-level predicate is NEVER applied to by-id writes.\n // The result (#1985): the CRUD check passes (member_default grants edit/\n // delete) and the owner/tenant RLS that was supposed to scope the write is\n // silently bypassed — any member could modify another user's record.\n //\n // Fix: before the mutation, compute the write-operation RLS filter and\n // verify the TARGET row satisfies it. We re-read the row through the\n // engine with `{ id } AND <writeFilter>`; a `find` does not re-enter this\n // block, so there is no recursion, and read-side RLS/tenant scoping\n // compose naturally. A `null` result means the row is either gone or\n // RLS-hidden → deny. When `computeRlsFilter` returns `null` (no policy\n // applies — e.g. an admin set with no RLS, or `modifyAllRecords`) the\n // check is skipped and behaviour is unchanged.\n if (\n (opCtx.operation === 'update' || opCtx.operation === 'delete') &&\n permissionSets.length > 0 &&\n !!opCtx.context?.userId &&\n this.ql\n ) {\n const targetId = this.extractSingleId(opCtx);\n if (targetId != null) {\n const writeFilter = await this.computeRlsFilter(\n permissionSets,\n opCtx.object,\n opCtx.operation,\n opCtx.context,\n );\n if (writeFilter) {\n let visible: unknown = null;\n try {\n visible = await this.ql.findOne(opCtx.object, {\n where: { $and: [{ id: targetId }, writeFilter] },\n context: opCtx.context,\n });\n } catch {\n // A read denial (e.g. no read permission) is itself a \"cannot\n // touch this row\" signal — fall through to the deny below.\n visible = null;\n }\n if (!visible) {\n throw new PermissionDeniedError(\n `[Security] Access denied: not permitted to ${opCtx.operation} this ` +\n `'${opCtx.object}' record (row-level security)`,\n {\n operation: opCtx.operation,\n object: opCtx.object,\n roles,\n permissionSets: explicitPermissionSets,\n recordId: targetId,\n },\n );\n }\n }\n }\n }\n\n // 2.5. Field-Level Security write enforcement.\n //\n // The client-side masker (ObjectForm / inline grid) already hides\n // non-editable fields from the UI, but that is a UX layer only —\n // a hand-crafted POST / direct ObjectQL call can still target a\n // forbidden field. We fail-closed here with an explicit 403 and\n // the offending field names, so:\n //\n // - honest clients get an actionable error (vs. silent drop,\n // which manifests as a confusing partial-save), and\n // - probing clients see that the boundary is enforced (vs.\n // getting a 200 with the field silently ignored, which\n // reveals nothing).\n //\n // Runs BEFORE the tenant/owner auto-injection (step 3.5) so the\n // system-set fields are not subject to the user's edit\n // permissions — they are populated from the execution context,\n // not from the caller's payload.\n if (\n (opCtx.operation === 'insert' || opCtx.operation === 'update') &&\n opCtx.data &&\n permissionSets.length > 0\n ) {\n const fieldPerms = this.permissionEvaluator.getFieldPermissions(\n opCtx.object,\n permissionSets,\n );\n if (Object.keys(fieldPerms).length > 0) {\n const forbidden = this.fieldMasker.detectForbiddenWrites(\n opCtx.data,\n fieldPerms,\n );\n if (forbidden.length > 0) {\n throw new PermissionDeniedError(\n `[Security] Field write denied: not permitted to edit ` +\n `[${forbidden.join(', ')}] on '${opCtx.object}'`,\n {\n operation: opCtx.operation,\n object: opCtx.object,\n roles,\n permissionSets: explicitPermissionSets,\n forbiddenFields: forbidden,\n },\n );\n }\n }\n }\n\n // 3.5. Auto-inject `owner_id` on insert from the\n // ExecutionContext. Without this, the row has `owner_id = NULL`\n // and the default `owner_only_writes` RLS policy hides it from\n // the very user who just created it.\n //\n // `organization_id` auto-injection has moved to\n // `@objectstack/plugin-org-scoping`. Install that plugin for\n // multi-tenant deployments.\n if (\n opCtx.operation === 'insert' &&\n opCtx.data &&\n typeof opCtx.data === 'object' &&\n !Array.isArray(opCtx.data) &&\n !!opCtx.context?.userId\n ) {\n const fields = await this.getObjectFieldNames(metadata, opCtx.object, ql);\n if (fields) {\n const data = opCtx.data as Record<string, unknown>;\n if (\n fields.has('owner_id') &&\n (data.owner_id == null || data.owner_id === '')\n ) {\n data.owner_id = opCtx.context!.userId;\n }\n }\n }\n\n // 3. RLS filter injection. The policy collection + field-existence\n // safety + compile (incl. the fail-closed deny sentinel) is shared with\n // the public getReadFilter service via computeRlsFilter, so the engine\n // find-path and the analytics raw-SQL path enforce identical scoping.\n if (opCtx.ast) {\n const rlsFilter = await this.computeRlsFilter(\n permissionSets,\n opCtx.object,\n opCtx.operation,\n opCtx.context,\n );\n if (rlsFilter) {\n if (opCtx.ast.where) {\n opCtx.ast.where = { $and: [opCtx.ast.where, rlsFilter] };\n } else {\n opCtx.ast.where = rlsFilter;\n }\n }\n }\n\n await next();\n\n // 4. Field-level security: mask restricted fields in read results\n if (opCtx.result && ['find', 'findOne'].includes(opCtx.operation)) {\n const fieldPerms = this.permissionEvaluator.getFieldPermissions(opCtx.object, permissionSets);\n if (Object.keys(fieldPerms).length > 0) {\n opCtx.result = this.fieldMasker.maskResults(opCtx.result, fieldPerms, opCtx.object);\n }\n }\n });\n\n ctx.logger.info('Security middleware registered on ObjectQL engine');\n\n // Defer platform admin bootstrap until all plugins finish starting —\n // sys_user / sys_permission_set objects must be registered (by\n // plugin-auth and platform-objects respectively) before we can\n // insert seed rows. Falls back to immediate execution when the\n // kernel does not expose `hook` (test stubs).\n let bootstrapRanOnce = false;\n const runBootstrap = async () => {\n try {\n const report = await bootstrapPlatformAdmin(ql, this.bootstrapPermissionSets, {\n logger: ctx.logger,\n });\n bootstrapRanOnce = true;\n ctx.logger.info('[security] platform bootstrap complete', report);\n return report;\n } catch (e) {\n ctx.logger.warn('[security] platform bootstrap failed', { error: (e as Error).message });\n return undefined;\n }\n };\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', runBootstrap);\n } else {\n void runBootstrap();\n }\n\n // Re-run bootstrap after a sys_user insert so the FIRST user that\n // signs up after boot is auto-promoted to platform admin (and, in\n // multi-tenant mode, bound to the seeded default organization)\n // without requiring a server restart. The function itself is\n // idempotent and bails out as soon as any platform admin exists.\n //\n // We deliberately do NOT auto-create a \"personal workspace\" for\n // every subsequent self-service signup. In a B2B / invitation-\n // driven product (the framework's primary target), users must\n // either accept an invitation or explicitly create their first\n // organization. The account UI's /register flow already routes\n // users with zero memberships to /organizations/new for exactly\n // this case.\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n await next();\n if (\n opCtx?.object === 'sys_user' &&\n (opCtx?.operation === 'create' || opCtx?.operation === 'insert')\n ) {\n if (bootstrapRanOnce) {\n await runBootstrap();\n }\n }\n });\n\n // ── Auto-grant `organization_admin` on sys_member lifecycle ─────────\n //\n // For every `sys_member` row whose role is `owner` or `admin`, keep\n // a `sys_user_permission_set` row scoped to that organization in\n // sync. See `auto-org-admin-grant.ts` for the full rationale and\n // the anti-escalation argument (org_admin is read-only on the\n // global RBAC tables, so a freshly-granted admin cannot rebind\n // themselves to `admin_full_access`).\n //\n // We register one middleware that handles insert / update / delete\n // uniformly by always reconciling every (user, org) pair touched\n // by the operation. `reconcileOrgAdminGrant` is idempotent so a\n // double-fire (e.g. better-auth followed by an org plugin\n // synchronizer) is harmless.\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n await next();\n if (opCtx?.object !== 'sys_member') return;\n const op = opCtx?.operation;\n if (\n op !== 'insert' &&\n op !== 'create' &&\n op !== 'update' &&\n op !== 'delete' &&\n op !== 'remove'\n ) {\n return;\n }\n const pairs = extractMemberPairs(opCtx);\n for (const { userId, orgId } of pairs) {\n try {\n await reconcileOrgAdminGrant(ql, userId, orgId, { logger: ctx.logger });\n } catch (e) {\n ctx.logger.warn?.('[security] org_admin reconcile failed', {\n userId,\n orgId,\n error: (e as Error).message,\n });\n }\n }\n });\n\n // Backfill organization_admin grants after the platform admin\n // bootstrap settles on kernel:ready. Idempotent — only inserts\n // missing rows and revokes orphaned ones, never duplicates.\n const runOrgAdminBackfill = async () => {\n try {\n await backfillOrgAdminGrants(ql, { logger: ctx.logger });\n } catch (e) {\n ctx.logger.warn?.('[security] organization_admin backfill failed', {\n error: (e as Error).message,\n });\n }\n };\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', runOrgAdminBackfill);\n } else {\n void runOrgAdminBackfill();\n }\n\n // Per-organization seed data replay on `sys_organization` insert\n // moved to `@objectstack/plugin-org-scoping` (along with\n // `claimOrphanOrgRows` / `cloneOrgSeedData`). Install that\n // plugin for multi-tenant deployments.\n }\n\n async destroy(): Promise<void> {\n // No cleanup needed\n }\n\n /**\n * ADR-0021 D-C — resolve the per-request READ scope (tenant + RLS predicate)\n * for one object as a canonical `FilterCondition`, WITHOUT touching the\n * ObjectQL engine. This is the seam the analytics raw-SQL path bridges to so\n * it enforces the SAME row scoping the engine middleware applies on `find`.\n *\n * Returns:\n * - `undefined` → no scope applies (system context, or an unauthenticated\n * request with no userId/roles/permissions — authn is gated elsewhere).\n * - a `FilterCondition` → AND it into the object's scan (the join's `ON`/\n * `WHERE` for analytics; the where clause for a plain find).\n * - the `RLS_DENY_FILTER` sentinel → policies applied but none compiled, or\n * resolution failed — fail-closed to zero rows. NEVER returns \"allow all\"\n * on error, so a degraded permission subsystem cannot leak cross-tenant\n * rows through analytics.\n *\n * Async because permission-set resolution can hit the database; the analytics\n * service pre-resolves these per request (base + every joined object) before\n * the synchronous SQL builder runs.\n */\n async getReadFilter(\n object: string,\n context?: any,\n ): Promise<Record<string, unknown> | null | undefined> {\n // System operations bypass scoping (mirrors the middleware's isSystem skip).\n if (context?.isSystem) return undefined;\n const roles = context?.roles ?? [];\n const explicit = context?.permissions ?? [];\n // Unauthenticated + role-less + permission-less → no scope (the auth layer,\n // not RLS, gates anonymous access; the analytics REST endpoint already 401s\n // without a token). Mirrors the middleware's early `return next()`.\n if (roles.length === 0 && explicit.length === 0 && !context?.userId) {\n return undefined;\n }\n try {\n const permissionSets = await this.resolvePermissionSetsForContext(context);\n const filter = await this.computeRlsFilter(permissionSets, object, 'find', context);\n return filter ?? undefined;\n } catch (e) {\n // Fail CLOSED — a resolution failure must deny (zero rows), never expose\n // every tenant's data through the raw-SQL analytics path.\n this.logger.error?.(\n `[security] getReadFilter failed for object '${object}' ` +\n `(user ${context?.userId ?? 'unknown'}) — denying (fail-closed)`,\n e instanceof Error ? e : new Error(String(e)),\n );\n return { ...RLS_DENY_FILTER };\n }\n }\n\n /**\n * Resolve the effective permission sets for an execution context — roles +\n * explicit permission sets, with the configured baseline applied both as an\n * implicit request (when none were named) and as a post-resolution fallback\n * (when named ones resolved to nothing). Shared by the engine middleware and\n * {@link getReadFilter} so both enforce identical RLS. May throw if the\n * underlying metadata/db resolution fails (callers fail-closed).\n */\n private async resolvePermissionSetsForContext(\n context: any,\n ): Promise<PermissionSet[]> {\n const roles = context?.roles ?? [];\n const explicitPermissionSets = context?.permissions ?? [];\n const requested = [...roles, ...explicitPermissionSets];\n // Implicit baseline: an authenticated request that named no roles/perms\n // still gets the configured baseline (default `member_default`) so tenant +\n // owner RLS apply before an admin assigns a profile.\n if (requested.length === 0 && context?.userId && this.fallbackPermissionSet) {\n requested.push(this.fallbackPermissionSet);\n }\n let permissionSets = await this.permissionEvaluator.resolvePermissionSets(\n requested,\n this.metadata,\n this.bootstrapPermissionSets,\n this.dbLoader,\n );\n // Post-resolution fallback — closes the fail-open hole where a populated\n // `roles` array maps to no permission set yet (no sys_role binding), which\n // would otherwise skip RLS entirely and expose every tenant's data.\n if (\n permissionSets.length === 0 &&\n context?.userId &&\n this.fallbackPermissionSet\n ) {\n permissionSets = await this.permissionEvaluator.resolvePermissionSets(\n [this.fallbackPermissionSet],\n this.metadata,\n this.bootstrapPermissionSets,\n this.dbLoader,\n );\n }\n return permissionSets;\n }\n\n /**\n * Resolve a single scalar primary-key id from an update/delete operation\n * context, mirroring the engine's \"single-id vs predicate\" rule\n * (`engine.ts` update/delete): only a scalar `data.id` or `where.id`\n * identifies one row. An operator object (`{ $in: [...] }`, …) is a\n * multi-row predicate and returns `null` (multi-row writes route through the\n * `*Many` paths, out of scope for the by-id pre-image check).\n */\n private extractSingleId(opCtx: any): string | number | bigint | null {\n const isScalar = (v: unknown): v is string | number | bigint =>\n v !== null && (typeof v === 'string' || typeof v === 'number' || typeof v === 'bigint');\n const data = opCtx?.data;\n if (data && typeof data === 'object' && !Array.isArray(data) && isScalar(data.id)) {\n return data.id;\n }\n const where = opCtx?.options?.where;\n if (where && typeof where === 'object' && 'id' in where && isScalar((where as any).id)) {\n return (where as any).id;\n }\n return null;\n }\n\n /**\n * Compile the applicable RLS policies for (object, operation) into a single\n * `FilterCondition`, applying the field-existence safety net (wildcard\n * policies targeting a column the object lacks fail-closed to the deny\n * sentinel, unless the object explicitly opted out of tenancy). Shared by the\n * engine middleware and {@link getReadFilter}. Returns `null` when no policy\n * applies (caller adds no filter).\n */\n private async computeRlsFilter(\n permissionSets: PermissionSet[],\n object: string,\n operation: string,\n context: any,\n ): Promise<Record<string, unknown> | null> {\n const allRlsPolicies = this.collectRLSPolicies(permissionSets, object, operation);\n if (allRlsPolicies.length === 0) return null;\n // Field-existence safety: wildcard policies (`object: '*'`) target fields\n // like `organization_id` that may not exist on every object. Treat such a\n // policy as a *deny* contribution (fail-closed) rather than dropping it —\n // unless the object explicitly opted out of tenancy, where it's \"not\n // applicable\" and skipped silently. When the schema lookup itself fails we\n // keep all policies (drivers surface column errors clearly at compile time).\n const objectFields = await this.getObjectFieldNames(this.metadata, object, this.ql);\n const tenancyDisabled = this.tenancyDisabledCache.get(object) === true;\n let dropped = 0;\n const compilable = objectFields\n ? allRlsPolicies.filter((p) => {\n const targetField = this.extractTargetField(p.using);\n if (!targetField) return true;\n if (objectFields.has(targetField)) return true;\n if (tenancyDisabled && targetField === 'organization_id') {\n return false;\n }\n dropped++;\n return false;\n })\n : allRlsPolicies;\n let rlsFilter = this.rlsCompiler.compileFilter(compilable, context);\n // Every applicable policy dropped for a missing field → deny sentinel.\n if (rlsFilter == null && dropped > 0) {\n rlsFilter = { ...RLS_DENY_FILTER };\n }\n return rlsFilter;\n }\n\n /**\n * Collect all RLS policies from permission sets applicable to the given object/operation.\n */\n private collectRLSPolicies(\n permissionSets: PermissionSet[],\n objectName: string,\n operation: string\n ): RowLevelSecurityPolicy[] {\n const allPolicies: RowLevelSecurityPolicy[] = [];\n\n for (const ps of permissionSets) {\n if (ps.rowLevelSecurity) {\n for (const policy of ps.rowLevelSecurity) {\n // When the org-scoping plugin is NOT installed, strip any\n // policy that filters on `current_user.organization_id` —\n // there is no meaningful tenant to compare against, so the\n // policy would either drop every row (when the field exists\n // on the object) or be dropped by the field-existence safety\n // net. Either way it's pure overhead. Substring match is\n // sufficient: every wildcard tenant policy in the default\n // permission sets uses exactly this token. Install\n // `@objectstack/plugin-org-scoping` to enable the\n // multi-tenant behavior.\n if (\n !this.orgScopingEnabled &&\n policy.using &&\n policy.using.includes('current_user.organization_id')\n ) {\n continue;\n }\n allPolicies.push(policy);\n }\n }\n }\n\n return this.rlsCompiler.getApplicablePolicies(objectName, operation, allPolicies);\n }\n\n /**\n * Resolve the column-name set for an object (lowercased). Returns\n * `null` if the schema can't be loaded — caller should fail-closed.\n */\n private async getObjectFieldNames(\n metadata: any,\n objectName: string,\n ql?: any,\n ): Promise<Set<string> | null> {\n if (this.fieldNamesCache.has(objectName)) {\n return this.fieldNamesCache.get(objectName) ?? null;\n }\n const result = await this.loadObjectFieldNames(metadata, objectName, ql);\n // Only cache positive resolutions — a `null` may simply mean the\n // schema isn't registered yet at boot, and we want subsequent calls\n // to retry rather than be permanently denied.\n if (result) {\n this.fieldNamesCache.set(objectName, result);\n }\n return result;\n }\n\n private async loadObjectFieldNames(\n metadata: any,\n objectName: string,\n ql?: any,\n ): Promise<Set<string> | null> {\n try {\n // Prefer ObjectQL's per-engine SchemaRegistry as the source of truth\n // for the live field set: it reflects registry-time augmentations\n // (system-field auto-injection like `organization_id`) that the\n // standalone metadata artifact loaded at boot may not include.\n // Fall back to the metadata service for objects ObjectQL doesn't\n // know about (system tables registered through other paths).\n let obj: any = typeof ql?.getSchema === 'function' ? ql.getSchema(objectName) : null;\n if (!obj || !obj.fields) {\n obj = await metadata?.get?.('object', objectName);\n }\n if (!obj || !obj.fields) return null;\n // Populate the tenancy opt-out cache alongside the field set so\n // the RLS filter pass can decide whether a wildcard\n // `organization_id` policy is genuinely \"applicable but\n // uncompilable\" (deny) versus \"not applicable on this object\"\n // (skip without contributing to the deny sentinel).\n const tenancyDisabled =\n (obj as any)?.tenancy?.enabled === false ||\n (obj as any)?.systemFields?.tenant === false;\n this.tenancyDisabledCache.set(objectName, !!tenancyDisabled);\n const set = new Set<string>(['id']);\n if (Array.isArray(obj.fields)) {\n for (const f of obj.fields) {\n if (f?.name) set.add(String(f.name));\n }\n } else if (typeof obj.fields === 'object') {\n for (const key of Object.keys(obj.fields)) {\n set.add(key);\n const v = (obj.fields as Record<string, any>)[key];\n if (v && typeof v === 'object' && v.name) set.add(String(v.name));\n }\n } else {\n return null;\n }\n return set;\n } catch {\n return null;\n }\n }\n\n /**\n * Extract the left-hand field name from a simple RLS expression like\n * `field = current_user.x` or `field IN (current_user.y)`. Returns\n * `null` for unsupported shapes (in which case we keep the policy).\n */\n private extractTargetField(using?: string): string | null {\n if (!using) return null;\n // Match `field =` or `field IN`/`in`. Note: `\\b` is omitted after `=`\n // because `=` is non-word and the next char (space) is non-word too —\n // a word boundary cannot exist between two non-word chars, so `=\\b`\n // would never match. We instead require the alternation token to be\n // followed by whitespace or `(`.\n const m = using.match(/^\\s*([a-z_][a-z0-9_]*)\\s*(?:=|IN|in)(?=\\s|\\()/);\n return m ? m[1] : null;\n }\n}\n"],"mappings":"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","names":["SystemUserId","SYSTEM_CTX","SystemUserId","SYSTEM_CTX","genId","tryFind","tryInsert","ObjectSchema","Field","ObjectSchema","Field","ObjectSchema","Field","SecurityTranslations"]}
1
+ {"version":3,"sources":["../src/translations/en.objects.generated.ts","../src/translations/zh-CN.objects.generated.ts","../src/translations/ja-JP.objects.generated.ts","../src/translations/es-ES.objects.generated.ts","../src/translations/index.ts","../src/permission-evaluator.ts","../src/rls-compiler.ts","../src/field-masker.ts","../src/errors.ts","../src/bootstrap-platform-admin.ts","../src/claim-seed-ownership.ts","../src/auto-org-admin-grant.ts","../src/objects/sys-role.object.ts","../src/objects/sys-permission-set.object.ts","../src/objects/sys-user-permission-set.object.ts","../src/objects/sys-role-permission-set.object.ts","../src/objects/default-permission-sets.ts","../src/manifest.ts","../src/security-plugin.ts","../src/app-default-profile.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'en'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const enObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"Role\",\n pluralLabel: \"Roles\",\n description: \"Role definitions for RBAC access control\",\n fields: {\n label: {\n label: \"Display Name\"\n },\n name: {\n label: \"API Name\",\n help: \"Unique machine name for the role (e.g. admin, editor, viewer)\"\n },\n description: {\n label: \"Description\"\n },\n permissions: {\n label: \"Permissions\",\n help: \"JSON-serialized array of permission strings\"\n },\n active: {\n label: \"Active\"\n },\n is_default: {\n label: \"Default Role\",\n help: \"Automatically assigned to new users\"\n },\n id: {\n label: \"Role ID\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\"\n },\n default_roles: {\n label: \"Default\"\n },\n custom: {\n label: \"Custom\"\n },\n all_roles: {\n label: \"All\"\n }\n },\n _actions: {\n activate_role: {\n label: \"Activate Role\",\n successMessage: \"Role activated\"\n },\n deactivate_role: {\n label: \"Deactivate Role\",\n confirmText: \"Deactivate this role? Users with the role keep their assignment but the role stops granting permissions until re-activated.\",\n successMessage: \"Role deactivated\"\n },\n set_default_role: {\n label: \"Set as Default\",\n confirmText: \"Make this the default role for new users? Existing users are unaffected.\",\n successMessage: \"Default role updated\"\n },\n clone_role: {\n label: \"Clone Role\",\n successMessage: \"Role cloned\"\n }\n }\n },\n sys_permission_set: {\n label: \"Permission Set\",\n pluralLabel: \"Permission Sets\",\n description: \"Named permission groupings for fine-grained access control\",\n fields: {\n label: {\n label: \"Display Name\"\n },\n name: {\n label: \"API Name\",\n help: \"Unique machine name for the permission set\"\n },\n description: {\n label: \"Description\"\n },\n object_permissions: {\n label: \"Object Permissions\",\n help: \"JSON-serialized object-level CRUD permissions\"\n },\n field_permissions: {\n label: \"Field Permissions\",\n help: \"JSON-serialized field-level read/write permissions\"\n },\n system_permissions: {\n label: \"System Permissions\",\n help: \"JSON-serialized array of system capability names (e.g. [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"Row-Level Security\",\n help: \"JSON-serialized array of row-level security policies (USING/CHECK clauses)\"\n },\n tab_permissions: {\n label: \"Tab Permissions\",\n help: \"JSON-serialized map of app tab visibility (visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"Active\"\n },\n id: {\n label: \"Permission Set ID\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n },\n _views: {\n active: {\n label: \"Active\"\n },\n inactive: {\n label: \"Inactive\"\n },\n all_permsets: {\n label: \"All\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"Activate\",\n successMessage: \"Permission set activated\"\n },\n deactivate_permission_set: {\n label: \"Deactivate\",\n confirmText: \"Deactivate this permission set? Existing assignments stay in place but stop granting access until re-activated.\",\n successMessage: \"Permission set deactivated\"\n },\n clone_permission_set: {\n label: \"Clone\",\n successMessage: \"Permission set cloned\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"User Permission Set\",\n pluralLabel: \"User Permission Sets\",\n description: \"Direct assignment of a permission set to a user (optionally scoped to an organization).\",\n fields: {\n id: {\n label: \"Assignment ID\",\n help: \"UUID of the assignment.\"\n },\n user_id: {\n label: \"User\",\n help: \"Foreign key to sys_user.\"\n },\n permission_set_id: {\n label: \"Permission Set\",\n help: \"Foreign key to sys_permission_set.\"\n },\n organization_id: {\n label: \"Organization\",\n help: \"Optional organization scope. NULL = applies in every org context.\"\n },\n granted_by: {\n label: \"Granted By\",\n help: \"User who granted this permission set.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"Role Permission Set\",\n pluralLabel: \"Role Permission Sets\",\n description: \"Binds a permission set to a role.\",\n fields: {\n id: {\n label: \"Binding ID\",\n help: \"UUID of the role-permission-set binding.\"\n },\n role_id: {\n label: \"Role\",\n help: \"Foreign key to sys_role.\"\n },\n permission_set_id: {\n label: \"Permission Set\",\n help: \"Foreign key to sys_permission_set.\"\n },\n created_at: {\n label: \"Created At\"\n },\n updated_at: {\n label: \"Updated At\"\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'zh-CN'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const zhCNObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"角色\",\n pluralLabel: \"角色\",\n description: \"用于 RBAC 访问控制的角色定义\",\n fields: {\n label: {\n label: \"显示名称\"\n },\n name: {\n label: \"API 名称\",\n help: \"角色的唯一机器名称(例如 admin、editor、viewer)\"\n },\n description: {\n label: \"描述\"\n },\n permissions: {\n label: \"权限\",\n help: \"权限字符串数组的 JSON 序列化内容\"\n },\n active: {\n label: \"启用\"\n },\n is_default: {\n label: \"默认角色\",\n help: \"自动分配给新用户\"\n },\n id: {\n label: \"角色 ID\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n active: {\n label: \"启用\"\n },\n default_roles: {\n label: \"默认\"\n },\n custom: {\n label: \"自定义\"\n },\n all_roles: {\n label: \"全部\"\n }\n },\n _actions: {\n activate_role: {\n label: \"激活角色\",\n successMessage: \"角色已激活\"\n },\n deactivate_role: {\n label: \"停用角色\",\n confirmText: \"确定要停用此角色吗?拥有该角色的用户仍保留其分配,但在重新激活之前该角色将不再授予权限。\",\n successMessage: \"角色已停用\"\n },\n set_default_role: {\n label: \"设为默认\",\n confirmText: \"将此角色设为新用户的默认角色吗?现有用户不受影响。\",\n successMessage: \"已更新默认角色\"\n },\n clone_role: {\n label: \"克隆角色\",\n successMessage: \"已克隆角色\"\n }\n }\n },\n sys_permission_set: {\n label: \"权限集\",\n pluralLabel: \"权限集\",\n description: \"用于精细化访问控制的命名权限分组\",\n fields: {\n label: {\n label: \"显示名称\"\n },\n name: {\n label: \"API 名称\",\n help: \"权限集的唯一机器名称\"\n },\n description: {\n label: \"描述\"\n },\n object_permissions: {\n label: \"对象权限\",\n help: \"对象级 CRUD 权限的 JSON 序列化内容\"\n },\n field_permissions: {\n label: \"字段权限\",\n help: \"字段级读写权限的 JSON 序列化内容\"\n },\n system_permissions: {\n label: \"系统权限\",\n help: \"系统能力名称的 JSON 序列化数组(例如 [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"行级安全\",\n help: \"行级安全策略的 JSON 序列化数组(USING/CHECK 子句)\"\n },\n tab_permissions: {\n label: \"标签页权限\",\n help: \"应用标签页可见性的 JSON 序列化映射(visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"启用\"\n },\n id: {\n label: \"权限集 ID\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n },\n _views: {\n active: {\n label: \"启用\"\n },\n inactive: {\n label: \"停用\"\n },\n all_permsets: {\n label: \"全部\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"激活\",\n successMessage: \"权限集已激活\"\n },\n deactivate_permission_set: {\n label: \"停用\",\n confirmText: \"确定要停用此权限集吗?现有分配仍将保留,但在重新激活之前将不再授予访问权限。\",\n successMessage: \"权限集已停用\"\n },\n clone_permission_set: {\n label: \"克隆\",\n successMessage: \"已克隆权限集\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"用户权限集\",\n pluralLabel: \"用户权限集\",\n description: \"将权限集直接分配给用户(可按组织范围限定)。\",\n fields: {\n id: {\n label: \"分配 ID\",\n help: \"该分配记录的 UUID。\"\n },\n user_id: {\n label: \"用户\",\n help: \"指向 sys_user 的外键。\"\n },\n permission_set_id: {\n label: \"权限集\",\n help: \"指向 sys_permission_set 的外键。\"\n },\n organization_id: {\n label: \"组织\",\n help: \"可选的组织范围。NULL = 在所有组织上下文中都生效。\"\n },\n granted_by: {\n label: \"授权人\",\n help: \"授予该权限集的用户。\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"角色权限集\",\n pluralLabel: \"角色权限集\",\n description: \"将权限集绑定到角色。\",\n fields: {\n id: {\n label: \"绑定 ID\",\n help: \"角色-权限集绑定记录的 UUID。\"\n },\n role_id: {\n label: \"角色\",\n help: \"指向 sys_role 的外键。\"\n },\n permission_set_id: {\n label: \"权限集\",\n help: \"指向 sys_permission_set 的外键。\"\n },\n created_at: {\n label: \"创建时间\"\n },\n updated_at: {\n label: \"更新时间\"\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'ja-JP'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const jaJPObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"ロール\",\n pluralLabel: \"ロール\",\n description: \"RBAC アクセス制御のためのロール定義\",\n fields: {\n label: {\n label: \"表示名\"\n },\n name: {\n label: \"API 名\",\n help: \"ロールの一意の機械名(例: admin、editor、viewer)\"\n },\n description: {\n label: \"説明\"\n },\n permissions: {\n label: \"権限\",\n help: \"権限文字列の JSON シリアライズ配列\"\n },\n active: {\n label: \"有効\"\n },\n is_default: {\n label: \"デフォルトロール\",\n help: \"新規ユーザーに自動的に割り当てられます\"\n },\n id: {\n label: \"ロール ID\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n },\n _views: {\n active: {\n label: \"有効\"\n },\n default_roles: {\n label: \"デフォルト\"\n },\n custom: {\n label: \"カスタム\"\n },\n all_roles: {\n label: \"すべて\"\n }\n },\n _actions: {\n activate_role: {\n label: \"ロールを有効化\",\n successMessage: \"ロールが有効化されました\"\n },\n deactivate_role: {\n label: \"ロールを無効化\",\n confirmText: \"このロールを無効化しますか?このロールを持つユーザーの割り当ては維持されますが、再度有効化するまで権限の付与は停止されます。\",\n successMessage: \"ロールが無効化されました\"\n },\n set_default_role: {\n label: \"デフォルトに設定\",\n confirmText: \"このロールを新規ユーザーのデフォルトロールにしますか?既存のユーザーには影響しません。\",\n successMessage: \"デフォルトロールを更新しました\"\n },\n clone_role: {\n label: \"ロールを複製\",\n successMessage: \"ロールを複製しました\"\n }\n }\n },\n sys_permission_set: {\n label: \"権限セット\",\n pluralLabel: \"権限セット\",\n description: \"細かいアクセス制御のための権限グループ\",\n fields: {\n label: {\n label: \"表示名\"\n },\n name: {\n label: \"API 名\",\n help: \"権限セットの一意の機械名\"\n },\n description: {\n label: \"説明\"\n },\n object_permissions: {\n label: \"オブジェクト権限\",\n help: \"JSON シリアライズされたオブジェクトレベルの CRUD 権限\"\n },\n field_permissions: {\n label: \"フィールド権限\",\n help: \"JSON シリアライズされたフィールドレベルの読み取り/書き込み権限\"\n },\n system_permissions: {\n label: \"システム権限\",\n help: \"システムケーパビリティ名のJSONシリアライズ配列(例: [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"行レベルセキュリティ\",\n help: \"行レベルセキュリティポリシーのJSONシリアライズ配列(USING/CHECK 句)\"\n },\n tab_permissions: {\n label: \"タブ権限\",\n help: \"アプリのタブ表示のJSONシリアライズマップ(visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"有効\"\n },\n id: {\n label: \"権限セット ID\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n },\n _views: {\n active: {\n label: \"有効\"\n },\n inactive: {\n label: \"無効\"\n },\n all_permsets: {\n label: \"すべて\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"有効化\",\n successMessage: \"権限セットが有効化されました\"\n },\n deactivate_permission_set: {\n label: \"無効化\",\n confirmText: \"この権限セットを無効化しますか?既存の割り当ては維持されますが、再度有効化するまでアクセスの付与は停止されます。\",\n successMessage: \"権限セットが無効化されました\"\n },\n clone_permission_set: {\n label: \"複製\",\n successMessage: \"権限セットを複製しました\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"ユーザー権限セット\",\n pluralLabel: \"ユーザー権限セット\",\n description: \"ユーザーへの権限セットの直接割り当て(組織スコープ可能)。\",\n fields: {\n id: {\n label: \"割り当て ID\",\n help: \"割り当ての UUID。\"\n },\n user_id: {\n label: \"ユーザー\",\n help: \"sys_user への外部キー。\"\n },\n permission_set_id: {\n label: \"権限セット\",\n help: \"sys_permission_set への外部キー。\"\n },\n organization_id: {\n label: \"組織\",\n help: \"オプションの組織スコープ。NULL = すべての組織コンテキストで適用。\"\n },\n granted_by: {\n label: \"付与者\",\n help: \"この権限セットを付与したユーザー。\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"ロール権限セット\",\n pluralLabel: \"ロール権限セット\",\n description: \"権限セットをロールにバインドします。\",\n fields: {\n id: {\n label: \"バインド ID\",\n help: \"ロール権限セットバインドの UUID。\"\n },\n role_id: {\n label: \"ロール\",\n help: \"sys_role への外部キー。\"\n },\n permission_set_id: {\n label: \"権限セット\",\n help: \"sys_permission_set への外部キー。\"\n },\n created_at: {\n label: \"作成日時\"\n },\n updated_at: {\n label: \"更新日時\"\n }\n }\n }\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-generated by 'os i18n extract' for locale 'es-ES'.\n * Edit translations in place; re-run extract (with --merge) to fill new gaps.\n * Do not hand-edit the structure — only the leaf string values.\n */\n\nimport type { TranslationData } from '@objectstack/spec/system';\n\nexport const esESObjects: NonNullable<TranslationData['objects']> = {\n sys_role: {\n label: \"Rol\",\n pluralLabel: \"Roles\",\n description: \"Definiciones de rol para el control de acceso RBAC\",\n fields: {\n label: {\n label: \"Nombre visible\"\n },\n name: {\n label: \"Nombre de API\",\n help: \"Nombre técnico único del rol (p. ej. admin, editor, viewer).\"\n },\n description: {\n label: \"Descripción\"\n },\n permissions: {\n label: \"Permisos\",\n help: \"Matriz serializada en JSON de cadenas de permisos.\"\n },\n active: {\n label: \"Activo\"\n },\n is_default: {\n label: \"Rol predeterminado\",\n help: \"Se asigna automáticamente a los nuevos usuarios.\"\n },\n id: {\n label: \"ID de rol\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n },\n _views: {\n active: {\n label: \"Activo\"\n },\n default_roles: {\n label: \"Predeterminado\"\n },\n custom: {\n label: \"Personalizado\"\n },\n all_roles: {\n label: \"Todos\"\n }\n },\n _actions: {\n activate_role: {\n label: \"Activar rol\",\n successMessage: \"Rol activado\"\n },\n deactivate_role: {\n label: \"Desactivar rol\",\n confirmText: \"¿Desactivar este rol? Los usuarios con el rol conservan su asignación, pero el rol deja de otorgar permisos hasta que se vuelva a activar.\",\n successMessage: \"Rol desactivado\"\n },\n set_default_role: {\n label: \"Establecer como predeterminado\",\n confirmText: \"¿Convertir este en el rol predeterminado para los nuevos usuarios? Los usuarios existentes no se ven afectados.\",\n successMessage: \"Rol predeterminado actualizado\"\n },\n clone_role: {\n label: \"Clonar rol\",\n successMessage: \"Rol clonado\"\n }\n }\n },\n sys_permission_set: {\n label: \"Conjunto de permisos\",\n pluralLabel: \"Conjuntos de permisos\",\n description: \"Agrupaciones de permisos con nombre para un control de acceso detallado\",\n fields: {\n label: {\n label: \"Nombre visible\"\n },\n name: {\n label: \"Nombre de API\",\n help: \"Nombre técnico único del conjunto de permisos.\"\n },\n description: {\n label: \"Descripción\"\n },\n object_permissions: {\n label: \"Permisos de objeto\",\n help: \"Permisos CRUD a nivel de objeto serializados en JSON.\"\n },\n field_permissions: {\n label: \"Permisos de campo\",\n help: \"Permisos de lectura/escritura a nivel de campo serializados en JSON.\"\n },\n system_permissions: {\n label: \"Permisos del sistema\",\n help: \"Array serializado en JSON de nombres de capacidades del sistema (p. ej. [\\\"setup.access\\\",\\\"studio.access\\\",\\\"manage_users\\\"])\"\n },\n row_level_security: {\n label: \"Seguridad a nivel de fila\",\n help: \"Array serializado en JSON de políticas de seguridad a nivel de fila (cláusulas USING/CHECK)\"\n },\n tab_permissions: {\n label: \"Permisos de pestañas\",\n help: \"Mapa serializado en JSON de la visibilidad de las pestañas de la app (visible | hidden | default_on | default_off)\"\n },\n active: {\n label: \"Activo\"\n },\n id: {\n label: \"ID de conjunto de permisos\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n },\n _views: {\n active: {\n label: \"Activo\"\n },\n inactive: {\n label: \"Inactivo\"\n },\n all_permsets: {\n label: \"Todos\"\n }\n },\n _actions: {\n activate_permission_set: {\n label: \"Activar\",\n successMessage: \"Conjunto de permisos activado\"\n },\n deactivate_permission_set: {\n label: \"Desactivar\",\n confirmText: \"¿Desactivar este conjunto de permisos? Las asignaciones existentes se mantienen, pero dejan de otorgar acceso hasta que se vuelva a activar.\",\n successMessage: \"Conjunto de permisos desactivado\"\n },\n clone_permission_set: {\n label: \"Clonar\",\n successMessage: \"Conjunto de permisos clonado\"\n }\n }\n },\n sys_user_permission_set: {\n label: \"Conjunto de permisos de usuario\",\n pluralLabel: \"Conjuntos de permisos de usuario\",\n description: \"Asignación directa de un conjunto de permisos a un usuario (opcionalmente con ámbito de organización).\",\n fields: {\n id: {\n label: \"ID de asignación\",\n help: \"UUID de la asignación.\"\n },\n user_id: {\n label: \"Usuario\",\n help: \"Clave foránea a sys_user.\"\n },\n permission_set_id: {\n label: \"Conjunto de permisos\",\n help: \"Clave foránea a sys_permission_set.\"\n },\n organization_id: {\n label: \"Organización\",\n help: \"Ámbito de organización opcional. NULL = se aplica en cualquier contexto de organización.\"\n },\n granted_by: {\n label: \"Concedido por\",\n help: \"Usuario que concedió este conjunto de permisos.\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n }\n },\n sys_role_permission_set: {\n label: \"Conjunto de permisos de rol\",\n pluralLabel: \"Conjuntos de permisos de rol\",\n description: \"Vincula un conjunto de permisos a un rol.\",\n fields: {\n id: {\n label: \"ID de vinculación\",\n help: \"UUID de la vinculación rol-conjunto de permisos.\"\n },\n role_id: {\n label: \"Rol\",\n help: \"Clave foránea a sys_role.\"\n },\n permission_set_id: {\n label: \"Conjunto de permisos\",\n help: \"Clave foránea a sys_permission_set.\"\n },\n created_at: {\n label: \"Creado el\"\n },\n updated_at: {\n label: \"Actualizado el\"\n }\n }\n }\n};\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * SecurityTranslations — i18n bundle owned by this plugin (ADR-0029 D8).\n *\n * Object label/field/view/action translations for the sys_* objects this\n * plugin owns. Loaded at runtime via the plugin's `kernel:ready` hook\n * (`i18n.loadTranslations`). Regenerate with `os i18n extract` against\n * `scripts/i18n-extract.config.ts`.\n */\n\nimport type { TranslationBundle } from '@objectstack/spec/system';\nimport { enObjects } from './en.objects.generated.js';\nimport { zhCNObjects } from './zh-CN.objects.generated.js';\nimport { jaJPObjects } from './ja-JP.objects.generated.js';\nimport { esESObjects } from './es-ES.objects.generated.js';\n\nexport const SecurityTranslations: TranslationBundle = {\n en: { objects: enObjects },\n 'zh-CN': { objects: zhCNObjects },\n 'ja-JP': { objects: jaJPObjects },\n 'es-ES': { objects: esESObjects },\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { PermissionSet, ObjectPermission, FieldPermission } from '@objectstack/spec/security';\n\n/**\n * Operation type mapping to permission checks\n */\nconst OPERATION_TO_PERMISSION: Record<string, keyof ObjectPermission> = {\n find: 'allowRead',\n findOne: 'allowRead',\n count: 'allowRead',\n aggregate: 'allowRead',\n insert: 'allowCreate',\n update: 'allowEdit',\n delete: 'allowDelete',\n};\n\n/**\n * Destructive operation class — operations that must FAIL CLOSED when they are\n * not mapped to a concrete permission key. See ADR-0049: an unrecognised\n * destructive operation (e.g. a future `transfer`/`restore`/`purge` added\n * without a matching `OPERATION_TO_PERMISSION` entry, gated by the spec's\n * `allowTransfer`/`allowRestore`/`allowPurge` bits) must be DENIED rather than\n * silently allowed by the default-allow fallthrough. Non-destructive unknown\n * operations retain default-allow so custom read-side operations are not broken.\n */\nconst DESTRUCTIVE_OPERATIONS = new Set<string>(['transfer', 'restore', 'purge']);\n\n/**\n * PermissionEvaluator\n * \n * Runtime evaluator for PermissionSet definitions.\n * Resolves aggregated permissions from roles to concrete allow/deny decisions.\n */\nexport class PermissionEvaluator {\n /**\n * Check if an operation is allowed on an object for the given permission sets.\n * Uses \"most permissive\" merging: if ANY permission set allows, it's allowed.\n */\n checkObjectPermission(\n operation: string,\n objectName: string,\n permissionSets: PermissionSet[]\n ): boolean {\n const permKey = OPERATION_TO_PERMISSION[operation];\n if (!permKey) {\n // Fail CLOSED for the destructive operation class (ADR-0049): an\n // unrecognised destructive op must be denied, never silently allowed.\n // Other unknown operations are allowed by default.\n return !DESTRUCTIVE_OPERATIONS.has(operation);\n }\n\n for (const ps of permissionSets) {\n // Honour the `'*'` wildcard sentinel — admin permission sets typically\n // grant blanket access via a single `objects: { '*': … }` entry rather\n // than enumerating every system object.\n const objPerm = ps.objects?.[objectName] ?? ps.objects?.['*'];\n if (objPerm) {\n // Check if modifyAllRecords is set (super-user bypass for write ops)\n if (['allowEdit', 'allowDelete'].includes(permKey) && objPerm.modifyAllRecords) {\n return true;\n }\n // Check if viewAllRecords is set (super-user bypass for read ops)\n if (permKey === 'allowRead' && (objPerm.viewAllRecords || objPerm.modifyAllRecords)) {\n return true;\n }\n // Check the specific permission\n if (objPerm[permKey]) {\n return true;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Get the merged field permissions for an object.\n * Returns a map of field names to their effective permissions.\n * Uses \"most permissive\" merging.\n */\n getFieldPermissions(\n objectName: string,\n permissionSets: PermissionSet[]\n ): Record<string, FieldPermission> {\n const result: Record<string, FieldPermission> = {};\n\n for (const ps of permissionSets) {\n if (!ps.fields) continue;\n\n for (const [key, perm] of Object.entries(ps.fields)) {\n // Field keys are in format: \"object_name.field_name\"\n if (!key.startsWith(`${objectName}.`)) continue;\n const fieldName = key.substring(objectName.length + 1);\n\n if (!result[fieldName]) {\n result[fieldName] = { readable: false, editable: false };\n }\n\n // Most permissive merge\n if (perm.readable) result[fieldName].readable = true;\n if (perm.editable) result[fieldName].editable = true;\n }\n }\n\n return result;\n }\n\n /**\n * Resolve permission sets for a list of identifier names from metadata.\n *\n * Identifiers are matched to `PermissionSet.name`. The names may be\n * either role names (when `sys_role.name` is reused as a permission set\n * name — common for default admin/member/viewer roles) or explicit\n * permission set names supplied through `ExecutionContext.permissions[]`\n * (resolved by `resolveExecutionContext` from `sys_user_permission_set`\n * and `sys_role_permission_set`).\n *\n * Async because the underlying metadata service exposes `list()` as a\n * Promise — synchronous iteration would silently yield zero results\n * (the historical SecurityPlugin behaviour, masking all enforcement).\n *\n * `bootstrapPermissionSets` is a fallback list of plugin-owned permission\n * sets (typically the platform defaults: admin_full_access /\n * member_default / viewer_readonly) that are registered via\n * `manifest.register({ permissions })` but do not currently propagate\n * into the metadata service's `list()` index. Without this fallback,\n * SecurityPlugin would never resolve the defaults and all enforcement\n * would be silently disabled for authenticated requests.\n */\n async resolvePermissionSets(\n identifiers: string[],\n metadataService: any,\n bootstrapPermissionSets: PermissionSet[] = [],\n /**\n * Optional async loader for permission set names that aren't found in\n * metadata or bootstrap. Lets callers query user-defined permission\n * sets persisted in `sys_permission_set`. Failures are swallowed.\n */\n dbLoader?: (unresolved: string[]) => Promise<PermissionSet[]>\n ): Promise<PermissionSet[]> {\n if (identifiers.length === 0) return [];\n\n const result: PermissionSet[] = [];\n const seen = new Set<string>();\n\n // Get all permission sets from metadata. Support both async (Manager) and\n // sync (test stub) implementations of `list`.\n let allPermSets: any = [];\n try {\n const listed = metadataService?.list?.('permission')\n ?? metadataService?.list?.('permissions')\n ?? [];\n allPermSets = typeof (listed as any)?.then === 'function' ? await listed : listed;\n } catch {\n allPermSets = [];\n }\n if (!Array.isArray(allPermSets)) allPermSets = [];\n\n const wanted = new Set(identifiers);\n for (const ps of allPermSets) {\n if (wanted.has(ps.name) && !seen.has(ps.name)) {\n seen.add(ps.name);\n result.push(ps);\n }\n }\n\n // Fallback: any wanted name not yet matched is sourced from the\n // bootstrap list (plugin-owned defaults). Avoids silent failure when\n // permission sets are registered via `manifest.register` but the\n // metadata service hasn't indexed them.\n for (const ps of bootstrapPermissionSets) {\n if (wanted.has(ps.name) && !seen.has(ps.name)) {\n seen.add(ps.name);\n result.push(ps);\n }\n }\n\n // Last-resort: query user-defined permission sets from the database.\n // Without this, custom permission sets (created via the admin UI as\n // `sys_permission_set` rows) would be silently ignored both for CRUD\n // enforcement and for field-level masking.\n if (dbLoader) {\n const unresolved = identifiers.filter((n) => !seen.has(n));\n if (unresolved.length > 0) {\n try {\n const dbRows = await dbLoader(unresolved);\n for (const ps of dbRows ?? []) {\n if (ps?.name && !seen.has(ps.name)) {\n seen.add(ps.name);\n result.push(ps);\n }\n }\n } catch {\n // Swallow — the request shouldn't fail just because the DB\n // lookup is unavailable.\n }\n }\n }\n\n return result;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { RowLevelSecurityPolicy } from '@objectstack/spec/security';\nimport type { ExecutionContext } from '@objectstack/spec/kernel';\n\n/**\n * RLS User Context\n * Variables available for RLS expression evaluation.\n */\ninterface RLSUserContext {\n id?: string;\n /**\n * Active organization id for the request. RLS expressions reference\n * this as `current_user.organization_id`. Sourced from\n * `ExecutionContext.tenantId` (the runtime keeps the abstract\n * \"tenant\" name, but at the data/RLS layer the canonical column is\n * `organization_id` — see better-auth's organization plugin).\n */\n organization_id?: string;\n roles?: string[];\n /**\n * IDs of all users that share the active organization with the\n * current user (incl. self). Pre-resolved by the runtime so RLS can\n * scope identity tables like `sys_user` via\n * `id IN (current_user.org_user_ids)` without needing subquery\n * support in the compiler. This is the one well-known membership set;\n * arbitrary §7.3.1 sets arrive via `ExecutionContext.rlsMembership`\n * and are merged in under their own keys (see {@link RLSCompiler.compileFilter}).\n */\n org_user_ids?: string[];\n /**\n * The caller's unique, auth-enforced email. RLS expressions reference it as\n * `current_user.email` for human-readable, *seedable* owner scoping\n * (`owner = current_user.email`). Email is exposed because it is UNIQUE; the\n * user's display `name` is deliberately NOT exposed — names collide, and a\n * collision on an ownership predicate is an access-control leak.\n */\n email?: string;\n [key: string]: unknown;\n}\n\n/**\n * Sentinel filter used when applicable RLS policies exist but none can\n * be compiled against the current execution context (typically because a\n * required `current_user.*` variable is missing — e.g. the user has no\n * active organization). The filter compares `id` against a non-printable\n * UUID-shaped string that no real record will ever carry, so the upstream\n * SQL layer naturally returns zero rows without raising an error. This\n * gives us **fail-closed** semantics for select/update/delete on tables\n * that the user is not entitled to see, without forcing every caller to\n * handle a thrown `PermissionDeniedError` for what is conceptually an\n * empty result set.\n *\n * Exposed for the SecurityPlugin's optional short-circuit path and for\n * tests; see {@link RLSCompiler.compileFilter}.\n */\nexport const RLS_DENY_FILTER: Record<string, unknown> = Object.freeze({\n id: '__rls_deny__:00000000-0000-0000-0000-000000000000',\n});\n\n/**\n * Recognize whether an RLS `using` / `check` expression matches one of the SHAPES\n * the compiler can compile (equality against a `current_user.*` var, equality\n * against a string literal, set-membership against a `current_user.*` array, or\n * the `1 = 1` allow-all). This is SHAPE-only — it does not check whether the\n * referenced context variable is populated at runtime.\n *\n * ADR-0056 D4: exposed so an authoring-time gate (`objectstack compile`) can REJECT\n * a predicate the runtime would silently drop — the class of bug where\n * `owner == current_user.name` (`==`, unsupported) compiled to nothing and left an\n * object unprotected. A `false` here means \"this predicate will never enforce\".\n */\nexport function isSupportedRlsExpression(expression: string): boolean {\n if (!expression) return false;\n const e = expression.trim();\n if (/^\\s*1\\s*=\\s*1\\s*$/.test(e)) return true;\n if (/^\\s*\\w+\\s*=\\s*current_user\\.\\w+\\s*$/.test(e)) return true;\n if (/^\\s*\\w+\\s*=\\s*'[^']*'\\s*$/.test(e)) return true;\n if (/^\\s*\\w+\\s+IN\\s+\\(\\s*current_user\\.\\w+\\s*\\)\\s*$/i.test(e)) return true;\n return false;\n}\n\n/**\n * RLSCompiler\n * \n * Compiles Row-Level Security policy expressions into query filters.\n * Converts `using` / `check` expressions into ObjectQL-compatible filter conditions.\n */\nexport class RLSCompiler {\n /** Optional logger so a SILENTLY-dropped (uncompilable-shape) policy is observable (ADR-0056 D4). */\n private logger?: { warn?: (message: string, meta?: Record<string, unknown>) => void };\n setLogger(logger: { warn?: (message: string, meta?: Record<string, unknown>) => void } | undefined): void {\n this.logger = logger;\n }\n\n /**\n * Compile RLS policies into a query filter for the given user context.\n * Multiple policies for the same object/operation are OR-combined (any match allows access).\n *\n * Return-value semantics:\n * - `null` → no policies applicable → caller applies no RLS filter.\n * - non-null → caller AND's it onto the existing where clause.\n * - {@link RLS_DENY_FILTER} → policies were defined but none could be\n * compiled (e.g. wildcard `tenant_isolation` against a user with no\n * active organization). The caller must treat this as \"deny by\n * default\" — its `id` comparison naturally yields zero rows on\n * select/update/delete, which is the safe fail-closed answer.\n */\n compileFilter(\n policies: RowLevelSecurityPolicy[],\n executionContext?: ExecutionContext\n ): Record<string, unknown> | null {\n if (policies.length === 0) return null;\n\n const userCtx: RLSUserContext = {\n id: executionContext?.userId,\n organization_id: executionContext?.tenantId,\n roles: executionContext?.roles,\n org_user_ids: (executionContext as any)?.org_user_ids,\n // Unique identifier — safe for ownership predicates (see RLSUserContext).\n email: (executionContext as any)?.email,\n };\n\n // §7.3.1 dynamic membership: the runtime pre-resolves arbitrary\n // set-membership (team members, territory accounts, shared records)\n // into `ExecutionContext.rlsMembership`. Merge each set under its key\n // so `field IN (current_user.<key>)` resolves without subquery support.\n // Arrays only; a missing/empty set still fails closed downstream.\n // We never let a membership key clobber the named fields above.\n const membership = (executionContext as any)?.rlsMembership;\n if (membership && typeof membership === 'object') {\n for (const [key, value] of Object.entries(membership)) {\n if (Array.isArray(value) && userCtx[key] === undefined) {\n userCtx[key] = value;\n }\n }\n }\n\n const filters: Record<string, unknown>[] = [];\n\n for (const policy of policies) {\n if (!policy.using) continue;\n const filter = this.compileExpression(policy.using, userCtx);\n if (filter) {\n filters.push(filter);\n } else if (!isSupportedRlsExpression(policy.using)) {\n // ADR-0056 D4: an UNSUPPORTED-SHAPE predicate (e.g. `==`, AND/OR, ranges)\n // compiles to nothing and would silently vanish, leaving the object\n // unprotected. Surface it instead of dropping in silence. (A SUPPORTED\n // shape that returned null is the intentional \"context var absent\" path —\n // it fails closed downstream and is not warned here.)\n this.logger?.warn?.(\n `[RLS] policy '${(policy as { name?: string }).name ?? '(unnamed)'}' on '${(policy as { object?: string }).object ?? '?'}' ` +\n `has an uncompilable predicate and was DROPPED (no enforcement): ${policy.using}`,\n );\n }\n }\n\n if (filters.length === 0) {\n // Policies *were* applicable but every one of them depended on a\n // `current_user.*` variable that wasn't populated (or used an\n // expression we couldn't compile). Fail closed — return a sentinel\n // filter that matches no rows. This prevents the \"user without an\n // active org sees every tenant's data\" class of bug.\n return RLS_DENY_FILTER;\n }\n if (filters.length === 1) return filters[0];\n\n // Multiple policies: OR-combine (any policy allows access)\n return { $or: filters };\n }\n\n /**\n * Compile a single RLS expression into a query filter.\n *\n * This reference compiler recognizes exactly four forms — anything else\n * returns `null` and (via {@link compileFilter}) fails closed:\n * - `field = current_user.property` → `{ field: <value> }`\n * - `field = 'literal_value'` → `{ field: 'literal_value' }`\n * - `field IN (current_user.array)` → `{ field: { $in: [...] } }`\n * (the array may be a §7.3.1 pre-resolved membership set)\n * - `1 = 1` → `{}` (always-true / no restriction)\n *\n * There is intentionally no support for subqueries, `LIKE`/`ILIKE`,\n * regex, `ANY`/`ALL`, `AND`/`OR`/`NOT`, or `NULL` checks — express those\n * needs as a `current_user.*` property the runtime pre-resolves instead.\n */\n compileExpression(\n expression: string,\n userCtx: RLSUserContext\n ): Record<string, unknown> | null {\n if (!expression) return null;\n\n // Always-true literal: \"1 = 1\" → no restriction (match every row).\n // Lets RLS.allowAllPolicy ('1 = 1' for privileged roles) grant access\n // instead of silently failing closed. An empty filter AND's onto the\n // caller's where clause as a no-op.\n if (/^\\s*1\\s*=\\s*1\\s*$/.test(expression)) {\n return {};\n }\n\n // Handle simple equality: \"field = current_user.property\"\n const eqMatch = expression.match(/^\\s*(\\w+)\\s*=\\s*current_user\\.(\\w+)\\s*$/);\n if (eqMatch) {\n const [, field, prop] = eqMatch;\n const value = userCtx[prop];\n // Skip when the user-context value is missing (undefined or null).\n // A `null` `organization_id` means \"no active organization\" — applying\n // the filter as `organization_id IS NULL` would silently expose every\n // un-tenanted row across tenants and break system tables that lack the\n // column entirely. Treating null as \"skip this policy\" makes the\n // tenant_isolation rule safely opt-out for users without an active org\n // while still applying when one is set.\n if (value === undefined || value === null) return null;\n return { [field]: value };\n }\n\n // Handle literal equality: \"field = 'value'\"\n const litMatch = expression.match(/^\\s*(\\w+)\\s*=\\s*'([^']*)'\\s*$/);\n if (litMatch) {\n const [, field, value] = litMatch;\n return { [field]: value };\n }\n\n // Handle IN: \"field IN (current_user.array_property)\"\n const inMatch = expression.match(/^\\s*(\\w+)\\s+IN\\s+\\(\\s*current_user\\.(\\w+)\\s*\\)\\s*$/i);\n if (inMatch) {\n const [, field, prop] = inMatch;\n const value = userCtx[prop];\n if (!Array.isArray(value) || value.length === 0) return null;\n return { [field]: { $in: value } };\n }\n\n // Unsupported expression: return null (no additional RLS filter applied).\n // Note: callers should treat absence of RLS policies as \"allow all\" only when\n // no policies are defined. If policies exist but cannot be compiled, the caller\n // may want to deny access as a safety measure.\n return null;\n }\n\n /**\n * Get applicable RLS policies for a given object and operation.\n */\n getApplicablePolicies(\n objectName: string,\n operation: string,\n allPolicies: RowLevelSecurityPolicy[]\n ): RowLevelSecurityPolicy[] {\n // Map engine operation to RLS operation type\n const rlsOp = this.mapOperationToRLS(operation);\n\n return allPolicies.filter(policy => {\n // Check object match\n if (policy.object !== objectName && policy.object !== '*') return false;\n\n // Check operation match\n if (policy.operation === 'all') return true;\n if (policy.operation === rlsOp) return true;\n\n return false;\n });\n }\n\n private mapOperationToRLS(operation: string): string {\n switch (operation) {\n case 'find':\n case 'findOne':\n case 'count':\n case 'aggregate':\n return 'select';\n case 'insert':\n return 'insert';\n case 'update':\n return 'update';\n case 'delete':\n return 'delete';\n default:\n return 'select';\n }\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport type { FieldPermission } from '@objectstack/spec/security';\n\n/**\n * FieldMasker\n * \n * Applies field-level security by stripping restricted fields from query results.\n */\nexport class FieldMasker {\n /**\n * Mask fields in query results based on field permissions.\n * Removes fields that the user does not have read access to.\n */\n maskResults(\n results: any | any[],\n fieldPermissions: Record<string, FieldPermission>,\n _objectName: string\n ): any | any[] {\n // If no field permissions defined, return results as-is\n if (Object.keys(fieldPermissions).length === 0) return results;\n\n // Get list of non-readable fields\n const hiddenFields = Object.entries(fieldPermissions)\n .filter(([, perm]) => !perm.readable)\n .map(([field]) => field);\n\n if (hiddenFields.length === 0) return results;\n\n if (Array.isArray(results)) {\n return results.map(record => this.maskRecord(record, hiddenFields));\n }\n\n return this.maskRecord(results, hiddenFields);\n }\n\n /**\n * Get non-editable fields for use in write operations.\n * Returns a list of field names that should be stripped from incoming data.\n */\n getNonEditableFields(\n fieldPermissions: Record<string, FieldPermission>\n ): string[] {\n return Object.entries(fieldPermissions)\n .filter(([, perm]) => !perm.editable)\n .map(([field]) => field);\n }\n\n /**\n * Strip non-editable fields from write data.\n */\n stripNonEditableFields(\n data: Record<string, any>,\n fieldPermissions: Record<string, FieldPermission>\n ): Record<string, any> {\n const nonEditable = this.getNonEditableFields(fieldPermissions);\n if (nonEditable.length === 0) return data;\n\n const result = { ...data };\n for (const field of nonEditable) {\n delete result[field];\n }\n return result;\n }\n\n /**\n * Detect which fields in the caller's write payload would touch a\n * field they are not allowed to edit. Returns the set of offending\n * field names (no duplicates, sorted for stable error messages).\n *\n * Used by the security middleware on insert/update to fail-closed\n * with an explicit 403 rather than silently dropping fields — a\n * silent drop hides the security boundary from honest clients\n * (their update partially \"doesn't save\") and gives an attacker no\n * negative signal that the field exists. Throwing makes the\n * boundary observable in both directions.\n *\n * `data` may be a single record or an array of records (bulk insert);\n * either way the returned list is the union across all rows.\n *\n * Fields without a permission entry pass through — permission sets\n * are an allow-list at the field level only for fields they\n * explicitly enumerate. Most objects do not declare per-field rules\n * and remain fully editable.\n */\n detectForbiddenWrites(\n data: Record<string, any> | Record<string, any>[],\n fieldPermissions: Record<string, FieldPermission>\n ): string[] {\n if (Object.keys(fieldPermissions).length === 0) return [];\n const nonEditable = new Set(this.getNonEditableFields(fieldPermissions));\n if (nonEditable.size === 0) return [];\n\n const offenders = new Set<string>();\n const rows = Array.isArray(data) ? data : [data];\n for (const row of rows) {\n if (!row || typeof row !== 'object') continue;\n for (const field of Object.keys(row)) {\n if (nonEditable.has(field)) offenders.add(field);\n }\n }\n return Array.from(offenders).sort();\n }\n\n private maskRecord(record: any, hiddenFields: string[]): any {\n if (!record || typeof record !== 'object') return record;\n\n const result = { ...record };\n for (const field of hiddenFields) {\n delete result[field];\n }\n return result;\n }\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Typed sentinel error thrown by `SecurityPlugin` when an operation is\n * denied. Caught by `@objectstack/runtime`'s HTTP dispatcher and translated\n * to HTTP 403.\n */\nexport class PermissionDeniedError extends Error {\n readonly code = 'PERMISSION_DENIED';\n readonly statusCode = 403;\n readonly details?: Record<string, unknown>;\n constructor(message: string, details?: Record<string, unknown>) {\n super(message);\n this.name = 'PermissionDeniedError';\n this.details = details;\n }\n}\n\nexport function isPermissionDeniedError(e: unknown): e is PermissionDeniedError {\n if (!e || typeof e !== 'object') return false;\n const anyE = e as any;\n return (\n anyE.name === 'PermissionDeniedError' ||\n anyE.code === 'PERMISSION_DENIED' ||\n (typeof anyE.message === 'string' && anyE.message.startsWith('[Security] Access denied'))\n );\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * bootstrapPlatformAdmin — first-boot platform admin promotion.\n *\n * Two responsibilities, both idempotent and run on `kernel:ready`:\n *\n * 1. **Seed `sys_permission_set` rows** for each `defaultPermissionSets`\n * entry (admin_full_access / member_default / viewer_readonly).\n *\n * 2. **Promote the first registered user to platform admin** by\n * inserting a `sys_user_permission_set` row that points at\n * `admin_full_access` with `organization_id = NULL` (= cross-tenant).\n * If a platform admin already exists, this is a no-op forever.\n *\n * The \"create a Default Organization for the freshly-promoted admin\"\n * behavior moved to `@objectstack/plugin-org-scoping` (see\n * `ensureDefaultOrganization`). Install that plugin to get\n * multi-tenant bootstrap.\n */\n\nimport type { PermissionSet } from '@objectstack/spec/security';\nimport { SystemUserId } from '@objectstack/spec/system';\nimport { claimSeedOwnership } from './claim-seed-ownership.js';\n\ninterface BootstrapOptions {\n /** Logger from PluginContext. */\n logger?: {\n info: (message: string, meta?: Record<string, any>) => void;\n warn: (message: string, meta?: Record<string, any>) => void;\n };\n}\n\nconst SYSTEM_CTX = { isSystem: true };\n\nasync function tryFind(ql: any, object: string, where: any, limit = 100): Promise<any[]> {\n try {\n const rows = await ql.find(object, { where, limit }, { context: SYSTEM_CTX });\n return Array.isArray(rows) ? rows : [];\n } catch {\n return [];\n }\n}\n\nasync function tryInsert(ql: any, object: string, data: any): Promise<any | null> {\n try {\n return await ql.insert(object, data, { context: SYSTEM_CTX });\n } catch {\n return null;\n }\n}\n\nfunction genId(prefix: string): string {\n const rand = Math.random().toString(36).slice(2, 10);\n const ts = Date.now().toString(36);\n return `${prefix}_${ts}${rand}`;\n}\n\n/**\n * Persist seed permission sets and promote the first registered user to\n * platform admin. Safe to call multiple times.\n */\nexport async function bootstrapPlatformAdmin(\n ql: any,\n bootstrapPermissionSets: PermissionSet[],\n options: BootstrapOptions = {},\n): Promise<{\n seeded: number;\n adminPromoted: boolean;\n reason?: string;\n /** Count of seeded rows re-owned to the freshly-promoted admin. */\n ownershipClaimed?: number;\n}> {\n const logger = options.logger;\n if (!ql || typeof ql.find !== 'function' || typeof ql.insert !== 'function') {\n return { seeded: 0, adminPromoted: false, reason: 'objectql_unavailable' };\n }\n\n // 1. Seed permission set rows.\n const seeded: Record<string, string> = {};\n for (const ps of bootstrapPermissionSets) {\n if (!ps.name) continue;\n const existing = await tryFind(ql, 'sys_permission_set', { name: ps.name }, 1);\n if (existing.length > 0 && existing[0].id) {\n seeded[ps.name] = existing[0].id;\n continue;\n }\n const id = genId('ps');\n const created = await tryInsert(ql, 'sys_permission_set', {\n id,\n name: ps.name,\n label: ps.label ?? ps.name,\n // `description` is not part of the typed PermissionSet shape (name/label\n // only); read it defensively so a runtime-provided description still\n // persists without tripping the dts typecheck.\n description: (ps as any).description ?? null,\n object_permissions: JSON.stringify(ps.objects ?? {}),\n field_permissions: JSON.stringify(ps.fields ?? {}),\n // Persist the remaining permset facets so the runtime resolver\n // (rest-server.ts / resolve-execution-context.ts) can hydrate\n // them back into ExecutionContext.systemPermissions etc. Without\n // these the platform-admin promotion grants the right LINK row\n // but the permission set itself carries no capabilities, so\n // `setup.access` / `studio.access` never reach the app filter\n // and the Setup app is invisible even to admin_full_access.\n system_permissions: JSON.stringify(ps.systemPermissions ?? []),\n row_level_security: JSON.stringify(ps.rowLevelSecurity ?? []),\n tab_permissions: JSON.stringify(ps.tabPermissions ?? {}),\n active: true,\n });\n if (created?.id) seeded[ps.name] = created.id;\n else if (created) seeded[ps.name] = id;\n }\n\n const seededCount = Object.keys(seeded).length;\n\n // 2. First-user platform admin promotion.\n const adminPsId = seeded['admin_full_access'];\n if (!adminPsId) {\n return { seeded: seededCount, adminPromoted: false, reason: 'admin_permission_set_missing' };\n }\n\n const existingAdminLinks = await tryFind(\n ql,\n 'sys_user_permission_set',\n { permission_set_id: adminPsId },\n 50,\n );\n // A platform admin \"already exists\" only if a *human* holds the\n // cross-tenant grant. The seed-data owner `usr_system` (provisioned by\n // the SeedLoader, see runtime/app-plugin.ts `ensureSeedIdentity`) must\n // never count — otherwise a DB where it was wrongly promoted would block\n // every real admin forever. Ignoring it here makes the bootstrap\n // self-healing on restart.\n if (existingAdminLinks.some((r) => !r.organization_id && r.user_id !== SystemUserId.SYSTEM)) {\n return { seeded: seededCount, adminPromoted: false, reason: 'already_have_admin' };\n }\n\n const allUsers = await tryFind(ql, 'sys_user', {}, 50);\n // Exclude the non-loginable system service account. It is created during\n // seed loading — *before* the first human sign-up — so without this filter\n // it is the earliest user and steals the platform-admin promotion, leaving\n // the real admin login without `setup.access` / `studio.access` (Setup and\n // Studio then stay invisible even though login succeeds).\n const humanUsers = allUsers.filter(\n (u) => u.id !== SystemUserId.SYSTEM && u.role !== 'system',\n );\n if (humanUsers.length === 0) {\n logger?.info?.('[security] no human users yet — first sign-up will be promoted to platform admin');\n return { seeded: seededCount, adminPromoted: false, reason: 'no_users' };\n }\n const sorted = [...humanUsers].sort((a, b) => {\n const ta = a.created_at ? new Date(a.created_at).getTime() : 0;\n const tb = b.created_at ? new Date(b.created_at).getTime() : 0;\n return ta - tb;\n });\n const target = sorted[0];\n\n const inserted = await tryInsert(ql, 'sys_user_permission_set', {\n id: genId('ups'),\n user_id: target.id,\n permission_set_id: adminPsId,\n organization_id: null,\n granted_by: null,\n });\n if (!inserted) {\n logger?.warn?.(`[security] failed to grant admin_full_access to first user ${target.email ?? target.id}`);\n return { seeded: seededCount, adminPromoted: false, reason: 'insert_failed' };\n }\n logger?.info?.(`[security] first user promoted to platform admin: ${target.email ?? target.id}`);\n\n // Hand seeded business records (owner_id NULL / usr_system) to the freshly\n // promoted admin so owner-keyed UX works out of the box. Best-effort and\n // idempotent — failures here must not undo the promotion above.\n let ownershipClaimed = 0;\n try {\n const claims = await claimSeedOwnership(ql, target.id, { logger });\n ownershipClaimed = claims.reduce((s, c) => s + c.count, 0);\n } catch (e) {\n logger?.warn?.('[security] seed ownership handoff failed', { error: (e as Error).message });\n }\n\n return { seeded: seededCount, adminPromoted: true, ownershipClaimed };\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * claimSeedOwnership — hand seeded business records to the first platform admin.\n *\n * Seed data is loaded during app-plugin `start()`, which runs BEFORE any human\n * user exists (the login admin is minted later, on `kernel:ready`). So seeded\n * rows land with `owner_id = NULL` (the author left it unset — the correct,\n * mistake-proof default) or `owner_id = usr_system` (the deterministic seed\n * identity bound to `os.user`). Either way the record is owned by nobody a\n * human can log in as, so owner-keyed UX — \"My\" views, owner reports, owner\n * notifications — is empty out of the box.\n *\n * This helper runs **once**, right after `bootstrapPlatformAdmin` promotes the\n * first human user to platform admin, and transfers ownership of those orphan\n * rows to that admin. It is the ownership twin of org-scoping's\n * `claimOrphanOrgRows` (which back-fills `organization_id`): walk every\n * user-authored object that declares the canonical `owner_id` column, and\n * re-own the rows that no human owns yet.\n *\n * Mistake-proof by construction: authors write plain seed records (no\n * `owner_id`), and the platform — not the author — performs the handoff. There\n * is nothing to remember and nothing to mistype.\n *\n * Idempotent: only NULL / `usr_system`-owned rows are touched, so once a real\n * admin owns them a re-run is a no-op. `managedBy` and `sys_*` tables are\n * skipped (their ownership, if any, is platform-controlled).\n */\n\nimport type { ServiceObject } from '@objectstack/spec/data';\nimport { SystemUserId } from '@objectstack/spec/system';\n\ninterface ClaimOwnershipOptions {\n logger?: {\n info: (message: string, meta?: Record<string, any>) => void;\n warn: (message: string, meta?: Record<string, any>) => void;\n };\n}\n\nconst SYSTEM_CTX = { isSystem: true };\n\nfunction hasOwnerField(schema: ServiceObject): boolean {\n const fields: any = (schema as any)?.fields;\n if (!fields) return false;\n if (Array.isArray(fields)) {\n return fields.some((f) => f?.name === 'owner_id');\n }\n return Object.prototype.hasOwnProperty.call(fields, 'owner_id');\n}\n\n/**\n * Re-own every orphan seed row (owner_id NULL or usr_system) to `adminUserId`.\n *\n * Walks `ql.registry.getAllObjects()`, filters to schemas that\n * (a) are not `managedBy` (skip sys_/auth/platform tables),\n * (b) are not `sys_*`-namespaced,\n * (c) declare an `owner_id` field,\n * and updates the unowned rows as `isSystem`. Returns a per-object summary.\n */\nexport async function claimSeedOwnership(\n ql: any,\n adminUserId: string,\n options: ClaimOwnershipOptions = {},\n): Promise<{ object: string; count: number }[]> {\n const logger = options.logger;\n if (!adminUserId || adminUserId === SystemUserId.SYSTEM) return [];\n if (!ql || typeof ql.update !== 'function' || typeof ql.find !== 'function') {\n return [];\n }\n const registry = (ql as any).registry;\n if (!registry || typeof registry.getAllObjects !== 'function') {\n logger?.warn?.('[security] claimSeedOwnership: registry unavailable');\n return [];\n }\n\n const schemas: ServiceObject[] = registry.getAllObjects();\n const results: { object: string; count: number }[] = [];\n\n for (const schema of schemas) {\n if (!schema?.name) continue;\n if ((schema as any).managedBy) continue;\n if (schema.name.startsWith('sys_')) continue;\n if (!hasOwnerField(schema)) continue;\n\n try {\n // Unowned = owner_id NULL (author left it unset) OR usr_system (seed\n // identity). Two narrow scans keep the where-clauses driver-portable\n // instead of relying on an OR/IN predicate.\n const seen = new Set<string>();\n const ids: string[] = [];\n for (const where of [{ owner_id: null }, { owner_id: SystemUserId.SYSTEM }]) {\n const rows = await ql.find(\n schema.name,\n { where, limit: 10_000, fields: ['id'] },\n { context: SYSTEM_CTX },\n );\n const list: any[] = Array.isArray(rows)\n ? rows\n : Array.isArray(rows?.records)\n ? rows.records\n : [];\n for (const r of list) {\n if (r?.id && !seen.has(r.id)) {\n seen.add(r.id);\n ids.push(r.id);\n }\n }\n }\n if (ids.length === 0) continue;\n\n let updated = 0;\n for (const id of ids) {\n try {\n await ql.update(\n schema.name,\n { id, owner_id: adminUserId },\n { context: SYSTEM_CTX },\n );\n updated += 1;\n } catch (e) {\n logger?.warn?.(`[security] claimSeedOwnership failed for ${schema.name}:${id}`, {\n error: (e as Error).message,\n });\n }\n }\n if (updated > 0) results.push({ object: schema.name, count: updated });\n } catch (e) {\n logger?.warn?.(`[security] claimSeedOwnership scan failed for ${schema.name}`, {\n error: (e as Error).message,\n });\n }\n }\n\n if (results.length > 0) {\n const total = results.reduce((s, r) => s + r.count, 0);\n logger?.info?.(`[security] handed ${total} seeded record(s) to first admin ${adminUserId}`, {\n breakdown: results,\n });\n }\n return results;\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Auto-grant `organization_admin` to org owners/admins.\n *\n * For every `sys_member` row whose `role` contains `owner` or `admin`,\n * ensure a `sys_user_permission_set` row exists that links the user to\n * the `organization_admin` permission set scoped to that organization.\n * For members whose role no longer qualifies (demotion or membership\n * removal), revoke the matching scoped grant.\n *\n * Lifecycle hookup (wired from `security-plugin.ts`):\n *\n * - after `sys_member` insert → reconcile (user_id, organization_id)\n * - after `sys_member` update → reconcile both old and new owner pair\n * - after `sys_member` delete → reconcile to revoke\n * - on `kernel:ready` → backfill across every existing member\n *\n * All operations are idempotent and failure-isolated so a missing\n * permission-set row, schema drift, or a stale row never blocks the\n * underlying `sys_member` mutation.\n *\n * **Why this isn't done by the better-auth org plugin directly:**\n * better-auth does not know about ObjectStack permission sets — it\n * only stores membership roles. Translating \"owner/admin role on this\n * org\" into \"owns the `organization_admin` permission set scoped to\n * this org\" is platform metadata policy and belongs here, alongside\n * `bootstrapPlatformAdmin` (which does the analogous thing for\n * platform admins).\n *\n * **Anti-escalation:** `organization_admin` itself (declared in\n * `platform-objects/src/security/default-permission-sets.ts`) is\n * deliberately read-only on the global RBAC tables\n * (`sys_permission_set`, `sys_user_permission_set`, `sys_role`, …),\n * so a freshly-granted org admin cannot rebind themselves to\n * `admin_full_access`.\n */\n\nconst SYSTEM_CTX = { isSystem: true } as const;\nconst PERMISSION_SET_NAME = 'organization_admin';\n\ninterface MaybeLogger {\n info?: (message: string, meta?: Record<string, any>) => void;\n warn?: (message: string, meta?: Record<string, any>) => void;\n debug?: (message: string, meta?: Record<string, any>) => void;\n}\n\nfunction genId(prefix: string): string {\n const rand = Math.random().toString(36).slice(2, 10);\n const ts = Date.now().toString(36);\n return `${prefix}_${ts}${rand}`;\n}\n\nasync function tryFind(ql: any, object: string, where: any, limit = 50): Promise<any[]> {\n try {\n const rows = await ql.find(object, { where, limit }, { context: SYSTEM_CTX });\n return Array.isArray(rows) ? rows : Array.isArray(rows?.records) ? rows.records : [];\n } catch {\n return [];\n }\n}\n\nasync function tryInsert(ql: any, object: string, data: any): Promise<any | null> {\n try {\n return await ql.insert(object, data, { context: SYSTEM_CTX });\n } catch {\n return null;\n }\n}\n\nasync function tryDelete(ql: any, object: string, id: string): Promise<boolean> {\n try {\n await ql.delete(object, id, { context: SYSTEM_CTX });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse a better-auth `sys_member.role` value into a lower-cased role\n * list. better-auth stores either a single role (`\"owner\"`) or a\n * comma-separated list (`\"owner,admin\"`).\n */\nfunction parseRoles(raw: unknown): string[] {\n if (typeof raw !== 'string') return [];\n return raw\n .split(',')\n .map((s) => s.trim().toLowerCase())\n .filter((s) => s.length > 0);\n}\n\nfunction isAdminRole(raw: unknown): boolean {\n const roles = parseRoles(raw);\n return roles.includes('owner') || roles.includes('admin');\n}\n\n/**\n * Resolve the `sys_permission_set.id` for `organization_admin`. Cached\n * across calls per ObjectQL instance via a WeakMap so repeated\n * reconciliations do not re-query.\n */\nconst permissionSetIdCache = new WeakMap<object, string>();\n\nasync function resolvePermissionSetId(ql: any): Promise<string | null> {\n const cached = permissionSetIdCache.get(ql);\n if (cached) return cached;\n const rows = await tryFind(ql, 'sys_permission_set', { name: PERMISSION_SET_NAME }, 1);\n const id = rows[0]?.id;\n if (typeof id === 'string' && id.length > 0) {\n permissionSetIdCache.set(ql, id);\n return id;\n }\n return null;\n}\n\n/**\n * Ensure (or revoke) the org-scoped `organization_admin` grant for\n * `(userId, orgId)` based on the current `sys_member` rows.\n *\n * - If ANY membership row for the pair carries an owner/admin role,\n * ensure exactly one `sys_user_permission_set` row exists.\n * - Else, remove every `sys_user_permission_set` row that links the\n * pair to `organization_admin` (handles demotion and membership\n * removal symmetrically).\n *\n * Returns a structured report for observability. Never throws.\n */\nexport async function reconcileOrgAdminGrant(\n ql: any,\n userId: string,\n orgId: string,\n options: { logger?: MaybeLogger } = {},\n): Promise<{\n action: 'granted' | 'revoked' | 'noop' | 'skipped';\n reason?: string;\n}> {\n const logger = options.logger;\n if (!ql || typeof ql.find !== 'function' || typeof ql.insert !== 'function') {\n return { action: 'skipped', reason: 'objectql_unavailable' };\n }\n if (!userId || !orgId) {\n return { action: 'skipped', reason: 'missing_keys' };\n }\n\n const permSetId = await resolvePermissionSetId(ql);\n if (!permSetId) {\n // organization_admin permission set isn't seeded yet (boot ordering)\n // — caller can retry later (e.g. via kernel:ready backfill).\n return { action: 'skipped', reason: 'permission_set_missing' };\n }\n\n // 1. Determine whether the user currently holds an admin-grade role\n // in this org. Better-auth allows multiple membership rows per\n // pair under some edge cases (legacy data) — any qualifying row\n // is enough.\n const memberships = await tryFind(\n ql,\n 'sys_member',\n { user_id: userId, organization_id: orgId },\n 10,\n );\n const shouldGrant = memberships.some((m: any) => isAdminRole(m?.role));\n\n // 2. Look at existing grants for this exact pair.\n const existingGrants = await tryFind(\n ql,\n 'sys_user_permission_set',\n { user_id: userId, organization_id: orgId, permission_set_id: permSetId },\n 5,\n );\n\n if (shouldGrant) {\n if (existingGrants.length > 0) {\n // Deduplicate stale duplicates if any slipped through.\n for (const extra of existingGrants.slice(1)) {\n if (extra?.id) await tryDelete(ql, 'sys_user_permission_set', String(extra.id));\n }\n return { action: 'noop' };\n }\n const created = await tryInsert(ql, 'sys_user_permission_set', {\n id: genId('ups'),\n user_id: userId,\n permission_set_id: permSetId,\n organization_id: orgId,\n granted_by: null,\n });\n if (created) {\n logger?.info?.('[security] granted organization_admin', { userId, orgId });\n return { action: 'granted' };\n }\n return { action: 'skipped', reason: 'insert_failed' };\n }\n\n // shouldGrant === false → revoke any pre-existing scoped grant.\n if (existingGrants.length === 0) {\n return { action: 'noop' };\n }\n let removed = 0;\n for (const row of existingGrants) {\n if (row?.id && (await tryDelete(ql, 'sys_user_permission_set', String(row.id)))) {\n removed += 1;\n }\n }\n if (removed > 0) {\n logger?.info?.('[security] revoked organization_admin', { userId, orgId, removed });\n return { action: 'revoked' };\n }\n return { action: 'skipped', reason: 'delete_failed' };\n}\n\n/**\n * Reconcile every `(user_id, organization_id)` pair that has at least\n * one `sys_member` row. Used by `kernel:ready` to backfill grants for\n * memberships that pre-date this feature, and as a safety net after\n * the platform admin bootstrap auto-creates the default organization.\n */\nexport async function backfillOrgAdminGrants(\n ql: any,\n options: { logger?: MaybeLogger; limit?: number } = {},\n): Promise<{ scanned: number; granted: number; revoked: number; skipped: number }> {\n const logger = options.logger;\n const limit = options.limit ?? 5000;\n const summary = { scanned: 0, granted: 0, revoked: 0, skipped: 0 };\n if (!ql || typeof ql.find !== 'function') return summary;\n\n const permSetId = await resolvePermissionSetId(ql);\n if (!permSetId) {\n logger?.debug?.('[security] organization_admin backfill skipped — permission set missing');\n return summary;\n }\n\n const members = await tryFind(ql, 'sys_member', {}, limit);\n // De-duplicate by (user_id, organization_id) pair — a user with two\n // membership rows (e.g. legacy duplicates) only needs one reconcile.\n const seen = new Set<string>();\n for (const m of members) {\n const userId = String(m?.user_id ?? '');\n const orgId = String(m?.organization_id ?? '');\n if (!userId || !orgId) continue;\n const key = `${userId}|${orgId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n summary.scanned += 1;\n const res = await reconcileOrgAdminGrant(ql, userId, orgId, { logger });\n if (res.action === 'granted') summary.granted += 1;\n else if (res.action === 'revoked') summary.revoked += 1;\n else if (res.action === 'skipped') summary.skipped += 1;\n }\n\n // Also revoke any organization_admin grant pointing at a (user, org)\n // pair with NO membership row left (orphaned grants from deletes\n // that fired before this hook existed).\n const allGrants = await tryFind(\n ql,\n 'sys_user_permission_set',\n { permission_set_id: permSetId },\n limit,\n );\n for (const g of allGrants) {\n const userId = String(g?.user_id ?? '');\n const orgId = String(g?.organization_id ?? '');\n if (!userId || !orgId) continue;\n const key = `${userId}|${orgId}`;\n if (seen.has(key)) continue;\n const res = await reconcileOrgAdminGrant(ql, userId, orgId, { logger });\n if (res.action === 'revoked') summary.revoked += 1;\n }\n\n logger?.info?.('[security] organization_admin backfill complete', summary);\n return summary;\n}\n\n/**\n * Extract (user_id, organization_id) candidate pairs from a\n * `sys_member` ObjectQL middleware context. Returns both the\n * pre-change and post-change pair so callers can reconcile each.\n */\nexport function extractMemberPairs(opCtx: any): Array<{ userId: string; orgId: string }> {\n const out = new Map<string, { userId: string; orgId: string }>();\n const add = (userId: unknown, orgId: unknown) => {\n if (typeof userId === 'string' && typeof orgId === 'string' && userId && orgId) {\n out.set(`${userId}|${orgId}`, { userId, orgId });\n }\n };\n // Post-write payload — most common case.\n add(opCtx?.result?.user_id, opCtx?.result?.organization_id);\n // Update payloads carry the new values in `data` and the prior row\n // in `before` (driver-dependent). We reconcile BOTH so a member\n // moved from org A to org B (or user changed) is handled.\n add(opCtx?.data?.user_id, opCtx?.data?.organization_id);\n add(opCtx?.before?.user_id, opCtx?.before?.organization_id);\n // For deletes the affected row is sometimes only in `existing`.\n add(opCtx?.existing?.user_id, opCtx?.existing?.organization_id);\n return Array.from(out.values());\n}\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_role — System Role Object\n *\n * RBAC role definition for the ObjectStack platform.\n * Roles group permissions and are assigned to users or members.\n *\n * @namespace sys\n */\nexport const SysRole = ObjectSchema.create({\n name: 'sys_role',\n label: 'Role',\n pluralLabel: 'Roles',\n icon: 'shield',\n isSystem: true,\n managedBy: 'config',\n // ADR-0010 §3.7 — RBAC primitive; tenants may add custom rows\n // (created via UI / API) but the schema itself is locked.\n protection: {\n lock: 'no-overlay',\n reason: 'RBAC schema is platform-defined — see ADR-0010.',\n docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',\n },\n description: 'Role definitions for RBAC access control',\n displayNameField: 'label',\n titleFormat: '{label}',\n compactLayout: ['label', 'name', 'active', 'is_default'],\n\n // Custom actions — system roles drive RBAC and are edited rarely but\n // require the four high-frequency sysadmin affordances every IdP\n // (Salesforce, ServiceNow, Okta) ships: activate/deactivate (lifecycle\n // without losing assignments), mark default (auto-assign to new users),\n // and clone (template for new roles). All operations hit the generic\n // data CRUD endpoint exposed by `apiEnabled` — no custom server route\n // required because `managedBy: 'config'` allows direct mutation.\n actions: [\n {\n name: 'activate_role',\n label: 'Activate Role',\n icon: 'circle-check',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_role/{id}',\n bodyExtra: { active: true },\n successMessage: 'Role activated',\n refreshAfter: true,\n },\n {\n name: 'deactivate_role',\n label: 'Deactivate Role',\n icon: 'circle-off',\n variant: 'danger',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_role/{id}',\n bodyExtra: { active: false },\n confirmText: 'Deactivate this role? Users with the role keep their assignment but the role stops granting permissions until re-activated.',\n successMessage: 'Role deactivated',\n refreshAfter: true,\n },\n {\n name: 'set_default_role',\n label: 'Set as Default',\n icon: 'star',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_role/{id}',\n bodyExtra: { is_default: true },\n confirmText: 'Make this the default role for new users? Existing users are unaffected.',\n successMessage: 'Default role updated',\n refreshAfter: true,\n },\n {\n // Clone — POST a new sys_role row pre-filled from the source. The\n // dialog asks only for the new API name / label so the operator\n // can rename atomically; permissions JSON is copied wholesale via\n // defaultFromRow.\n name: 'clone_role',\n label: 'Clone Role',\n icon: 'copy',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'POST',\n target: '/api/v1/data/sys_role',\n bodyExtra: { is_default: false, active: true },\n successMessage: 'Role cloned',\n refreshAfter: true,\n params: [\n { name: 'label', label: 'New Display Name', type: 'text', required: true },\n { name: 'name', label: 'New API Name', type: 'text', required: true, helpText: 'Unique snake_case machine name' },\n { field: 'description', defaultFromRow: true },\n { field: 'permissions', defaultFromRow: true },\n ],\n },\n ],\n\n listViews: {\n active: {\n type: 'grid',\n name: 'active',\n label: 'Active',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'is_default', 'updated_at'],\n filter: [{ field: 'active', operator: 'equals', value: true }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n default_roles: {\n type: 'grid',\n name: 'default_roles',\n label: 'Default',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'description', 'active'],\n filter: [{ field: 'is_default', operator: 'equals', value: true }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n custom: {\n type: 'grid',\n name: 'custom',\n label: 'Custom',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'active', 'updated_at'],\n filter: [{ field: 'is_default', operator: 'equals', value: false }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n all_roles: {\n type: 'grid',\n name: 'all_roles',\n label: 'All',\n data: { provider: 'object', object: 'sys_role' },\n columns: ['label', 'name', 'active', 'is_default', 'updated_at'],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n },\n\n fields: {\n // ── Identity ─────────────────────────────────────────────────\n label: Field.text({\n label: 'Display Name',\n required: true,\n searchable: true,\n maxLength: 255,\n group: 'Identity',\n }),\n\n name: Field.text({\n label: 'API Name',\n required: true,\n searchable: true,\n maxLength: 100,\n description: 'Unique machine name for the role (e.g. admin, editor, viewer)',\n group: 'Identity',\n }),\n\n description: Field.textarea({\n label: 'Description',\n required: false,\n group: 'Identity',\n }),\n\n // ── Configuration ────────────────────────────────────────────\n permissions: Field.textarea({\n label: 'Permissions',\n required: false,\n description: 'JSON-serialized array of permission strings',\n group: 'Configuration',\n }),\n\n // ── Status ───────────────────────────────────────────────────\n active: Field.boolean({\n label: 'Active',\n defaultValue: true,\n group: 'Status',\n }),\n\n is_default: Field.boolean({\n label: 'Default Role',\n defaultValue: false,\n description: 'Automatically assigned to new users',\n group: 'Status',\n }),\n\n // ── System ───────────────────────────────────────────────────\n id: Field.text({\n label: 'Role ID',\n required: true,\n readonly: true,\n group: 'System',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['name'], unique: true },\n { fields: ['active'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_permission_set — System Permission Set Object\n *\n * Named groupings of fine-grained permissions.\n * Permission sets can be assigned to roles or directly to users\n * for granular access control.\n *\n * @namespace sys\n */\nexport const SysPermissionSet = ObjectSchema.create({\n name: 'sys_permission_set',\n label: 'Permission Set',\n pluralLabel: 'Permission Sets',\n icon: 'lock',\n isSystem: true,\n managedBy: 'config',\n // ADR-0010 §3.7 — RBAC primitive; tenants may add custom rows\n // (created via UI / API) but the schema itself is locked.\n protection: {\n lock: 'no-overlay',\n reason: 'RBAC schema is platform-defined — see ADR-0010.',\n docsUrl: 'https://docs.objectstack.ai/adr/0010-metadata-protection',\n },\n description: 'Named permission groupings for fine-grained access control',\n displayNameField: 'label',\n titleFormat: '{label}',\n compactLayout: ['label', 'name', 'active'],\n\n // Custom actions — permission sets are templates assigned to roles or\n // users (via sys_role_permission_set / sys_user_permission_set). The\n // sysadmin operations that don't live on the parent-detail tabs are\n // lifecycle (activate/deactivate without losing assignments) and\n // clone (build a new permset by tweaking an existing one). Both hit\n // the generic data CRUD endpoint — managedBy: 'config' permits it.\n actions: [\n {\n name: 'activate_permission_set',\n label: 'Activate',\n icon: 'circle-check',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_permission_set/{id}',\n bodyExtra: { active: true },\n successMessage: 'Permission set activated',\n refreshAfter: true,\n },\n {\n name: 'deactivate_permission_set',\n label: 'Deactivate',\n icon: 'circle-off',\n variant: 'danger',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'PATCH',\n target: '/api/v1/data/sys_permission_set/{id}',\n bodyExtra: { active: false },\n confirmText: 'Deactivate this permission set? Existing assignments stay in place but stop granting access until re-activated.',\n successMessage: 'Permission set deactivated',\n refreshAfter: true,\n },\n {\n name: 'clone_permission_set',\n label: 'Clone',\n icon: 'copy',\n variant: 'secondary',\n mode: 'custom',\n locations: ['list_item', 'record_header'],\n type: 'api',\n method: 'POST',\n target: '/api/v1/data/sys_permission_set',\n bodyExtra: { active: true },\n successMessage: 'Permission set cloned',\n refreshAfter: true,\n params: [\n { name: 'label', label: 'New Display Name', type: 'text', required: true },\n { name: 'name', label: 'New API Name', type: 'text', required: true, helpText: 'Unique snake_case machine name' },\n { field: 'description', defaultFromRow: true },\n { field: 'object_permissions', defaultFromRow: true },\n { field: 'field_permissions', defaultFromRow: true },\n ],\n },\n ],\n\n listViews: {\n active: {\n type: 'grid',\n name: 'active',\n label: 'Active',\n data: { provider: 'object', object: 'sys_permission_set' },\n columns: ['label', 'name', 'description', 'updated_at'],\n filter: [{ field: 'active', operator: 'equals', value: true }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n inactive: {\n type: 'grid',\n name: 'inactive',\n label: 'Inactive',\n data: { provider: 'object', object: 'sys_permission_set' },\n columns: ['label', 'name', 'updated_at'],\n filter: [{ field: 'active', operator: 'equals', value: false }],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n all_permsets: {\n type: 'grid',\n name: 'all_permsets',\n label: 'All',\n data: { provider: 'object', object: 'sys_permission_set' },\n columns: ['label', 'name', 'active', 'updated_at'],\n sort: [{ field: 'label', order: 'asc' }],\n pagination: { pageSize: 50 },\n },\n },\n\n fields: {\n // ── Identity ─────────────────────────────────────────────────\n label: Field.text({\n label: 'Display Name',\n required: true,\n searchable: true,\n maxLength: 255,\n group: 'Identity',\n }),\n\n name: Field.text({\n label: 'API Name',\n required: true,\n searchable: true,\n maxLength: 100,\n description: 'Unique machine name for the permission set',\n group: 'Identity',\n }),\n\n description: Field.textarea({\n label: 'Description',\n required: false,\n group: 'Identity',\n }),\n\n // ── Permissions ──────────────────────────────────────────────\n object_permissions: Field.textarea({\n label: 'Object Permissions',\n required: false,\n description: 'JSON-serialized object-level CRUD permissions',\n group: 'Permissions',\n }),\n\n field_permissions: Field.textarea({\n label: 'Field Permissions',\n required: false,\n description: 'JSON-serialized field-level read/write permissions',\n group: 'Permissions',\n }),\n\n system_permissions: Field.textarea({\n label: 'System Permissions',\n required: false,\n description: 'JSON-serialized array of system capability names (e.g. [\"setup.access\",\"studio.access\",\"manage_users\"])',\n group: 'Permissions',\n }),\n\n row_level_security: Field.textarea({\n label: 'Row-Level Security',\n required: false,\n description: 'JSON-serialized array of row-level security policies (USING/CHECK clauses)',\n group: 'Permissions',\n }),\n\n tab_permissions: Field.textarea({\n label: 'Tab Permissions',\n required: false,\n description: 'JSON-serialized map of app tab visibility (visible | hidden | default_on | default_off)',\n group: 'Permissions',\n }),\n\n // ── Status ───────────────────────────────────────────────────\n active: Field.boolean({\n label: 'Active',\n defaultValue: true,\n group: 'Status',\n }),\n\n // ── System ───────────────────────────────────────────────────\n id: Field.text({\n label: 'Permission Set ID',\n required: true,\n readonly: true,\n group: 'System',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n group: 'System',\n }),\n },\n\n indexes: [\n { fields: ['name'], unique: true },\n { fields: ['active'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_user_permission_set — User ↔ PermissionSet assignment.\n *\n * Salesforce-style additive permission grant: a user may be assigned any\n * number of `sys_permission_set` rows, optionally scoped to a specific\n * organization. The runtime resolver (`resolveExecutionContext` in\n * `@objectstack/runtime`) reads this table when building the per-request\n * `ExecutionContext.permissions[]`.\n *\n * Uniqueness is `(user_id, permission_set_id, organization_id)` so the\n * same permission set can be granted independently in each org context\n * the user belongs to.\n *\n * @namespace sys\n */\nexport const SysUserPermissionSet = ObjectSchema.create({\n name: 'sys_user_permission_set',\n label: 'User Permission Set',\n pluralLabel: 'User Permission Sets',\n icon: 'user-check',\n isSystem: true,\n managedBy: 'system',\n description: 'Direct assignment of a permission set to a user (optionally scoped to an organization).',\n titleFormat: '{user_id} → {permission_set_id}',\n compactLayout: ['user_id', 'permission_set_id', 'organization_id'],\n\n fields: {\n id: Field.text({\n label: 'Assignment ID',\n required: true,\n readonly: true,\n description: 'UUID of the assignment.',\n }),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n required: true,\n description: 'Foreign key to sys_user.',\n }),\n\n permission_set_id: Field.lookup('sys_permission_set', {\n label: 'Permission Set',\n required: true,\n description: 'Foreign key to sys_permission_set.',\n }),\n\n organization_id: Field.lookup('sys_organization', {\n label: 'Organization',\n required: false,\n description: 'Optional organization scope. NULL = applies in every org context.',\n }),\n\n granted_by: Field.lookup('sys_user', {\n label: 'Granted By',\n required: false,\n description: 'User who granted this permission set.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['user_id', 'permission_set_id', 'organization_id'], unique: true },\n { fields: ['user_id'] },\n { fields: ['organization_id'] },\n { fields: ['permission_set_id'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_role_permission_set — Role ↔ PermissionSet binding.\n *\n * Allows administrators to compose a `sys_role` from one or more\n * `sys_permission_set` rows. At request time, the runtime resolver\n * (`resolveExecutionContext`) collects every permission set bound to\n * the user's roles via this table and injects their names into\n * `ExecutionContext.permissions[]` for downstream RBAC evaluation.\n *\n * @namespace sys\n */\nexport const SysRolePermissionSet = ObjectSchema.create({\n name: 'sys_role_permission_set',\n label: 'Role Permission Set',\n pluralLabel: 'Role Permission Sets',\n icon: 'shield-plus',\n isSystem: true,\n managedBy: 'system',\n description: 'Binds a permission set to a role.',\n titleFormat: '{role_id} → {permission_set_id}',\n compactLayout: ['role_id', 'permission_set_id'],\n\n fields: {\n id: Field.text({\n label: 'Binding ID',\n required: true,\n readonly: true,\n description: 'UUID of the role-permission-set binding.',\n }),\n\n role_id: Field.lookup('sys_role', {\n label: 'Role',\n required: true,\n description: 'Foreign key to sys_role.',\n }),\n\n permission_set_id: Field.lookup('sys_permission_set', {\n label: 'Permission Set',\n required: true,\n description: 'Foreign key to sys_permission_set.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n },\n\n indexes: [\n { fields: ['role_id', 'permission_set_id'], unique: true },\n { fields: ['role_id'] },\n { fields: ['permission_set_id'] },\n ],\n\n enable: {\n trackHistory: true,\n searchable: true,\n apiEnabled: true,\n apiMethods: ['get', 'list', 'create', 'update', 'delete'],\n trash: true,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { PermissionSetSchema, type PermissionSet } from '@objectstack/spec/security';\n\n/**\n * Identity tables managed by the better-auth plugin (see\n * `packages/platform-objects/src/identity/`). Mutations to these tables\n * MUST flow through the better-auth API endpoints (sign-up, password\n * reset, organization invite/remove-member, api-key/create, …) rather\n * than the generic CRUD pipeline so that password hashing, token\n * signing, email verification, invitation flows and scope hashing all\n * fire correctly.\n *\n * The default member/viewer permission sets therefore explicitly DENY\n * `allowCreate / allowEdit / allowDelete` on these objects while still\n * permitting reads (subject to the rest of the RLS chain). Admin\n * permission sets keep their `*` wildcard so they can rescue data\n * directly when needed.\n *\n * Each entry mirrors the `managedBy: 'better-auth'` flag declared on\n * the corresponding object schema in `packages/platform-objects/src/identity/`.\n */\nconst BETTER_AUTH_MANAGED_OBJECTS = [\n 'sys_user',\n 'sys_account',\n 'sys_session',\n 'sys_organization',\n 'sys_member',\n 'sys_invitation',\n 'sys_team',\n 'sys_team_member',\n 'sys_api_key',\n 'sys_two_factor',\n 'sys_verification',\n 'sys_jwks',\n 'sys_device_code',\n 'sys_oauth_application',\n 'sys_oauth_access_token',\n 'sys_oauth_refresh_token',\n 'sys_oauth_consent',\n] as const;\n\nconst denyWritesOnManagedObjects = (): Record<string, {\n allowRead: boolean;\n allowCreate: boolean;\n allowEdit: boolean;\n allowDelete: boolean;\n}> => Object.fromEntries(\n BETTER_AUTH_MANAGED_OBJECTS.map((name) => [\n name,\n { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n ]),\n);\n\n/**\n * Default permission sets seeded by the platform.\n *\n * These are referenced by name (`admin_full_access`, `member_default`,\n * `viewer_readonly`) from `sys_role_permission_set` rows or assigned\n * directly to users via `sys_user_permission_set`.\n *\n * The runtime SecurityPlugin reads these via the metadata service when a\n * permission set name appears in the request `ExecutionContext.permissions[]`.\n *\n * Each entry is run through `PermissionSetSchema.parse(...)` so Zod fills\n * in the boolean/`priority`/`enabled` defaults — keeping the literal\n * source readable while still satisfying the strict output type.\n *\n * `objects: { '*': … }` uses the wildcard sentinel honoured by\n * `PermissionEvaluator` — admins do not need an explicit row per object.\n * Per-object entries fully override the wildcard for that object (see\n * `PermissionEvaluator.checkObjectPermission` — lookup, not merge).\n *\n * RLS policies use the canonical `current_user.*` placeholders compiled\n * by `RLSCompiler`. The active organization is exposed under\n * `current_user.organization_id` (sourced from\n * `ExecutionContext.tenantId` at request time) — there is no rewrite\n * step or `tenantField` indirection in SecurityPlugin. Schemas with a\n * different physical tenant column should fork these defaults.\n */\nexport const defaultPermissionSets: PermissionSet[] = [\n PermissionSetSchema.parse({\n name: 'admin_full_access',\n label: 'Administrator — Full Access',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: true,\n allowEdit: true,\n allowDelete: true,\n viewAllRecords: true,\n modifyAllRecords: true,\n },\n },\n systemPermissions: [\n 'manage_users',\n 'manage_metadata',\n 'manage_platform_settings',\n 'setup.access',\n 'studio.access',\n ],\n }),\n // ── Organization Administrator ──────────────────────────────────────\n //\n // Third tier between platform admin (`admin_full_access`) and rank-and-file\n // member. Lives at the *organization* scope: full CRUD on business\n // objects within their org (governed by `tenant_isolation` RLS), plus\n // `setup.access` so the Setup app shell is reachable.\n //\n // **Deliberately withheld** vs `admin_full_access`:\n // - `studio.access` — schema-design surfaces are platform-level (a\n // tenant cannot mutate the shared metadata) and Studio is hidden.\n // - `manage_metadata` — same reasoning.\n // - `manage_platform_settings` — global settings manifests\n // (mail / storage / AI / knowledge) and platform-only Setup pages\n // (sharing rules, audit logs, OAuth apps, JWKS, …) require this\n // and are hidden / 403'd for org admins. Tenant-scoped manifests\n // (`branding`, `feature_flags`) keep using `setup.access` so org\n // admins CAN configure their own org's branding.\n //\n // **Anti-escalation**: writes to the global RBAC tables\n // (`sys_role`, `sys_permission_set`, `sys_role_permission_set`,\n // `sys_user_permission_set`, `sys_user_role`) are denied. Allowing\n // them would let an org admin bind `admin_full_access` (which has no\n // RLS) to themselves and break out of tenant isolation. Reads are\n // permitted so the Roles / Permission Sets nav entries still render.\n //\n // Auto-granted to every `sys_member` whose role contains `owner` or\n // `admin` by `plugin-security/src/auto-org-admin-grant.ts`.\n PermissionSetSchema.parse({\n name: 'organization_admin',\n label: 'Organization Administrator',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: true,\n allowEdit: true,\n allowDelete: true,\n viewAllRecords: true,\n modifyAllRecords: true,\n },\n // Identity tables — go through better-auth endpoints (invite,\n // accept, remove-member, transfer, …) rather than raw CRUD.\n ...denyWritesOnManagedObjects(),\n // RBAC tables — read-only to prevent privilege escalation.\n sys_role: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_permission_set: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_role_permission_set: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_user_permission_set: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n sys_user_role: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },\n },\n systemPermissions: ['manage_org_users', 'setup.access'],\n rowLevelSecurity: [\n {\n name: 'tenant_isolation',\n object: '*',\n operation: 'all',\n using: 'organization_id = current_user.organization_id',\n },\n // ── better-auth system tables that lack `organization_id` and would\n // otherwise be denied by the wildcard policy. Same self-only\n // carve-outs as `member_default` — an org admin does not get to\n // inspect cross-tenant identity rows.\n {\n name: 'sys_organization_self',\n object: 'sys_organization',\n operation: 'all',\n using: 'id = current_user.organization_id',\n },\n {\n name: 'sys_user_self',\n object: 'sys_user',\n operation: 'select',\n using: 'id = current_user.id',\n },\n {\n name: 'sys_user_org_members',\n object: 'sys_user',\n operation: 'select',\n using: 'id IN (current_user.org_user_ids)',\n },\n {\n name: 'sys_session_self',\n object: 'sys_session',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_account_self',\n object: 'sys_account',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_team_member_self',\n object: 'sys_team_member',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_two_factor_self',\n object: 'sys_two_factor',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_user_preference_self',\n object: 'sys_user_preference',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_api_key_self',\n object: 'sys_api_key',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_device_code_self',\n object: 'sys_device_code',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_access_token_self',\n object: 'sys_oauth_access_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_refresh_token_self',\n object: 'sys_oauth_refresh_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_consent_self',\n object: 'sys_oauth_consent',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n // OAuth applications a user has registered themselves (self-service\n // developer flow exposed in the Account app's Developer section).\n // `sys_oauth_application` has no `organization_id` so the wildcard\n // `tenant_isolation` policy would otherwise deny every row.\n {\n name: 'sys_oauth_application_self',\n object: 'sys_oauth_application',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n // Org-scoped visibility for organization-owned identity-adjacent\n // tables. Org admins may inspect their own org's invitations and\n // memberships (read; writes still flow through better-auth).\n {\n name: 'sys_member_org',\n object: 'sys_member',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n {\n name: 'sys_invitation_org',\n object: 'sys_invitation',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n {\n name: 'sys_team_org',\n object: 'sys_team',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n ],\n }),\n PermissionSetSchema.parse({\n name: 'member_default',\n label: 'Member — Standard Access',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: true,\n allowEdit: true,\n allowDelete: true,\n },\n // Identity tables are managed by better-auth — no direct writes.\n ...denyWritesOnManagedObjects(),\n },\n rowLevelSecurity: [\n {\n name: 'tenant_isolation',\n object: '*',\n operation: 'all',\n using: 'organization_id = current_user.organization_id',\n },\n // Owner-scoped writes/deletes for rank-and-file members: you may modify\n // and delete the records you created, not other users'. Keyed on\n // `created_by` — the column the engine stamps on EVERY record — rather\n // than `owner_id`, which author-defined objects almost never declare. The\n // old `owner_id` key referenced a missing column on real objects, so\n // `computeRlsFilter` dropped the policy and the scoping silently no-op'd\n // (any member could edit/delete any record — #1985). These policies are\n // ENFORCED on writes via the security middleware's pre-image check (a\n // by-id update/delete never builds an RLS `where`, so the predicate is\n // verified against the target row before the mutation). Objects that\n // model transferable ownership with a dedicated owner field should\n // override these with a per-object policy.\n {\n name: 'owner_only_writes',\n object: '*',\n operation: 'update',\n using: 'created_by = current_user.id',\n },\n {\n name: 'owner_only_deletes',\n object: '*',\n operation: 'delete',\n using: 'created_by = current_user.id',\n },\n // ── better-auth system tables that lack `organization_id` and would\n // otherwise be left unprotected by the wildcard rule above. ────\n //\n // The security plugin's RLS injector treats wildcard policies that\n // target a missing field as `RLS_DENY_FILTER` (zero rows) unless a\n // per-object policy contributes an alternate match. Each `*_self`\n // policy below restores per-user visibility on a better-auth table\n // that has `user_id` but no `organization_id`. Tables without\n // `user_id` (`sys_verification`, `sys_jwks`, empty `sys_passkey`)\n // stay DENY for non-admins by design — only platform admins (via\n // `admin_full_access`, which has no RLS) should inspect them.\n {\n name: 'sys_organization_self',\n object: 'sys_organization',\n operation: 'all',\n using: 'id = current_user.organization_id',\n },\n {\n name: 'sys_user_self',\n object: 'sys_user',\n operation: 'select',\n using: 'id = current_user.id',\n },\n // Org collaborators: members can see other users in the same\n // organization. Without this, owner/assignee lookups, @-mention\n // suggestions, reviewer pickers and team-roster surfaces all\n // collapse to just the current user. `org_user_ids` is\n // pre-resolved by runtime/resolve-execution-context from\n // `sys_member` for the active organization. Sensitive credential\n // tables (`sys_account`, `sys_session`, `sys_api_key`, …) keep\n // their stricter self-only carve-outs above.\n {\n name: 'sys_user_org_members',\n object: 'sys_user',\n operation: 'select',\n using: 'id IN (current_user.org_user_ids)',\n },\n {\n name: 'sys_session_self',\n object: 'sys_session',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_account_self',\n object: 'sys_account',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_team_member_self',\n object: 'sys_team_member',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_two_factor_self',\n object: 'sys_two_factor',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_user_preference_self',\n object: 'sys_user_preference',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_api_key_self',\n object: 'sys_api_key',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_device_code_self',\n object: 'sys_device_code',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_access_token_self',\n object: 'sys_oauth_access_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_refresh_token_self',\n object: 'sys_oauth_refresh_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_consent_self',\n object: 'sys_oauth_consent',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n // OAuth applications a user has registered themselves (Account →\n // Developer → OAuth Applications). `sys_oauth_application` has no\n // `organization_id`, so without this carve-out the wildcard\n // `tenant_isolation` policy returns zero rows even for the owner.\n {\n name: 'sys_oauth_application_self',\n object: 'sys_oauth_application',\n operation: 'all',\n using: 'user_id = current_user.id',\n },\n ],\n }),\n PermissionSetSchema.parse({\n name: 'viewer_readonly',\n label: 'Viewer — Read-Only',\n isProfile: true,\n objects: {\n '*': {\n allowRead: true,\n allowCreate: false,\n allowEdit: false,\n allowDelete: false,\n },\n // Belt-and-suspenders: explicit deny on managed objects even though\n // the wildcard already denies — keeps the policy readable when\n // future relaxations might widen the wildcard.\n ...denyWritesOnManagedObjects(),\n },\n rowLevelSecurity: [\n {\n name: 'tenant_isolation',\n object: '*',\n operation: 'select',\n using: 'organization_id = current_user.organization_id',\n },\n {\n name: 'sys_organization_self',\n object: 'sys_organization',\n operation: 'select',\n using: 'id = current_user.organization_id',\n },\n {\n name: 'sys_user_self',\n object: 'sys_user',\n operation: 'select',\n using: 'id = current_user.id',\n },\n // Org collaborators (read-only): see `sys_user_org_members` in\n // `member_default` for rationale.\n {\n name: 'sys_user_org_members',\n object: 'sys_user',\n operation: 'select',\n using: 'id IN (current_user.org_user_ids)',\n },\n {\n name: 'sys_session_self',\n object: 'sys_session',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_account_self',\n object: 'sys_account',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_team_member_self',\n object: 'sys_team_member',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_two_factor_self',\n object: 'sys_two_factor',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_user_preference_self',\n object: 'sys_user_preference',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_api_key_self',\n object: 'sys_api_key',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_device_code_self',\n object: 'sys_device_code',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_access_token_self',\n object: 'sys_oauth_access_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_refresh_token_self',\n object: 'sys_oauth_refresh_token',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n {\n name: 'sys_oauth_consent_self',\n object: 'sys_oauth_consent',\n operation: 'select',\n using: 'user_id = current_user.id',\n },\n ],\n }),\n];\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Canonical plugin-security manifest source.\n *\n * Both `objectstack.config.ts` (compile-time) and `security-plugin.ts`\n * (runtime `manifest.register`) import from this file so the two\n * registration paths cannot drift (D7).\n */\n\nimport {\n SysPermissionSet,\n SysRole,\n SysUserPermissionSet,\n SysRolePermissionSet,\n defaultPermissionSets,\n} from './objects/index.js';\n\nexport const SECURITY_PLUGIN_ID = 'com.objectstack.plugin-security';\nexport const SECURITY_PLUGIN_VERSION = '1.0.0';\n\n/** Security objects owned by plugin-security. */\nexport const securityObjects = [\n SysRole,\n SysPermissionSet,\n SysUserPermissionSet,\n SysRolePermissionSet,\n];\n\n/** Default platform permission sets (admin / member / viewer). */\nexport const securityDefaultPermissionSets = defaultPermissionSets;\n\n/** Manifest header shared by compile-time config and runtime registration. */\nexport const securityPluginManifestHeader = {\n id: SECURITY_PLUGIN_ID,\n namespace: 'sys',\n version: SECURITY_PLUGIN_VERSION,\n type: 'plugin' as const,\n scope: 'system' as const,\n defaultDatasource: 'cloud',\n name: 'Security Plugin',\n description: 'RBAC roles and permission sets for ObjectStack (Role, PermissionSet)',\n};\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { Plugin, PluginContext } from '@objectstack/core';\nimport type { PermissionSet, RowLevelSecurityPolicy } from '@objectstack/spec/security';\nimport { PermissionEvaluator } from './permission-evaluator.js';\nimport { RLSCompiler, RLS_DENY_FILTER } from './rls-compiler.js';\nimport { FieldMasker } from './field-masker.js';\nimport { PermissionDeniedError } from './errors.js';\nimport { bootstrapPlatformAdmin } from './bootstrap-platform-admin.js';\nimport {\n backfillOrgAdminGrants,\n extractMemberPairs,\n reconcileOrgAdminGrant,\n} from './auto-org-admin-grant.js';\nimport {\n securityObjects,\n securityDefaultPermissionSets,\n securityPluginManifestHeader,\n} from './manifest.js';\n\nexport interface SecurityPluginOptions {\n /**\n * Additional permission sets to register with the metadata service on\n * plugin start. Defaults to {@link securityDefaultPermissionSets}\n * (admin_full_access / member_default / viewer_readonly).\n */\n defaultPermissionSets?: PermissionSet[];\n /**\n * Permission set name applied as an implicit baseline whenever an\n * authenticated request has no resolved permission sets (and no roles\n * that map to one). This guarantees baseline tenant/owner RLS for\n * every logged-in user even before an admin assigns explicit\n * profiles. Set to `null` to disable.\n *\n * @default 'member_default'\n */\n fallbackPermissionSet?: string | null;\n}\n\n/**\n * SecurityPlugin\n *\n * Provides RBAC, Row-Level Security, and Field-Level Security runtime.\n * Registers as an engine middleware on the ObjectQL engine.\n *\n * This plugin is fully optional — without it, the system operates\n * without permission checks (same as current behavior).\n *\n * **Multi-tenant Organization scoping is provided by the separate\n * `@objectstack/plugin-org-scoping` package** (auto-stamps\n * `organization_id` on insert, per-org seed replay, default-org\n * bootstrap). When that plugin is installed, SecurityPlugin detects\n * it via `getService('org-scoping')` and keeps the wildcard\n * `current_user.organization_id` RLS policies that ship with the\n * default permission sets. Without it, those policies are stripped so\n * single-tenant deployments don't pay the field-existence safety-net\n * cost on every find.\n *\n * Dependencies:\n * - objectql service (ObjectQL engine with middleware support)\n * - metadata service (MetadataFacade for reading permission sets and RLS policies)\n */\nexport class SecurityPlugin implements Plugin {\n name = 'com.objectstack.security';\n type = 'standard';\n version = '1.0.0';\n dependencies = ['com.objectstack.engine.objectql'];\n\n private permissionEvaluator = new PermissionEvaluator();\n private rlsCompiler = new RLSCompiler();\n private fieldMasker = new FieldMasker();\n private readonly bootstrapPermissionSets: PermissionSet[];\n private readonly fallbackPermissionSet: string | null;\n /**\n * Runtime probe — set in `start()` from\n * `ctx.getService('org-scoping')`. When `false`, wildcard RLS\n * policies that reference `current_user.organization_id` are\n * stripped from the per-request policy set (saves the\n * field-existence safety net cost on every find in single-tenant\n * deployments). When `true`, the policies apply normally.\n */\n private orgScopingEnabled = false;\n /**\n * Per-object field-name cache. Populated lazily from the metadata\n * service / ObjectQL registry on first access per object. Schemas are\n * effectively immutable for the lifetime of the kernel today (hot\n * reload tears the kernel down), so we don't bother with\n * invalidation — a kernel restart drops the cache.\n */\n private readonly fieldNamesCache = new Map<string, Set<string> | null>();\n /**\n * Per-object cache of tenancy opt-out. `true` means the schema\n * explicitly disabled multi-tenancy (`tenancy.enabled === false` or\n * `systemFields.tenant === false`). Wildcard policies that target\n * the conventional tenant column (`organization_id`) are treated as\n * *not applicable* on these tables instead of triggering the\n * field-missing deny sentinel — without this, every read of a\n * cross-org catalog (e.g. `sys_package`, the Marketplace) returns\n * zero rows.\n */\n private readonly tenancyDisabledCache = new Map<string, boolean>();\n /**\n * Service handles captured in `start()` so the request-time RLS resolution\n * (used by BOTH the engine middleware and the public {@link getReadFilter}\n * service method) shares one code path. `null` until `start()` wires them.\n */\n private metadata: any = null;\n private ql: any = null;\n /** ADR-0055: cache the resolved master-detail relation per controlled_by_parent object. */\n private cbpRelCache = new Map<string, { fk: string; master: string } | null>();\n private dbLoader?: (names: string[]) => Promise<PermissionSet[]>;\n private logger: { info?: (...a: any[]) => void; warn?: (...a: any[]) => void; error?: (...a: any[]) => void } = {};\n\n constructor(options: SecurityPluginOptions = {}) {\n this.bootstrapPermissionSets =\n options.defaultPermissionSets ?? securityDefaultPermissionSets;\n this.fallbackPermissionSet =\n options.fallbackPermissionSet === undefined\n // ADR-0056 D7: an app may declare its default profile via `isDefault: true`\n // on a permission set; it becomes the fallback for users with no explicit\n // grants. Falls back to the built-in `member_default` when none is declared.\n ? (this.bootstrapPermissionSets.find((p) => (p as { isDefault?: boolean }).isDefault)?.name ?? 'member_default')\n : options.fallbackPermissionSet;\n }\n\n async init(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Initializing Security Plugin...');\n\n // Register security services\n ctx.registerService('security.permissions', this.permissionEvaluator);\n ctx.registerService('security.rls', this.rlsCompiler);\n ctx.registerService('security.fieldMasker', this.fieldMasker);\n // Bootstrap permission sets (admin_full_access, member_default,\n // viewer_readonly by default) — exposed as a service so other\n // plugins (e.g. plugin-hono-server's /me/permissions endpoint)\n // can pass them as the fallback list to\n // `PermissionEvaluator.resolvePermissionSets` without re-importing\n // the platform-objects package directly.\n ctx.registerService('security.bootstrapPermissionSets', this.bootstrapPermissionSets);\n ctx.registerService('security.fallbackPermissionSet', this.fallbackPermissionSet);\n\n ctx.getService<{ register(m: any): void }>('manifest').register({\n ...securityPluginManifestHeader,\n objects: securityObjects,\n // Permission sets ride along on the manifest so the metadata service\n // can resolve them by name when SecurityPlugin middleware queries\n // `metadata.list('permissions')`.\n permissions: this.bootstrapPermissionSets,\n // ADR-0029 D7 — contribute the RBAC entries into the Setup app's\n // `group_access_control` slot. This plugin owns these objects (K2), so it\n // ships their menu too; when the plugin is absent the entries don't appear.\n navigationContributions: [\n {\n app: 'setup',\n group: 'group_access_control',\n priority: 100,\n items: [\n { id: 'nav_roles', type: 'object', label: 'Roles', objectName: 'sys_role', icon: 'shield-check' },\n { id: 'nav_permission_sets', type: 'object', label: 'Permission Sets', objectName: 'sys_permission_set', icon: 'lock' },\n ],\n },\n ],\n });\n\n // ADR-0029 D8 — contribute this plugin's object translations to the i18n\n // service on kernel:ready (the i18n plugin may register after this one).\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', async () => {\n try {\n const i18n = ctx.getService<any>('i18n');\n if (i18n && typeof i18n.loadTranslations === 'function') {\n const { SecurityTranslations } = await import('./translations/index.js');\n for (const [locale, data] of Object.entries(SecurityTranslations)) {\n i18n.loadTranslations(locale, data as Record<string, unknown>);\n }\n }\n } catch { /* i18n optional */ }\n });\n }\n\n ctx.logger.info('Security Plugin initialized', {\n defaultPermissionSets: this.bootstrapPermissionSets.map((p) => p.name),\n });\n }\n\n async start(ctx: PluginContext): Promise<void> {\n ctx.logger.info('Starting Security Plugin...');\n\n // Get required services\n let ql: any;\n let metadata: any;\n\n try {\n ql = ctx.getService('objectql');\n metadata = ctx.getService('metadata');\n } catch (e) {\n ctx.logger.warn('ObjectQL or metadata service not available, security middleware not registered');\n return;\n }\n\n if (!ql || typeof ql.registerMiddleware !== 'function') {\n ctx.logger.warn('ObjectQL engine does not support middleware, security middleware not registered');\n return;\n }\n\n // Capture handles so the request-time RLS resolution is shared by the\n // engine middleware AND the public getReadFilter service method.\n this.metadata = metadata;\n this.ql = ql;\n this.logger = ctx.logger;\n this.rlsCompiler.setLogger?.(ctx.logger);\n\n // Probe for OrgScopingPlugin presence. When registered, its\n // `init()` exposes itself as the `org-scoping` service. We capture\n // the boolean once at start time (plugin DI graph is static after\n // start) and let `collectRLSPolicies` consult it on every request.\n try {\n const orgScoping = ctx.getService('org-scoping');\n this.orgScopingEnabled = !!orgScoping;\n } catch {\n this.orgScopingEnabled = false;\n }\n if (this.orgScopingEnabled) {\n ctx.logger.info(\n '[security] org-scoping plugin detected — wildcard `organization_id` RLS policies will apply',\n );\n } else {\n ctx.logger.info(\n '[security] org-scoping plugin not present — wildcard `organization_id` RLS policies will be stripped (single-tenant mode)',\n );\n }\n\n // Construct a dbLoader once that lets resolvePermissionSets\n // surface user-defined permission sets from `sys_permission_set`\n // (created via the admin UI) in addition to plugin-registered\n // ones. Uses `isSystem` to bypass tenant RLS.\n const dbLoader = ql\n ? async (names: string[]) => {\n let rows: any;\n try {\n rows = await ql.find(\n 'sys_permission_set',\n { where: { name: { $in: names } }, limit: names.length },\n { context: { isSystem: true } },\n );\n } catch {\n rows = [];\n }\n const list = Array.isArray(rows) ? rows : rows?.records ?? [];\n return list.map((r: any) => ({\n name: r.name,\n label: r.label,\n objects: typeof r.object_permissions === 'string'\n ? JSON.parse(r.object_permissions || '{}')\n : r.object_permissions ?? {},\n fields: typeof r.field_permissions === 'string'\n ? JSON.parse(r.field_permissions || '{}')\n : r.field_permissions ?? {},\n }));\n }\n : undefined;\n this.dbLoader = dbLoader;\n\n // ADR-0021 D-C — expose the per-request READ scope as a reusable service.\n // The analytics raw-SQL path (which bypasses this engine middleware)\n // auto-bridges to `getService('security').getReadFilter(object, context)`\n // to enforce tenant/RLS on every base + joined object. We register the\n // service only once the metadata/ql/dbLoader handles are wired (above), so\n // a degraded start never exposes a half-initialised resolver.\n try {\n ctx.registerService('security', {\n getReadFilter: (object: string, context?: any) => this.getReadFilter(object, context),\n });\n ctx.logger.info('[security] registered \"security\" service (getReadFilter) for raw-SQL RLS bridging');\n } catch (e) {\n ctx.logger.warn?.('[security] failed to register \"security\" service', {\n error: (e as Error).message,\n });\n }\n\n // Register security middleware\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n // System operations bypass security\n if (opCtx.context?.isSystem) {\n return next();\n }\n\n // ADR-0056 (Option A) — declaration-derived PUBLIC-FORM grant. A public\n // form submission carries `publicFormGrant: { object }` derived from the\n // form's declared target (set by the rest-server form-submit route). It\n // authorizes ONLY create + the immediate read-back on THAT object — never\n // anything else, and never the anonymous fall-open. This lets public forms\n // work under secure-by-default (requireAuth) WITHOUT a deployment-configured\n // `guest_portal`, scoped to exactly the declared object (the field\n // allow-list is enforced at the route; the context is request-scoped).\n const formGrant = opCtx.context?.publicFormGrant;\n if (formGrant && typeof formGrant === 'object' && (formGrant as { object?: string }).object) {\n const grantObject = (formGrant as { object: string }).object;\n const allowed =\n opCtx.object === grantObject &&\n ['insert', 'find', 'findOne', 'count'].includes(opCtx.operation);\n if (allowed) return next();\n throw new PermissionDeniedError(\n `[Security] Access denied: public-form grant permits only create/read-back on '${grantObject}', ` +\n `not '${opCtx.operation}' on '${opCtx.object}'`,\n { operation: opCtx.operation, object: opCtx.object },\n );\n }\n\n const roles = opCtx.context?.roles ?? [];\n const explicitPermissionSets = opCtx.context?.permissions ?? [];\n\n // Skip security checks if no roles AND no explicit permission sets\n // AND no userId (anonymous/unauthenticated). The auth middleware\n // should handle authentication separately.\n if (\n roles.length === 0 &&\n explicitPermissionSets.length === 0 &&\n !opCtx.context?.userId\n ) {\n return next();\n }\n\n // 1. Resolve permission sets from BOTH role names and explicit\n // permission set names attached to the execution context. The\n // resolution (incl. the implicit + post-resolution baseline\n // fallback) is shared with the public getReadFilter service via\n // resolvePermissionSetsForContext — keeping the find-path RLS and\n // the analytics raw-SQL RLS provably in lock-step.\n let permissionSets: PermissionSet[] = [];\n try {\n permissionSets = await this.resolvePermissionSetsForContext(opCtx.context);\n } catch (e) {\n // Fail CLOSED. A permission-resolution failure must DENY the request,\n // never bypass the checks (that would let a degraded metadata service\n // expose every tenant's data). System/bootstrap operations already\n // short-circuited above (`opCtx.context?.isSystem`), so reaching here\n // means an authenticated user request whose RBAC/RLS could not be\n // resolved — deny it and alert.\n ctx.logger.error(\n `[security] permission resolution failed for operation '${opCtx.operation}' on ` +\n `object '${opCtx.object}' (user ${opCtx.context?.userId ?? 'unknown'}) — ` +\n `denying request (fail-closed)`,\n e instanceof Error ? e : new Error(String(e)),\n );\n throw new PermissionDeniedError(\n `[Security] Access denied: permission subsystem unavailable for ` +\n `operation '${opCtx.operation}' on object '${opCtx.object}'`,\n );\n }\n\n // 2. CRUD permission check\n if (permissionSets.length > 0) {\n const allowed = this.permissionEvaluator.checkObjectPermission(\n opCtx.operation,\n opCtx.object,\n permissionSets\n );\n\n if (!allowed) {\n throw new PermissionDeniedError(\n `[Security] Access denied: operation '${opCtx.operation}' on object '${opCtx.object}' ` +\n `is not permitted for roles [${roles.join(', ')}]`,\n { operation: opCtx.operation, object: opCtx.object, roles, permissionSets: explicitPermissionSets },\n );\n }\n }\n\n // 2.7. Row-level WRITE authorization (pre-image check).\n //\n // RLS is injected as a `where` filter on the read path (step 3, via\n // `opCtx.ast`), but a single-id update/delete goes straight to\n // `driver.update(object, id, …)` / `driver.delete(object, id)` — it builds\n // no `ast`, so the row-level predicate is NEVER applied to by-id writes.\n // The result (#1985): the CRUD check passes (member_default grants edit/\n // delete) and the owner/tenant RLS that was supposed to scope the write is\n // silently bypassed — any member could modify another user's record.\n //\n // Fix: before the mutation, compute the write-operation RLS filter and\n // verify the TARGET row satisfies it. We re-read the row through the\n // engine with `{ id } AND <writeFilter>`; a `find` does not re-enter this\n // block, so there is no recursion, and read-side RLS/tenant scoping\n // compose naturally. A `null` result means the row is either gone or\n // RLS-hidden → deny. When `computeRlsFilter` returns `null` (no policy\n // applies — e.g. an admin set with no RLS, or `modifyAllRecords`) the\n // check is skipped and behaviour is unchanged.\n if (\n (opCtx.operation === 'update' || opCtx.operation === 'delete') &&\n permissionSets.length > 0 &&\n !!opCtx.context?.userId &&\n this.ql\n ) {\n const targetId = this.extractSingleId(opCtx);\n if (targetId != null) {\n const writeFilter = await this.computeRlsFilter(\n permissionSets,\n opCtx.object,\n opCtx.operation,\n opCtx.context,\n );\n if (writeFilter) {\n let visible: unknown = null;\n try {\n visible = await this.ql.findOne(opCtx.object, {\n where: { $and: [{ id: targetId }, writeFilter] },\n context: opCtx.context,\n });\n } catch {\n // A read denial (e.g. no read permission) is itself a \"cannot\n // touch this row\" signal — fall through to the deny below.\n visible = null;\n }\n if (!visible) {\n throw new PermissionDeniedError(\n `[Security] Access denied: not permitted to ${opCtx.operation} this ` +\n `'${opCtx.object}' record (row-level security)`,\n {\n operation: opCtx.operation,\n object: opCtx.object,\n roles,\n permissionSets: explicitPermissionSets,\n recordId: targetId,\n },\n );\n }\n }\n }\n }\n\n // 2.8. ADR-0055 — controlled-by-parent WRITE: a detail write (insert/update/\n // delete) requires edit access to its master. The detail itself carries no\n // authored RLS, so the #1994 pre-image check above is a no-op for it; this\n // closes the by-id write path by checking the master instead.\n if (\n (opCtx.operation === 'insert' || opCtx.operation === 'update' || opCtx.operation === 'delete') &&\n permissionSets.length > 0 &&\n !!opCtx.context?.userId &&\n this.ql\n ) {\n await this.assertControlledByParentWrite(\n permissionSets,\n opCtx.object,\n opCtx.operation,\n opCtx,\n opCtx.context,\n );\n }\n\n // 2.5. Field-Level Security write enforcement.\n //\n // The client-side masker (ObjectForm / inline grid) already hides\n // non-editable fields from the UI, but that is a UX layer only —\n // a hand-crafted POST / direct ObjectQL call can still target a\n // forbidden field. We fail-closed here with an explicit 403 and\n // the offending field names, so:\n //\n // - honest clients get an actionable error (vs. silent drop,\n // which manifests as a confusing partial-save), and\n // - probing clients see that the boundary is enforced (vs.\n // getting a 200 with the field silently ignored, which\n // reveals nothing).\n //\n // Runs BEFORE the tenant/owner auto-injection (step 3.5) so the\n // system-set fields are not subject to the user's edit\n // permissions — they are populated from the execution context,\n // not from the caller's payload.\n if (\n (opCtx.operation === 'insert' || opCtx.operation === 'update') &&\n opCtx.data &&\n permissionSets.length > 0\n ) {\n const fieldPerms = this.permissionEvaluator.getFieldPermissions(\n opCtx.object,\n permissionSets,\n );\n if (Object.keys(fieldPerms).length > 0) {\n const forbidden = this.fieldMasker.detectForbiddenWrites(\n opCtx.data,\n fieldPerms,\n );\n if (forbidden.length > 0) {\n throw new PermissionDeniedError(\n `[Security] Field write denied: not permitted to edit ` +\n `[${forbidden.join(', ')}] on '${opCtx.object}'`,\n {\n operation: opCtx.operation,\n object: opCtx.object,\n roles,\n permissionSets: explicitPermissionSets,\n forbiddenFields: forbidden,\n },\n );\n }\n }\n }\n\n // 3.5. Auto-inject `owner_id` on insert from the\n // ExecutionContext. Without this, the row has `owner_id = NULL`\n // and the default `owner_only_writes` RLS policy hides it from\n // the very user who just created it.\n //\n // `organization_id` auto-injection has moved to\n // `@objectstack/plugin-org-scoping`. Install that plugin for\n // multi-tenant deployments.\n if (\n opCtx.operation === 'insert' &&\n opCtx.data &&\n typeof opCtx.data === 'object' &&\n !Array.isArray(opCtx.data) &&\n !!opCtx.context?.userId\n ) {\n const fields = await this.getObjectFieldNames(metadata, opCtx.object, ql);\n if (fields) {\n const data = opCtx.data as Record<string, unknown>;\n if (\n fields.has('owner_id') &&\n (data.owner_id == null || data.owner_id === '')\n ) {\n data.owner_id = opCtx.context!.userId;\n }\n }\n }\n\n // 3. RLS filter injection. The policy collection + field-existence\n // safety + compile (incl. the fail-closed deny sentinel) is shared with\n // the public getReadFilter service via computeRlsFilter, so the engine\n // find-path and the analytics raw-SQL path enforce identical scoping.\n if (opCtx.ast) {\n const extra: Record<string, unknown>[] = [];\n const rlsFilter = await this.computeRlsFilter(\n permissionSets,\n opCtx.object,\n opCtx.operation,\n opCtx.context,\n );\n if (rlsFilter) extra.push(rlsFilter);\n // ADR-0055: a controlled_by_parent object derives its read scope from the\n // master record — `masterFK IN (accessible master ids)`, AND-ed in.\n const cbpFilter = await this.computeControlledByParentFilter(\n permissionSets,\n opCtx.object,\n opCtx.context,\n );\n if (cbpFilter) extra.push(cbpFilter);\n if (extra.length) {\n opCtx.ast.where = opCtx.ast.where\n ? { $and: [opCtx.ast.where, ...extra] }\n : extra.length === 1\n ? extra[0]\n : { $and: extra };\n }\n }\n\n await next();\n\n // 4. Field-level security: mask restricted fields in read results\n if (opCtx.result && ['find', 'findOne'].includes(opCtx.operation)) {\n const fieldPerms = this.permissionEvaluator.getFieldPermissions(opCtx.object, permissionSets);\n if (Object.keys(fieldPerms).length > 0) {\n opCtx.result = this.fieldMasker.maskResults(opCtx.result, fieldPerms, opCtx.object);\n }\n }\n });\n\n ctx.logger.info('Security middleware registered on ObjectQL engine');\n\n // Defer platform admin bootstrap until all plugins finish starting —\n // sys_user / sys_permission_set objects must be registered (by\n // plugin-auth and platform-objects respectively) before we can\n // insert seed rows. Falls back to immediate execution when the\n // kernel does not expose `hook` (test stubs).\n let bootstrapRanOnce = false;\n const runBootstrap = async () => {\n try {\n const report = await bootstrapPlatformAdmin(ql, this.bootstrapPermissionSets, {\n logger: ctx.logger,\n });\n bootstrapRanOnce = true;\n ctx.logger.info('[security] platform bootstrap complete', report);\n return report;\n } catch (e) {\n ctx.logger.warn('[security] platform bootstrap failed', { error: (e as Error).message });\n return undefined;\n }\n };\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', runBootstrap);\n } else {\n void runBootstrap();\n }\n\n // Re-run bootstrap after a sys_user insert so the FIRST user that\n // signs up after boot is auto-promoted to platform admin (and, in\n // multi-tenant mode, bound to the seeded default organization)\n // without requiring a server restart. The function itself is\n // idempotent and bails out as soon as any platform admin exists.\n //\n // We deliberately do NOT auto-create a \"personal workspace\" for\n // every subsequent self-service signup. In a B2B / invitation-\n // driven product (the framework's primary target), users must\n // either accept an invitation or explicitly create their first\n // organization. The account UI's /register flow already routes\n // users with zero memberships to /organizations/new for exactly\n // this case.\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n await next();\n if (\n opCtx?.object === 'sys_user' &&\n (opCtx?.operation === 'create' || opCtx?.operation === 'insert')\n ) {\n if (bootstrapRanOnce) {\n await runBootstrap();\n }\n }\n });\n\n // ── Auto-grant `organization_admin` on sys_member lifecycle ─────────\n //\n // For every `sys_member` row whose role is `owner` or `admin`, keep\n // a `sys_user_permission_set` row scoped to that organization in\n // sync. See `auto-org-admin-grant.ts` for the full rationale and\n // the anti-escalation argument (org_admin is read-only on the\n // global RBAC tables, so a freshly-granted admin cannot rebind\n // themselves to `admin_full_access`).\n //\n // We register one middleware that handles insert / update / delete\n // uniformly by always reconciling every (user, org) pair touched\n // by the operation. `reconcileOrgAdminGrant` is idempotent so a\n // double-fire (e.g. better-auth followed by an org plugin\n // synchronizer) is harmless.\n ql.registerMiddleware(async (opCtx: any, next: () => Promise<void>) => {\n await next();\n if (opCtx?.object !== 'sys_member') return;\n const op = opCtx?.operation;\n if (\n op !== 'insert' &&\n op !== 'create' &&\n op !== 'update' &&\n op !== 'delete' &&\n op !== 'remove'\n ) {\n return;\n }\n const pairs = extractMemberPairs(opCtx);\n for (const { userId, orgId } of pairs) {\n try {\n await reconcileOrgAdminGrant(ql, userId, orgId, { logger: ctx.logger });\n } catch (e) {\n ctx.logger.warn?.('[security] org_admin reconcile failed', {\n userId,\n orgId,\n error: (e as Error).message,\n });\n }\n }\n });\n\n // Backfill organization_admin grants after the platform admin\n // bootstrap settles on kernel:ready. Idempotent — only inserts\n // missing rows and revokes orphaned ones, never duplicates.\n const runOrgAdminBackfill = async () => {\n try {\n await backfillOrgAdminGrants(ql, { logger: ctx.logger });\n } catch (e) {\n ctx.logger.warn?.('[security] organization_admin backfill failed', {\n error: (e as Error).message,\n });\n }\n };\n if (typeof (ctx as any).hook === 'function') {\n (ctx as any).hook('kernel:ready', runOrgAdminBackfill);\n } else {\n void runOrgAdminBackfill();\n }\n\n // Per-organization seed data replay on `sys_organization` insert\n // moved to `@objectstack/plugin-org-scoping` (along with\n // `claimOrphanOrgRows` / `cloneOrgSeedData`). Install that\n // plugin for multi-tenant deployments.\n }\n\n async destroy(): Promise<void> {\n // No cleanup needed\n }\n\n /**\n * ADR-0021 D-C — resolve the per-request READ scope (tenant + RLS predicate)\n * for one object as a canonical `FilterCondition`, WITHOUT touching the\n * ObjectQL engine. This is the seam the analytics raw-SQL path bridges to so\n * it enforces the SAME row scoping the engine middleware applies on `find`.\n *\n * Returns:\n * - `undefined` → no scope applies (system context, or an unauthenticated\n * request with no userId/roles/permissions — authn is gated elsewhere).\n * - a `FilterCondition` → AND it into the object's scan (the join's `ON`/\n * `WHERE` for analytics; the where clause for a plain find).\n * - the `RLS_DENY_FILTER` sentinel → policies applied but none compiled, or\n * resolution failed — fail-closed to zero rows. NEVER returns \"allow all\"\n * on error, so a degraded permission subsystem cannot leak cross-tenant\n * rows through analytics.\n *\n * Async because permission-set resolution can hit the database; the analytics\n * service pre-resolves these per request (base + every joined object) before\n * the synchronous SQL builder runs.\n */\n async getReadFilter(\n object: string,\n context?: any,\n ): Promise<Record<string, unknown> | null | undefined> {\n // System operations bypass scoping (mirrors the middleware's isSystem skip).\n if (context?.isSystem) return undefined;\n const roles = context?.roles ?? [];\n const explicit = context?.permissions ?? [];\n // Unauthenticated + role-less + permission-less → no scope (the auth layer,\n // not RLS, gates anonymous access; the analytics REST endpoint already 401s\n // without a token). Mirrors the middleware's early `return next()`.\n if (roles.length === 0 && explicit.length === 0 && !context?.userId) {\n return undefined;\n }\n try {\n const permissionSets = await this.resolvePermissionSetsForContext(context);\n const filter = await this.computeRlsFilter(permissionSets, object, 'find', context);\n return filter ?? undefined;\n } catch (e) {\n // Fail CLOSED — a resolution failure must deny (zero rows), never expose\n // every tenant's data through the raw-SQL analytics path.\n this.logger.error?.(\n `[security] getReadFilter failed for object '${object}' ` +\n `(user ${context?.userId ?? 'unknown'}) — denying (fail-closed)`,\n e instanceof Error ? e : new Error(String(e)),\n );\n return { ...RLS_DENY_FILTER };\n }\n }\n\n /**\n * Resolve the effective permission sets for an execution context — roles +\n * explicit permission sets, with the configured baseline applied both as an\n * implicit request (when none were named) and as a post-resolution fallback\n * (when named ones resolved to nothing). Shared by the engine middleware and\n * {@link getReadFilter} so both enforce identical RLS. May throw if the\n * underlying metadata/db resolution fails (callers fail-closed).\n */\n private async resolvePermissionSetsForContext(\n context: any,\n ): Promise<PermissionSet[]> {\n const roles = context?.roles ?? [];\n const explicitPermissionSets = context?.permissions ?? [];\n const requested = [...roles, ...explicitPermissionSets];\n // Implicit baseline: an authenticated request that named no roles/perms\n // still gets the configured baseline (default `member_default`) so tenant +\n // owner RLS apply before an admin assigns a profile.\n if (requested.length === 0 && context?.userId && this.fallbackPermissionSet) {\n requested.push(this.fallbackPermissionSet);\n }\n let permissionSets = await this.permissionEvaluator.resolvePermissionSets(\n requested,\n this.metadata,\n this.bootstrapPermissionSets,\n this.dbLoader,\n );\n // Post-resolution fallback — closes the fail-open hole where a populated\n // `roles` array maps to no permission set yet (no sys_role binding), which\n // would otherwise skip RLS entirely and expose every tenant's data.\n if (\n permissionSets.length === 0 &&\n context?.userId &&\n this.fallbackPermissionSet\n ) {\n permissionSets = await this.permissionEvaluator.resolvePermissionSets(\n [this.fallbackPermissionSet],\n this.metadata,\n this.bootstrapPermissionSets,\n this.dbLoader,\n );\n }\n return permissionSets;\n }\n\n /**\n * Resolve a single scalar primary-key id from an update/delete operation\n * context, mirroring the engine's \"single-id vs predicate\" rule\n * (`engine.ts` update/delete): only a scalar `data.id` or `where.id`\n * identifies one row. An operator object (`{ $in: [...] }`, …) is a\n * multi-row predicate and returns `null` (multi-row writes route through the\n * `*Many` paths, out of scope for the by-id pre-image check).\n */\n private extractSingleId(opCtx: any): string | number | bigint | null {\n const isScalar = (v: unknown): v is string | number | bigint =>\n v !== null && (typeof v === 'string' || typeof v === 'number' || typeof v === 'bigint');\n const data = opCtx?.data;\n if (data && typeof data === 'object' && !Array.isArray(data) && isScalar(data.id)) {\n return data.id;\n }\n const where = opCtx?.options?.where;\n if (where && typeof where === 'object' && 'id' in where && isScalar((where as any).id)) {\n return (where as any).id;\n }\n return null;\n }\n\n /**\n * Compile the applicable RLS policies for (object, operation) into a single\n * `FilterCondition`, applying the field-existence safety net (wildcard\n * policies targeting a column the object lacks fail-closed to the deny\n * sentinel, unless the object explicitly opted out of tenancy). Shared by the\n * engine middleware and {@link getReadFilter}. Returns `null` when no policy\n * applies (caller adds no filter).\n */\n private async computeRlsFilter(\n permissionSets: PermissionSet[],\n object: string,\n operation: string,\n context: any,\n ): Promise<Record<string, unknown> | null> {\n const allRlsPolicies = this.collectRLSPolicies(permissionSets, object, operation);\n if (allRlsPolicies.length === 0) return null;\n // Field-existence safety: wildcard policies (`object: '*'`) target fields\n // like `organization_id` that may not exist on every object. Treat such a\n // policy as a *deny* contribution (fail-closed) rather than dropping it —\n // unless the object explicitly opted out of tenancy, where it's \"not\n // applicable\" and skipped silently. When the schema lookup itself fails we\n // keep all policies (drivers surface column errors clearly at compile time).\n const objectFields = await this.getObjectFieldNames(this.metadata, object, this.ql);\n const tenancyDisabled = this.tenancyDisabledCache.get(object) === true;\n let dropped = 0;\n const compilable = objectFields\n ? allRlsPolicies.filter((p) => {\n const targetField = this.extractTargetField(p.using);\n if (!targetField) return true;\n if (objectFields.has(targetField)) return true;\n if (tenancyDisabled && targetField === 'organization_id') {\n return false;\n }\n dropped++;\n return false;\n })\n : allRlsPolicies;\n let rlsFilter = this.rlsCompiler.compileFilter(compilable, context);\n // Every applicable policy dropped for a missing field → deny sentinel.\n if (rlsFilter == null && dropped > 0) {\n rlsFilter = { ...RLS_DENY_FILTER };\n }\n return rlsFilter;\n }\n\n /**\n * Resolve a controlled_by_parent object's master-detail relation (the FK field\n * key + the master object name), or null. Prefers a required `master_detail`\n * field; falls back to any `master_detail`, then a required `lookup`. Cached.\n */\n private resolveCbpRelation(object: string): { fk: string; master: string } | null {\n if (this.cbpRelCache.has(object)) return this.cbpRelCache.get(object) ?? null;\n let rel: { fk: string; master: string } | null = null;\n const schema = typeof this.ql?.getSchema === 'function' ? this.ql.getSchema(object) : null;\n const fields = schema?.fields;\n const entries: Array<[string, any]> = Array.isArray(fields)\n ? fields.map((f: any) => [f?.name, f] as [string, any])\n : fields && typeof fields === 'object'\n ? (Object.entries(fields) as Array<[string, any]>)\n : [];\n const ref = (f: any) => f?.reference ?? f?.reference_to ?? f?.referenceTo;\n const pick = (pred: (f: any) => boolean) => entries.find(([, f]) => pred(f) && ref(f));\n const found =\n pick((f) => f?.type === 'master_detail' && f?.required) ??\n pick((f) => f?.type === 'master_detail') ??\n pick((f) => f?.type === 'lookup' && f?.required);\n if (found) rel = { fk: String(found[0]), master: String(ref(found[1])) };\n this.cbpRelCache.set(object, rel);\n return rel;\n }\n\n /**\n * ADR-0055 — master-detail \"controlled by parent\" READ derivation.\n *\n * For an object whose `sharingModel` is `controlled_by_parent`, access is\n * derived from the master: return a filter `masterFK IN (<master ids this user\n * can read>)`. The id set is resolved by running the MASTER's own read RLS\n * (reused via `computeRlsFilter`) under a system context — no middleware\n * re-entry, so no recursion. An empty set yields `{ masterFK: { $in: [] } }`,\n * which matches no rows (fail closed). A misconfigured object (no\n * master_detail/lookup to derive from) denies all reads (defense-in-depth;\n * spec validation should prevent authoring it). Returns null when the object is\n * not controlled_by_parent.\n *\n * v1 scope (ADR-0055): single level — the master's OWN controlled_by_parent is\n * not traversed transitively; master accessibility is the master's RLS filter\n * (sharing-service grants on the master are not folded in).\n */\n private async computeControlledByParentFilter(\n permissionSets: PermissionSet[],\n object: string,\n context: any,\n ): Promise<Record<string, unknown> | null> {\n if (!this.ql || !context?.userId) return null;\n const schema = typeof this.ql.getSchema === 'function' ? this.ql.getSchema(object) : null;\n const sharingModel = schema?.sharingModel ?? schema?.security?.sharingModel;\n if (sharingModel !== 'controlled_by_parent') return null;\n\n const rel = this.resolveCbpRelation(object);\n if (!rel) return { ...RLS_DENY_FILTER };\n\n const masterFilter = await this.computeRlsFilter(permissionSets, rel.master, 'find', context);\n let masterIds: string[] = [];\n try {\n const rows = await this.ql.find(rel.master, {\n where: masterFilter ?? {},\n fields: ['id'],\n context: { isSystem: true },\n });\n masterIds = (Array.isArray(rows) ? rows : [])\n .map((r: any) => r?.id)\n .filter((id: any) => id != null);\n } catch {\n masterIds = [];\n }\n return { [rel.fk]: { $in: masterIds } };\n }\n\n /**\n * ADR-0055 — master-detail \"controlled by parent\" WRITE enforcement.\n *\n * A by-id write (insert/update/delete) to a controlled_by_parent detail\n * requires EDIT access to its master: the caller must hold CRUD `update` on the\n * master object AND the master row must be visible under the master's write RLS.\n * This is the write-side companion to the read derivation — the RLS read filter\n * never applies to a by-id write (the #1994 class), so without this a member\n * could mutate a detail under a master they cannot edit. Throws on denial;\n * no-op when the object is not controlled_by_parent.\n *\n * v1 scope: single-id writes. Bulk writes flow through the AST and are already\n * scoped by the controlled-by-parent READ filter (to readable masters).\n */\n private async assertControlledByParentWrite(\n permissionSets: PermissionSet[],\n object: string,\n operation: string,\n opCtx: any,\n context: any,\n ): Promise<void> {\n const schema = typeof this.ql?.getSchema === 'function' ? this.ql.getSchema(object) : null;\n const sharingModel = schema?.sharingModel ?? schema?.security?.sharingModel;\n if (sharingModel !== 'controlled_by_parent') return;\n\n const deny = (reason: string, recordId?: unknown) => {\n throw new PermissionDeniedError(\n `[Security] Access denied: ${operation} on '${object}' requires edit access to its master record (${reason})`,\n { operation, object, recordId },\n );\n };\n\n const rel = this.resolveCbpRelation(object);\n if (!rel) deny('controlled_by_parent declared but no master_detail relation');\n\n // Resolve the master id: from the incoming body on insert, else from the\n // target row (read as system — we only need its FK value).\n let masterId: unknown;\n if (operation === 'insert') {\n const data = opCtx.data;\n masterId = data && typeof data === 'object' && !Array.isArray(data) ? (data as any)[rel!.fk] : undefined;\n } else {\n const targetId = this.extractSingleId(opCtx);\n if (targetId == null) return; // bulk write — scoped by the read filter on the AST\n let row: any = null;\n try {\n row = await this.ql.findOne(object, { where: { id: targetId }, context: { isSystem: true } });\n } catch {\n row = null;\n }\n if (!row) deny('target record not found', targetId);\n masterId = row[rel!.fk];\n }\n if (masterId == null) deny('detail record has no master reference');\n\n // Master edit access = CRUD update on the master AND master row visible under\n // the master's write RLS.\n if (!this.permissionEvaluator.checkObjectPermission('update', rel!.master, permissionSets)) {\n deny(`no edit permission on master '${rel!.master}'`, masterId);\n }\n const masterWriteFilter = await this.computeRlsFilter(permissionSets, rel!.master, 'update', context);\n if (masterWriteFilter) {\n let visible: unknown = null;\n try {\n visible = await this.ql.findOne(rel!.master, {\n where: { $and: [{ id: masterId }, masterWriteFilter] },\n context,\n });\n } catch {\n visible = null;\n }\n if (!visible) deny(`master '${rel!.master}' not editable by this user (row-level security)`, masterId);\n }\n }\n\n /**\n * Collect all RLS policies from permission sets applicable to the given object/operation.\n */\n private collectRLSPolicies(\n permissionSets: PermissionSet[],\n objectName: string,\n operation: string\n ): RowLevelSecurityPolicy[] {\n const allPolicies: RowLevelSecurityPolicy[] = [];\n\n for (const ps of permissionSets) {\n if (ps.rowLevelSecurity) {\n for (const policy of ps.rowLevelSecurity) {\n // When the org-scoping plugin is NOT installed, strip any\n // policy that filters on `current_user.organization_id` —\n // there is no meaningful tenant to compare against, so the\n // policy would either drop every row (when the field exists\n // on the object) or be dropped by the field-existence safety\n // net. Either way it's pure overhead. Substring match is\n // sufficient: every wildcard tenant policy in the default\n // permission sets uses exactly this token. Install\n // `@objectstack/plugin-org-scoping` to enable the\n // multi-tenant behavior.\n if (\n !this.orgScopingEnabled &&\n policy.using &&\n policy.using.includes('current_user.organization_id')\n ) {\n continue;\n }\n allPolicies.push(policy);\n }\n }\n }\n\n return this.rlsCompiler.getApplicablePolicies(objectName, operation, allPolicies);\n }\n\n /**\n * Resolve the column-name set for an object (lowercased). Returns\n * `null` if the schema can't be loaded — caller should fail-closed.\n */\n private async getObjectFieldNames(\n metadata: any,\n objectName: string,\n ql?: any,\n ): Promise<Set<string> | null> {\n if (this.fieldNamesCache.has(objectName)) {\n return this.fieldNamesCache.get(objectName) ?? null;\n }\n const result = await this.loadObjectFieldNames(metadata, objectName, ql);\n // Only cache positive resolutions — a `null` may simply mean the\n // schema isn't registered yet at boot, and we want subsequent calls\n // to retry rather than be permanently denied.\n if (result) {\n this.fieldNamesCache.set(objectName, result);\n }\n return result;\n }\n\n private async loadObjectFieldNames(\n metadata: any,\n objectName: string,\n ql?: any,\n ): Promise<Set<string> | null> {\n try {\n // Prefer ObjectQL's per-engine SchemaRegistry as the source of truth\n // for the live field set: it reflects registry-time augmentations\n // (system-field auto-injection like `organization_id`) that the\n // standalone metadata artifact loaded at boot may not include.\n // Fall back to the metadata service for objects ObjectQL doesn't\n // know about (system tables registered through other paths).\n let obj: any = typeof ql?.getSchema === 'function' ? ql.getSchema(objectName) : null;\n if (!obj || !obj.fields) {\n obj = await metadata?.get?.('object', objectName);\n }\n if (!obj || !obj.fields) return null;\n // Populate the tenancy opt-out cache alongside the field set so\n // the RLS filter pass can decide whether a wildcard\n // `organization_id` policy is genuinely \"applicable but\n // uncompilable\" (deny) versus \"not applicable on this object\"\n // (skip without contributing to the deny sentinel).\n const tenancyDisabled =\n (obj as any)?.tenancy?.enabled === false ||\n (obj as any)?.systemFields?.tenant === false;\n this.tenancyDisabledCache.set(objectName, !!tenancyDisabled);\n const set = new Set<string>(['id']);\n if (Array.isArray(obj.fields)) {\n for (const f of obj.fields) {\n if (f?.name) set.add(String(f.name));\n }\n } else if (typeof obj.fields === 'object') {\n for (const key of Object.keys(obj.fields)) {\n set.add(key);\n const v = (obj.fields as Record<string, any>)[key];\n if (v && typeof v === 'object' && v.name) set.add(String(v.name));\n }\n } else {\n return null;\n }\n return set;\n } catch {\n return null;\n }\n }\n\n /**\n * Extract the left-hand field name from a simple RLS expression like\n * `field = current_user.x` or `field IN (current_user.y)`. Returns\n * `null` for unsupported shapes (in which case we keep the policy).\n */\n private extractTargetField(using?: string): string | null {\n if (!using) return null;\n // Match `field =` or `field IN`/`in`. Note: `\\b` is omitted after `=`\n // because `=` is non-word and the next char (space) is non-word too —\n // a word boundary cannot exist between two non-word chars, so `=\\b`\n // would never match. We instead require the alternation token to be\n // followed by whitespace or `(`.\n const m = using.match(/^\\s*([a-z_][a-z0-9_]*)\\s*(?:=|IN|in)(?=\\s|\\()/);\n return m ? m[1] : null;\n }\n}\n","// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * ADR-0056 D7 — resolve the app-declared default profile NAME from a stack's\n * `permissions[]` array.\n *\n * A permission set marked `isProfile && isDefault` declares the app's default\n * access posture for users with no explicit grants. The {@link SecurityPlugin}\n * constructor scans its `defaultPermissionSets` option for that flag — but the\n * CLI constructs `new SecurityPlugin()` with NO options, so an `isDefault`\n * profile declared purely in app METADATA would never be honored. The CLI calls\n * this helper to pull the name out of the stack and pass it as\n * `fallbackPermissionSet`, wiring the declaration through to `pnpm dev`.\n *\n * Returns the first matching profile's `name`, or `undefined` when none is\n * declared (callers then keep the built-in `member_default` fallback).\n */\nexport function appDefaultProfileName(permissions: unknown): string | undefined {\n if (!Array.isArray(permissions)) return undefined;\n for (const p of permissions) {\n if (p && typeof p === 'object') {\n const ps = p as { name?: unknown; isProfile?: unknown; isDefault?: unknown };\n // `isProfile !== false` mirrors the stack convention where profiles double\n // as the user's baseline; permission-set add-ons set `isProfile: false`.\n if (\n ps.isDefault === true &&\n ps.isProfile !== false &&\n typeof ps.name === 'string' &&\n ps.name.length > 0\n ) {\n return ps.name;\n }\n }\n }\n return undefined;\n}\n"],"mappings":"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","names":["SystemUserId","SYSTEM_CTX","SystemUserId","SYSTEM_CTX","genId","tryFind","tryInsert","ObjectSchema","Field","ObjectSchema","Field","ObjectSchema","Field","SecurityTranslations"]}