Skip to content

Commit

Permalink
Add an extensions API endpoint for downloading signatures
Browse files Browse the repository at this point in the history
closes #504
  • Loading branch information
lubosmj authored and ipanova committed Feb 15, 2022
1 parent ba6000c commit a1a75ad
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGES/504.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added an extensions API endpoint for downloading image signatures.
43 changes: 41 additions & 2 deletions pulp_container/app/registry_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
RegistryPermission,
TokenPermission,
)
from pulp_container.constants import EMPTY_BLOB
from pulp_container.constants import EMPTY_BLOB, SIGNATURE_HEADER

FakeView = namedtuple("FakeView", ["action", "get_object"])

Expand Down Expand Up @@ -197,7 +197,7 @@ def default_response_headers(self):
Provide common headers to all responses.
"""
headers = super().default_response_headers
headers.update({"Docker-Distribution-Api-Version": "registry/2.0"})
headers.update({"Docker-Distribution-Api-Version": "registry/2.0", SIGNATURE_HEADER: "1"})
return headers

def get_exception_handler_context(self):
Expand Down Expand Up @@ -888,3 +888,42 @@ def receive_artifact(self, chunk):
artifact = Artifact.objects.get(sha256=artifact.sha256)
artifact.touch()
return artifact


class Signatures(ContainerRegistryApiMixin, ViewSet):
"""A ViewSet for image signatures."""

lookup_value_regex = "sha256:[0-9a-f]{64}"

def head(self, request, path, pk=None):
"""Respond to HEAD requests querying signatures by sha256."""
return self.get(request, path, pk=pk)

def get(self, request, path, pk):
"""Return a signature identified by its sha256 checksum."""
_, _, repository_version = self.get_drv_pull(path)

try:
manifest = models.Manifest.objects.get(digest=pk)
except models.Manifest.DoesNotExit:
raise ManifestNotFound(reference=pk)

signatures = models.ManifestSignature.objects.filter(
signed_manifest=manifest, pk__in=repository_version.content
)

return Response(self.get_response_data(signatures))

@staticmethod
def get_response_data(signatures):
"""Extract version, type, name, and content from the passed signature data."""
data = []
for signature in signatures:
signature = {
"schemaVersion": 2,
"type": signature.type,
"name": signature.name,
"content": signature.data,
}
data.append(signature)
return {"signatures": data}
4 changes: 1 addition & 3 deletions pulp_container/app/tasks/sync_stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from pulpcore.plugin.stages import DeclarativeArtifact, DeclarativeContent, Stage
from pulpcore.plugin.constants import TASK_STATES

from pulp_container.constants import MEDIA_TYPE, SIGNATURE_SOURCE, SIGNATURE_TYPE
from pulp_container.constants import MEDIA_TYPE, SIGNATURE_HEADER, SIGNATURE_SOURCE, SIGNATURE_TYPE
from pulp_container.app.models import (
Blob,
BlobManifest,
Expand All @@ -40,8 +40,6 @@
)
}

SIGNATURE_HEADER = "X-Registry-Supports-Signatures"


def _save_artifact_blocking(artifact_attributes):
saved_artifact = Artifact(**artifact_attributes)
Expand Down
2 changes: 2 additions & 0 deletions pulp_container/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
BlobUploads,
CatalogView,
Manifests,
Signatures,
TagsListView,
VersionView,
)
Expand All @@ -25,6 +26,7 @@
router.register(r"^v2/(?P<path>.+)/blobs/uploads\/?", BlobUploads, basename="docker-upload")
router.register(r"^v2/(?P<path>.+)/blobs", Blobs, basename="blobs")
router.register(r"^v2/(?P<path>.+)/manifests", Manifests, basename="manifests")
router.register(r"^extensions/v2/(?P<path>.+)/signatures", Signatures, basename="signatures")

urlpatterns = [
path("token/", BearerTokenView.as_view()),
Expand Down
3 changes: 3 additions & 0 deletions pulp_container/app/webserver_snippets/apache.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
ProxyPass /v2 ${pulp-api}/v2
ProxyPassReverse /v2 ${pulp-api}/v2

ProxyPass /extensions/v2 ${pulp-api}/extensions/v2
ProxyPassReverse /extensions/v2 ${pulp-api}/extensions/v2

ProxyPass /pulp/container ${pulp-content}/pulp/container
ProxyPassReverse /pulp/container ${pulp-content}/pulp/container

Expand Down
10 changes: 10 additions & 0 deletions pulp_container/app/webserver_snippets/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ location /v2/ {
client_max_body_size 0;
}

location extensions/v2/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://pulp-api;
}

location /pulp/container/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
Expand Down
2 changes: 2 additions & 0 deletions pulp_container/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +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"

0 comments on commit a1a75ad

Please sign in to comment.