diff --git a/endpoints/v1/registry.py b/endpoints/v1/registry.py index c83cfe2fb..330774df6 100644 --- a/endpoints/v1/registry.py +++ b/endpoints/v1/registry.py @@ -437,6 +437,13 @@ def put_image_json(namespace, repository, image_id): abort(404, 'Repository does not exist: %(namespace)s/%(repository)s', issue='no-repo', namespace=namespace, repository=repository) + parent_id = data.get('parent', None) + if parent_id: + logger.debug('Looking up parent image') + if model.docker_v1_metadata(namespace, repository, parent_id) is None: + abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s', + issue='invalid-request', image_id=image_id, parent_id=parent_id) + v1_metadata = model.docker_v1_metadata(namespace, repository, image_id) if v1_metadata is None: username = get_authenticated_user() and get_authenticated_user().username @@ -451,13 +458,6 @@ def put_image_json(namespace, repository, image_id): model.create_temp_hidden_tag(namespace, repository, image_id, app.config['PUSH_TEMP_TAG_EXPIRATION_SEC']) - parent_id = data.get('parent', None) - if parent_id: - logger.debug('Looking up parent image') - if model.docker_v1_metadata(namespace, repository, parent_id) is None: - abort(400, 'Image %(image_id)s depends on non existing parent image %(parent_id)s', - issue='invalid-request', image_id=image_id, parent_id=parent_id) - logger.debug('Checking if image already exists') if v1_metadata and not model.is_image_uploading(namespace, repository, image_id): exact_abort(409, 'Image already exists') diff --git a/test/registry/protocol_v1.py b/test/registry/protocol_v1.py index d5b776c54..e1eb9a411 100644 --- a/test/registry/protocol_v1.py +++ b/test/registry/protocol_v1.py @@ -13,6 +13,7 @@ class V1ProtocolSteps(Enum): PUT_IMAGES = 'put-images' GET_IMAGES = 'get-images' PUT_TAG = 'put-tag' + PUT_IMAGE_JSON = 'put-image-json' class V1Protocol(RegistryProtocol): @@ -34,6 +35,9 @@ class V1Protocol(RegistryProtocol): Failures.DISALLOWED_LIBRARY_NAMESPACE: 400, Failures.NAMESPACE_DISABLED: 400, }, + V1ProtocolSteps.PUT_IMAGE_JSON: { + Failures.INVALID_IMAGES: 400, + }, V1ProtocolSteps.PUT_TAG: { Failures.MISSING_TAG: 404, Failures.INVALID_TAG: 400, @@ -77,7 +81,7 @@ class V1Protocol(RegistryProtocol): headers = {'X-Docker-Token': 'true'} result = self.conduct(session, 'GET', prefix + 'images', auth=auth, headers=headers, expected_status=(200, expected_failure, V1ProtocolSteps.GET_IMAGES)) - if expected_failure is not None: + if result.status_code != 200: return headers = {} @@ -91,6 +95,10 @@ class V1Protocol(RegistryProtocol): assert len(image_ids.values()) == len(tag_names) for tag_name in tag_names: + if tag_name not in image_ids: + assert expected_failure == Failures.UNKNOWN_TAG + return None + tag_image_id = image_ids[tag_name] if not options.munge_shas: # Ensure we have a matching image ID. @@ -133,8 +141,7 @@ class V1Protocol(RegistryProtocol): expected_status=(201, expected_failure, V1ProtocolSteps.PUT_IMAGES), json_data={}, auth=auth) - - if expected_failure is not None: + if result.status_code != 201: return headers = {} @@ -152,8 +159,12 @@ class V1Protocol(RegistryProtocol): if image.config is not None: image_json_data['config'] = image.config - self.conduct(session, 'PUT', '/v1/images/%s/json' % image.id, - json_data=image_json_data, headers=headers) + response = self.conduct(session, 'PUT', '/v1/images/%s/json' % image.id, + json_data=image_json_data, headers=headers, + expected_status=(200, expected_failure, + V1ProtocolSteps.PUT_IMAGE_JSON)) + if response.status_code != 200: + break # PUT /v1/images/{imageID}/layer self.conduct(session, 'PUT', '/v1/images/%s/layer' % image.id, diff --git a/test/registry/protocol_v2.py b/test/registry/protocol_v2.py index 045a3ba3c..4ae3399cc 100644 --- a/test/registry/protocol_v2.py +++ b/test/registry/protocol_v2.py @@ -18,6 +18,7 @@ class V2ProtocolSteps(Enum): MOUNT_BLOB = 'mount-blob' CATALOG = 'catalog' LIST_TAGS = 'list-tags' + START_UPLOAD = 'start-upload' class V2Protocol(RegistryProtocol): @@ -36,15 +37,21 @@ class V2Protocol(RegistryProtocol): }, V2ProtocolSteps.GET_MANIFEST: { Failures.UNKNOWN_TAG: 404, - Failures.UNAUTHORIZED: 403, + Failures.UNAUTHORIZED: 401, + Failures.DISALLOWED_LIBRARY_NAMESPACE: 400, + }, + V2ProtocolSteps.BLOB_HEAD_CHECK: { + Failures.DISALLOWED_LIBRARY_NAMESPACE: 400, + }, + V2ProtocolSteps.START_UPLOAD: { Failures.DISALLOWED_LIBRARY_NAMESPACE: 400, }, V2ProtocolSteps.PUT_MANIFEST: { Failures.DISALLOWED_LIBRARY_NAMESPACE: 400, Failures.MISSING_TAG: 404, - Failures.INVALID_TAG: 400, + Failures.INVALID_TAG: 404, Failures.INVALID_IMAGES: 400, - Failures.INVALID_BLOB: 400, + Failures.INVALID_BLOB: 404, Failures.UNSUPPORTED_CONTENT_TYPE: 415, }, } @@ -103,8 +110,9 @@ class V2Protocol(RegistryProtocol): response = self.conduct(session, 'GET', '/v2/auth', params=params, auth=auth, expected_status=(200, expected_failure, V2ProtocolSteps.AUTH)) - - if expected_failure is None: + expect_token = (expected_failure is None or + not V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure)) + if expect_token: assert response.json().get('token') is not None return response.json().get('token'), response @@ -123,6 +131,7 @@ class V2Protocol(RegistryProtocol): token, _ = self.auth(session, credentials, namespace, repo_name, scopes=scopes, expected_failure=expected_failure) if token is None: + assert V2Protocol.FAILURE_CODES[V2ProtocolSteps.AUTH].get(expected_failure) return headers = { @@ -182,8 +191,11 @@ class V2Protocol(RegistryProtocol): # Start a new upload of the layer data. response = self.conduct(session, 'POST', '/v2/%s/blobs/uploads/' % self.repo_name(namespace, repo_name), - expected_status=202, + expected_status=(202, expected_failure, + V2ProtocolSteps.START_UPLOAD), headers=headers) + if response.status_code != 202: + continue upload_uuid = response.headers['Docker-Upload-UUID'] new_upload_location = response.headers['Location'] diff --git a/test/registry/registry_tests.py b/test/registry/registry_tests.py index 6b47ad763..bd1da71ee 100644 --- a/test/registry/registry_tests.py +++ b/test/registry/registry_tests.py @@ -341,7 +341,7 @@ def test_push_library_with_support_disabled(pusher, basic_images, liveserver_ses should fail. """ credentials = ('devtable', 'password') - + with FeatureFlagValue('LIBRARY_SUPPORT', False, registry_server_executor.on(liveserver)): # Attempt to push a new repository. pusher.push(liveserver_session, '', 'newrepo', 'latest', basic_images, @@ -527,7 +527,6 @@ def test_expiration_label(label_value, expected_expiration, manifest_protocol, l @pytest.mark.parametrize('content_type', [ 'application/vnd.oci.image.manifest.v1+json', 'application/vnd.docker.distribution.manifest.v2+json', - 'application/vnd.foo.bar', ]) def test_unsupported_manifest_content_type(content_type, manifest_protocol, basic_images, liveserver_session, app_reloader):