From 2e30c47045c4f769abea28cb15fa66b3dcd110b3 Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Wed, 7 Jun 2017 10:01:37 -0400 Subject: [PATCH 1/2] Re-enable builds and tag modification when signing is enabled --- endpoints/api/__init__.py | 17 ------- endpoints/api/build.py | 5 +- endpoints/api/tag.py | 5 +- .../api/test/test_disallow_under_trust.py | 50 ------------------- endpoints/api/trigger.py | 10 +--- endpoints/web.py | 4 -- endpoints/webhooks.py | 2 - 7 files changed, 3 insertions(+), 90 deletions(-) delete mode 100644 endpoints/api/test/test_disallow_under_trust.py diff --git a/endpoints/api/__init__.py b/endpoints/api/__init__.py index 2ffd359be..18c4366de 100644 --- a/endpoints/api/__init__.py +++ b/endpoints/api/__init__.py @@ -387,23 +387,6 @@ def define_json_response(schema_name): return wrapper -def disallow_under_trust(func): - """ Disallows the decorated operation for repository when it has trust enabled. - """ - @wraps(func) - def wrapper(self, *args, **kwargs): - if features.SIGNING: - namespace = args[0] - repository = args[1] - - repo = model.repository.get_repository(namespace, repository) - if repo is not None and repo.trust_enabled: - raise InvalidRequest('Cannot call this method on a repostory with trust enabled') - - return func(self, *args, **kwargs) - return wrapper - - import endpoints.api.billing import endpoints.api.build import endpoints.api.discovery diff --git a/endpoints/api/build.py b/endpoints/api/build.py index 2f9a96375..7a20c2872 100644 --- a/endpoints/api/build.py +++ b/endpoints/api/build.py @@ -19,8 +19,7 @@ from data.buildlogs import BuildStatusRetrievalError from endpoints.api import (RepositoryParamResource, parse_args, query_param, nickname, resource, require_repo_read, require_repo_write, validate_json_request, ApiResource, internal_only, format_date, api, path_param, - require_repo_admin, abort, disallow_for_app_repositories, - disallow_under_trust) + require_repo_admin, abort, disallow_for_app_repositories) from endpoints.building import start_build, PreparedBuild, MaximumBuildsQueuedException from endpoints.exception import Unauthorized, NotFound, InvalidRequest from util.names import parse_robot_username @@ -226,7 +225,6 @@ class RepositoryBuildList(RepositoryParamResource): @require_repo_write @nickname('requestRepoBuild') @disallow_for_app_repositories - @disallow_under_trust @validate_json_request('RepositoryBuildRequest') def post(self, namespace, repository): """ Request that a repository be built and pushed from the specified input. """ @@ -363,7 +361,6 @@ class RepositoryBuildResource(RepositoryParamResource): @require_repo_admin @nickname('cancelRepoBuild') - @disallow_under_trust @disallow_for_app_repositories def delete(self, namespace, repository, build_uuid): """ Cancels a repository build. """ diff --git a/endpoints/api/tag.py b/endpoints/api/tag.py index adc4a60d2..ed170a7ff 100644 --- a/endpoints/api/tag.py +++ b/endpoints/api/tag.py @@ -5,7 +5,7 @@ from flask import request, abort from endpoints.api import ( resource, nickname, require_repo_read, require_repo_write, RepositoryParamResource, log_action, validate_json_request, path_param, parse_args, query_param, truthy_bool, - disallow_for_app_repositories, disallow_under_trust) + disallow_for_app_repositories) from endpoints.exception import NotFound from endpoints.api.image import image_view from endpoints.v2.manifest import _generate_and_store_manifest @@ -87,7 +87,6 @@ class RepositoryTag(RepositoryParamResource): @require_repo_write @disallow_for_app_repositories - @disallow_under_trust @nickname('changeTagImage') @validate_json_request('MoveTag') def put(self, namespace, repository, tag): @@ -128,7 +127,6 @@ class RepositoryTag(RepositoryParamResource): @require_repo_write @disallow_for_app_repositories - @disallow_under_trust @nickname('deleteFullTag') def delete(self, namespace, repository, tag): """ Delete the specified repository tag. """ @@ -225,7 +223,6 @@ class RestoreTag(RepositoryParamResource): @require_repo_write @disallow_for_app_repositories - @disallow_under_trust @nickname('restoreTag') @validate_json_request('RestoreTag') def post(self, namespace, repository, tag): diff --git a/endpoints/api/test/test_disallow_under_trust.py b/endpoints/api/test/test_disallow_under_trust.py deleted file mode 100644 index 2f5f381de..000000000 --- a/endpoints/api/test/test_disallow_under_trust.py +++ /dev/null @@ -1,50 +0,0 @@ -import pytest - -from data import model -from endpoints.api.build import RepositoryBuildList, RepositoryBuildResource -from endpoints.api.tag import RepositoryTag, RestoreTag -from endpoints.api.trigger import (BuildTrigger, BuildTriggerSubdirs, - BuildTriggerActivate, BuildTriggerAnalyze, ActivateBuildTrigger, - BuildTriggerFieldValues, BuildTriggerSources, - BuildTriggerSourceNamespaces) -from endpoints.api.test.shared import client_with_identity, conduct_api_call -from test.fixtures import * - -BUILD_ARGS = {'build_uuid': '1234'} -IMAGE_ARGS = {'imageid': '1234', 'image_id': 1234} -MANIFEST_ARGS = {'manifestref': 'sha256:abcd1234'} -LABEL_ARGS = {'manifestref': 'sha256:abcd1234', 'labelid': '1234'} -NOTIFICATION_ARGS = {'uuid': '1234'} -TAG_ARGS = {'tag': 'foobar'} -TRIGGER_ARGS = {'trigger_uuid': '1234'} -FIELD_ARGS = {'trigger_uuid': '1234', 'field_name': 'foobar'} - -@pytest.mark.parametrize('resource, method, params', [ - (RepositoryBuildList, 'post', None), - (RepositoryBuildResource, 'delete', BUILD_ARGS), - (RepositoryTag, 'put', TAG_ARGS), - (RepositoryTag, 'delete', TAG_ARGS), - (RestoreTag, 'post', TAG_ARGS), - (BuildTrigger, 'delete', TRIGGER_ARGS), - (BuildTriggerSubdirs, 'post', TRIGGER_ARGS), - (BuildTriggerActivate, 'post', TRIGGER_ARGS), - (BuildTriggerAnalyze, 'post', TRIGGER_ARGS), - (ActivateBuildTrigger, 'post', TRIGGER_ARGS), - (BuildTriggerFieldValues, 'post', FIELD_ARGS), - (BuildTriggerSources, 'post', TRIGGER_ARGS), - (BuildTriggerSourceNamespaces, 'get', TRIGGER_ARGS), -]) -def test_disallowed_for_apps(resource, method, params, client): - namespace = 'devtable' - repository = 'somerepo' - - devtable = model.user.get_user('devtable') - repo = model.repository.create_repository(namespace, repository, devtable, repo_kind='image') - model.repository.set_trust(repo, True) - - params = params or {} - params['repository'] = '%s/%s' % (namespace, repository) - - with client_with_identity('devtable', client) as cl: - conduct_api_call(cl, resource, method, params, None, 400) - diff --git a/endpoints/api/trigger.py b/endpoints/api/trigger.py index f5e982595..6cefadc13 100644 --- a/endpoints/api/trigger.py +++ b/endpoints/api/trigger.py @@ -19,7 +19,7 @@ from data.model.build import update_build_trigger from endpoints.api import (RepositoryParamResource, nickname, resource, require_repo_admin, log_action, request_error, query_param, parse_args, internal_only, validate_json_request, api, path_param, abort, - disallow_for_app_repositories, disallow_under_trust) + disallow_for_app_repositories) from endpoints.api.build import build_status_view, trigger_view, RepositoryBuildStatus from endpoints.api.trigger_analyzer import TriggerAnalyzer from endpoints.building import start_build, MaximumBuildsQueuedException @@ -72,7 +72,6 @@ class BuildTrigger(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('deleteBuildTrigger') def delete(self, namespace_name, repo_name, trigger_uuid): """ Delete the specified build trigger. """ @@ -114,7 +113,6 @@ class BuildTriggerSubdirs(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('listBuildTriggerSubdirs') @validate_json_request('BuildTriggerSubdirRequest') def post(self, namespace_name, repo_name, trigger_uuid): @@ -179,7 +177,6 @@ class BuildTriggerActivate(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('activateBuildTrigger') @validate_json_request('BuildTriggerActivateRequest') def post(self, namespace_name, repo_name, trigger_uuid): @@ -276,7 +273,6 @@ class BuildTriggerAnalyze(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('analyzeBuildTrigger') @validate_json_request('BuildTriggerAnalyzeRequest') def post(self, namespace_name, repo_name, trigger_uuid): @@ -339,7 +335,6 @@ class ActivateBuildTrigger(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('manuallyStartBuildTrigger') @validate_json_request('RunParameters') def post(self, namespace_name, repo_name, trigger_uuid): @@ -401,7 +396,6 @@ class BuildTriggerFieldValues(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('listTriggerFieldValues') def post(self, namespace_name, repo_name, trigger_uuid, field_name): """ List the field values for a custom run field. """ @@ -443,7 +437,6 @@ class BuildTriggerSources(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('listTriggerBuildSources') @validate_json_request('BuildTriggerSourcesRequest') def post(self, namespace_name, repo_name, trigger_uuid): @@ -475,7 +468,6 @@ class BuildTriggerSourceNamespaces(RepositoryParamResource): @require_repo_admin @disallow_for_app_repositories - @disallow_under_trust @nickname('listTriggerBuildSourceNamespaces') def get(self, namespace_name, repo_name, trigger_uuid): """ List the build sources for the trigger configuration thus far. """ diff --git a/endpoints/web.py b/endpoints/web.py index cd158bbc6..0380d9c5e 100644 --- a/endpoints/web.py +++ b/endpoints/web.py @@ -677,8 +677,6 @@ def attach_bitbucket_trigger(namespace_name, repo_name): abort(404, message=msg) elif repo.kind.name != 'image': abort(501) - elif repo.trust_enabled: - abort(400) trigger = model.build.create_build_trigger(repo, BitbucketBuildTrigger.service_name(), None, current_user.db_user()) @@ -714,8 +712,6 @@ def attach_custom_build_trigger(namespace_name, repo_name): abort(404, message=msg) elif repo.kind.name != 'image': abort(501) - elif repo.trust_enabled: - abort(400) trigger = model.build.create_build_trigger(repo, CustomBuildTrigger.service_name(), None, current_user.db_user()) diff --git a/endpoints/webhooks.py b/endpoints/webhooks.py index e5f4c60b6..6277724cf 100644 --- a/endpoints/webhooks.py +++ b/endpoints/webhooks.py @@ -89,8 +89,6 @@ def build_trigger_webhook(trigger_uuid, **kwargs): if trigger.repository.kind.name != 'image': abort(501, 'Build triggers cannot be invoked on application repositories') - elif trigger.repository.trust_enabled: - abort(400, 'Build triggers cannot be invoked on repositories with trust enabled') logger.debug('Passing webhook request to handler %s', handler) try: From 7b3cb9c8b7fad5774bfbf5b0fbf21fd77eb1bec7 Mon Sep 17 00:00:00 2001 From: Evan Cordell Date: Tue, 13 Jun 2017 09:56:47 -0400 Subject: [PATCH 2/2] Re-enable builds and tag operations in the UI --- static/directives/header-bar.html | 6 +++--- .../directives/repo-view/repo-panel-builds.html | 6 +++--- static/directives/repo-view/repo-panel-info.html | 2 +- static/directives/repo-view/repo-panel-tags.html | 6 +++--- static/directives/tag-operations-dialog.html | 11 ++++++----- .../repository-signing-config.component.html | 16 +++++++++++----- static/js/directives/ui/tag-operations-dialog.js | 16 ++++++++-------- static/js/types/common.types.ts | 1 + 8 files changed, 36 insertions(+), 28 deletions(-) diff --git a/static/directives/header-bar.html b/static/directives/header-bar.html index bf6ede974..ab71d1ced 100644 --- a/static/directives/header-bar.html +++ b/static/directives/header-bar.html @@ -89,14 +89,14 @@ New Robot Account - +
  • + !currentPageContext.repository.tag_operations_disabled"> New Dockerfile Build diff --git a/static/directives/repo-view/repo-panel-builds.html b/static/directives/repo-view/repo-panel-builds.html index edeb0cecb..fcca2174b 100644 --- a/static/directives/repo-view/repo-panel-builds.html +++ b/static/directives/repo-view/repo-panel-builds.html @@ -1,13 +1,13 @@
    -

    Repository Builds

    -
    +
    Builds cannot be performed on this repository because Quay Trust is enabled, which requires that all operations be signed by a user.
    @@ -83,7 +83,7 @@
    -
    +
    diff --git a/static/directives/repo-view/repo-panel-info.html b/static/directives/repo-view/repo-panel-info.html index 341b3855d..5e2b47d51 100644 --- a/static/directives/repo-view/repo-panel-info.html +++ b/static/directives/repo-view/repo-panel-info.html @@ -32,7 +32,7 @@
    No builds have been run for this repository.
    -
    +
    Click on the Builds tab to start a new build.
    diff --git a/static/directives/repo-view/repo-panel-tags.html b/static/directives/repo-view/repo-panel-tags.html index a3b1d3e5a..0e572a568 100644 --- a/static/directives/repo-view/repo-panel-tags.html +++ b/static/directives/repo-view/repo-panel-tags.html @@ -53,7 +53,7 @@
  • + ng-class="repository.tag_operations_disabled ? 'disabled-option' : ''"> Delete Tags
  • @@ -243,7 +243,7 @@ + ng-class="repository.tag_operations_disabled ? 'disabled-option' : ''"> Add New Tag Edit Labels + ng-class="repository.tag_operations_disabled ? 'disabled-option' : ''"> Delete Tag diff --git a/static/directives/tag-operations-dialog.html b/static/directives/tag-operations-dialog.html index 53277a958..5f5f7b2be 100644 --- a/static/directives/tag-operations-dialog.html +++ b/static/directives/tag-operations-dialog.html @@ -144,16 +144,17 @@ manifest-digest="restoreTagInfo.manifest_digest">? - - diff --git a/static/js/directives/ui/tag-operations-dialog.js b/static/js/directives/ui/tag-operations-dialog.js index 8d88de4ad..186713108 100644 --- a/static/js/directives/ui/tag-operations-dialog.js +++ b/static/js/directives/ui/tag-operations-dialog.js @@ -35,9 +35,9 @@ angular.module('quay').directive('tagOperationsDialog', function () { }); }; - $scope.alertOnTrust = function() { - if ($scope.repository.trust_enabled) { - $('#trustEnabledModal').modal('show'); + $scope.alertOnTagOpsDisabled = function() { + if ($scope.repository.tag_operations_disabled) { + $('#tagOperationsDisabledModal').modal('show'); return true; } @@ -62,7 +62,7 @@ angular.module('quay').directive('tagOperationsDialog', function () { $scope.createOrMoveTag = function(image, tag) { if (!$scope.repository.can_write) { return; } - if ($scope.alertOnTrust()) { + if ($scope.alertOnTagOpsDisabled()) { return; } @@ -242,7 +242,7 @@ angular.module('quay').directive('tagOperationsDialog', function () { $scope.actionHandler = { 'askDeleteTag': function(tag) { - if ($scope.alertOnTrust()) { + if ($scope.alertOnTagOpsDisabled()) { return; } @@ -252,7 +252,7 @@ angular.module('quay').directive('tagOperationsDialog', function () { }, 'askDeleteMultipleTags': function(tags) { - if ($scope.alertOnTrust()) { + if ($scope.alertOnTagOpsDisabled()) { return; } @@ -262,7 +262,7 @@ angular.module('quay').directive('tagOperationsDialog', function () { }, 'askAddTag': function(image) { - if ($scope.alertOnTrust()) { + if ($scope.alertOnTagOpsDisabled()) { return; } @@ -297,7 +297,7 @@ angular.module('quay').directive('tagOperationsDialog', function () { }, 'askRestoreTag': function(tag, image_id, opt_manifest_digest) { - if ($scope.alertOnTrust()) { + if ($scope.alertOnTagOpsDisabled()) { return; } diff --git a/static/js/types/common.types.ts b/static/js/types/common.types.ts index 088867010..7e910476e 100644 --- a/static/js/types/common.types.ts +++ b/static/js/types/common.types.ts @@ -81,6 +81,7 @@ export type Repository = { kind?: string; namespace?: string; trust_enabled?: boolean; + tag_operations_disabled?: boolean; };