diff --git a/app.py b/app.py index 0ee5dd845..3870e9b93 100644 --- a/app.py +++ b/app.py @@ -7,7 +7,8 @@ from flask.ext.principal import Principal from flask.ext.login import LoginManager from flask.ext.mail import Mail -from config import ProductionConfig, DebugConfig, LocalHostedConfig +from config import (ProductionConfig, DebugConfig, LocalHostedConfig, + TestConfig) from util import analytics @@ -22,6 +23,9 @@ if stack.startswith('prod'): elif stack.startswith('localhosted'): logger.info('Running with debug config on production data.') config = LocalHostedConfig() +elif stack.startswith('test'): + logger.info('Running with test config on ephemeral data.') + config = TestConfig() else: logger.info('Running with debug config.') config = DebugConfig() @@ -36,6 +40,6 @@ login_manager.init_app(app) mail = Mail() mail.init_app(app) -stripe.api_key = app.config['STRIPE_SECRET_KEY'] +stripe.api_key = app.config.get('STRIPE_SECRET_KEY', None) -mixpanel = analytics.init_app(app) +mixpanel = app.config['ANALYTICS'].init_app(app) diff --git a/config.py b/config.py index de81bdfe6..d09cbc87f 100644 --- a/config.py +++ b/config.py @@ -2,6 +2,13 @@ import logging import sys from peewee import MySQLDatabase, SqliteDatabase +from storage.s3 import S3Storage +from storage.local import LocalStorage +from data.userfiles import UserRequestFiles +from util import analytics + +from test.teststorage import FakeStorage, FakeUserfiles +from test import analytics as fake_analytics LOG_FORMAT = '%(asctime)-15s - %(levelname)s - %(pathname)s - ' + \ @@ -31,6 +38,12 @@ class SQLiteDB(object): DB_DRIVER = SqliteDatabase +class EphemeralDB(object): + DB_NAME = ':memory:' + DB_CONNECTION_ARGS = {} + DB_DRIVER = SqliteDatabase + + class RDSMySQL(object): DB_NAME = 'quay' DB_CONNECTION_ARGS = { @@ -49,12 +62,27 @@ class AWSCredentials(object): class S3Storage(AWSCredentials): - STORAGE_KIND = 's3' + STORAGE = S3Storage('', AWSCredentials.AWS_ACCESS_KEY, + AWSCredentials.AWS_SECRET_KEY, + AWSCredentials.REGISTRY_S3_BUCKET) class LocalStorage(object): - STORAGE_KIND = 'local' - LOCAL_STORAGE_DIR = 'test/data/registry' + STORAGE = LocalStorage('test/data/registry') + + +class FakeStorage(object): + STORAGE = FakeStorage() + + +class FakeUserfiles(object): + USERFILES = FakeUserfiles() + + +class S3Userfiles(AWSCredentials): + USERFILES = UserRequestFiles(AWSCredentials.AWS_ACCESS_KEY, + AWSCredentials.AWS_SECRET_KEY, + AWSCredentials.REGISTRY_S3_BUCKET) class StripeTestConfig(object): @@ -67,11 +95,16 @@ class StripeLiveConfig(object): STRIPE_PUBLISHABLE_KEY = 'pk_live_P5wLU0vGdHnZGyKnXlFG4oiu' +class FakeAnalytics(object): + ANALYTICS = fake_analytics + + class MixpanelTestConfig(object): + ANALYTICS = analytics MIXPANEL_KEY = '38014a0f27e7bdc3ff8cc7cc29c869f9' -class MixpanelProdConfig(object): +class MixpanelProdConfig(MixpanelTestConfig): MIXPANEL_KEY = '50ff2b2569faa3a51c8f5724922ffb7e' @@ -100,9 +133,18 @@ class BuildNodeConfig(object): BUILD_NODE_PULL_TOKEN = 'F02O2E86CQLKZUQ0O81J8XDHQ6F0N1V36L9JTOEEK6GKKMT1GI8PTJQT4OU88Y6G' +class TestConfig(FlaskConfig, FakeStorage, EphemeralDB, FakeUserfiles, + FakeAnalytics): + LOGGING_CONFIG = { + 'level': logging.DEBUG, + 'format': LOG_FORMAT + } + POPULATE_DB_TEST_DATA = True + + class DebugConfig(FlaskConfig, MailConfig, LocalStorage, SQLiteDB, StripeTestConfig, MixpanelTestConfig, GitHubTestConfig, - DigitalOceanConfig, AWSCredentials, BuildNodeConfig): + DigitalOceanConfig, BuildNodeConfig, S3Userfiles): LOGGING_CONFIG = { 'level': logging.DEBUG, 'format': LOG_FORMAT @@ -115,7 +157,7 @@ class DebugConfig(FlaskConfig, MailConfig, LocalStorage, SQLiteDB, class LocalHostedConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL, StripeLiveConfig, MixpanelTestConfig, GitHubProdConfig, DigitalOceanConfig, - BuildNodeConfig): + BuildNodeConfig, S3Userfiles): LOGGING_CONFIG = { 'level': logging.DEBUG, 'format': LOG_FORMAT @@ -125,7 +167,8 @@ class LocalHostedConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL, class ProductionConfig(FlaskConfig, MailConfig, S3Storage, RDSMySQL, StripeLiveConfig, MixpanelProdConfig, - GitHubProdConfig, DigitalOceanConfig, BuildNodeConfig): + GitHubProdConfig, DigitalOceanConfig, BuildNodeConfig, + S3Userfiles): LOGGING_CONFIG = { 'stream': sys.stderr, 'level': logging.DEBUG, diff --git a/endpoints/api.py b/endpoints/api.py index 36a32053f..6fdf887b1 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -11,10 +11,7 @@ from flask.ext.principal import identity_changed, AnonymousIdentity from functools import wraps from collections import defaultdict -import storage - from data import model -from data.userfiles import UserRequestFiles from data.queue import dockerfile_build_queue from data.plans import USER_PLANS, BUSINESS_PLANS, get_plan from app import app @@ -33,7 +30,8 @@ from endpoints.web import common_login from util.cache import cache_control -store = storage.load() +store = app.config['STORAGE'] +user_files = app.config['USERFILES'] logger = logging.getLogger(__name__) @@ -263,11 +261,6 @@ def get_matching_entities(prefix): }) -user_files = UserRequestFiles(app.config['AWS_ACCESS_KEY'], - app.config['AWS_SECRET_KEY'], - app.config['REGISTRY_S3_BUCKET']) - - def team_view(orgname, t): view_permission = ViewTeamPermission(orgname, t.name) role = model.get_team_org_role(t).name @@ -454,6 +447,7 @@ def delete_organization_team_member(orgname, teamname, membername): @app.route('/api/repository', methods=['POST']) @api_login_required +@required_json_args('repository', 'visibility', 'description') def create_repo_api(): owner = current_user.db_user() json = request.get_json() @@ -468,7 +462,7 @@ def create_repo_api(): if existing: return make_response('Repository already exists', 400) - visibility = request.get_json()['visibility'] + visibility = json['visibility'] repo = model.create_repository(namespace_name, repository_name, owner, visibility) @@ -563,7 +557,7 @@ def update_repo_api(namespace, repository): 'success': True }) - abort(404) + abort(403) @app.route('/api/repository//changevisibility', @@ -1107,6 +1101,7 @@ def subscription_view(stripe_subscription, used_repos): @app.route('/api/user/plan', methods=['PUT']) @api_login_required +@required_json_args('token', 'plan') def subscribe_api(): request_data = request.get_json() plan = request_data['plan'] diff --git a/endpoints/registry.py b/endpoints/registry.py index b736dc95e..5d71a1f81 100644 --- a/endpoints/registry.py +++ b/endpoints/registry.py @@ -6,7 +6,6 @@ from functools import wraps from datetime import datetime from time import time -import storage from data.queue import image_diff_queue from app import app @@ -17,7 +16,7 @@ from auth.permissions import (ReadRepositoryPermission, from data import model -store = storage.load() +store = app.config['STORAGE'] logger = logging.getLogger(__name__) diff --git a/endpoints/tags.py b/endpoints/tags.py index 2607bbde2..c9b2af2ae 100644 --- a/endpoints/tags.py +++ b/endpoints/tags.py @@ -4,8 +4,6 @@ import json from flask import abort, request, jsonify, make_response -import storage - from app import app from util.names import parse_repository_name from auth.auth import process_auth @@ -14,7 +12,6 @@ from auth.permissions import (ReadRepositoryPermission, from data import model -store = storage.load() logger = logging.getLogger(__name__) diff --git a/initdb.py b/initdb.py index d80852f25..db73945b4 100644 --- a/initdb.py +++ b/initdb.py @@ -8,15 +8,13 @@ from datetime import datetime, timedelta from flask import url_for from peewee import SqliteDatabase, create_model_tables, drop_model_tables -import storage - from data.database import * from data import model from app import app logger = logging.getLogger(__name__) -store = storage.load() +store = app.config['STORAGE'] SAMPLE_DIFFS = ['test/data/sample/diffs/diffs%s.json' % i for i in range(1, 10)] @@ -141,6 +139,10 @@ def populate_database(): new_user_3.verified = True new_user_3.save() + reader = model.create_user('reader', 'password', 'no1@thanks.com') + reader.verified = True + reader.save() + __generate_repository(new_user_1, 'simple', 'Simple repository.', False, [], (4, [], ['latest', 'prod'])) @@ -168,7 +170,8 @@ def populate_database(): __generate_repository(new_user_1, 'shared', 'Shared repository, another user can write.', False, - [(new_user_2, 'write')], (5, [], 'latest')) + [(new_user_2, 'write'), (reader, 'read')], + (5, [], 'latest')) building = __generate_repository(new_user_1, 'building', 'Empty repository which is building.', @@ -186,6 +189,7 @@ def populate_database(): model.set_team_repo_permission(reader_team.name, org_repo.namespace, org_repo.name, 'read') model.add_user_to_team(new_user_2, reader_team) + model.add_user_to_team(reader, reader_team) token = model.create_access_token(building, 'write') tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name) @@ -197,6 +201,7 @@ def populate_database(): build.save() +logging.basicConfig(level=logging.WARNING) if __name__ == '__main__': logging.basicConfig(**app.config['LOGGING_CONFIG']) initialize_database() diff --git a/storage/__init__.py b/storage/__init__.py index de86f4be4..e69de29bb 100644 --- a/storage/__init__.py +++ b/storage/__init__.py @@ -1,147 +0,0 @@ -import logging - -import contextlib -import tempfile - -from app import app - - -__all__ = ['load'] -logger = logging.getLogger(__name__) - - -class Storage(object): - - """Storage is organized as follow: - $ROOT/images//json - $ROOT/images//layer - $ROOT/repositories/// - """ - - # Useful if we want to change those locations later without rewriting - # the code which uses Storage - repositories = 'repositories' - images = 'images' - # Set the IO buffer to 64kB - buffer_size = 64 * 1024 - - #FIXME(samalba): Move all path resolver in each module (out of the base) - def images_list_path(self, namespace, repository): - return '{0}/{1}/{2}/_images_list'.format(self.repositories, - namespace, - repository) - - def image_json_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/json'.format(self.images, namespace, - repository, image_id) - - def image_mark_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/_inprogress'.format(self.images, namespace, - repository, image_id) - - def image_checksum_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/_checksum'.format(self.images, namespace, - repository, image_id) - - def image_layer_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/layer'.format(self.images, namespace, - repository, image_id) - - def image_ancestry_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/ancestry'.format(self.images, namespace, - repository, image_id) - - def repository_namespace_path(self, namespace, repository): - return '{0}/{1}/{2}/'.format(self.images, namespace, repository) - - def image_file_trie_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/files.trie'.format(self.images, namespace, - repository, image_id) - - def image_file_diffs_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/diffs.json'.format(self.images, namespace, - repository, image_id) - - def get_content(self, path): - raise NotImplementedError - - def put_content(self, path, content): - raise NotImplementedError - - def stream_read(self, path): - raise NotImplementedError - - def stream_read_file(self, path): - raise NotImplementedError - - def stream_write(self, path, fp): - raise NotImplementedError - - def list_directory(self, path=None): - raise NotImplementedError - - def exists(self, path): - raise NotImplementedError - - def remove(self, path): - raise NotImplementedError - - def get_size(self, path): - raise NotImplementedError - - -@contextlib.contextmanager -def store_stream(stream): - """Stores the entire stream to a temporary file.""" - tmpf = tempfile.TemporaryFile() - while True: - try: - buf = stream.read(4096) - if not buf: - break - tmpf.write(buf) - except IOError: - break - tmpf.seek(0) - yield tmpf - tmpf.close() - - -def temp_store_handler(): - tmpf = tempfile.TemporaryFile() - - def fn(buf): - try: - tmpf.write(buf) - except IOError: - pass - - return tmpf, fn - - -from local import LocalStorage -from s3 import S3Storage - - -_storage = {} - - -def load(kind=None): - """Returns the right storage class according to the configuration.""" - global _storage - - kind = app.config['STORAGE_KIND'] - if kind in _storage: - return _storage[kind] - if kind == 's3': - logger.debug('Using s3 storage.') - store = S3Storage('', app.config['AWS_ACCESS_KEY'], - app.config['AWS_SECRET_KEY'], - app.config['REGISTRY_S3_BUCKET']) - elif kind == 'local': - logger.debug('Using local storage.') - store = LocalStorage(app.config['LOCAL_STORAGE_DIR']) - else: - raise ValueError('Not supported storage \'{0}\''.format(kind)) - _storage[kind] = store - return store diff --git a/storage/basestorage.py b/storage/basestorage.py new file mode 100644 index 000000000..283fde227 --- /dev/null +++ b/storage/basestorage.py @@ -0,0 +1,78 @@ +class Storage(object): + + """Storage is organized as follow: + $ROOT/images//json + $ROOT/images//layer + $ROOT/repositories/// + """ + + # Useful if we want to change those locations later without rewriting + # the code which uses Storage + repositories = 'repositories' + images = 'images' + # Set the IO buffer to 64kB + buffer_size = 64 * 1024 + + #FIXME(samalba): Move all path resolver in each module (out of the base) + def images_list_path(self, namespace, repository): + return '{0}/{1}/{2}/_images_list'.format(self.repositories, + namespace, + repository) + + def image_json_path(self, namespace, repository, image_id): + return '{0}/{1}/{2}/{3}/json'.format(self.images, namespace, + repository, image_id) + + def image_mark_path(self, namespace, repository, image_id): + return '{0}/{1}/{2}/{3}/_inprogress'.format(self.images, namespace, + repository, image_id) + + def image_checksum_path(self, namespace, repository, image_id): + return '{0}/{1}/{2}/{3}/_checksum'.format(self.images, namespace, + repository, image_id) + + def image_layer_path(self, namespace, repository, image_id): + return '{0}/{1}/{2}/{3}/layer'.format(self.images, namespace, + repository, image_id) + + def image_ancestry_path(self, namespace, repository, image_id): + return '{0}/{1}/{2}/{3}/ancestry'.format(self.images, namespace, + repository, image_id) + + def repository_namespace_path(self, namespace, repository): + return '{0}/{1}/{2}/'.format(self.images, namespace, repository) + + def image_file_trie_path(self, namespace, repository, image_id): + return '{0}/{1}/{2}/{3}/files.trie'.format(self.images, namespace, + repository, image_id) + + def image_file_diffs_path(self, namespace, repository, image_id): + return '{0}/{1}/{2}/{3}/diffs.json'.format(self.images, namespace, + repository, image_id) + + def get_content(self, path): + raise NotImplementedError + + def put_content(self, path, content): + raise NotImplementedError + + def stream_read(self, path): + raise NotImplementedError + + def stream_read_file(self, path): + raise NotImplementedError + + def stream_write(self, path, fp): + raise NotImplementedError + + def list_directory(self, path=None): + raise NotImplementedError + + def exists(self, path): + raise NotImplementedError + + def remove(self, path): + raise NotImplementedError + + def get_size(self, path): + raise NotImplementedError diff --git a/storage/local.py b/storage/local.py index 93b2103ca..84bc29260 100644 --- a/storage/local.py +++ b/storage/local.py @@ -2,7 +2,7 @@ import os import shutil -from . import Storage +from basestorage import Storage class LocalStorage(Storage): diff --git a/storage/s3.py b/storage/s3.py index cac2fc227..10e7bb50d 100644 --- a/storage/s3.py +++ b/storage/s3.py @@ -5,7 +5,7 @@ import logging import boto.s3.connection import boto.s3.key -from . import Storage +from basestorage import Storage logger = logging.getLogger(__name__) diff --git a/test/analytics.py b/test/analytics.py new file mode 100644 index 000000000..f181a8ad0 --- /dev/null +++ b/test/analytics.py @@ -0,0 +1,6 @@ +class FakeMixpanel(object): + def send(self, endpoint, json_message): + pass + +def init_app(app): + return FakeMixpanel() diff --git a/test/specs.py b/test/specs.py index c0d10938b..be860f126 100644 --- a/test/specs.py +++ b/test/specs.py @@ -7,25 +7,36 @@ from uuid import uuid4 PUBLIC_REPO = 'public/publicrepo' -PRIVATE_REPO = 'devtable/complex' +PRIVATE_REPO = 'devtable/shared' ORG = 'devtableorg' ORG_REPO = ORG + '/orgrepo' -ORG_OWNERS = 'owners' ORG_READERS = 'readers' ORG_OWNER = 'devtable' +ORG_OWNERS = 'owners' +ORG_READERS = 'readers' -FAKE_IMAGE_ID = uuid4() -FAKE_TAG_NAME = uuid4() -FAKE_USERNAME = uuid4() -FAKE_TEAMNAME = uuid4() -FAKE_TOKEN = uuid4() +FAKE_IMAGE_ID = str(uuid4()) +FAKE_TAG_NAME = str(uuid4()) +FAKE_USERNAME = str(uuid4()) +FAKE_TOKEN = str(uuid4()) + +NEW_ORG_REPO_DETAILS = { + 'repository': str(uuid4()), + 'visibility': 'private', + 'description': '', + 'namespace': ORG, +} + +class hashabledict(dict): + def __hash__(self): + return hash(tuple(sorted(self.items()))) def open_kwargs(method='GET', json_object=None): - kwargs = { - 'method': method, - } + kwargs = hashabledict([ + ('method', method), + ]) if json_object is not None: kwargs['data'] = json.dumps(json_object) @@ -43,387 +54,488 @@ def open_kwargs(method='GET', json_object=None): def build_anon_spec(): return OrderedDict([ - (url_for('welcome'), (200, open_kwargs())), + ((url_for('welcome'), open_kwargs()), 200), - (url_for('plans_list'), (200, open_kwargs())), + ((url_for('plans_list'), open_kwargs()), 200), - (url_for('get_logged_in_user'), (200, open_kwargs())), + ((url_for('get_logged_in_user'), open_kwargs()), 200), - (url_for('change_user_details'), (401, open_kwargs('PUT'))), + ((url_for('change_user_details'), open_kwargs('PUT')), 401), - (url_for('create_user_api'), (400, open_kwargs('POST'))), + ((url_for('create_user_api'), open_kwargs('POST')), 400), - (url_for('signin_api'), (400, open_kwargs('POST'))), + ((url_for('signin_api'), open_kwargs('POST')), 400), - (url_for('send_recovery'), (400, open_kwargs('POST'))), + ((url_for('send_recovery'), open_kwargs('POST')), 400), - (url_for('get_matching_users', prefix='dev'), (401, open_kwargs())), + ((url_for('get_matching_users', prefix='dev'), open_kwargs()), 401), - (url_for('get_matching_entities', prefix='dev'), (401, open_kwargs())), + ((url_for('get_matching_entities', prefix='dev'), open_kwargs()), 401), - (url_for('get_organization', orgname=ORG), (401, open_kwargs())), + ((url_for('get_organization', orgname=ORG), open_kwargs()), 401), - (url_for('get_organization_private_allowed', orgname=ORG), - (401, open_kwargs())), + ((url_for('get_organization_private_allowed', orgname=ORG), + open_kwargs()), 401), - (url_for('update_organization_team', orgname=ORG, teamname=ORG_OWNERS), - (401, open_kwargs('PUT'))), + ((url_for('update_organization_team', orgname=ORG, teamname=ORG_OWNERS), + open_kwargs('PUT')), 401), + ((url_for('update_organization_team', orgname=ORG, teamname=ORG_READERS), + open_kwargs('PUT')), 401), - (url_for('delete_organization_team', orgname=ORG, teamname=ORG_OWNERS), - (401, open_kwargs('DELETE'))), + ((url_for('delete_organization_team', orgname=ORG, teamname=ORG_OWNERS), + open_kwargs('DELETE')), 401), + ((url_for('delete_organization_team', orgname=ORG, teamname=ORG_READERS), + open_kwargs('DELETE')), 401), - (url_for('get_organization_team_members', orgname=ORG, - teamname=ORG_OWNERS), (401, open_kwargs())), + ((url_for('get_organization_team_members', orgname=ORG, + teamname=ORG_OWNERS), open_kwargs()), 401), + ((url_for('get_organization_team_members', orgname=ORG, + teamname=ORG_READERS), open_kwargs()), 401), - (url_for('update_organization_team_member', orgname=ORG, - teamname=ORG_OWNERS, membername=ORG_OWNER), - (401, open_kwargs('PUT'))), + ((url_for('update_organization_team_member', orgname=ORG, + teamname=ORG_OWNERS, membername=ORG_OWNER), + open_kwargs('PUT')), 401), + ((url_for('update_organization_team_member', orgname=ORG, + teamname=ORG_READERS, membername=ORG_OWNER), + open_kwargs('PUT')), 401), - (url_for('delete_organization_team_member', orgname=ORG, - teamname=ORG_OWNERS, membername=ORG_OWNER), - (401, open_kwargs('DELETE'))), + ((url_for('delete_organization_team_member', orgname=ORG, + teamname=ORG_OWNERS, membername=ORG_OWNER), + open_kwargs('DELETE')), 401), + ((url_for('delete_organization_team_member', orgname=ORG, + teamname=ORG_READERS, membername=ORG_OWNER), + open_kwargs('DELETE')), 401), - (url_for('create_repo_api'), (401, open_kwargs('POST'))), + ((url_for('create_repo_api'), open_kwargs('POST', NEW_ORG_REPO_DETAILS)), + 401), - (url_for('match_repos_api'), (200, open_kwargs())), + ((url_for('match_repos_api'), open_kwargs()), 200), - (url_for('list_repos_api'), (200, open_kwargs())), + ((url_for('list_repos_api'), open_kwargs()), 200), - (url_for('update_repo_api', repository=PUBLIC_REPO), - (401, open_kwargs('PUT'))), - (url_for('update_repo_api', repository=ORG_REPO), - (401, open_kwargs('PUT'))), - (url_for('update_repo_api', repository=PRIVATE_REPO), - (401, open_kwargs('PUT'))), + ((url_for('update_repo_api', repository=PUBLIC_REPO), open_kwargs('PUT')), + 401), + ((url_for('update_repo_api', repository=ORG_REPO), open_kwargs('PUT')), + 401), + ((url_for('update_repo_api', repository=PRIVATE_REPO), + open_kwargs('PUT')), 401), - (url_for('change_repo_visibility_api', repository=PUBLIC_REPO), - (401, open_kwargs('POST'))), - (url_for('change_repo_visibility_api', repository=ORG_REPO), - (401, open_kwargs('POST'))), - (url_for('change_repo_visibility_api', repository=PRIVATE_REPO), - (401, open_kwargs('POST'))), + ((url_for('change_repo_visibility_api', repository=PUBLIC_REPO), + open_kwargs('POST')), 401), + ((url_for('change_repo_visibility_api', repository=ORG_REPO), + open_kwargs('POST')), 401), + ((url_for('change_repo_visibility_api', repository=PRIVATE_REPO), + open_kwargs('POST')), 401), - (url_for('delete_repository', repository=PUBLIC_REPO), - (401, open_kwargs('DELETE'))), - (url_for('delete_repository', repository=ORG_REPO), - (401, open_kwargs('DELETE'))), - (url_for('delete_repository', repository=PRIVATE_REPO), - (401, open_kwargs('DELETE'))), + ((url_for('delete_repository', repository=PUBLIC_REPO), + open_kwargs('DELETE')), 401), + ((url_for('delete_repository', repository=ORG_REPO), + open_kwargs('DELETE')), 401), + ((url_for('delete_repository', repository=PRIVATE_REPO), + open_kwargs('DELETE')), 401), - (url_for('get_repo_api', repository=PUBLIC_REPO),(200, open_kwargs())), - (url_for('get_repo_api', repository=ORG_REPO), (403, open_kwargs())), - (url_for('get_repo_api', repository=PRIVATE_REPO), (403, open_kwargs())), + ((url_for('get_repo_api', repository=PUBLIC_REPO), open_kwargs()), 200), + ((url_for('get_repo_api', repository=ORG_REPO), open_kwargs()), 403), + ((url_for('get_repo_api', repository=PRIVATE_REPO), open_kwargs()), 403), - (url_for('get_repo_builds', repository=PUBLIC_REPO), - (401, open_kwargs())), - (url_for('get_repo_builds', repository=ORG_REPO), (401, open_kwargs())), - (url_for('get_repo_builds', repository=PRIVATE_REPO), - (401, open_kwargs())), + ((url_for('get_repo_builds', repository=PUBLIC_REPO), open_kwargs()), + 401), + ((url_for('get_repo_builds', repository=ORG_REPO), open_kwargs()), 401), + ((url_for('get_repo_builds', repository=PRIVATE_REPO), open_kwargs()), + 401), - (url_for('get_filedrop_url'), (401, open_kwargs('POST'))), + ((url_for('get_filedrop_url'), open_kwargs('POST')), 401), - (url_for('request_repo_build', repository=PUBLIC_REPO), - (401, open_kwargs('POST'))), - (url_for('request_repo_build', repository=ORG_REPO), - (401, open_kwargs('POST'))), - (url_for('request_repo_build', repository=PRIVATE_REPO), - (401, open_kwargs('POST'))), + ((url_for('request_repo_build', repository=PUBLIC_REPO), + open_kwargs('POST')), 401), + ((url_for('request_repo_build', repository=ORG_REPO), + open_kwargs('POST')), 401), + ((url_for('request_repo_build', repository=PRIVATE_REPO), + open_kwargs('POST')), 401), - (url_for('list_repository_images', repository=PUBLIC_REPO), - (200, open_kwargs())), - (url_for('list_repository_images', repository=ORG_REPO), - (403, open_kwargs())), - (url_for('list_repository_images', repository=PRIVATE_REPO), - (403, open_kwargs())), + ((url_for('list_repository_images', repository=PUBLIC_REPO), + open_kwargs()), 200), + ((url_for('list_repository_images', repository=ORG_REPO), + open_kwargs()), 403), + ((url_for('list_repository_images', repository=PRIVATE_REPO), + open_kwargs()), 403), - (url_for('get_image', repository=PUBLIC_REPO, image_id=FAKE_IMAGE_ID), - (404, open_kwargs())), - (url_for('get_image', repository=ORG_REPO, image_id=FAKE_IMAGE_ID), - (403, open_kwargs())), - (url_for('get_image', repository=PRIVATE_REPO, image_id=FAKE_IMAGE_ID), - (403, open_kwargs())), + ((url_for('get_image', repository=PUBLIC_REPO, image_id=FAKE_IMAGE_ID), + open_kwargs()), 404), + ((url_for('get_image', repository=ORG_REPO, image_id=FAKE_IMAGE_ID), + open_kwargs()), 403), + ((url_for('get_image', repository=PRIVATE_REPO, image_id=FAKE_IMAGE_ID), + open_kwargs()), 403), - (url_for('get_image_changes', repository=PUBLIC_REPO, - image_id=FAKE_IMAGE_ID), (404, open_kwargs())), - (url_for('get_image_changes', repository=ORG_REPO, - image_id=FAKE_IMAGE_ID), (403, open_kwargs())), - (url_for('get_image_changes', repository=PRIVATE_REPO, - image_id=FAKE_IMAGE_ID), (403, open_kwargs())), + ((url_for('get_image_changes', repository=PUBLIC_REPO, + image_id=FAKE_IMAGE_ID), open_kwargs()), 404), + ((url_for('get_image_changes', repository=ORG_REPO, + image_id=FAKE_IMAGE_ID), open_kwargs()), 403), + ((url_for('get_image_changes', repository=PRIVATE_REPO, + image_id=FAKE_IMAGE_ID), open_kwargs()), 403), - (url_for('list_tag_images', repository=PUBLIC_REPO, tag=FAKE_TAG_NAME), - (404, open_kwargs())), - (url_for('list_tag_images', repository=ORG_REPO, tag=FAKE_TAG_NAME), - (403, open_kwargs())), - (url_for('list_tag_images', repository=PRIVATE_REPO, tag=FAKE_TAG_NAME), - (403, open_kwargs())), + ((url_for('list_tag_images', repository=PUBLIC_REPO, tag=FAKE_TAG_NAME), + open_kwargs()), 404), + ((url_for('list_tag_images', repository=ORG_REPO, tag=FAKE_TAG_NAME), + open_kwargs()), 403), + ((url_for('list_tag_images', repository=PRIVATE_REPO, tag=FAKE_TAG_NAME), + open_kwargs()), 403), + + ((url_for('list_repo_team_permissions', repository=PUBLIC_REPO), + open_kwargs()), 401), + ((url_for('list_repo_team_permissions', repository=ORG_REPO), + open_kwargs()), 401), + ((url_for('list_repo_team_permissions', repository=PRIVATE_REPO), + open_kwargs()), 401), - (url_for('list_repo_team_permissions', repository=PUBLIC_REPO), - (401, open_kwargs())), - (url_for('list_repo_team_permissions', repository=ORG_REPO), - (401, open_kwargs())), - (url_for('list_repo_team_permissions', repository=PRIVATE_REPO), - (401, open_kwargs())), + ((url_for('list_repo_user_permissions', repository=PUBLIC_REPO), + open_kwargs()), 401), + ((url_for('list_repo_user_permissions', repository=ORG_REPO), + open_kwargs()), 401), + ((url_for('list_repo_user_permissions', repository=PRIVATE_REPO), + open_kwargs()), 401), - (url_for('list_repo_user_permissions', repository=PUBLIC_REPO), - (401, open_kwargs())), - (url_for('list_repo_user_permissions', repository=ORG_REPO), - (401, open_kwargs())), - (url_for('list_repo_user_permissions', repository=PRIVATE_REPO), - (401, open_kwargs())), + ((url_for('get_user_permissions', repository=PUBLIC_REPO, + username=FAKE_USERNAME), open_kwargs()), 401), + ((url_for('get_user_permissions', repository=ORG_REPO, + username=FAKE_USERNAME), open_kwargs()), 401), + ((url_for('get_user_permissions', repository=PRIVATE_REPO, + username=FAKE_USERNAME), open_kwargs()), 401), - (url_for('get_user_permissions', repository=PUBLIC_REPO, - username=FAKE_USERNAME), (401, open_kwargs())), - (url_for('get_user_permissions', repository=ORG_REPO, - username=FAKE_USERNAME), (401, open_kwargs())), - (url_for('get_user_permissions', repository=PRIVATE_REPO, - username=FAKE_USERNAME), (401, open_kwargs())), + ((url_for('get_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_OWNERS), open_kwargs()), 401), + ((url_for('get_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_READERS), open_kwargs()), 401), + ((url_for('get_team_permissions', repository=ORG_REPO, + teamname=ORG_OWNERS), open_kwargs()), 401), + ((url_for('get_team_permissions', repository=ORG_REPO, + teamname=ORG_READERS), open_kwargs()), 401), + ((url_for('get_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_OWNERS), open_kwargs()), 401), + ((url_for('get_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_READERS), open_kwargs()), 401), - (url_for('get_team_permissions', repository=PUBLIC_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs())), - (url_for('get_team_permissions', repository=ORG_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs())), - (url_for('get_team_permissions', repository=PRIVATE_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs())), + ((url_for('change_user_permissions', repository=PUBLIC_REPO, + username=FAKE_USERNAME), open_kwargs('PUT')), 401), + ((url_for('change_user_permissions', repository=ORG_REPO, + username=FAKE_USERNAME), open_kwargs('PUT')), 401), + ((url_for('change_user_permissions', repository=PRIVATE_REPO, + username=FAKE_USERNAME), open_kwargs('PUT')), 401), - (url_for('change_user_permissions', repository=PUBLIC_REPO, - username=FAKE_USERNAME), (401, open_kwargs('PUT'))), - (url_for('change_user_permissions', repository=ORG_REPO, - username=FAKE_USERNAME), (401, open_kwargs('PUT'))), - (url_for('change_user_permissions', repository=PRIVATE_REPO, - username=FAKE_USERNAME), (401, open_kwargs('PUT'))), + ((url_for('change_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_OWNERS), open_kwargs('PUT')), 401), + ((url_for('change_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_READERS), open_kwargs('PUT')), 401), + ((url_for('change_team_permissions', repository=ORG_REPO, + teamname=ORG_OWNERS), open_kwargs('PUT')), 401), + ((url_for('change_team_permissions', repository=ORG_REPO, + teamname=ORG_READERS), open_kwargs('PUT')), 401), + ((url_for('change_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_OWNERS), open_kwargs('PUT')), 401), + ((url_for('change_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_READERS), open_kwargs('PUT')), 401), - (url_for('change_team_permissions', repository=PUBLIC_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs('PUT'))), - (url_for('change_team_permissions', repository=ORG_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs('PUT'))), - (url_for('change_team_permissions', repository=PRIVATE_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs('PUT'))), + ((url_for('delete_user_permissions', repository=PUBLIC_REPO, + username=FAKE_USERNAME), open_kwargs('DELETE')), 401), + ((url_for('delete_user_permissions', repository=ORG_REPO, + username=FAKE_USERNAME), open_kwargs('DELETE')), 401), + ((url_for('delete_user_permissions', repository=PRIVATE_REPO, + username=FAKE_USERNAME), open_kwargs('DELETE')), 401), - (url_for('delete_user_permissions', repository=PUBLIC_REPO, - username=FAKE_USERNAME), (401, open_kwargs('DELETE'))), - (url_for('delete_user_permissions', repository=ORG_REPO, - username=FAKE_USERNAME), (401, open_kwargs('DELETE'))), - (url_for('delete_user_permissions', repository=PRIVATE_REPO, - username=FAKE_USERNAME), (401, open_kwargs('DELETE'))), + ((url_for('delete_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_OWNERS), open_kwargs('DELETE')), 401), + ((url_for('delete_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_READERS), open_kwargs('DELETE')), 401), + ((url_for('delete_team_permissions', repository=ORG_REPO, + teamname=ORG_OWNERS), open_kwargs('DELETE')), 401), + ((url_for('delete_team_permissions', repository=ORG_REPO, + teamname=ORG_READERS), open_kwargs('DELETE')), 401), + ((url_for('delete_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_OWNERS), open_kwargs('DELETE')), 401), + ((url_for('delete_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_READERS), open_kwargs('DELETE')), 401), - (url_for('delete_team_permissions', repository=PUBLIC_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs('DELETE'))), - (url_for('delete_team_permissions', repository=ORG_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs('DELETE'))), - (url_for('delete_team_permissions', repository=PRIVATE_REPO, - teamname=FAKE_TEAMNAME), (401, open_kwargs('DELETE'))), + ((url_for('list_repo_tokens', repository=PUBLIC_REPO), open_kwargs()), + 401), + ((url_for('list_repo_tokens', repository=ORG_REPO), open_kwargs()), 401), + ((url_for('list_repo_tokens', repository=PRIVATE_REPO), open_kwargs()), + 401), - (url_for('list_repo_tokens', repository=PUBLIC_REPO), - (401, open_kwargs())), - (url_for('list_repo_tokens', repository=ORG_REPO), (401, open_kwargs())), - (url_for('list_repo_tokens', repository=PRIVATE_REPO), - (401, open_kwargs())), + ((url_for('get_tokens', repository=PUBLIC_REPO, code=FAKE_TOKEN), + open_kwargs()), 401), + ((url_for('get_tokens', repository=ORG_REPO, code=FAKE_TOKEN), + open_kwargs()), 401), + ((url_for('get_tokens', repository=PRIVATE_REPO, code=FAKE_TOKEN), + open_kwargs()), 401), - (url_for('get_tokens', repository=PUBLIC_REPO, code=FAKE_TOKEN), - (401, open_kwargs())), - (url_for('get_tokens', repository=ORG_REPO, code=FAKE_TOKEN), - (401, open_kwargs())), - (url_for('get_tokens', repository=PRIVATE_REPO, code=FAKE_TOKEN), - (401, open_kwargs())), + ((url_for('create_token', repository=PUBLIC_REPO), open_kwargs('POST')), + 401), + ((url_for('create_token', repository=ORG_REPO), open_kwargs('POST')), + 401), + ((url_for('create_token', repository=PRIVATE_REPO), open_kwargs('POST')), + 401), - (url_for('create_token', repository=PUBLIC_REPO), - (401, open_kwargs('POST'))), - (url_for('create_token', repository=ORG_REPO), - (401, open_kwargs('POST'))), - (url_for('create_token', repository=PRIVATE_REPO), - (401, open_kwargs('POST'))), + ((url_for('change_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), + open_kwargs('PUT')), 401), + ((url_for('change_token', repository=ORG_REPO, code=FAKE_TOKEN), + open_kwargs('PUT')), 401), + ((url_for('change_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), + open_kwargs('PUT')), 401), - (url_for('change_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), - (401, open_kwargs('PUT'))), - (url_for('change_token', repository=ORG_REPO, code=FAKE_TOKEN), - (401, open_kwargs('PUT'))), - (url_for('change_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), - (401, open_kwargs('PUT'))), + ((url_for('delete_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), + open_kwargs('DELETE')), 401), + ((url_for('delete_token', repository=ORG_REPO, code=FAKE_TOKEN), + open_kwargs('DELETE')), 401), + ((url_for('delete_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), + open_kwargs('DELETE')), 401), - (url_for('delete_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), - (401, open_kwargs('DELETE'))), - (url_for('delete_token', repository=ORG_REPO, code=FAKE_TOKEN), - (401, open_kwargs('DELETE'))), - (url_for('delete_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), - (401, open_kwargs('DELETE'))), + ((url_for('subscribe_api'), open_kwargs('PUT')), 401), - (url_for('subscribe_api'), (401, open_kwargs('PUT'))), + ((url_for('subscribe_org_api', orgname=ORG), open_kwargs('PUT')), 401), - (url_for('subscribe_org_api', orgname=ORG), (401, open_kwargs('PUT'))), + ((url_for('get_subscription'), open_kwargs()), 401), - (url_for('get_subscription'), (401, open_kwargs())), - - (url_for('get_org_subscription', orgname=ORG), (401, open_kwargs())), + ((url_for('get_org_subscription', orgname=ORG), open_kwargs()), 401), ]) def build_no_access_spec(): changes = OrderedDict([ - (url_for('change_user_details'), (200, open_kwargs('PUT'))), + ((url_for('change_user_details'), open_kwargs('PUT')), 200), - (url_for('get_matching_users', prefix='dev'), (200, open_kwargs())), + ((url_for('get_matching_users', prefix='dev'), open_kwargs()), 200), - (url_for('get_matching_entities', prefix='dev'), (200, open_kwargs())), + ((url_for('get_matching_entities', prefix='dev'), open_kwargs()), 200), - (url_for('get_organization', orgname=ORG), (403, open_kwargs())), + ((url_for('get_organization', orgname=ORG), open_kwargs()), 403), - (url_for('get_organization_private_allowed', orgname=ORG), - (403, open_kwargs())), + ((url_for('get_organization_private_allowed', orgname=ORG), + open_kwargs()), 403), - (url_for('update_organization_team', orgname=ORG, teamname=ORG_OWNERS), - (403, open_kwargs('PUT'))), + ((url_for('update_organization_team', orgname=ORG, teamname=ORG_OWNERS), + open_kwargs('PUT')), 403), + ((url_for('update_organization_team', orgname=ORG, teamname=ORG_READERS), + open_kwargs('PUT')), 403), - (url_for('delete_organization_team', orgname=ORG, teamname=ORG_OWNERS), - (403, open_kwargs('DELETE'))), + ((url_for('delete_organization_team', orgname=ORG, teamname=ORG_OWNERS), + open_kwargs('DELETE')), 403), + ((url_for('delete_organization_team', orgname=ORG, teamname=ORG_READERS), + open_kwargs('DELETE')), 403), - (url_for('get_organization_team_members', orgname=ORG, - teamname=ORG_OWNERS), (403, open_kwargs())), + ((url_for('get_organization_team_members', orgname=ORG, + teamname=ORG_OWNERS), open_kwargs()), 403), + ((url_for('get_organization_team_members', orgname=ORG, + teamname=ORG_READERS), open_kwargs()), 403), - (url_for('update_organization_team_member', orgname=ORG, - teamname=ORG_OWNERS, membername=ORG_OWNER), - (403, open_kwargs('PUT'))), + ((url_for('update_organization_team_member', orgname=ORG, + teamname=ORG_OWNERS, membername=ORG_OWNER), + open_kwargs('PUT')), 403), + ((url_for('update_organization_team_member', orgname=ORG, + teamname=ORG_READERS, membername=ORG_OWNER), + open_kwargs('PUT')), 403), - (url_for('delete_organization_team_member', orgname=ORG, - teamname=ORG_OWNERS, membername=ORG_OWNER), - (403, open_kwargs('DELETE'))), + ((url_for('delete_organization_team_member', orgname=ORG, + teamname=ORG_OWNERS, membername=ORG_OWNER), + open_kwargs('DELETE')), 403), + ((url_for('delete_organization_team_member', orgname=ORG, + teamname=ORG_READERS, membername=ORG_OWNER), + open_kwargs('DELETE')), 403), - (url_for('create_repo_api'), (403, open_kwargs('POST'))), + ((url_for('create_repo_api'), open_kwargs('POST', NEW_ORG_REPO_DETAILS)), + 403), - (url_for('update_repo_api', repository=PUBLIC_REPO), - (403, open_kwargs('PUT'))), - (url_for('update_repo_api', repository=ORG_REPO), - (403, open_kwargs('PUT'))), - (url_for('update_repo_api', repository=PRIVATE_REPO), - (403, open_kwargs('PUT'))), + ((url_for('update_repo_api', repository=PUBLIC_REPO), open_kwargs('PUT')), + 403), + ((url_for('update_repo_api', repository=ORG_REPO), open_kwargs('PUT')), + 403), + ((url_for('update_repo_api', repository=PRIVATE_REPO), + open_kwargs('PUT')), 403), - (url_for('change_repo_visibility_api', repository=PUBLIC_REPO), - (403, open_kwargs('POST'))), - (url_for('change_repo_visibility_api', repository=ORG_REPO), - (403, open_kwargs('POST'))), - (url_for('change_repo_visibility_api', repository=PRIVATE_REPO), - (403, open_kwargs('POST'))), + ((url_for('change_repo_visibility_api', repository=PUBLIC_REPO), + open_kwargs('POST')), 403), + ((url_for('change_repo_visibility_api', repository=ORG_REPO), + open_kwargs('POST')), 403), + ((url_for('change_repo_visibility_api', repository=PRIVATE_REPO), + open_kwargs('POST')), 403), - (url_for('delete_repository', repository=PUBLIC_REPO), - (403, open_kwargs('DELETE'))), - (url_for('delete_repository', repository=ORG_REPO), - (403, open_kwargs('DELETE'))), - (url_for('delete_repository', repository=PRIVATE_REPO), - (403, open_kwargs('DELETE'))), + ((url_for('delete_repository', repository=PUBLIC_REPO), + open_kwargs('DELETE')), 403), + ((url_for('delete_repository', repository=ORG_REPO), + open_kwargs('DELETE')), 403), + ((url_for('delete_repository', repository=PRIVATE_REPO), + open_kwargs('DELETE')), 403), - (url_for('get_repo_builds', repository=PUBLIC_REPO), - (403, open_kwargs())), - (url_for('get_repo_builds', repository=ORG_REPO), (403, open_kwargs())), - (url_for('get_repo_builds', repository=PRIVATE_REPO), - (403, open_kwargs())), + ((url_for('get_repo_builds', repository=PUBLIC_REPO), open_kwargs()), + 403), + ((url_for('get_repo_builds', repository=ORG_REPO), open_kwargs()), 403), + ((url_for('get_repo_builds', repository=PRIVATE_REPO), open_kwargs()), + 403), - (url_for('get_filedrop_url'), (400, open_kwargs('POST'))), + ((url_for('get_filedrop_url'), open_kwargs('POST')), 400), - (url_for('request_repo_build', repository=PUBLIC_REPO), - (403, open_kwargs('POST'))), - (url_for('request_repo_build', repository=ORG_REPO), - (403, open_kwargs('POST'))), - (url_for('request_repo_build', repository=PRIVATE_REPO), - (403, open_kwargs('POST'))), + ((url_for('request_repo_build', repository=PUBLIC_REPO), + open_kwargs('POST')), 403), + ((url_for('request_repo_build', repository=ORG_REPO), + open_kwargs('POST')), 403), + ((url_for('request_repo_build', repository=PRIVATE_REPO), + open_kwargs('POST')), 403), - (url_for('list_repo_team_permissions', repository=PUBLIC_REPO), - (403, open_kwargs())), - (url_for('list_repo_team_permissions', repository=ORG_REPO), - (403, open_kwargs())), - (url_for('list_repo_team_permissions', repository=PRIVATE_REPO), - (403, open_kwargs())), + ((url_for('list_repo_team_permissions', repository=PUBLIC_REPO), + open_kwargs()), 403), + ((url_for('list_repo_team_permissions', repository=ORG_REPO), + open_kwargs()), 403), + ((url_for('list_repo_team_permissions', repository=PRIVATE_REPO), + open_kwargs()), 403), - (url_for('list_repo_user_permissions', repository=PUBLIC_REPO), - (403, open_kwargs())), - (url_for('list_repo_user_permissions', repository=ORG_REPO), - (403, open_kwargs())), - (url_for('list_repo_user_permissions', repository=PRIVATE_REPO), - (403, open_kwargs())), + ((url_for('list_repo_user_permissions', repository=PUBLIC_REPO), + open_kwargs()), 403), + ((url_for('list_repo_user_permissions', repository=ORG_REPO), + open_kwargs()), 403), + ((url_for('list_repo_user_permissions', repository=PRIVATE_REPO), + open_kwargs()), 403), - (url_for('get_user_permissions', repository=PUBLIC_REPO, - username=FAKE_USERNAME), (403, open_kwargs())), - (url_for('get_user_permissions', repository=ORG_REPO, - username=FAKE_USERNAME), (403, open_kwargs())), - (url_for('get_user_permissions', repository=PRIVATE_REPO, - username=FAKE_USERNAME), (403, open_kwargs())), + ((url_for('get_user_permissions', repository=PUBLIC_REPO, + username=FAKE_USERNAME), open_kwargs()), 403), + ((url_for('get_user_permissions', repository=ORG_REPO, + username=FAKE_USERNAME), open_kwargs()), 403), + ((url_for('get_user_permissions', repository=PRIVATE_REPO, + username=FAKE_USERNAME), open_kwargs()), 403), - (url_for('get_team_permissions', repository=PUBLIC_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs())), - (url_for('get_team_permissions', repository=ORG_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs())), - (url_for('get_team_permissions', repository=PRIVATE_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs())), + ((url_for('get_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_OWNERS), open_kwargs()), 403), + ((url_for('get_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_READERS), open_kwargs()), 403), + ((url_for('get_team_permissions', repository=ORG_REPO, + teamname=ORG_OWNERS), open_kwargs()), 403), + ((url_for('get_team_permissions', repository=ORG_REPO, + teamname=ORG_READERS), open_kwargs()), 403), + ((url_for('get_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_OWNERS), open_kwargs()), 403), + ((url_for('get_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_READERS), open_kwargs()), 403), - (url_for('change_user_permissions', repository=PUBLIC_REPO, - username=FAKE_USERNAME), (403, open_kwargs('PUT'))), - (url_for('change_user_permissions', repository=ORG_REPO, - username=FAKE_USERNAME), (403, open_kwargs('PUT'))), - (url_for('change_user_permissions', repository=PRIVATE_REPO, - username=FAKE_USERNAME), (403, open_kwargs('PUT'))), + ((url_for('change_user_permissions', repository=PUBLIC_REPO, + username=FAKE_USERNAME), open_kwargs('PUT')), 403), + ((url_for('change_user_permissions', repository=ORG_REPO, + username=FAKE_USERNAME), open_kwargs('PUT')), 403), + ((url_for('change_user_permissions', repository=PRIVATE_REPO, + username=FAKE_USERNAME), open_kwargs('PUT')), 403), - (url_for('change_team_permissions', repository=PUBLIC_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs('PUT'))), - (url_for('change_team_permissions', repository=ORG_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs('PUT'))), - (url_for('change_team_permissions', repository=PRIVATE_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs('PUT'))), + ((url_for('change_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_OWNERS), open_kwargs('PUT')), 403), + ((url_for('change_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_READERS), open_kwargs('PUT')), 403), + ((url_for('change_team_permissions', repository=ORG_REPO, + teamname=ORG_OWNERS), open_kwargs('PUT')), 403), + ((url_for('change_team_permissions', repository=ORG_REPO, + teamname=ORG_READERS), open_kwargs('PUT')), 403), + ((url_for('change_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_OWNERS), open_kwargs('PUT')), 403), + ((url_for('change_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_READERS), open_kwargs('PUT')), 403), - (url_for('delete_user_permissions', repository=PUBLIC_REPO, - username=FAKE_USERNAME), (403, open_kwargs('DELETE'))), - (url_for('delete_user_permissions', repository=ORG_REPO, - username=FAKE_USERNAME), (403, open_kwargs('DELETE'))), - (url_for('delete_user_permissions', repository=PRIVATE_REPO, - username=FAKE_USERNAME), (403, open_kwargs('DELETE'))), + ((url_for('delete_user_permissions', repository=PUBLIC_REPO, + username=FAKE_USERNAME), open_kwargs('DELETE')), 403), + ((url_for('delete_user_permissions', repository=ORG_REPO, + username=FAKE_USERNAME), open_kwargs('DELETE')), 403), + ((url_for('delete_user_permissions', repository=PRIVATE_REPO, + username=FAKE_USERNAME), open_kwargs('DELETE')), 403), - (url_for('delete_team_permissions', repository=PUBLIC_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs('DELETE'))), - (url_for('delete_team_permissions', repository=ORG_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs('DELETE'))), - (url_for('delete_team_permissions', repository=PRIVATE_REPO, - teamname=FAKE_TEAMNAME), (403, open_kwargs('DELETE'))), + ((url_for('delete_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_OWNERS), open_kwargs('DELETE')), 403), + ((url_for('delete_team_permissions', repository=PUBLIC_REPO, + teamname=ORG_READERS), open_kwargs('DELETE')), 403), + ((url_for('delete_team_permissions', repository=ORG_REPO, + teamname=ORG_OWNERS), open_kwargs('DELETE')), 403), + ((url_for('delete_team_permissions', repository=ORG_REPO, + teamname=ORG_READERS), open_kwargs('DELETE')), 403), + ((url_for('delete_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_OWNERS), open_kwargs('DELETE')), 403), + ((url_for('delete_team_permissions', repository=PRIVATE_REPO, + teamname=ORG_READERS), open_kwargs('DELETE')), 403), - (url_for('list_repo_tokens', repository=PUBLIC_REPO), - (403, open_kwargs())), - (url_for('list_repo_tokens', repository=ORG_REPO), (403, open_kwargs())), - (url_for('list_repo_tokens', repository=PRIVATE_REPO), - (403, open_kwargs())), + ((url_for('list_repo_tokens', repository=PUBLIC_REPO), open_kwargs()), + 403), + ((url_for('list_repo_tokens', repository=ORG_REPO), open_kwargs()), 403), + ((url_for('list_repo_tokens', repository=PRIVATE_REPO), open_kwargs()), + 403), - (url_for('get_tokens', repository=PUBLIC_REPO, code=FAKE_TOKEN), - (403, open_kwargs())), - (url_for('get_tokens', repository=ORG_REPO, code=FAKE_TOKEN), - (403, open_kwargs())), - (url_for('get_tokens', repository=PRIVATE_REPO, code=FAKE_TOKEN), - (403, open_kwargs())), + ((url_for('get_tokens', repository=PUBLIC_REPO, code=FAKE_TOKEN), + open_kwargs()), 403), + ((url_for('get_tokens', repository=ORG_REPO, code=FAKE_TOKEN), + open_kwargs()), 403), + ((url_for('get_tokens', repository=PRIVATE_REPO, code=FAKE_TOKEN), + open_kwargs()), 403), - (url_for('create_token', repository=PUBLIC_REPO), - (403, open_kwargs('POST'))), - (url_for('create_token', repository=ORG_REPO), - (403, open_kwargs('POST'))), - (url_for('create_token', repository=PRIVATE_REPO), - (403, open_kwargs('POST'))), + ((url_for('create_token', repository=PUBLIC_REPO), open_kwargs('POST')), + 403), + ((url_for('create_token', repository=ORG_REPO), open_kwargs('POST')), + 403), + ((url_for('create_token', repository=PRIVATE_REPO), open_kwargs('POST')), + 403), - (url_for('change_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), - (403, open_kwargs('PUT'))), - (url_for('change_token', repository=ORG_REPO, code=FAKE_TOKEN), - (403, open_kwargs('PUT'))), - (url_for('change_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), - (403, open_kwargs('PUT'))), + ((url_for('change_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), + open_kwargs('PUT')), 403), + ((url_for('change_token', repository=ORG_REPO, code=FAKE_TOKEN), + open_kwargs('PUT')), 403), + ((url_for('change_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), + open_kwargs('PUT')), 403), - (url_for('delete_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), - (403, open_kwargs('DELETE'))), - (url_for('delete_token', repository=ORG_REPO, code=FAKE_TOKEN), - (403, open_kwargs('DELETE'))), - (url_for('delete_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), - (403, open_kwargs('DELETE'))), + ((url_for('delete_token', repository=PUBLIC_REPO, code=FAKE_TOKEN), + open_kwargs('DELETE')), 403), + ((url_for('delete_token', repository=ORG_REPO, code=FAKE_TOKEN), + open_kwargs('DELETE')), 403), + ((url_for('delete_token', repository=PRIVATE_REPO, code=FAKE_TOKEN), + open_kwargs('DELETE')), 403), - (url_for('subscribe_api'), (403, open_kwargs('PUT'))), + ((url_for('subscribe_api'), open_kwargs('PUT')), 400), - (url_for('subscribe_org_api', orgname=ORG), (403, open_kwargs('PUT'))), + ((url_for('subscribe_org_api', orgname=ORG), open_kwargs('PUT')), 403), - (url_for('get_subscription'), (200, open_kwargs())), + ((url_for('get_subscription'), open_kwargs()), 200), - (url_for('get_org_subscription', orgname=ORG), (403, open_kwargs())), + ((url_for('get_org_subscription', orgname=ORG), open_kwargs()), 403), ]) to_update = build_anon_spec() to_update.update(changes) - return to_update \ No newline at end of file + return to_update + + +def build_read_access_spec(): + changes = OrderedDict([ + ((url_for('get_organization', orgname=ORG), open_kwargs()), 200), + + ((url_for('get_organization_team_members', orgname=ORG, + teamname=ORG_READERS), open_kwargs()), 200), + + ((url_for('create_repo_api'), open_kwargs('POST', NEW_ORG_REPO_DETAILS)), + 403), + + ((url_for('get_repo_api', repository=ORG_REPO), open_kwargs()), 200), + ((url_for('get_repo_api', repository=PRIVATE_REPO), open_kwargs()), 200), + + ((url_for('list_repository_images', repository=ORG_REPO), + open_kwargs()), 200), + ((url_for('list_repository_images', repository=PRIVATE_REPO), + open_kwargs()), 200), + + ((url_for('get_image', repository=ORG_REPO, image_id=FAKE_IMAGE_ID), + open_kwargs()), 404), + ((url_for('get_image', repository=PRIVATE_REPO, image_id=FAKE_IMAGE_ID), + open_kwargs()), 404), + + ((url_for('get_image_changes', repository=ORG_REPO, + image_id=FAKE_IMAGE_ID), open_kwargs()), 404), + ((url_for('get_image_changes', repository=PRIVATE_REPO, + image_id=FAKE_IMAGE_ID), open_kwargs()), 404), + + ((url_for('list_tag_images', repository=ORG_REPO, tag=FAKE_TAG_NAME), + open_kwargs()), 404), + ((url_for('list_tag_images', repository=PRIVATE_REPO, tag=FAKE_TAG_NAME), + open_kwargs()), 404), + ]) + + to_update = build_no_access_spec() + to_update.update(changes) + return to_update diff --git a/test/test_api_security.py b/test/test_api_security.py index f63d92c5c..2a2bb3c48 100644 --- a/test/test_api_security.py +++ b/test/test_api_security.py @@ -6,10 +6,12 @@ import endpoints.api from app import app from data import model from initdb import wipe_database, initialize_database, populate_database -from specs import build_anon_spec, build_no_access_spec +from specs import (build_anon_spec, build_no_access_spec, + build_read_access_spec) NO_ACCESS_USER = 'freshuser' +READ_ACCESS_USER = 'reader' class ApiTestCase(unittest.TestCase): @@ -19,31 +21,64 @@ class ApiTestCase(unittest.TestCase): populate_database() +class SpecTestBuilder(type): + @staticmethod + def _test_generator(url, expected_status, open_kwargs, auth_username=None): + def test(self): + with app.test_client() as c: + if auth_username: + # Temporarily remove the teardown functions + teardown_funcs = app.teardown_request_funcs[None] + app.teardown_request_funcs[None] = [] + + with c.session_transaction() as sess: + sess['user_id'] = auth_username + sess['identity.id'] = auth_username + sess['identity.auth_type'] = 'username' + + # Restore the teardown functions + app.teardown_request_funcs[None] = teardown_funcs + + rv = c.open(url, **open_kwargs) + msg = '%s %s: %s expected: %s' % (open_kwargs['method'], url, + rv.status_code, expected_status) + self.assertEqual(rv.status_code, expected_status, msg) + return test + + + def __new__(cls, name, bases, attrs): + with app.test_request_context() as ctx: + spec = attrs['spec_func']() + for (url, open_kwargs), expected_status in spec.items(): + test = SpecTestBuilder._test_generator(url, expected_status, + open_kwargs, + attrs['auth_username']) + + test_name_url = url.replace('/', '_').replace('-', '_') + test_name = 'test_%s_%s' % (open_kwargs['method'].lower(), + test_name_url) + attrs[test_name] = test + + return type(name, bases, attrs) + + class TestAnonymousAccess(ApiTestCase): - def __runspec(self, client, spec): - for url, (expected_status, open_kwargs) in spec.items(): - rv = client.open(url, **open_kwargs) - msg = '%s %s: %s expected: %s' % (open_kwargs['method'], url, - rv.status_code, expected_status) - self.assertEqual(rv.status_code, expected_status, msg) + __metaclass__ = SpecTestBuilder + spec_func = build_anon_spec + auth_username = None - def test_anonymous_public_access(self): - with app.test_request_context() as ctx: - spec = build_anon_spec() - with app.test_client() as c: - self.__runspec(c, spec) +class TestNoAccess(ApiTestCase): + __metaclass__ = SpecTestBuilder + spec_func = build_no_access_spec + auth_username = NO_ACCESS_USER - def test_authenticated_but_not_authorized(self): - with app.test_request_context() as ctx: - spec = build_no_access_spec() - with app.test_client() as c: - with c.session_transaction() as sess: - sess['user_id'] = NO_ACCESS_USER - - self.__runspec(c, spec) +class TestNoAccess(ApiTestCase): + __metaclass__ = SpecTestBuilder + spec_func = build_read_access_spec + auth_username = READ_ACCESS_USER if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/test/teststorage.py b/test/teststorage.py new file mode 100644 index 000000000..c29484ce4 --- /dev/null +++ b/test/teststorage.py @@ -0,0 +1,34 @@ +from uuid import uuid4 + +from storage.basestorage import Storage + + +class FakeStorage(Storage): + def _init_path(self, path=None, create=False): + return path + + def get_content(self, path): + raise IOError('Fake files are fake!') + + def put_content(self, path, content): + return path + + def stream_read(self, path): + yield '' + + def stream_write(self, path, fp): + pass + + def exists(self, path): + return True + + +class FakeUserfiles(object): + def prepare_for_drop(self, mime_type): + return ('http://fake/url', uuid4()) + + def store_file(self, flask_file): + raise NotImplementedError() + + def get_file_url(self, file_id, expires_in=300): + return ('http://fake/url') diff --git a/workers/dockerfilebuild.py b/workers/dockerfilebuild.py index 4cdeb0e70..b78cb8b0c 100644 --- a/workers/dockerfilebuild.py +++ b/workers/dockerfilebuild.py @@ -13,7 +13,6 @@ from base64 import b64encode from requests.exceptions import ConnectionError from data.queue import dockerfile_build_queue -from data.userfiles import UserRequestFiles from data import model from data.database import db as db_connection from app import app @@ -151,9 +150,7 @@ def babysit_builder(request): ssh_client.exec_command(remove_auth_cmd) # Prepare the signed resource url the build node can fetch the job from - user_files = UserRequestFiles(app.config['AWS_ACCESS_KEY'], - app.config['AWS_SECRET_KEY'], - app.config['REGISTRY_S3_BUCKET']) + user_files = app.config['USERFILES'] resource_url = user_files.get_file_url(repository_build.resource_key) # Start the build server