Skip to content

Commit

Permalink
Add support to sync signatures using docker API extension
Browse files Browse the repository at this point in the history
closes pulp#528
  • Loading branch information
goosemania committed Jan 13, 2022
1 parent 06d9945 commit 2251a50
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGES/528.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added support for syncing signatures using docker API extension.
4 changes: 2 additions & 2 deletions pulp_container/app/registry_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"])

Expand Down Expand Up @@ -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,
Expand Down
82 changes: 57 additions & 25 deletions pulp_container/app/tasks/sync_stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -347,6 +353,29 @@ def _create_manifest_declarative_artifact(self, relative_url, saved_artifact, di
)
return da

def _create_signature_declarative_content(
self, signature_raw, man_dc, name=None, signature_b64=None
):
signature_json = extract_data_from_signature(signature_raw, man_dc.content.digest)
if signature_json is None:
return

sig_digest = hashlib.sha256(signature_raw).hexdigest()
signature = ManifestSignature(
name=name or f"{man_dc.content.digest}@{sig_digest[:32]}",
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_b64 or base64.b64encode(signature_raw).decode(),
)
sig_dc = DeclarativeContent(
content=signature,
extra_data={"signed_manifest_dc": man_dc},
)
return sig_dc

def create_manifest(self, list_dc, manifest_data):
"""
Create an Image Manifest from manifest data in a ManifestList.
Expand Down Expand Up @@ -459,33 +488,36 @@ async def create_signatures(self, man_dc, signature_source):
signature_raw = f.read()

signature_counter += 1
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=f"{man_dc.content.digest}@{sig_digest[:32]}",
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=base64.b64encode(signature_raw).decode(),
)
sig_dc = DeclarativeContent(
content=signature,
extra_data={"signed_manifest_dc": man_dc},
)
signature_dcs.append(sig_dc)

return signature_dcs
sig_dc = self._create_signature_declarative_content(signature_raw, man_dc)
if sig_dc:
signature_dcs.append(sig_dc)

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.get("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)
sig_dc = self._create_signature_declarative_content(
signature_raw, man_dc, signature["name"], signature_base64
)
if sig_dc:
signature_dcs.append(sig_dc)

return []
return signature_dcs

def _include_layer(self, layer):
"""
Expand Down
2 changes: 1 addition & 1 deletion pulp_container/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 2251a50

Please sign in to comment.