Enhancements for Docker schema implementations in preparing for supporting schema 2 in the OCI model
This adds additional required properties and methods to the Docker schema interface to allow us to treat both schema1 and schema2 manifests and lists logically equivalent from the OCI mode perspective
This commit is contained in:
parent
6b86b87a16
commit
e344d4a5cf
12 changed files with 447 additions and 22 deletions
|
@ -151,7 +151,7 @@ class DockerSchema1Manifest(ManifestInterface):
|
|||
},
|
||||
},
|
||||
},
|
||||
'required': [DOCKER_SCHEMA1_SIGNATURES_KEY, DOCKER_SCHEMA1_REPO_TAG_KEY,
|
||||
'required': [DOCKER_SCHEMA1_REPO_TAG_KEY,
|
||||
DOCKER_SCHEMA1_REPO_NAME_KEY, DOCKER_SCHEMA1_FS_LAYERS_KEY,
|
||||
DOCKER_SCHEMA1_HISTORY_KEY],
|
||||
}
|
||||
|
@ -170,8 +170,9 @@ class DockerSchema1Manifest(ManifestInterface):
|
|||
except ValidationError as ve:
|
||||
raise MalformedSchema1Manifest('manifest data does not match schema: %s' % ve)
|
||||
|
||||
self._signatures = self._parsed[DOCKER_SCHEMA1_SIGNATURES_KEY]
|
||||
self._signatures = self._parsed.get(DOCKER_SCHEMA1_SIGNATURES_KEY)
|
||||
self._tag = self._parsed[DOCKER_SCHEMA1_REPO_TAG_KEY]
|
||||
self._architecture = self._parsed[DOCKER_SCHEMA1_ARCH_KEY]
|
||||
|
||||
repo_name = self._parsed[DOCKER_SCHEMA1_REPO_NAME_KEY]
|
||||
repo_name_tuple = repo_name.split('/')
|
||||
|
@ -191,6 +192,9 @@ class DockerSchema1Manifest(ManifestInterface):
|
|||
return DockerSchema1Manifest(encoded_bytes.encode('utf-8'), validate)
|
||||
|
||||
def _validate(self):
|
||||
if not self._signatures:
|
||||
return
|
||||
|
||||
for signature in self._signatures:
|
||||
bytes_to_verify = '{0}.{1}'.format(signature['protected'],
|
||||
base64url_encode(self._payload))
|
||||
|
@ -208,11 +212,12 @@ class DockerSchema1Manifest(ManifestInterface):
|
|||
|
||||
@property
|
||||
def content_type(self):
|
||||
return DOCKER_SCHEMA1_SIGNED_MANIFEST_CONTENT_TYPE
|
||||
return (DOCKER_SCHEMA1_SIGNED_MANIFEST_CONTENT_TYPE
|
||||
if self._signatures else DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE)
|
||||
|
||||
@property
|
||||
def media_type(self):
|
||||
return DOCKER_SCHEMA1_SIGNED_MANIFEST_CONTENT_TYPE
|
||||
return self.content_type
|
||||
|
||||
@property
|
||||
def signatures(self):
|
||||
|
@ -297,6 +302,24 @@ class DockerSchema1Manifest(ManifestInterface):
|
|||
def blob_digests(self):
|
||||
return [str(layer.digest) for layer in self.layers]
|
||||
|
||||
def child_manifests(self, lookup_manifest_fn):
|
||||
return None
|
||||
|
||||
def get_manifest_labels(self, lookup_config_fn):
|
||||
return self.layers[-1].v1_metadata.labels
|
||||
|
||||
def unsigned(self):
|
||||
if self.media_type == DOCKER_SCHEMA1_MANIFEST_CONTENT_TYPE:
|
||||
return self
|
||||
|
||||
# Create an unsigned version of the manifest.
|
||||
builder = DockerSchema1ManifestBuilder(self._namespace, self._repo_name, self._tag,
|
||||
self._architecture)
|
||||
for layer in reversed(self.layers):
|
||||
builder.add_layer(str(layer.digest), layer.raw_v1_metadata)
|
||||
|
||||
return builder.build()
|
||||
|
||||
def _generate_layers(self):
|
||||
"""
|
||||
Returns a generator of objects that have the blobSum and v1Compatibility keys in them,
|
||||
|
@ -330,12 +353,18 @@ class DockerSchema1Manifest(ManifestInterface):
|
|||
|
||||
@property
|
||||
def _payload(self):
|
||||
if self._signatures is None:
|
||||
return self._bytes
|
||||
|
||||
protected = str(self._signatures[0][DOCKER_SCHEMA1_PROTECTED_KEY])
|
||||
parsed_protected = json.loads(base64url_decode(protected))
|
||||
signed_content_head = self._bytes[:parsed_protected[DOCKER_SCHEMA1_FORMAT_LENGTH_KEY]]
|
||||
signed_content_tail = base64url_decode(str(parsed_protected[DOCKER_SCHEMA1_FORMAT_TAIL_KEY]))
|
||||
return signed_content_head + signed_content_tail
|
||||
|
||||
def generate_legacy_layers(self, images_map, lookup_config_fn):
|
||||
return self.rewrite_invalid_image_ids(images_map)
|
||||
|
||||
def rewrite_invalid_image_ids(self, images_map):
|
||||
"""
|
||||
Rewrites Docker v1 image IDs and returns a generator of DockerV1Metadata.
|
||||
|
@ -428,9 +457,9 @@ class DockerSchema1ManifestBuilder(object):
|
|||
return self
|
||||
|
||||
|
||||
def build(self, json_web_key):
|
||||
def build(self, json_web_key=None):
|
||||
"""
|
||||
Builds a DockerSchema1Manifest object complete with signature.
|
||||
Builds a DockerSchema1Manifest object, with optional signature.
|
||||
"""
|
||||
payload = OrderedDict(self._base_payload)
|
||||
payload.update({
|
||||
|
@ -439,6 +468,8 @@ class DockerSchema1ManifestBuilder(object):
|
|||
})
|
||||
|
||||
payload_str = json.dumps(payload, indent=3)
|
||||
if json_web_key is None:
|
||||
return DockerSchema1Manifest(payload_str)
|
||||
|
||||
split_point = payload_str.rfind('\n}')
|
||||
|
||||
|
|
Reference in a new issue