1
0
mirror of https://github.com/quay/quay.git synced 2026-01-26 06:21:37 +03:00
Files
quay/endpoints/api/test/test_global_readonly_superuser.py
Harish Govindarajulu 129ca2ae29 fix(ui): Enable organization/user visibility for read-only superusers (PROJQUAY-6882) (#4545)
* fix(ui): Enable organization/user visibility for read-only superusers (PROJQUAY-6882)

Users listed under GLOBAL_READONLY_SUPER_USERS can now see all
organizations and users in the UI, matching regular superuser visibility
with read-only restrictions on actions.

- Update UseCurrentUser to include global_readonly_super_user in isSuperUser check
- Add Cypress tests for read-only superuser visibility and action restrictions
- Settings column actions correctly hidden via existing canModify permission

* fix(ui): Add global_readonly_super_user field to API responses (PROJQUAY-6882)

- Add global_readonly_super_user field to user API response in endpoints/api/user.py
- Allow read-only superusers to view organization teams in endpoints/api/organization.py
- Allow read-only superusers to view robot permissions in endpoints/api/robot.py

* fix(ui): Prevent read-only superusers from deleting orgs/users

Security fix: Read-only superusers should not be able to delete
orgs or users they don't own, even though they can view them.

* Fix inline import + incorrect assert + add codecov tests

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-20 01:31:59 -06:00

806 lines
34 KiB
Python

"""
Tests for Global Read-Only Superuser functionality.
This test module validates that Global Read-Only Superusers have the correct
permissions - read access to all content but blocked from write operations.
"""
import pytest
from mock import patch
from data import model
from endpoints.api import allow_if_global_readonly_superuser, allow_if_superuser
from endpoints.api.appspecifictokens import AppTokens
from endpoints.api.logs import OrgAggregateLogs, OrgLogs, UserAggregateLogs, UserLogs
from endpoints.api.organization import Organization, OrganizationList
from endpoints.api.repository import Repository, RepositoryList
from endpoints.api.superuser import SuperUserAggregateLogs, SuperUserLogs
from endpoints.api.test.shared import conduct_api_call
from endpoints.api.user import User
from endpoints.test.shared import client_with_identity
from features import FeatureNameValue
from test.fixtures import *
@pytest.fixture()
def regular_user(initialized_db):
"""Get a regular non-superuser."""
return model.user.get_user("freshuser")
# =============================================================================
# Helper Function Tests
# =============================================================================
class TestGlobalReadOnlySuperuserHelperFunctions:
"""Test the helper functions for global read-only superuser detection."""
def test_allow_if_superuser_function_exists(self, app):
"""Test that allow_if_superuser() function exists and is callable."""
assert callable(allow_if_superuser)
def test_allow_if_global_readonly_superuser_function_exists(self, app):
"""Test that allow_if_global_readonly_superuser() function exists and is callable."""
assert callable(allow_if_global_readonly_superuser)
# =============================================================================
# App Token Access Tests (Well-Written Integration Tests)
# =============================================================================
class TestAppTokenGlobalReadOnlySuperuserBehavior:
"""
Test app token functionality for global read-only superusers.
These tests use real fixtures and minimal mocking to validate actual behavior.
"""
def test_app_token_list_regular_user_access(self, app):
"""Test that regular users only see their own app tokens."""
# Create test tokens for different users
devtable_user = model.user.get_user("devtable")
freshuser = model.user.get_user("freshuser")
devtable_token = model.appspecifictoken.create_token(devtable_user, "DevTable Token")
freshuser_token = model.appspecifictoken.create_token(freshuser, "Fresh User Token")
try:
# Use freshuser (regular user, not superuser) to test regular user access
with client_with_identity("freshuser", app) as cl:
resp = conduct_api_call(cl, AppTokens, "GET", None, None, 200)
token_uuids = {token["uuid"] for token in resp.json["tokens"]}
# Regular user should only see their own tokens
assert freshuser_token.uuid in token_uuids
assert devtable_token.uuid not in token_uuids
finally:
# Clean up
devtable_token.delete_instance()
freshuser_token.delete_instance()
# =============================================================================
# Write Operation Blocking Tests
# =============================================================================
class TestRepositoryWriteOperationsBlocking:
"""Test that repository write operations are blocked for global read-only superusers."""
def test_repository_creation_blocked(self, app):
"""
Test that repository creation is blocked for global readonly superusers.
Permission blocking happens at the CreateRepositoryPermission class level.
"""
from unittest.mock import MagicMock, patch
# Mock the permission class to deny creation
mock_permission = MagicMock()
mock_permission.can.return_value = False
with (
patch(
"endpoints.api.repository.CreateRepositoryPermission", return_value=mock_permission
),
patch("endpoints.api.repository.allow_if_superuser", return_value=False),
):
with client_with_identity("reader", app) as cl:
repo_data = {
"repository": "test-blocked-repo",
"visibility": "private",
"description": "Should be blocked",
}
# Should return 403 Unauthorized for write operations
resp = conduct_api_call(cl, RepositoryList, "POST", None, repo_data, 403)
class TestOrganizationReadOperations:
"""Test that organization read operations work correctly for superusers."""
def test_organization_details_accessible_to_any_superuser(self, app):
"""
Test that organization details (email and teams) are visible to both
regular superusers and global readonly superusers (not just org members).
"""
from unittest.mock import patch
with patch("endpoints.api.organization.allow_if_any_superuser", return_value=True):
with client_with_identity("reader", app) as cl:
resp = conduct_api_call(
cl, Organization, "GET", {"orgname": "buynlarge"}, None, 200
)
assert resp.status_code == 200
# Superusers should be able to see the organization email
assert "email" in resp.json
# Email should not be empty for superusers
assert resp.json.get("email") is not None
# Superusers should also be able to see the organization teams
assert "teams" in resp.json
assert "ordered_teams" in resp.json
class TestOrganizationWriteOperationsBlocking:
"""Test that organization write operations are blocked for global read-only superusers."""
def test_organization_creation_blocked(self, app):
"""
Test that organization creation is blocked for global readonly superusers.
When SUPERUSERS_ORG_CREATION_ONLY is enabled, global readonly superusers
cannot create organizations (blocked by allow_if_superuser check).
"""
from unittest.mock import patch
from endpoints.test.shared import toggle_feature
# Enable the feature that requires superuser for org creation
with toggle_feature("SUPERUSERS_ORG_CREATION_ONLY", True):
with patch("endpoints.api.organization.allow_if_superuser", return_value=False):
with client_with_identity("reader", app) as cl:
org_data = {"name": "test-blocked-org", "email": "test@example.com"}
# Should return 403 Unauthorized for write operations
resp = conduct_api_call(cl, OrganizationList, "POST", None, org_data, 403)
# =============================================================================
# Audit Log Access Tests (With Mocking for Permission System)
# =============================================================================
class TestAuditLogAccess:
"""Test audit log access for global read-only superusers."""
def test_superuser_audit_logs_accessible(self, app):
"""Test that superuser audit logs are accessible to global readonly superusers."""
from unittest.mock import patch
with (
patch("endpoints.api.SuperUserPermission") as mock_super,
patch("endpoints.api.GlobalReadOnlySuperUserPermission") as mock_global_ro,
patch("endpoints.api.superuser.allow_if_any_superuser", return_value=True),
):
mock_super.return_value.can.return_value = False
mock_global_ro.return_value.can.return_value = True
with client_with_identity("reader", app) as cl:
resp = conduct_api_call(cl, SuperUserLogs, "GET", None, None, 200)
assert resp.status_code == 200
assert "logs" in resp.json
def test_superuser_aggregated_logs_accessible(self, app):
"""Test that superuser aggregated logs are accessible to global readonly superusers."""
from unittest.mock import patch
with (
patch("endpoints.api.SuperUserPermission") as mock_super,
patch("endpoints.api.GlobalReadOnlySuperUserPermission") as mock_global_ro,
patch("endpoints.api.superuser.allow_if_any_superuser", return_value=True),
):
mock_super.return_value.can.return_value = False
mock_global_ro.return_value.can.return_value = True
with client_with_identity("reader", app) as cl:
resp = conduct_api_call(cl, SuperUserAggregateLogs, "GET", None, None, 200)
assert resp.status_code == 200
assert "aggregated" in resp.json
def test_user_logs_accessible(self, app):
"""Test that user logs are accessible to global readonly superusers."""
from unittest.mock import patch
with patch("endpoints.api.logs.allow_if_global_readonly_superuser", return_value=True):
with client_with_identity("reader", app) as cl:
resp = conduct_api_call(cl, UserLogs, "GET", None, None, 200)
assert resp.status_code == 200
assert "logs" in resp.json
def test_user_aggregated_logs_accessible(self, app):
"""Test that user aggregated logs are accessible to global readonly superusers."""
from unittest.mock import patch
with patch("endpoints.api.logs.allow_if_global_readonly_superuser", return_value=True):
with client_with_identity("reader", app) as cl:
resp = conduct_api_call(cl, UserAggregateLogs, "GET", None, None, 200)
assert resp.status_code == 200
assert "aggregated" in resp.json
def test_organization_logs_accessible(self, app):
"""Test that organization logs are accessible to global readonly superusers."""
from unittest.mock import patch
with patch("endpoints.api.logs.allow_if_global_readonly_superuser", return_value=True):
with client_with_identity("reader", app) as cl:
resp = conduct_api_call(cl, OrgLogs, "GET", {"orgname": "buynlarge"}, None, 200)
assert resp.status_code == 200
assert "logs" in resp.json
def test_organization_aggregated_logs_accessible(self, app):
"""Test that organization aggregated logs are accessible to global readonly superusers."""
from unittest.mock import patch
with patch("endpoints.api.logs.allow_if_global_readonly_superuser", return_value=True):
with client_with_identity("reader", app) as cl:
resp = conduct_api_call(
cl, OrgAggregateLogs, "GET", {"orgname": "buynlarge"}, None, 200
)
assert resp.status_code == 200
assert "aggregated" in resp.json
# =============================================================================
# Log Export Operations (Special Case - Read Operation That Uses POST)
# =============================================================================
class TestLogExportOperations:
"""Test that log export operations are allowed for global read-only superusers."""
def test_logs_export_allowed(self, app):
"""
Test that log export operations are allowed for global readonly superusers.
Log export is a read operation for compliance/auditing purposes, even though it uses POST.
"""
from unittest.mock import patch
from endpoints.api.logs import ExportUserLogs
with patch("endpoints.api.logs.allow_if_global_readonly_superuser", return_value=True):
with client_with_identity("reader", app) as cl:
export_data = {"callback_email": "test@example.com"}
# This should succeed or fail for validation reasons, not permissions
# We accept both 200 and 400, but verify 400 is NOT a permission error
try:
resp = conduct_api_call(cl, ExportUserLogs, "POST", None, export_data, 200)
assert resp.status_code == 200
assert "export_id" in resp.json
except AssertionError:
# May fail with 400 for validation reasons unrelated to permissions
resp = conduct_api_call(cl, ExportUserLogs, "POST", None, export_data, 400)
# Should NOT be a permission error about global readonly blocking
assert "Global readonly users cannot export logs" not in resp.json.get(
"message", ""
)
# =============================================================================
# Organization Logs Access Without Full Access (Bug PROJQUAY-9790)
# =============================================================================
class TestOrganizationLogsAccessWithoutFullAccess:
"""
Test that global readonly superusers can access organization logs even when
FEATURE_SUPERUSERS_FULL_ACCESS is disabled.
This verifies the fix for bug PROJQUAY-9790 where global readonly superusers
were incorrectly blocked from accessing organization logs when
FEATURE_SUPERUSERS_FULL_ACCESS was set to false.
"""
@pytest.fixture(autouse=True)
def setup(self, app):
"""Configure test environment with SUPERUSERS_FULL_ACCESS disabled."""
import features
from data import model
# Disable SUPERUSERS_FULL_ACCESS to test the bug scenario
features.import_features(
{
"FEATURE_SUPER_USERS": True,
"FEATURE_SUPERUSERS_FULL_ACCESS": False,
}
)
# Create a test organization owned by randomuser (not devtable or globalreadonlysuperuser)
# This ensures devtable has no admin permissions on it
randomuser = model.user.get_user("randomuser")
try:
org = model.organization.get_organization("testorglogs")
except model.InvalidOrganizationException:
org = model.organization.create_organization(
"testorglogs", "testorglogs@test.com", randomuser
)
# Create an owners team for testing team access (if it doesn't exist)
try:
model.team.get_organization_team("testorglogs", "owners")
except model.InvalidTeamException:
model.team.create_team("owners", org, "admin", "Team for owners")
yield
# Note: We don't clean up the organization because it has foreign key constraints
# and the test database is reset between test runs anyway
# Reset to default test config
features.import_features(
{
"FEATURE_SUPER_USERS": True,
"FEATURE_SUPERUSERS_FULL_ACCESS": True,
}
)
def test_global_readonly_superuser_can_access_org_logs_without_full_access(self, app):
"""
Test that global readonly superusers can access organization logs even when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
This is the main test for bug PROJQUAY-9790. Global readonly superusers should
always be able to access logs for auditing purposes, regardless of the
SUPERUSERS_FULL_ACCESS setting.
"""
from endpoints.api.logs import ExportOrgLogs
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access organization logs
resp = conduct_api_call(cl, OrgLogs, "GET", {"orgname": "testorglogs"}, None, 200)
assert resp.status_code == 200
assert "logs" in resp.json
# Should also be able to access aggregated logs
resp = conduct_api_call(
cl, OrgAggregateLogs, "GET", {"orgname": "testorglogs"}, None, 200
)
assert resp.status_code == 200
assert "aggregated" in resp.json
# Should be able to export logs (read operation even though it uses POST)
export_data = {"callback_email": "test@example.com"}
try:
resp = conduct_api_call(
cl, ExportOrgLogs, "POST", {"orgname": "testorglogs"}, export_data, 200
)
assert resp.status_code == 200
except AssertionError:
# May fail with 400 for validation reasons, but should NOT be a permission error
resp = conduct_api_call(
cl, ExportOrgLogs, "POST", {"orgname": "testorglogs"}, export_data, 400
)
# Verify it's not a permission error
error_type = resp.json.get("error_type", "")
assert (
error_type != "insufficient_scope"
), f"Global readonly superuser should be able to export org logs, got: {resp.json}"
def test_regular_superuser_cannot_access_org_logs_without_full_access(self, app):
"""
Test that regular superusers CANNOT access organization logs when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
This verifies that the fix for PROJQUAY-9790 doesn't accidentally grant
regular superusers access to organization logs when they shouldn't have it.
"""
from endpoints.api.logs import ExportOrgLogs
# Use devtable (regular superuser, not global readonly)
with client_with_identity("devtable", app) as cl:
# Should NOT be able to access organization logs without FULL_ACCESS
resp = conduct_api_call(cl, OrgLogs, "GET", {"orgname": "testorglogs"}, None, 403)
assert resp.status_code == 403
# Should NOT be able to access aggregated logs
resp = conduct_api_call(
cl, OrgAggregateLogs, "GET", {"orgname": "testorglogs"}, None, 403
)
assert resp.status_code == 403
# Should NOT be able to export logs
export_data = {"callback_email": "test@example.com"}
resp = conduct_api_call(
cl, ExportOrgLogs, "POST", {"orgname": "testorglogs"}, export_data, 403
)
assert resp.status_code == 403
def test_global_readonly_superuser_can_access_team_members_without_full_access(self, app):
"""
Test that global readonly superusers can access team members when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
This tests the fix for team member access. Global readonly superusers should
be able to view team members for auditing purposes.
"""
from endpoints.api.team import TeamMemberList
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access team members
resp = conduct_api_call(
cl, TeamMemberList, "GET", {"orgname": "buynlarge", "teamname": "owners"}, None, 200
)
assert resp.status_code == 200
assert "members" in resp.json
def test_global_readonly_superuser_can_access_team_permissions_without_full_access(self, app):
"""
Test that global readonly superusers can access team permissions when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
This tests the fix for the reported issue. Global readonly superusers should
be able to view team permissions for auditing purposes.
"""
from endpoints.api.team import TeamPermissions
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access team permissions
resp = conduct_api_call(
cl,
TeamPermissions,
"GET",
{"orgname": "buynlarge", "teamname": "owners"},
None,
200,
)
assert resp.status_code == 200
assert "permissions" in resp.json
def test_regular_superuser_cannot_access_team_data_without_full_access(self, app):
"""
Test that regular superusers CANNOT access team members/permissions when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
This verifies that the fix doesn't accidentally grant regular superusers
access to team data when they shouldn't have it.
"""
from endpoints.api.team import TeamMemberList, TeamPermissions
# Use devtable (regular superuser, not global readonly)
with client_with_identity("devtable", app) as cl:
# Should NOT be able to access team members without FULL_ACCESS
# Using testorglogs org where devtable has no membership
resp = conduct_api_call(
cl,
TeamMemberList,
"GET",
{"orgname": "testorglogs", "teamname": "owners"},
None,
403,
)
assert resp.status_code == 403
def test_global_readonly_superuser_can_access_org_members_without_full_access(self, app):
"""
Test that global readonly superusers can access organization members when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
"""
from endpoints.api.organization import (
OrganizationMember,
OrganizationMemberList,
)
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access organization member list
resp = conduct_api_call(
cl, OrganizationMemberList, "GET", {"orgname": "buynlarge"}, None, 200
)
assert resp.status_code == 200
assert "members" in resp.json
# Should be able to access individual member details
resp = conduct_api_call(
cl,
OrganizationMember,
"GET",
{"orgname": "buynlarge", "membername": "devtable"},
None,
200,
)
assert resp.status_code == 200
assert "name" in resp.json
def test_global_readonly_superuser_can_access_org_applications_without_full_access(self, app):
"""
Test that global readonly superusers can access organization OAuth applications
when FEATURE_SUPERUSERS_FULL_ACCESS is false.
"""
from endpoints.api.organization import OrganizationApplications
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access organization applications
resp = conduct_api_call(
cl, OrganizationApplications, "GET", {"orgname": "buynlarge"}, None, 200
)
assert resp.status_code == 200
assert "applications" in resp.json
def test_global_readonly_superuser_can_access_org_prototypes_without_full_access(self, app):
"""
Test that global readonly superusers can access organization prototype
permissions when FEATURE_SUPERUSERS_FULL_ACCESS is false.
"""
from endpoints.api.prototype import PermissionPrototypeList
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access organization prototype permissions
resp = conduct_api_call(
cl,
PermissionPrototypeList,
"GET",
{"orgname": "buynlarge"},
None,
200,
)
assert resp.status_code == 200
assert "prototypes" in resp.json
# =============================================================================
# Quota Access Tests (PROJQUAY-9804)
# =============================================================================
class TestQuotaAccessWithoutFullAccess:
"""
Test that global readonly superusers can access quota limits when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
Fixes issue PROJQUAY-9804 where global readonly superusers were blocked from
accessing quota limit endpoints.
"""
@pytest.fixture(autouse=True)
def setup(self, app):
"""Configure test environment with SUPERUSERS_FULL_ACCESS disabled."""
import features
# Disable SUPERUSERS_FULL_ACCESS to test the bug scenario
features.import_features(
{
"FEATURE_SUPER_USERS": True,
"FEATURE_SUPERUSERS_FULL_ACCESS": False,
}
)
yield
# Reset to default test config
features.import_features(
{
"FEATURE_SUPER_USERS": True,
"FEATURE_SUPERUSERS_FULL_ACCESS": True,
}
)
def test_global_readonly_superuser_can_access_quota_limit_list(self, app):
"""
Test that global readonly superusers can access quota limit list
when FEATURE_SUPERUSERS_FULL_ACCESS is false.
"""
from endpoints.api.namespacequota import OrganizationQuotaLimitList
# Create a test quota with limits for an organization
org = model.organization.get_organization("buynlarge")
# Create quota if it doesn't exist
try:
quota = model.namespacequota.get_namespace_quota_list("buynlarge")
if not quota:
quota = model.namespacequota.create_namespace_quota(org, 1024 * 1024 * 1024) # 1 GB
else:
quota = quota[0]
except Exception:
quota = model.namespacequota.create_namespace_quota(org, 1024 * 1024 * 1024) # 1 GB
# Create quota limits if they don't exist
try:
existing_limits = list(model.namespacequota.get_namespace_quota_limit_list(quota))
if not existing_limits:
model.namespacequota.create_namespace_quota_limit(quota, "Warning", 80)
model.namespacequota.create_namespace_quota_limit(quota, "Reject", 95)
except Exception:
pass # Limits may already exist
try:
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access quota limit list
resp = conduct_api_call(
cl,
OrganizationQuotaLimitList,
"GET",
{"orgname": "buynlarge", "quota_id": quota.id},
None,
200,
)
assert resp.status_code == 200
# Should return a list of quota limits
assert isinstance(resp.json, list)
finally:
# Clean up - delete quota limits and quota
try:
for limit in model.namespacequota.get_namespace_quota_limit_list(quota):
model.namespacequota.delete_namespace_quota_limit(limit)
model.namespacequota.delete_namespace_quota(quota)
except Exception:
pass # Best effort cleanup
def test_global_readonly_superuser_can_access_individual_quota_limit(self, app):
"""
Test that global readonly superusers can access individual quota limits
when FEATURE_SUPERUSERS_FULL_ACCESS is false.
"""
from endpoints.api.namespacequota import OrganizationQuotaLimit
# Create a test quota with limits for an organization
org = model.organization.get_organization("buynlarge")
# Create quota if it doesn't exist
try:
quota = model.namespacequota.get_namespace_quota_list("buynlarge")
if not quota:
quota = model.namespacequota.create_namespace_quota(org, 1024 * 1024 * 1024) # 1 GB
else:
quota = quota[0]
except Exception:
quota = model.namespacequota.create_namespace_quota(org, 1024 * 1024 * 1024) # 1 GB
# Create quota limit
try:
existing_limits = list(model.namespacequota.get_namespace_quota_limit_list(quota))
if existing_limits:
limit = existing_limits[0]
else:
limit = model.namespacequota.create_namespace_quota_limit(quota, "Warning", 80)
except Exception:
limit = model.namespacequota.create_namespace_quota_limit(quota, "Warning", 80)
try:
# Use globalreadonlysuperuser (configured in testconfig.py)
with client_with_identity("globalreadonlysuperuser", app) as cl:
# Should be able to access individual quota limit
resp = conduct_api_call(
cl,
OrganizationQuotaLimit,
"GET",
{"orgname": "buynlarge", "quota_id": quota.id, "limit_id": limit.id},
None,
200,
)
assert resp.status_code == 200
# Should return quota limit details
assert "id" in resp.json
assert "type" in resp.json
assert "limit_percent" in resp.json
finally:
# Clean up
try:
for limit in model.namespacequota.get_namespace_quota_limit_list(quota):
model.namespacequota.delete_namespace_quota_limit(limit)
model.namespacequota.delete_namespace_quota(quota)
except Exception:
pass # Best effort cleanup
def test_regular_superuser_cannot_access_quota_limits_without_full_access(self, app):
"""
Test that regular superusers CANNOT access quota limits when
FEATURE_SUPERUSERS_FULL_ACCESS is false.
This verifies that the fix doesn't accidentally grant regular superusers
access when they shouldn't have it.
"""
from endpoints.api.namespacequota import OrganizationQuotaLimitList
# Use orgwithnosuperuser - an org that devtable doesn't belong to
org = model.organization.get_organization("orgwithnosuperuser")
# Get or create quota
try:
quota = model.namespacequota.get_namespace_quota_list("orgwithnosuperuser")
if not quota:
quota = model.namespacequota.create_namespace_quota(org, 1024 * 1024 * 1024) # 1 GB
else:
quota = quota[0]
except Exception:
quota = model.namespacequota.create_namespace_quota(org, 1024 * 1024 * 1024) # 1 GB
try:
# Use devtable (regular superuser, not global readonly)
# accessing orgwithnosuperuser where they have no membership
with client_with_identity("devtable", app) as cl:
# Should NOT be able to access quota limit list without FULL_ACCESS
resp = conduct_api_call(
cl,
OrganizationQuotaLimitList,
"GET",
{"orgname": "orgwithnosuperuser", "quota_id": quota.id},
None,
403,
)
assert resp.status_code == 403
finally:
# Clean up only if we created the quota
# Note: orgwithnosuperuser may already have a quota from initdb.py (line 1421)
# so we only clean up if we created it in this test
pass
class TestUserAPIGlobalReadOnlySuperuserField:
"""Test that the User API correctly includes global_readonly_super_user field."""
def test_global_readonly_superuser_sees_field_in_user_api(self, app):
"""
Test that global readonly superusers see the global_readonly_super_user field
in their user API response.
"""
with patch(
"endpoints.api.user.features.SUPER_USERS", FeatureNameValue("SUPER_USERS", True)
):
with patch(
"endpoints.api.user.GlobalReadOnlySuperUserPermission"
) as mock_global_ro_perm:
# Mock the permission to return True for global readonly superuser
mock_global_ro_perm.return_value.can.return_value = True
with client_with_identity("globalreadonlysuperuser", app) as cl:
resp = conduct_api_call(cl, User, "GET", None, None, 200)
assert resp.status_code == 200
# Global readonly superuser should see the field
assert "global_readonly_super_user" in resp.json
# And it should be True for themselves
assert resp.json["global_readonly_super_user"] is True
def test_regular_superuser_does_not_see_global_readonly_field(self, app):
"""
Test that regular superusers do not see the global_readonly_super_user field
in their user API response (since they're not global readonly superusers).
"""
with patch(
"endpoints.api.user.features.SUPER_USERS", FeatureNameValue("SUPER_USERS", True)
):
with patch("endpoints.api.user.SuperUserPermission") as mock_super_perm:
# Mock the permission to return True for regular superuser
mock_super_perm.return_value.can.return_value = True
with client_with_identity("devtable", app) as cl:
resp = conduct_api_call(cl, User, "GET", None, None, 200)
assert resp.status_code == 200
# Regular superuser should see super_user field
assert "super_user" in resp.json
assert resp.json["super_user"] is True
# But should NOT see global_readonly_super_user field since they're not one
assert "global_readonly_super_user" not in resp.json
def test_regular_user_does_not_see_global_readonly_field(self, app):
"""
Test that regular users do not see the global_readonly_super_user field
in their user API response.
"""
with patch(
"endpoints.api.user.features.SUPER_USERS", FeatureNameValue("SUPER_USERS", True)
):
with client_with_identity("freshuser", app) as cl:
resp = conduct_api_call(cl, User, "GET", None, None, 200)
assert resp.status_code == 200
# Regular user should NOT see global_readonly_super_user field
assert "global_readonly_super_user" not in resp.json
# Regular user should also NOT see super_user field
assert "super_user" not in resp.json