From b7cd7b36ea4dfa0edafbe52e5fa34da7ba2e86cc Mon Sep 17 00:00:00 2001 From: Tasko Olevski Date: Wed, 16 Oct 2024 15:33:56 +0200 Subject: [PATCH] fix: image checks for some oci images fail (#1995) This occurs because some images (most likely when they support multiple architectures) have an index instead of just a manifest. An OCI index refers to a set of images. But when we were checking for images we were only checking for the manifest and did not have the option to support an index content type. --- renku_notebooks/api/classes/image.py | 18 +++++++++++++++--- tests/unit/test_public_image_checks.py | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/renku_notebooks/api/classes/image.py b/renku_notebooks/api/classes/image.py index da3d5608a..45ab6d483 100644 --- a/renku_notebooks/api/classes/image.py +++ b/renku_notebooks/api/classes/image.py @@ -3,7 +3,7 @@ from dataclasses import dataclass, field from enum import Enum from pathlib import Path -from typing import Any, Optional +from typing import Any, Optional, cast import requests from werkzeug.datastructures import WWWAuthenticate @@ -13,7 +13,8 @@ class ManifestTypes(Enum): docker_v2: str = "application/vnd.docker.distribution.manifest.v2+json" - oci_v1: str = "application/vnd.oci.image.manifest.v1+json" + oci_v1_manifest: str = "application/vnd.oci.image.manifest.v1+json" + oci_v1_index: str = "application/vnd.oci.image.index.v1+json" @dataclass @@ -62,8 +63,19 @@ def get_image_manifest(self, image: "Image") -> Optional[dict[str, Any]]: headers["Authorization"] = f"Bearer {token}" res = requests.get(image_digest_url, headers=headers) if res.status_code != 200: - headers["Accept"] = ManifestTypes.oci_v1.value + headers["Accept"] = ManifestTypes.oci_v1_manifest.value res = requests.get(image_digest_url, headers=headers) + if res.status_code != 200: + headers["Accept"] = ManifestTypes.oci_v1_index.value + res = requests.get(image_digest_url, headers=headers) + if res.status_code == 200: + index_parsed = res.json() + manifest = next( + (man for man in index_parsed.get("manifests", []) if man.get("platform", {}).get("os") == "linux"), + None, + ) + manifest = cast(dict[str, Any] | None, manifest) + return manifest if res.status_code != 200: return None return res.json() diff --git a/tests/unit/test_public_image_checks.py b/tests/unit/test_public_image_checks.py index 1deb0c8fd..a0b72b61c 100644 --- a/tests/unit/test_public_image_checks.py +++ b/tests/unit/test_public_image_checks.py @@ -183,6 +183,7 @@ def test_public_image_name_parsing(name, expected): ("renku/singleuser", True), ("madeuprepo/madeupproject:tag", False), ("olevski90/oci-image:0.0.1", True), + ("ghcr.io/linuxserver/nginx:latest", True) ], ) @pytest.mark.integration