152 lines
5.2 KiB
Python
152 lines
5.2 KiB
Python
|
import json
|
||
|
import pytest
|
||
|
|
||
|
from image.docker.schema1 import (DockerSchema1Manifest, DOCKER_SCHEMA1_CONTENT_TYPES,
|
||
|
DockerSchema1ManifestBuilder)
|
||
|
from image.docker.schema2 import DOCKER_SCHEMA2_MANIFEST_CONTENT_TYPE
|
||
|
from image.docker.schema2.manifest import DockerSchema2Manifest
|
||
|
from image.docker.schema2.list import (MalformedSchema2ManifestList, DockerSchema2ManifestList,
|
||
|
DockerSchema2ManifestListBuilder, MismatchManifestException)
|
||
|
from image.docker.schema2.test.test_manifest import MANIFEST_BYTES as v22_bytes
|
||
|
from image.docker.schemautil import ContentRetrieverForTesting
|
||
|
from image.docker.test.test_schema1 import MANIFEST_BYTES as v21_bytes
|
||
|
from util.bytes import Bytes
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize('json_data', [
|
||
|
'',
|
||
|
'{}',
|
||
|
"""
|
||
|
{
|
||
|
"unknown": "key"
|
||
|
}
|
||
|
""",
|
||
|
])
|
||
|
def test_malformed_manifest_lists(json_data):
|
||
|
with pytest.raises(MalformedSchema2ManifestList):
|
||
|
DockerSchema2ManifestList(Bytes.for_string_or_unicode(json_data))
|
||
|
|
||
|
|
||
|
MANIFESTLIST_BYTES = json.dumps({
|
||
|
"schemaVersion": 2,
|
||
|
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
|
||
|
"manifests": [
|
||
|
{
|
||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||
|
"size": 946,
|
||
|
"digest": "sha256:e6",
|
||
|
"platform": {
|
||
|
"architecture": "ppc64le",
|
||
|
"os": "linux",
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
"mediaType": "application/vnd.docker.distribution.manifest.v1+json",
|
||
|
"size": 878,
|
||
|
"digest": "sha256:5b",
|
||
|
"platform": {
|
||
|
"architecture": "amd64",
|
||
|
"os": "linux",
|
||
|
"features": [
|
||
|
"sse4"
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
]
|
||
|
})
|
||
|
|
||
|
NO_AMD_MANIFESTLIST_BYTES = json.dumps({
|
||
|
"schemaVersion": 2,
|
||
|
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
|
||
|
"manifests": [
|
||
|
{
|
||
|
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
|
||
|
"size": 946,
|
||
|
"digest": "sha256:e6",
|
||
|
"platform": {
|
||
|
"architecture": "ppc64le",
|
||
|
"os": "linux",
|
||
|
}
|
||
|
},
|
||
|
]
|
||
|
})
|
||
|
|
||
|
retriever = ContentRetrieverForTesting({
|
||
|
'sha256:e6': v22_bytes,
|
||
|
'sha256:5b': v21_bytes,
|
||
|
})
|
||
|
|
||
|
def test_valid_manifestlist():
|
||
|
manifestlist = DockerSchema2ManifestList(Bytes.for_string_or_unicode(MANIFESTLIST_BYTES))
|
||
|
assert len(manifestlist.manifests(retriever)) == 2
|
||
|
|
||
|
assert manifestlist.media_type == 'application/vnd.docker.distribution.manifest.list.v2+json'
|
||
|
assert manifestlist.bytes.as_encoded_str() == MANIFESTLIST_BYTES
|
||
|
assert manifestlist.manifest_dict == json.loads(MANIFESTLIST_BYTES)
|
||
|
assert manifestlist.get_layers(retriever) is None
|
||
|
assert not manifestlist.blob_digests
|
||
|
|
||
|
for index, manifest in enumerate(manifestlist.manifests(retriever)):
|
||
|
if index == 0:
|
||
|
assert isinstance(manifest.manifest_obj, DockerSchema2Manifest)
|
||
|
assert manifest.manifest_obj.schema_version == 2
|
||
|
else:
|
||
|
assert isinstance(manifest.manifest_obj, DockerSchema1Manifest)
|
||
|
assert manifest.manifest_obj.schema_version == 1
|
||
|
|
||
|
# Check retrieval of a schema 2 manifest. This should return None, because the schema 2 manifest
|
||
|
# is not amd64-compatible.
|
||
|
schema2_manifest = manifestlist.convert_manifest([DOCKER_SCHEMA2_MANIFEST_CONTENT_TYPE], 'foo',
|
||
|
'bar', 'baz', retriever)
|
||
|
assert schema2_manifest is None
|
||
|
|
||
|
# Check retrieval of a schema 1 manifest.
|
||
|
compatible_manifest = manifestlist.get_schema1_manifest('foo', 'bar', 'baz', retriever)
|
||
|
assert compatible_manifest.schema_version == 1
|
||
|
|
||
|
schema1_manifest = manifestlist.convert_manifest(DOCKER_SCHEMA1_CONTENT_TYPES, 'foo',
|
||
|
'bar', 'baz', retriever)
|
||
|
assert schema1_manifest.schema_version == 1
|
||
|
assert schema1_manifest.digest == compatible_manifest.digest
|
||
|
|
||
|
# Ensure it validates.
|
||
|
manifestlist.validate(retriever)
|
||
|
|
||
|
|
||
|
def test_get_schema1_manifest_no_matching_list():
|
||
|
manifestlist = DockerSchema2ManifestList(Bytes.for_string_or_unicode(NO_AMD_MANIFESTLIST_BYTES))
|
||
|
assert len(manifestlist.manifests(retriever)) == 1
|
||
|
|
||
|
assert manifestlist.media_type == 'application/vnd.docker.distribution.manifest.list.v2+json'
|
||
|
assert manifestlist.bytes.as_encoded_str() == NO_AMD_MANIFESTLIST_BYTES
|
||
|
|
||
|
compatible_manifest = manifestlist.get_schema1_manifest('foo', 'bar', 'baz', retriever)
|
||
|
assert compatible_manifest is None
|
||
|
|
||
|
|
||
|
def test_builder():
|
||
|
existing = DockerSchema2ManifestList(Bytes.for_string_or_unicode(MANIFESTLIST_BYTES))
|
||
|
builder = DockerSchema2ManifestListBuilder()
|
||
|
for index, manifest in enumerate(existing.manifests(retriever)):
|
||
|
builder.add_manifest(manifest.manifest_obj, "amd64", "os")
|
||
|
|
||
|
built = builder.build()
|
||
|
assert len(built.manifests(retriever)) == 2
|
||
|
|
||
|
|
||
|
def test_invalid_manifestlist():
|
||
|
# Build a manifest list with a schema 1 manifest of the wrong architecture.
|
||
|
builder = DockerSchema1ManifestBuilder('foo', 'bar', 'baz')
|
||
|
builder.add_layer('sha:2356', '{"id": "foo"}')
|
||
|
manifest = builder.build().unsigned()
|
||
|
|
||
|
listbuilder = DockerSchema2ManifestListBuilder()
|
||
|
listbuilder.add_manifest(manifest, 'amd32', 'linux')
|
||
|
manifestlist = listbuilder.build()
|
||
|
|
||
|
retriever = ContentRetrieverForTesting()
|
||
|
retriever.add_digest(manifest.digest, manifest.bytes.as_encoded_str())
|
||
|
|
||
|
with pytest.raises(MismatchManifestException):
|
||
|
manifestlist.validate(retriever)
|