From 568ca1d7ba2c84e4a7c65165c0f3e84b70baacbc Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Wed, 8 Aug 2018 22:23:42 -0400 Subject: [PATCH 1/4] delete trailing whitespace --- endpoints/v2/blob.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/endpoints/v2/blob.py b/endpoints/v2/blob.py index 5b6551a54..ccff226d5 100644 --- a/endpoints/v2/blob.py +++ b/endpoints/v2/blob.py @@ -47,13 +47,13 @@ def _get_repository_blob(namespace_name, repo_name, digest): blob = model.get_blob_by_digest(namespace_name, repo_name, digest) if blob is None: return None - + return blob._asdict() blob_cache_key = cache_key.for_repository_blob(namespace_name, repo_name, digest) blob_dict = model_cache.retrieve(blob_cache_key, load_blob) return Blob(**blob_dict) if blob_dict is not None else None - + @v2_bp.route(BLOB_DIGEST_ROUTE, methods=['HEAD']) @parse_repository_name() From b7573a8c88d08d44b3a77e4097d43609facbb63f Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Wed, 8 Aug 2018 22:23:52 -0400 Subject: [PATCH 2/4] endpoints/v2: fail clients not accepting schema v1 --- endpoints/v2/manifest.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/endpoints/v2/manifest.py b/endpoints/v2/manifest.py index a3a118c92..1f0ef9748 100644 --- a/endpoints/v2/manifest.py +++ b/endpoints/v2/manifest.py @@ -17,7 +17,8 @@ from endpoints.v2.errors import (BlobUnknown, ManifestInvalid, ManifestUnknown, NameInvalid, TagExpired) from endpoints.v2.labelhandlers import handle_label from image.docker import ManifestException -from image.docker.schema1 import DockerSchema1Manifest, DockerSchema1ManifestBuilder +from image.docker.schema1 import (DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE, + DockerSchema1Manifest, DockerSchema1ManifestBuilder) from image.docker.schema2 import DOCKER_SCHEMA2_CONTENT_TYPES, OCI_CONTENT_TYPES from notifications import spawn_notification from util.audit import track_and_log @@ -92,7 +93,8 @@ def fetch_manifest_by_digest(namespace_name, repo_name, manifest_ref): def _reject_manifest2_schema2(func): @wraps(func) def wrapped(*args, **kwargs): - if request.content_type in (DOCKER_SCHEMA2_CONTENT_TYPES | OCI_CONTENT_TYPES): + if _doesnt_accept_schema_v1() or \ + request.content_type in DOCKER_SCHEMA2_CONTENT_TYPES | OCI_CONTENT_TYPES: raise ManifestInvalid(detail={'message': 'manifest schema version not supported'}, http_status_code=415) return func(*args, **kwargs) @@ -100,6 +102,12 @@ def _reject_manifest2_schema2(func): return wrapped +def _doesnt_accept_schema_v1(): + # If the client doesn't specify anything, still give them Schema v1. + return len(request.accept_mimetypes) != 0 and \ + DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE not in request.accept_mimetypes + + @v2_bp.route(MANIFEST_TAGNAME_ROUTE, methods=['PUT']) @_reject_manifest2_schema2 @parse_repository_name() From 6d4300a92ae1ee86fba180add479fbd96a83417a Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Thu, 9 Aug 2018 14:17:49 -0400 Subject: [PATCH 3/4] test/registry: add accept header test --- test/registry/protocol_v2.py | 1 + test/registry/protocols.py | 1 + test/registry/registry_tests.py | 27 ++++++++++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/test/registry/protocol_v2.py b/test/registry/protocol_v2.py index 4ae3399cc..42512cd80 100644 --- a/test/registry/protocol_v2.py +++ b/test/registry/protocol_v2.py @@ -136,6 +136,7 @@ class V2Protocol(RegistryProtocol): headers = { 'Authorization': 'Bearer ' + token, + 'Accept': options.accept_mimetypes, } # Build fake manifests. diff --git a/test/registry/protocols.py b/test/registry/protocols.py index 2cd073441..021ebdc67 100644 --- a/test/registry/protocols.py +++ b/test/registry/protocols.py @@ -64,6 +64,7 @@ class ProtocolOptions(object): self.chunks_for_upload = None self.skip_head_checks = False self.manifest_content_type = None + self.accept_mimetypes = '*/*' self.mount_blobs = None diff --git a/test/registry/registry_tests.py b/test/registry/registry_tests.py index bd1da71ee..419d56add 100644 --- a/test/registry/registry_tests.py +++ b/test/registry/registry_tests.py @@ -8,6 +8,8 @@ import binascii import bencode import resumablehashlib +from werkzeug.datastructures import Accept + from test.fixtures import * from test.registry.liveserverfixture import * from test.registry.fixtures import * @@ -17,6 +19,7 @@ from test.registry.protocols import Failures, Image, layer_bytes_for_contents, P from app import instance_keys from data.model.tag import list_repository_tags +from image.docker.schema1 import DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE from util.security.registry_jwt import decode_bearer_header from util.timedeltastring import convert_to_timedelta @@ -341,7 +344,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, @@ -543,6 +546,28 @@ def test_unsupported_manifest_content_type(content_type, manifest_protocol, basi expected_failure=Failures.UNSUPPORTED_CONTENT_TYPE) +@pytest.mark.parametrize('accept_mimetypes', [ + [('application/vnd.oci.image.manifest.v1+json', 1)], + [('application/vnd.docker.distribution.manifest.v2+json', 1), + ('application/vnd.docker.distribution.manifest.list.v2+json', 1)], + [('application/vnd.foo.bar', 1)], +]) +def test_unsupported_manifest_accept_headers(accept_mimetypes, manifest_protocol, basic_images, + liveserver_session, app_reloader): + """ Test: Attempt to push a manifest with an unsupported accept headers. """ + credentials = ('devtable', 'password') + + options = ProtocolOptions() + options.manifest_content_type = DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE + options.accept_mimetypes = str(Accept(accept_mimetypes)) + + # Attempt to push a new repository. + manifest_protocol.push(liveserver_session, 'devtable', 'newrepo', 'latest', basic_images, + credentials=credentials, + options=options, + expected_failure=Failures.UNSUPPORTED_CONTENT_TYPE) + + def test_invalid_blob_reference(manifest_protocol, basic_images, liveserver_session, app_reloader): """ Test: Attempt to push a manifest with an invalid blob reference. """ credentials = ('devtable', 'password') From 9f8b1e2831dbbd0c42caf3988bb3eaf8c7372ff0 Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Wed, 15 Aug 2018 13:21:00 -0400 Subject: [PATCH 4/4] gitignore: ignore all of the pytest cache --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 81091fdc1..f23f57274 100644 --- a/.gitignore +++ b/.gitignore @@ -26,5 +26,4 @@ build/ .vscode *.iml .DS_Store -.pytest_cache/v/cache/lastfailed -.pytest_cache/v/cache/nodeids +.pytest_cache/*