Fix handling of repository names that match known endpoints (build, trigger, etc) and add tests to ensure it is fixed
This commit is contained in:
parent
cbd8cf3bb5
commit
e699739b23
3 changed files with 69 additions and 57 deletions
|
@ -1005,7 +1005,7 @@ def list_repos():
|
|||
return jsonify(response)
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>', methods=['PUT'])
|
||||
@api.route('/repository/<repopath:repository>', methods=['PUT'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def update_repo(namespace, repository):
|
||||
|
@ -1027,7 +1027,7 @@ def update_repo(namespace, repository):
|
|||
abort(403)
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/changevisibility',
|
||||
@api.route('/repository/<repopath:repository>/changevisibility',
|
||||
methods=['POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1048,7 +1048,7 @@ def change_repo_visibility(namespace, repository):
|
|||
abort(403)
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>', methods=['DELETE'])
|
||||
@api.route('/repository/<repopath:repository>', methods=['DELETE'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def delete_repository(namespace, repository):
|
||||
|
@ -1079,7 +1079,7 @@ def image_view(image):
|
|||
}
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>', methods=['GET'])
|
||||
@parse_repository_name
|
||||
def get_repo(namespace, repository):
|
||||
logger.debug('Get repo: %s/%s' % (namespace, repository))
|
||||
|
@ -1159,7 +1159,7 @@ def build_status_view(build_obj, can_write=False):
|
|||
}
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/build/', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>/build/', methods=['GET'])
|
||||
@parse_repository_name
|
||||
def get_repo_builds(namespace, repository):
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
@ -1176,7 +1176,7 @@ def get_repo_builds(namespace, repository):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/build/<build_uuid>/status',
|
||||
@api.route('/repository/<repopath:repository>/build/<build_uuid>/status',
|
||||
methods=['GET'])
|
||||
@parse_repository_name
|
||||
def get_repo_build_status(namespace, repository, build_uuid):
|
||||
|
@ -1193,7 +1193,7 @@ def get_repo_build_status(namespace, repository, build_uuid):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/build/<build_uuid>/archiveurl',
|
||||
@api.route('/repository/<repopath:repository>/build/<build_uuid>/archiveurl',
|
||||
methods=['GET'])
|
||||
@parse_repository_name
|
||||
def get_repo_build_archive_url(namespace, repository, build_uuid):
|
||||
|
@ -1211,7 +1211,7 @@ def get_repo_build_archive_url(namespace, repository, build_uuid):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/build/<build_uuid>/logs',
|
||||
@api.route('/repository/<repopath:repository>/build/<build_uuid>/logs',
|
||||
methods=['GET'])
|
||||
@parse_repository_name
|
||||
def get_repo_build_logs(namespace, repository, build_uuid):
|
||||
|
@ -1236,7 +1236,7 @@ def get_repo_build_logs(namespace, repository, build_uuid):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/build/', methods=['POST'])
|
||||
@api.route('/repository/<repopath:repository>/build/', methods=['POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def request_repo_build(namespace, repository):
|
||||
|
@ -1282,7 +1282,7 @@ def webhook_view(webhook):
|
|||
}
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/webhook/', methods=['POST'])
|
||||
@api.route('/repository/<repopath:repository>/webhook/', methods=['POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def create_webhook(namespace, repository):
|
||||
|
@ -1303,7 +1303,7 @@ def create_webhook(namespace, repository):
|
|||
abort(403) # Permissions denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/webhook/<public_id>',
|
||||
@api.route('/repository/<repopath:repository>/webhook/<public_id>',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1320,7 +1320,7 @@ def get_webhook(namespace, repository, public_id):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/webhook/', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>/webhook/', methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def list_webhooks(namespace, repository):
|
||||
|
@ -1334,7 +1334,7 @@ def list_webhooks(namespace, repository):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/webhook/<public_id>',
|
||||
@api.route('/repository/<repopath:repository>/webhook/<public_id>',
|
||||
methods=['DELETE'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1350,7 +1350,7 @@ def delete_webhook(namespace, repository, public_id):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>',
|
||||
@api.route('/repository/<repopath:repository>/trigger/<trigger_uuid>',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1372,7 +1372,7 @@ def _prepare_webhook_url(scheme, username, password, hostname, path):
|
|||
return urlparse.urlunparse((scheme, auth_hostname, path, '', '', ''))
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/subdir',
|
||||
@api.route('/repository/<repopath:repository>/trigger/<trigger_uuid>/subdir',
|
||||
methods=['POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1405,7 +1405,7 @@ def list_build_trigger_subdirs(namespace, repository, trigger_uuid):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/activate',
|
||||
@api.route('/repository/<repopath:repository>/trigger/<trigger_uuid>/activate',
|
||||
methods=['POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1464,7 +1464,7 @@ def activate_build_trigger(namespace, repository, trigger_uuid):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/start',
|
||||
@api.route('/repository/<repopath:repository>/trigger/<trigger_uuid>/start',
|
||||
methods=['POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1502,7 +1502,7 @@ def manually_start_build_trigger(namespace, repository, trigger_uuid):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/builds',
|
||||
@api.route('/repository/<repopath:repository>/trigger/<trigger_uuid>/builds',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1519,7 +1519,7 @@ def list_trigger_recent_builds(namespace, repository, trigger_uuid):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>/sources',
|
||||
@api.route('/repository/<repopath:repository>/trigger/<trigger_uuid>/sources',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1543,7 +1543,7 @@ def list_trigger_build_sources(namespace, repository, trigger_uuid):
|
|||
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>/trigger/', methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def list_build_triggers(namespace, repository):
|
||||
|
@ -1557,7 +1557,7 @@ def list_build_triggers(namespace, repository):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/trigger/<trigger_uuid>',
|
||||
@api.route('/repository/<repopath:repository>/trigger/<trigger_uuid>',
|
||||
methods=['DELETE'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1617,7 +1617,7 @@ def wrap_role_view_org(role_json, user, org_members):
|
|||
return role_json
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/image/', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>/image/', methods=['GET'])
|
||||
@parse_repository_name
|
||||
def list_repository_images(namespace, repository):
|
||||
permission = ReadRepositoryPermission(namespace, repository)
|
||||
|
@ -1642,7 +1642,7 @@ def list_repository_images(namespace, repository):
|
|||
abort(403)
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/image/<image_id>',
|
||||
@api.route('/repository/<repopath:repository>/image/<image_id>',
|
||||
methods=['GET'])
|
||||
@parse_repository_name
|
||||
def get_image(namespace, repository, image_id):
|
||||
|
@ -1656,7 +1656,7 @@ def get_image(namespace, repository, image_id):
|
|||
abort(403)
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/image/<image_id>/changes',
|
||||
@api.route('/repository/<repopath:repository>/image/<image_id>/changes',
|
||||
methods=['GET'])
|
||||
@cache_control(max_age=60*60) # Cache for one hour
|
||||
@parse_repository_name
|
||||
|
@ -1681,7 +1681,7 @@ def get_image_changes(namespace, repository, image_id):
|
|||
abort(403)
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/tag/<tag>',
|
||||
@api.route('/repository/<repopath:repository>/tag/<tag>',
|
||||
methods=['DELETE'])
|
||||
@parse_repository_name
|
||||
def delete_full_tag(namespace, repository, tag):
|
||||
|
@ -1700,7 +1700,7 @@ def delete_full_tag(namespace, repository, tag):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/tag/<tag>/images',
|
||||
@api.route('/repository/<repopath:repository>/tag/<tag>/images',
|
||||
methods=['GET'])
|
||||
@parse_repository_name
|
||||
def list_tag_images(namespace, repository, tag):
|
||||
|
@ -1724,7 +1724,7 @@ def list_tag_images(namespace, repository, tag):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/team/',
|
||||
@api.route('/repository/<repopath:repository>/permissions/team/',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1741,7 +1741,7 @@ def list_repo_team_permissions(namespace, repository):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/user/',
|
||||
@api.route('/repository/<repopath:repository>/permissions/user/',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1782,7 +1782,7 @@ def list_repo_user_permissions(namespace, repository):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/user/<username>',
|
||||
@api.route('/repository/<repopath:repository>/permissions/user/<username>',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1807,7 +1807,7 @@ def get_user_permissions(namespace, repository, username):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/team/<teamname>',
|
||||
@api.route('/repository/<repopath:repository>/permissions/team/<teamname>',
|
||||
methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1822,7 +1822,7 @@ def get_team_permissions(namespace, repository, teamname):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/user/<username>',
|
||||
@api.route('/repository/<repopath:repository>/permissions/user/<username>',
|
||||
methods=['PUT', 'POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1861,7 +1861,7 @@ def change_user_permissions(namespace, repository, username):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/team/<teamname>',
|
||||
@api.route('/repository/<repopath:repository>/permissions/team/<teamname>',
|
||||
methods=['PUT', 'POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1889,7 +1889,7 @@ def change_team_permissions(namespace, repository, teamname):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/user/<username>',
|
||||
@api.route('/repository/<repopath:repository>/permissions/user/<username>',
|
||||
methods=['DELETE'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1910,7 +1910,7 @@ def delete_user_permissions(namespace, repository, username):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/permissions/team/<teamname>',
|
||||
@api.route('/repository/<repopath:repository>/permissions/team/<teamname>',
|
||||
methods=['DELETE'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -1936,7 +1936,7 @@ def token_view(token_obj):
|
|||
}
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/tokens/', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>/tokens/', methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def list_repo_tokens(namespace, repository):
|
||||
|
@ -1951,7 +1951,7 @@ def list_repo_tokens(namespace, repository):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/tokens/<code>', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>/tokens/<code>', methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def get_tokens(namespace, repository, code):
|
||||
|
@ -1967,7 +1967,7 @@ def get_tokens(namespace, repository, code):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/tokens/', methods=['POST'])
|
||||
@api.route('/repository/<repopath:repository>/tokens/', methods=['POST'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def create_token(namespace, repository):
|
||||
|
@ -1989,7 +1989,7 @@ def create_token(namespace, repository):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/tokens/<code>', methods=['PUT'])
|
||||
@api.route('/repository/<repopath:repository>/tokens/<code>', methods=['PUT'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def change_token(namespace, repository, code):
|
||||
|
@ -2014,7 +2014,7 @@ def change_token(namespace, repository, code):
|
|||
abort(403) # Permission denied
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/tokens/<code>',
|
||||
@api.route('/repository/<repopath:repository>/tokens/<code>',
|
||||
methods=['DELETE'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
|
@ -2427,7 +2427,7 @@ def log_view(log):
|
|||
|
||||
|
||||
|
||||
@api.route('/repository/<path:repository>/logs', methods=['GET'])
|
||||
@api.route('/repository/<repopath:repository>/logs', methods=['GET'])
|
||||
@api_login_required
|
||||
@parse_repository_name
|
||||
def list_repo_logs(namespace, repository):
|
||||
|
|
|
@ -12,13 +12,20 @@ from data import model
|
|||
from data.queue import dockerfile_build_queue
|
||||
from app import app, login_manager
|
||||
from auth.permissions import QuayDeferredPermissionUser
|
||||
from werkzeug.routing import BaseConverter
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
route_data = None
|
||||
|
||||
class RepoPathConverter(BaseConverter):
|
||||
regex = '[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+'
|
||||
weight = 200
|
||||
|
||||
app.url_map.converters['repopath'] = RepoPathConverter
|
||||
|
||||
|
||||
def get_route_data():
|
||||
global route_data
|
||||
if route_data:
|
||||
|
|
|
@ -71,6 +71,9 @@ UPDATE_REPO_DETAILS = {
|
|||
'description': 'A new description',
|
||||
}
|
||||
|
||||
FAKE_TRIGGER_CONFIG = {
|
||||
'active': True
|
||||
}
|
||||
|
||||
class TestSpec(object):
|
||||
def __init__(self, url, anon_code=401, no_access_code=403, read_code=403,
|
||||
|
@ -458,29 +461,31 @@ def build_specs():
|
|||
TestSpec(url_for('api.get_build_trigger', repository=PRIVATE_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), admin_code=404),
|
||||
|
||||
TestSpec(url_for('api.list_build_trigger_subdirs', repository=PUBLIC_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), 403, 403, 403, 403),
|
||||
TestSpec(url_for('api.list_build_trigger_subdirs', repository=ORG_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), 403, 403, 403, 404),
|
||||
TestSpec(url_for('api.list_build_trigger_subdirs', repository=PRIVATE_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), 403, 403, 403, 404),
|
||||
TestSpec(url_for('api.list_build_trigger_subdirs',
|
||||
repository=PUBLIC_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
401, 403, 403, 403).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
TestSpec(url_for('api.list_build_trigger_subdirs',
|
||||
repository=ORG_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
401, 403, 403, 404).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
TestSpec(url_for('api.list_build_trigger_subdirs', repository=PRIVATE_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
401, 403, 403, 404).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
|
||||
TestSpec(url_for('api.activate_build_trigger', repository=PUBLIC_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), 403, 403, 403, 403),
|
||||
TestSpec(url_for('api.activate_build_trigger', repository=ORG_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), 403, 403, 403, 404),
|
||||
TestSpec(url_for('api.activate_build_trigger', repository=PRIVATE_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), 403, 403, 403, 404),
|
||||
TestSpec(url_for('api.activate_build_trigger', repository=PUBLIC_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
401, 403, 403, 403).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
TestSpec(url_for('api.activate_build_trigger', repository=ORG_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
401, 403, 403, 404).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
TestSpec(url_for('api.activate_build_trigger', repository=PRIVATE_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
401, 403, 403, 404).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
|
||||
TestSpec(url_for('api.manually_start_build_trigger',
|
||||
repository=PUBLIC_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
403, 403, 403, 403),
|
||||
401, 403, 403, 403).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
TestSpec(url_for('api.manually_start_build_trigger',
|
||||
repository=ORG_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
403, 403, 403, 404),
|
||||
401, 403, 403, 404).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
TestSpec(url_for('api.manually_start_build_trigger',
|
||||
repository=PRIVATE_REPO, trigger_uuid=TRIGGER_UUID),
|
||||
403, 403, 403, 404),
|
||||
401, 403, 403, 404).set_method('POST').set_data_from_obj(FAKE_TRIGGER_CONFIG),
|
||||
|
||||
TestSpec(url_for('api.list_trigger_recent_builds', repository=PUBLIC_REPO,
|
||||
trigger_uuid=TRIGGER_UUID), admin_code=403),
|
||||
|
|
Reference in a new issue