Skip to main content

Overview

This page documents the core types used for access control in Syft: ACLRequest, AccessLevel, User, and Access. These types work together to define who can access what resources and at what permission level.

ACLRequest

Represents a request to access a resource with a specific permission level.
from syft_permissions import ACLRequest

Fields

path
str
required
Relative path within the datasite to the resource being accessed. The path is relative to the datasite root.
level
AccessLevel
required
The level of access being requested (READ, WRITE, or ADMIN).
user
User
required
The user making the access request.

Example

from syft_permissions import ACLRequest, AccessLevel, User

request = ACLRequest(
    path="reports/q1.csv",
    level=AccessLevel.READ,
    user=User(id="[email protected]")
)

Usage with ACLService

from syft_permissions import ACLService, ACLRequest, AccessLevel, User

service = ACLService(owner="[email protected]")
# ... load permissions ...

# Check if alice can read the file
request = ACLRequest(
    path="reports/q1.csv",
    level=AccessLevel.READ,
    user=User(id="[email protected]")
)

if service.can_access(request):
    # Grant access to the file
    with open("reports/q1.csv") as f:
        data = f.read()
else:
    # Deny access
    raise PermissionError("Access denied")

AccessLevel

Enumeration of permission levels, implemented as an IntEnum for hierarchical comparison.
from syft_permissions import AccessLevel

Values

READ
int
default:"1"
Read-only access to view or download resources.
WRITE
int
default:"2"
Write access to modify or upload resources. Implies READ access.
ADMIN
int
default:"4"
Administrative access to manage permissions and perform all operations. Implies both WRITE and READ access.

Access Hierarchy

Access levels are hierarchical:
  • ADMIN implies WRITE and READ
  • WRITE implies READ
  • READ is the base level
This hierarchy is enforced automatically when checking permissions.

Example

from syft_permissions import AccessLevel

# Using access levels
print(AccessLevel.READ)    # 1
print(AccessLevel.WRITE)   # 2
print(AccessLevel.ADMIN)   # 4

# Comparison (due to IntEnum)
print(AccessLevel.ADMIN > AccessLevel.WRITE)  # True
print(AccessLevel.WRITE > AccessLevel.READ)   # True

Permission Checking Logic

When a user has a certain access level, they automatically have all lower levels:
from syft_permissions import Rule, Access, AccessLevel

# User has ADMIN access
rule = Rule(
    pattern="**",
    access=Access(admin=["[email protected]"])
)

# Alice can:
# - Perform ADMIN operations ✓
# - Perform WRITE operations ✓ (implied)
# - Perform READ operations ✓ (implied)
# User has WRITE access
rule = Rule(
    pattern="**",
    access=Access(write=["[email protected]"])
)

# Bob can:
# - Perform ADMIN operations ✗
# - Perform WRITE operations ✓
# - Perform READ operations ✓ (implied)
# User has READ access
rule = Rule(
    pattern="**",
    access=Access(read=["[email protected]"])
)

# Charlie can:
# - Perform ADMIN operations ✗
# - Perform WRITE operations ✗
# - Perform READ operations ✓

User

Represents a user in the permission system.
from syft_permissions import User

Fields

id
str
required
User identifier, typically an email address. Used for matching against access control lists and templates.

Example

from syft_permissions import User

user = User(id="[email protected]")
print(user.id)  # "[email protected]"

Owner vs Regular Users

The datasite owner (specified in ACLService) is a special user who bypasses all permission checks:
from syft_permissions import ACLService, ACLRequest, AccessLevel, User

service = ACLService(owner="[email protected]")

# Owner can access anything, even with no rules defined
owner_request = ACLRequest(
    path="any/path/anywhere",
    level=AccessLevel.ADMIN,
    user=User(id="[email protected]")
)

service.can_access(owner_request)  # True (owner bypass)

# Regular user cannot access without matching rules
user_request = ACLRequest(
    path="any/path/anywhere",
    level=AccessLevel.READ,
    user=User(id="[email protected]")
)

service.can_access(user_request)  # False (no rules)

Access

Defines access control lists (ACLs) specifying which users have which permissions.
from syft_permissions import Access

Fields

admin
list[str]
default:"[]"
List of users or patterns with administrative access. Users in this list can perform all operations.
write
list[str]
default:"[]"
List of users or patterns with write access. Users in this list can modify resources and have implied read access.
read
list[str]
default:"[]"
List of users or patterns with read access. Users in this list can view resources.

Access List Patterns

Each access list supports multiple pattern types:

Exact Email

Access(read=["[email protected]"])
Grants access to a specific user by exact email match.

Domain Wildcard

Access(read=["*@company.com"])
Grants access to all users from a specific domain using fnmatch pattern matching.

Everyone

Access(read=["*"])
Grants access to all users (public access).

USER Placeholder

Access(write=["USER"])
Special placeholder that behaves differently based on the rule pattern:
  • With template patterns ({{.UserEmail}}/**): Resolves to the requesting user’s email
  • Without template patterns: Resolves to * (any authenticated user)
This enables per-user private directories:
Rule(
    pattern="{{.UserEmail}}/**",
    access=Access(write=["USER"])
)

# When [email protected] requests access to "[email protected]/file.txt":
# - Pattern resolves to: "[email protected]/**"
# - USER resolves to: "[email protected]"
# - Result: Match! Alice can write to her own directory.

# When [email protected] requests access to "[email protected]/file.txt":
# - Pattern resolves to: "[email protected]/**"
# - Result: No match. Alice cannot access Bob's directory.

Examples

Public Read Access

from syft_permissions import Access

access = Access(read=["*"])

Company-Wide Access

from syft_permissions import Access

access = Access(
    read=["*@company.com"],
    write=["[email protected]"]
)

Multi-User Access

from syft_permissions import Access

access = Access(
    read=["[email protected]", "[email protected]", "*@partner.com"],
    write=["[email protected]"],
    admin=["[email protected]"]
)

Per-User Directories

from syft_permissions import Rule, Access

# Users can write to their own directories
rule = Rule(
    pattern="{{.UserEmail}}/**",
    access=Access(write=["USER"])
)

Mixed Patterns

from syft_permissions import Access

# Combine exact emails, domain wildcards, and public access
access = Access(
    admin=["[email protected]"],
    write=["*@company.com", "[email protected]"],
    read=["*"]  # Public read
)

Empty Access Lists

Empty access lists deny all access:
from syft_permissions import Access

# No one can access (except the owner)
access = Access()
# Equivalent to:
# Access(admin=[], write=[], read=[])

Complete Example

Here’s a comprehensive example combining all access control types:
from syft_permissions import (
    ACLService,
    ACLRequest,
    AccessLevel,
    User,
    RuleSet,
    Rule,
    Access
)

# Initialize service
service = ACLService(owner="[email protected]")

# Define a ruleset with various access patterns
ruleset = RuleSet(
    path="",
    rules=[
        # Admin-only configuration
        Rule(
            pattern="config/**",
            access=Access(admin=["[email protected]"])
        ),
        
        # Per-user private directories
        Rule(
            pattern="users/{{.UserEmail}}/**",
            access=Access(write=["USER"])
        ),
        
        # Team collaboration space
        Rule(
            pattern="team/**",
            access=Access(
                write=["*@company.com"],
                read=["*@partner.com"]
            )
        ),
        
        # Public reports
        Rule(
            pattern="reports/**/*.pdf",
            access=Access(read=["*"])
        ),
        
        # Default: deny all
        Rule(
            pattern="**",
            access=Access()
        )
    ]
)

service.add_ruleset(ruleset)

# Test access for different scenarios
test_cases = [
    # Admin can access config
    ("[email protected]", "config/settings.yaml", AccessLevel.ADMIN, True),
    
    # Regular employee cannot access config
    ("[email protected]", "config/settings.yaml", AccessLevel.READ, False),
    
    # Users can write to their own directories
    ("[email protected]", "users/[email protected]/notes.txt", AccessLevel.WRITE, True),
    
    # Users cannot access other users' directories
    ("[email protected]", "users/[email protected]/notes.txt", AccessLevel.READ, False),
    
    # Company employees can write to team space
    ("[email protected]", "team/project.txt", AccessLevel.WRITE, True),
    
    # Partners can read team space
    ("[email protected]", "team/project.txt", AccessLevel.READ, True),
    
    # Partners cannot write to team space
    ("[email protected]", "team/project.txt", AccessLevel.WRITE, False),
    
    # Anyone can read public reports
    ("[email protected]", "reports/2024/q1.pdf", AccessLevel.READ, True),
    
    # No one can write public reports (no write rule)
    ("[email protected]", "reports/2024/q1.pdf", AccessLevel.WRITE, False),
]

for user_email, path, level, expected in test_cases:
    request = ACLRequest(
        path=path,
        level=level,
        user=User(id=user_email)
    )
    result = service.can_access(request)
    status = "✓" if result == expected else "✗"
    print(f"{status} {user_email} {level.name} {path}: {result}")

See Also

  • ACLService - Use these types to check permissions
  • RuleSet - Define rules using Access
  • Rule - Configure access patterns

Build docs developers (and LLMs) love