How Entity Access Control and Share Permission Management Work in Macro
Entity access control and share permission management in Macro rely on the SharePermission model, which links every shareable entity to a specific access level and enforces authorization through compile-time checked database operations.
The macro-inc/macro repository implements a type-safe permission system that governs access to documents, projects, chats, and calls. This system uses a centralized SharePermission architecture to ensure consistent enforcement of view, comment, edit, and owner privileges across all entity types.
The SharePermission Model
At the core of Macro's access control system is the SharePermission (or SharePermissionV2) struct defined in models_permissions/src/share_permission/mod.rs. Every shareable entity—whether a document, project, thread, or call—maintains a relationship to a row in the SharePermission table. This row stores the permission ID and the specific AccessLevel granted to the user or channel.
When an entity is created, the system inserts a corresponding permission record. For example, a DocumentPermission row points to a SharePermission entry, establishing the ownership and access constraints for that specific document. Permission IDs propagate throughout the codebase to enforce access checks at every operation boundary.
Access Level Hierarchy
The system defines a strict hierarchy of access levels in models_permissions/src/share_permission/access_level.rs. The AccessLevel enum specifies four distinct permission tiers:
- View – Read-only access to the entity
- Comment – Ability to view and add comments
- Edit – Full modification rights without ownership transfer
- Owner – Full control including permission management and deletion
These levels enforce a one-way privilege escalation; an operation requiring Edit access will reject requests from users holding only View or Comment permissions.
Permission Lookup and Validation Flow
Every permission update follows a consistent three-step flow implemented across the database client modules:
Step 1: Lookup
Services retrieve the existing permission ID using macro_db_client::share_permission::get::get_share_permission_id. This function queries the database to locate the SharePermission record associated with the target entity.
Step 2: Validation
The system compares the requester's current AccessLevel against the requirements of the requested operation. For example, a user must hold Edit or Owner privileges to modify document content. The validation logic resides in service layers such as services/document_storage_service/src/service/entity_mutation.rs.
Step 3: Persist
Upon validation, the system calls type-specific creation or edit functions. These include create_project_permission for new project shares or edit_thread_permission for updating existing thread access. All database operations use sqlx query macros, ensuring compile-time schema validation and preventing SQL injection vulnerabilities.
Channel-Specific Sharing
Macro extends the permission model to channels through ChannelSharePermission rows defined in models_permissions/src/share_permission/channel_share_permission.rs. These rows map a channel identifier to a share permission ID, enabling fine-grained access control for collaborative spaces.
The channel_permission module within macro_db_client handles insertion and updates. The function insert_channel_share_permission creates these associations, binding a channel to a specific permission level such as AccessLevel::Comment.
Code Implementation Examples
Creating a New Project Permission
When initializing a project with shared access, services construct a SharePermissionV2 struct and persist it through the database client:
use macro_db_client::share_permission::create::create_project_permission;
use models_permissions::share_permission::{SharePermissionV2, LinkShare, AccessLevel};
use uuid::Uuid;
let share_permission = SharePermissionV2 {
id: Uuid::new_v4(),
link_share: LinkShare::Public,
access_level: AccessLevel::Edit,
// …other fields…
};
create_project_permission(&share_permission).await?;
Fetching and Validating Document Access
Service layers enforce access control by retrieving permissions before executing operations:
use macro_db_client::share_permission::get::get_document_share_permission;
use models_permissions::share_permission::AccessLevel;
let perm = get_document_share_permission(&document_id).await?;
match perm.access_level {
AccessLevel::Edit | AccessLevel::Owner => { /* allow edit */ }
_ => { /* deny with insufficient permissions error */ }
}
Updating Channel Permissions
To grant channel-level access, the system first looks up the permission ID, then inserts a channel-specific mapping:
use macro_db_client::share_permission::get::get_share_permission_id;
use macro_db_client::share_permission::channel_permission::create::insert_channel_share_permission;
use models_permissions::share_permission::AccessLevel;
let permission_id = get_share_permission_id(&channel_id).await?;
insert_channel_share_permission(
&permission_id,
&channel_id,
AccessLevel::Comment,
).await?;
Key Source Files
The permission system spans multiple crates and modules:
| Component | File Path |
|---|---|
| Core permission model | models_permissions/src/share_permission/mod.rs |
| Access level definitions | models_permissions/src/share_permission/access_level.rs |
| Channel share structures | models_permissions/src/share_permission/channel_share_permission.rs |
| Database read operations | macro_db_client/src/share_permission/get.rs |
| Database create operations | macro_db_client/src/share_permission/create.rs |
| Database update operations | macro_db_client/src/share_permission/edit.rs |
| Channel permission DB logic | macro_db_client/src/share_permission/channel_permission/create.rs |
| Service layer mutations | services/document_storage_service/src/service/entity_mutation.rs |
| Outbound mutation handling | services/document_storage_service/src/outbound/entity_mutation.rs |
Summary
- Entity access control and share permission management in Macro center on the
SharePermissionmodel, which associates every entity with a UUID-based permission record. - The AccessLevel enum defines a strict hierarchy: view, comment, edit, and owner.
- Authorization follows a three-step pattern: lookup the permission ID, validate the access level, and persist changes through type-safe database functions.
- ChannelSharePermission extends the model to collaborative channels, managed through dedicated modules in
macro_db_client. - All database interactions use
sqlxmacros for compile-time verification, ensuring schema consistency across the Rust codebase.
Frequently Asked Questions
How does Macro verify a user has permission to edit a document?
The system calls macro_db_client::share_permission::get::get_document_share_permission to retrieve the permission record, then compares the stored AccessLevel against the required level. Only users with Edit or Owner levels proceed with the operation; others receive an insufficient permissions error.
What is the difference between SharePermission and ChannelSharePermission?
SharePermission defines the access level for individual entities like documents or projects, while ChannelSharePermission maps these permissions to entire channels. This allows teams to share access across collaborative spaces while maintaining the same underlying permission ID and access level hierarchy defined in models_permissions/src/share_permission/channel_share_permission.rs.
Where are permission creation functions implemented?
Creation logic resides in macro_db_client/src/share_permission/create.rs, which provides functions like create_project_permission for entity-specific shares. Channel-specific mappings use insert_channel_share_permission from the channel_permission submodule. These functions leverage sqlx query macros for compile-time safety.
Can access levels be customized beyond the four default tiers?
According to the source code in models_permissions/src/share_permission/access_level.rs, the system uses a fixed enum of view, comment, edit, and owner levels. The current implementation does not support dynamic or custom access levels; all permission checks validate against these four statically defined variants.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →