mirror of
https://github.com/quay/quay.git
synced 2025-11-17 23:02:34 +03:00
fix(api): superuser panel access without SUPERUSERS_FULL_ACCESS (PROJQUAY-9693) (#4455)
fix(api): implement proper superuser permission model and fix access controls Fixes multiple issues with superuser functionality and implements a comprehensive permission model for FEATURE_SUPERUSERS_FULL_ACCESS: **Permission Model:** - Global Readonly Superusers (auditors): Always have read access to all content, independent of FEATURE_SUPERUSERS_FULL_ACCESS setting - Regular Superusers: Can access /v1/superuser endpoints and their own content. Require FEATURE_SUPERUSERS_FULL_ACCESS=true for cross-namespace read access - Full Access Superusers: Regular superusers with FULL_ACCESS enabled, can perform CRUD on content they don't own - Write operations: Only allowed for full access superusers (global readonly superusers never get write access) **Key Fixes:** 1. Fixed superuser panel endpoints returning 403 when FULL_ACCESS was disabled. Basic panel operations (user list, logs, org list, messages) now work with just FEATURE_SUPER_USERS enabled. 2. Updated decorators to properly differentiate between basic superuser operations and permission bypass operations. 3. Implemented license bypass: Superusers with FULL_ACCESS now bypass license/quota limits when creating or modifying private repositories. 4. Fixed 18 permission checks across 7 files to properly implement cross-namespace access controls for different superuser types. **Changes:** - endpoints/api/__init__.py: Fixed allow_if_superuser(), require_repo_permission, and decorators - endpoints/api/superuser.py: Updated SuperUserAppTokens permission check - endpoints/api/organization.py: Updated 4 GET endpoints to require FULL_ACCESS - endpoints/api/namespacequota.py: Updated 2 GET endpoints to require FULL_ACCESS - endpoints/api/team.py: Updated 2 GET endpoints to require FULL_ACCESS - endpoints/api/prototype.py: Updated 1 GET endpoint to require FULL_ACCESS - endpoints/api/policy.py: Updated auto-prune policy endpoints - endpoints/api/robot.py: Updated robot endpoints - endpoints/api/build.py: Updated repository build logs - endpoints/api/repository.py: Added license bypass for superusers with FULL_ACCESS - endpoints/api/repository_models_pre_oci.py: Updated repository visibility query - endpoints/api/logs.py: Fixed log access to require FULL_ACCESS for permission bypass - endpoints/api/test/test_superuser_full_access.py: Added comprehensive test suite - endpoints/api/test/test_appspecifictoken.py: Updated test mocking and added 403 test - test/test_api_usage.py: Updated test expectations for license bypass behavior 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ Manage default permissions added to repositories.
|
||||
|
||||
from flask import request
|
||||
|
||||
import features
|
||||
from app import avatar
|
||||
from auth import scopes
|
||||
from auth.auth_context import get_authenticated_user
|
||||
@@ -14,6 +15,7 @@ from endpoints.api import (
|
||||
allow_if_any_superuser,
|
||||
allow_if_global_readonly_superuser,
|
||||
allow_if_superuser,
|
||||
allow_if_superuser_with_full_access,
|
||||
log_action,
|
||||
nickname,
|
||||
path_param,
|
||||
@@ -147,7 +149,7 @@ class PermissionPrototypeList(ApiResource):
|
||||
List the existing prototypes for this organization.
|
||||
"""
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can() or allow_if_any_superuser():
|
||||
if permission.can() or (features.SUPERUSERS_FULL_ACCESS and allow_if_any_superuser()):
|
||||
try:
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
@@ -173,7 +175,7 @@ class PermissionPrototypeList(ApiResource):
|
||||
Create a new permission prototype.
|
||||
"""
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can() or allow_if_superuser():
|
||||
if permission.can() or allow_if_superuser_with_full_access():
|
||||
try:
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
@@ -264,7 +266,7 @@ class PermissionPrototype(ApiResource):
|
||||
Delete an existing permission prototype.
|
||||
"""
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can() or allow_if_superuser():
|
||||
if permission.can() or allow_if_superuser_with_full_access():
|
||||
try:
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
@@ -288,7 +290,7 @@ class PermissionPrototype(ApiResource):
|
||||
Update the role of an existing permission prototype.
|
||||
"""
|
||||
permission = AdministerOrganizationPermission(orgname)
|
||||
if permission.can() or allow_if_superuser():
|
||||
if permission.can() or allow_if_superuser_with_full_access():
|
||||
try:
|
||||
org = model.organization.get_organization(orgname)
|
||||
except model.InvalidOrganizationException:
|
||||
|
||||
Reference in New Issue
Block a user