from mock import patch import pytest from flask_principal import AnonymousIdentity from endpoints.api import api from endpoints.api.organization import OrganizationCollaboratorList from endpoints.api.repositorynotification import RepositoryNotification from endpoints.api.permission import RepositoryUserTransitivePermission from endpoints.api.team import OrganizationTeamSyncing from endpoints.api.test.shared import conduct_api_call from endpoints.api.repository import RepositoryTrust from endpoints.api.signing import RepositorySignatures from endpoints.api.search import ConductRepositorySearch from endpoints.api.superuser import SuperUserRepositoryBuildLogs, SuperUserRepositoryBuildResource from endpoints.api.superuser import SuperUserRepositoryBuildStatus from endpoints.api.appspecifictokens import AppTokens, AppToken from endpoints.api.manifest import RepositoryManifest from endpoints.api.trigger import BuildTrigger from endpoints.test.shared import client_with_identity, toggle_feature from test.fixtures import * ORG_PARAMS = {'orgname': 'buynlarge'} TEAM_PARAMS = {'orgname': 'buynlarge', 'teamname': 'owners'} BUILD_PARAMS = {'build_uuid': 'test-1234'} REPO_PARAMS = {'repository': 'devtable/someapp'} SEARCH_PARAMS = {'query': ''} NOTIFICATION_PARAMS = {'namespace': 'devtable', 'repository': 'devtable/simple', 'uuid': 'some uuid'} TOKEN_PARAMS = {'token_uuid': 'someuuid'} TRIGGER_PARAMS = {'repository': 'devtable/simple', 'trigger_uuid': 'someuuid'} MANIFEST_PARAMS = {'repository': 'devtable/simple', 'manifestref': 'sha256:deadbeef'} @pytest.mark.parametrize('resource,method,params,body,identity,expected', [ (AppTokens, 'GET', {}, {}, None, 401), (AppTokens, 'GET', {}, {}, 'freshuser', 200), (AppTokens, 'GET', {}, {}, 'reader', 200), (AppTokens, 'GET', {}, {}, 'devtable', 200), (AppTokens, 'POST', {}, {}, None, 403), (AppTokens, 'POST', {}, {}, 'freshuser', 400), (AppTokens, 'POST', {}, {}, 'reader', 400), (AppTokens, 'POST', {}, {}, 'devtable', 400), (AppToken, 'GET', TOKEN_PARAMS, {}, None, 401), (AppToken, 'GET', TOKEN_PARAMS, {}, 'freshuser', 404), (AppToken, 'GET', TOKEN_PARAMS, {}, 'reader', 404), (AppToken, 'GET', TOKEN_PARAMS, {}, 'devtable', 404), (AppToken, 'DELETE', TOKEN_PARAMS, {}, None, 403), (AppToken, 'DELETE', TOKEN_PARAMS, {}, 'freshuser', 404), (AppToken, 'DELETE', TOKEN_PARAMS, {}, 'reader', 404), (AppToken, 'DELETE', TOKEN_PARAMS, {}, 'devtable', 404), (RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, None, 401), (RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, 'freshuser', 403), (RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, 'reader', 403), (RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, 'devtable', 404), (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, None, 401), (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'freshuser', 403), (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'reader', 403), (OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'devtable', 200), (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, None, 403), (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'freshuser', 403), (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'reader', 403), (OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'devtable', 400), (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, None, 403), (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'freshuser', 403), (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'reader', 403), (OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'devtable', 200), (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, None, 200), (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'freshuser', 200), (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'reader', 200), (ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'devtable', 200), (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, None, 401), (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'freshuser', 403), (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'reader', 403), (SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'devtable', 400), (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, None, 401), (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'freshuser', 403), (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'reader', 403), (SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'devtable', 400), (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, None, 401), (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'freshuser', 403), (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'reader', 403), (SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'devtable', 404), (RepositorySignatures, 'GET', REPO_PARAMS, {}, 'freshuser', 403), (RepositorySignatures, 'GET', REPO_PARAMS, {}, 'reader', 403), (RepositorySignatures, 'GET', REPO_PARAMS, {}, 'devtable', 404), (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, None, 403), (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'freshuser', 403), (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'reader', 403), (RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'devtable', 400), (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, None, 403), (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'freshuser', 403), (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'reader', 403), (RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'devtable', 404), (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, None, 401), (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'freshuser', 403), (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'reader', 403), (BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'devtable', 404), (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, None, 403), (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'freshuser', 403), (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'reader', 403), (BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'devtable', 404), (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, None, 403), (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'freshuser', 403), (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'reader', 403), (BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'devtable', 400), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, None, 401), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'freshuser', 403), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'reader', 403), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'devtable', 403), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, None, 401), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'freshuser', 403), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'reader', 403), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'devtable', 404), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, None, 401), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'freshuser', 403), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'reader', 403), (RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'devtable', 404), (RepositoryUserTransitivePermission, 'GET', {'username': 'devtable','repository': 'devtable/shared'}, None, 'devtable', 200), (RepositoryUserTransitivePermission, 'GET', {'username': 'devtable','repository': 'devtable/nope'}, None, 'devtable', 404), ]) def test_api_security(resource, method, params, body, identity, expected, client): with client_with_identity(identity, client) as cl: conduct_api_call(cl, resource, method, params, body, expected) @pytest.mark.parametrize('is_superuser', [ (True), (False), ]) @pytest.mark.parametrize('allow_nonsuperuser', [ (True), (False), ]) @pytest.mark.parametrize('method, expected', [ ('POST', 400), ('DELETE', 200), ]) def test_team_sync_security(is_superuser, allow_nonsuperuser, method, expected, client): def is_superuser_method(_): return is_superuser with patch('auth.permissions.superusers.is_superuser', is_superuser_method): with toggle_feature('NONSUPERUSER_TEAM_SYNCING_SETUP', allow_nonsuperuser): with client_with_identity('devtable', client) as cl: expect_success = is_superuser or allow_nonsuperuser expected_status = expected if expect_success else 403 conduct_api_call(cl, OrganizationTeamSyncing, method, TEAM_PARAMS, {}, expected_status)