From a1181b72970e3943dc9aefe4658ff957021e725a Mon Sep 17 00:00:00 2001 From: Tatiana Tereshchenko Date: Wed, 12 Jan 2022 20:01:55 +0100 Subject: [PATCH] Add support to sync signatures using docker API extension closes #528 --- CHANGES/528.feature | 1 + pulp_container/app/registry_api.py | 4 +- pulp_container/app/tasks/sync_stages.py | 51 +++++++++++++++++++++++-- pulp_container/constants.py | 2 +- 4 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 CHANGES/528.feature diff --git a/CHANGES/528.feature b/CHANGES/528.feature new file mode 100644 index 000000000..ca3629878 --- /dev/null +++ b/CHANGES/528.feature @@ -0,0 +1 @@ +Added support for syncing signatures using docker API extension. diff --git a/pulp_container/app/registry_api.py b/pulp_container/app/registry_api.py index 7af44b9db..1b38bbe1d 100644 --- a/pulp_container/app/registry_api.py +++ b/pulp_container/app/registry_api.py @@ -59,7 +59,7 @@ RegistryPermission, TokenPermission, ) -from pulp_container.constants import EMPTY_BLOB, SIGNATURE_HEADER +from pulp_container.constants import EMPTY_BLOB, SIGNATURE_API_EXTENSION_VERSION, SIGNATURE_HEADER FakeView = namedtuple("FakeView", ["action", "get_object"]) @@ -1002,7 +1002,7 @@ def get_response_data(signatures): data = [] for signature in signatures: signature = { - "schemaVersion": 2, + "schemaVersion": SIGNATURE_API_EXTENSION_VERSION, "type": signature.type, "name": signature.name, "content": signature.data, diff --git a/pulp_container/app/tasks/sync_stages.py b/pulp_container/app/tasks/sync_stages.py index a737cca8a..680bcc5d1 100644 --- a/pulp_container/app/tasks/sync_stages.py +++ b/pulp_container/app/tasks/sync_stages.py @@ -15,7 +15,13 @@ from pulpcore.plugin.stages import DeclarativeArtifact, DeclarativeContent, Stage from pulpcore.plugin.constants import TASK_STATES -from pulp_container.constants import MEDIA_TYPE, SIGNATURE_HEADER, SIGNATURE_SOURCE, SIGNATURE_TYPE +from pulp_container.constants import ( + MEDIA_TYPE, + SIGNATURE_API_EXTENSION_VERSION, + SIGNATURE_HEADER, + SIGNATURE_SOURCE, + SIGNATURE_TYPE, +) from pulp_container.app.models import ( Blob, BlobManifest, @@ -482,8 +488,47 @@ async def create_signatures(self, man_dc, signature_source): return signature_dcs elif signature_source == SIGNATURE_SOURCE.API_EXTENSION: - # TODO in a PR for the extension support - pass + signatures_url = urlpath_sanitize( + self.remote.url, + "extensions/v2", + self.remote.upstream_name, + "signatures", + man_dc.content.digest, + ) + signatures_downloader = self.remote.get_downloader(url=signatures_url) + await signatures_downloader.run() + with open(signatures_downloader.path) as signatures_fd: + api_extension_signatures = json.loads(signatures_fd.read()) + for signature in api_extension_signatures: + if ( + signature["schemaVersion"] == SIGNATURE_API_EXTENSION_VERSION + and signature["type"] == SIGNATURE_TYPE.ATOMIC_SHORT + ): + signature_base64 = signature["content"] + signature_raw = base64.b64decode(signature_base64) + signature_json = extract_data_from_signature( + signature_raw, man_dc.content.digest + ) + if signature_json is None: + continue + + sig_digest = hashlib.sha256(signature_raw).hexdigest() + signature = ManifestSignature( + name=signature["name"], + digest=f"sha256:{sig_digest}", + type=SIGNATURE_TYPE.ATOMIC_SHORT, + key_id=signature_json["signing_key_id"], + timestamp=signature_json["signature_timestamp"], + creator=signature_json["optional"].get("creator"), + data=signature_base64, + ) + sig_dc = DeclarativeContent( + content=signature, + extra_data={"signed_manifest_dc": man_dc}, + ) + signature_dcs.append(sig_dc) + + return signature_dcs return [] diff --git a/pulp_container/constants.py b/pulp_container/constants.py index 498db001c..0e107f069 100644 --- a/pulp_container/constants.py +++ b/pulp_container/constants.py @@ -33,5 +33,5 @@ ATOMIC_SHORT="atomic", # short version is used in the JSON produced by API extension ) SIGNATURE_SOURCE = SimpleNamespace(SIGSTORE="sigstore", API_EXTENSION="API extension") - SIGNATURE_HEADER = "X-Registry-Supports-Signatures" +SIGNATURE_API_EXTENSION_VERSION = 2 \ No newline at end of file