Copr provides a flexible permission system that allows project owners to grant build and administrative access to other users.
Permission Model
Permissions are managed through the CoprPermission model, which establishes relationships between users and projects with specific access levels.
class CoprPermission :
user_id: Integer # User receiving permission
copr_id: Integer # Project granting permission
copr_builder: SmallInteger # Builder permission level
copr_admin: SmallInteger # Admin permission level
Permission Types
There are two types of permissions that can be granted:
Builder Permission
Allows a user to:
Submit new builds to the project
Rebuild existing packages
Cancel their own builds
Admin Permission
Allows a user to:
Everything a builder can do
Edit project settings
Manage chroots
Approve or deny permission requests from other users
Delete builds
Manage packages
Admin permission implicitly grants builder permission.
Permission States
Each permission type can be in one of these states:
State Value Description nothing0 No permission (default) request1 Permission requested, pending approval approved2 Permission granted
These correspond to helpers.PermissionEnum: PermissionEnum.nothing = 0 # No access
PermissionEnum.request = 1 # Awaiting approval
PermissionEnum.approved = 2 # Access granted
Checking Permissions
Can User Build?
Check if a user can submit builds to a project:
if user.can_build_in(copr):
# User can submit builds
build = create_build( ... )
A user can build in a project if:
They are a Copr admin (system-wide admin)
They are the project owner
They are a group member (for group projects)
They have approved builder permission
They have approved admin permission
Can User Edit?
Check if a user can edit project settings:
if user.can_edit(copr):
# User can modify project
copr.description = "New description"
A user can edit a project if:
They are the project owner (for personal projects)
They are a Copr admin (unless ignore_admin=True)
They have approved admin permission
They are a group member (for group projects)
For group projects, the user who created the project doesn’t get exclusive edit rights. Group membership is validated every time.
Group Permissions
Group projects have special permission handling:
if copr.is_a_group_project:
# Check if user is in the group
if user.can_build_in_group(copr.group):
# User is a group member
Group Membership
Group membership is determined by FAS (Fedora Account System) groups:
user.user_teams # List of FAS group names
user.user_groups # List of Group objects
group.fas_name # FAS group name
Show Group Permission Check Flow
def can_build_in_group ( user , group ):
"""
Check if user can build in group project
"""
return group.fas_name in user.user_teams
For group projects:
User’s FAS groups are retrieved from openid_groups
If project’s group FAS name matches user’s team, access granted
Managing Permissions
Get User Permissions
Retrieve permissions for a specific project:
permissions = user.permissions_for_copr(copr)
if permissions:
builder_state = permissions.copr_builder
admin_state = permissions.copr_admin
This method caches permissions during a single request for performance.
Get All User Permissions
for perm in user.copr_permissions:
print ( f "Project: { perm.copr.full_name } " )
print ( f "Builder: { perm.copr_builder } " )
print ( f "Admin: { perm.copr_admin } " )
user.copr_permissions automatically filters out permissions for deleted projects. Use user.copr_permissions_unfiltered to include deleted projects.
Set Permissions
permission = CoprPermission.query.filter_by(
user = target_user,
copr = project
).first()
if not permission:
permission = CoprPermission( user = target_user, copr = project)
# Grant builder access
permission.set_permission( 'builder' , PermissionEnum( 'approved' ))
# Grant admin access
permission.set_permission( 'admin' , PermissionEnum( 'approved' ))
db.session.add(permission)
db.session.commit()
Get Permission Value
builder_perm = permission.get_permission( 'builder' )
admin_perm = permission.get_permission( 'admin' )
if builder_perm == PermissionEnum( 'approved' ):
print ( "User has builder access" )
Admin Notifications
Project admins receive notifications for important events:
admin_emails = copr.admin_mails
# Returns list of email addresses:
# - Project owner's email
# - All users with approved admin permission
Use this for:
Build failure notifications
Permission requests
Project status changes
System Administrators
Copr system administrators have special privileges:
if user.admin:
# Can edit ANY project
# Can approve ANY permission request
# Can access ANY builds
To check edit permissions while ignoring admin status: if user.can_edit(copr, ignore_admin = True ):
# Check without admin override
Proven Users
Proven users have elevated build privileges:
if user.proven:
# Can modify builder memory
# Can modify build timeout
Proven status is separate from admin status and project permissions.
Permission Request Workflow
User Requests Permission
User requests builder or admin access to a project: permission.set_permission( 'builder' , PermissionEnum( 'request' ))
Owner/Admin Reviews
Project owner or admins see pending requests and review them.
Approve or Deny
Admin approves: permission.set_permission( 'builder' , PermissionEnum( 'approved' ))
Or denies by setting back to: permission.set_permission( 'builder' , PermissionEnum( 'nothing' ))
User Receives Access
User can now build in the project (if approved).
API Usage
Check Build Permission
Grant Admin Access
from copr.v3 import Client
from coprs.models import User, Copr
user = User.query.filter_by( username = "someuser" ).first()
copr = Copr.query.filter_by( name = "project" ).first()
if user.can_build_in(copr):
client = Client.create_from_config_file()
client.build_proxy.create_from_urls( ... )
Common Patterns
Bulk Permission Check
Check if user can build in multiple projects:
accessible_projects = [
copr for copr in project_list
if user.can_build_in(copr)
]
Permission Matrix
Generate permission overview for a user:
for perm in user.copr_permissions:
status = []
if perm.copr_builder == PermissionEnum( 'approved' ):
status.append( 'builder' )
if perm.copr_admin == PermissionEnum( 'approved' ):
status.append( 'admin' )
print ( f " { perm.copr.full_name } : { ', ' .join(status) } " )
Best Practices
Principle of Least Privilege : Grant builder access unless admin is required
Review Requests Promptly : Don’t leave permission requests pending
Use Groups : For team projects, use group ownership instead of individual permissions
Audit Regularly : Review who has access to sensitive projects
Revoke When Needed : Remove permissions when users leave teams
Limitations and Constraints
Permission changes take effect immediately
No permission history/audit log is maintained
Cannot grant partial admin rights (all-or-nothing)
Group membership checked against FAS on every request
Deleted projects retain permission records (use copr_permissions, not copr_permissions_unfiltered)
Security Considerations
System admins can access everything - limit admin privileges
Group projects rely on FAS group membership - ensure FAS is properly configured
Permission requests should be reviewed carefully before approval
No automated approval - all permissions require explicit approval