From c34eacb4fa071661e66b8de2a8c9e232a017270f Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Wed, 25 Jul 2018 15:26:48 -0400 Subject: [PATCH] Fix issue accessing a null tagmanifest under a tag in a repository --- endpoints/api/repository_models_pre_oci.py | 3 ++- endpoints/api/test/test_repository.py | 15 +++++++++++++++ test/registry/fixtures.py | 8 +++++++- test/registry/registry_tests.py | 17 +++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/endpoints/api/repository_models_pre_oci.py b/endpoints/api/repository_models_pre_oci.py index d9f468b52..7c60138f3 100644 --- a/endpoints/api/repository_models_pre_oci.py +++ b/endpoints/api/repository_models_pre_oci.py @@ -160,7 +160,8 @@ class PreOCIModel(RepositoryDataInterface): return ImageRepositoryRepository(base, [ Tag(tag.name, tag.image.docker_image_id, tag.image.aggregate_size, tag.lifetime_start_ts, - tag.tagmanifest.digest, tag.lifetime_end_ts) for tag in tags + tag.tagmanifest.digest if hasattr(tag, 'tagmanifest') else None, + tag.lifetime_end_ts) for tag in tags ], [Count(count.date, count.count) for count in counts], repo.badge_token, repo.trust_enabled) diff --git a/endpoints/api/test/test_repository.py b/endpoints/api/test/test_repository.py index 8d632f132..9d72be3b3 100644 --- a/endpoints/api/test/test_repository.py +++ b/endpoints/api/test/test_repository.py @@ -121,6 +121,21 @@ def test_create_repository(repo_name, expected_status, client): assert model.repository.get_repository('devtable', repo_name).name == repo_name +@pytest.mark.parametrize('has_tag_manifest', [ + True, + False, +]) +def test_get_repo(has_tag_manifest, client, initialized_db): + with client_with_identity('devtable', client) as cl: + if not has_tag_manifest: + database.TagManifestLabel.delete().execute() + database.TagManifest.delete().execute() + + params = {'repository': 'devtable/simple'} + response = conduct_api_call(cl, Repository, 'GET', params).json + assert response['kind'] == 'image' + + def test_get_app_repo(client, initialized_db): with client_with_identity('devtable', client) as cl: devtable = model.user.get_user('devtable') diff --git a/test/registry/fixtures.py b/test/registry/fixtures.py index 04781f40e..4f869aab1 100644 --- a/test/registry/fixtures.py +++ b/test/registry/fixtures.py @@ -13,7 +13,8 @@ from flask import jsonify, g from flask_principal import Identity from app import storage -from data.database import close_db_filter, configure, DerivedStorageForImage, QueueItem, Image +from data.database import (close_db_filter, configure, DerivedStorageForImage, QueueItem, Image, + TagManifest) from data import model from endpoints.csrf import generate_csrf_token from util.log import logfile_path @@ -105,6 +106,10 @@ def registry_server_executor(app): namespace_obj.save() return 'OK' + def delete_manifests(): + TagManifest.delete().execute() + return 'OK' + executor = LiveServerExecutor() executor.register('generate_csrf', generate_csrf) executor.register('set_supports_direct_download', set_supports_direct_download) @@ -118,6 +123,7 @@ def registry_server_executor(app): executor.register('reload_app', reload_app) executor.register('create_app_repository', create_app_repository) executor.register('disable_namespace', disable_namespace) + executor.register('delete_manifests', delete_manifests) return executor diff --git a/test/registry/registry_tests.py b/test/registry/registry_tests.py index 15c4d2531..9a2760b7d 100644 --- a/test/registry/registry_tests.py +++ b/test/registry/registry_tests.py @@ -34,6 +34,23 @@ def test_basic_push_pull(pusher, puller, basic_images, liveserver_session, app_r credentials=credentials) +def test_no_tag_manifests(pusher, puller, basic_images, liveserver_session, app_reloader, + liveserver, registry_server_executor): + """ Test: Basic pull without manifests. """ + credentials = ('devtable', 'password') + + # Push a new repository. + pusher.push(liveserver_session, 'devtable', 'newrepo', 'latest', basic_images, + credentials=credentials) + + # Delete all tag manifests. + registry_server_executor.on(liveserver).delete_manifests() + + # Ensure we can still pull. + puller.pull(liveserver_session, 'devtable', 'newrepo', 'latest', basic_images, + credentials=credentials) + + def test_basic_push_pull_by_manifest(manifest_protocol, basic_images, liveserver_session, app_reloader): """ Test: Basic push and pull-by-manifest of an image to a new repository. """