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 SharePermission model, 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 sqlx macros 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →