From b13c4fa1b2c709cf4033b9de165a0ef8122f3ffd Mon Sep 17 00:00:00 2001 From: "Andoni A." <14891798+andoniaf@users.noreply.github.com> Date: Fri, 20 Feb 2026 08:24:59 +0100 Subject: [PATCH] fix(sdk): handle registry URL in Image provider connection test - Detect registry URLs (e.g. docker.io/namespace) vs image references - Use list_repositories for registry URLs, list_tags for images - Add test for registry URL connection test --- prowler/providers/image/image_provider.py | 28 +++++++++++++++++++- tests/providers/image/image_provider_test.py | 18 +++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/prowler/providers/image/image_provider.py b/prowler/providers/image/image_provider.py index e096595f14..c0ad68d855 100644 --- a/prowler/providers/image/image_provider.py +++ b/prowler/providers/image/image_provider.py @@ -906,11 +906,17 @@ class ImageProvider(Provider): """ Test connection to container registry by verifying image accessibility. + Handles two cases: + - Image reference (e.g. ``alpine:3.18``, ``ghcr.io/user/repo:tag``): + verifies the specific tag exists. + - Registry URL (e.g. ``docker.io/namespace``, ``ghcr.io/org``): + verifies we can list repositories in that namespace. + Uses registry HTTP APIs directly instead of Trivy to avoid false failures caused by Trivy DB download issues. Args: - image: Container image to test + image: Container image or registry URL to test raise_on_exception: Whether to raise exceptions provider_id: Fallback for image name registry_username: Registry username for basic auth @@ -935,6 +941,26 @@ class ImageProvider(Provider): else: repo_and_tag = image + # Determine if this is a registry URL (namespace only) or a full + # image reference. A registry URL like ``docker.io/andoniaf`` has + # a registry host but the remaining part contains no ``/`` (no + # repo) and no ``:`` (no tag). + is_registry_url = ( + registry_host and "/" not in repo_and_tag and ":" not in repo_and_tag + ) + + if is_registry_url: + # Registry enumeration mode — test by listing repositories + adapter = create_registry_adapter( + registry_url=image, + username=registry_username, + password=registry_password, + token=registry_token, + ) + adapter.list_repositories() + return Connection(is_connected=True) + + # Image reference mode — verify the specific tag exists if ":" in repo_and_tag: repository, tag = repo_and_tag.rsplit(":", 1) else: diff --git a/tests/providers/image/image_provider_test.py b/tests/providers/image/image_provider_test.py index 8ce9c41a83..8d1dc0e6d3 100644 --- a/tests/providers/image/image_provider_test.py +++ b/tests/providers/image/image_provider_test.py @@ -325,6 +325,24 @@ class TestImageProvider: assert result.is_connected is False assert "not found" in result.error + @patch("prowler.providers.image.image_provider.create_registry_adapter") + def test_test_connection_registry_url(self, mock_factory): + """Test registry URL (namespace) uses list_repositories.""" + mock_adapter = MagicMock() + mock_adapter.list_repositories.return_value = ["andoniaf/myapp"] + mock_factory.return_value = mock_adapter + + result = ImageProvider.test_connection(image="docker.io/andoniaf") + + assert result.is_connected is True + mock_factory.assert_called_once_with( + registry_url="docker.io/andoniaf", + username=None, + password=None, + token=None, + ) + mock_adapter.list_repositories.assert_called_once() + def test_build_status_extended(self): """Test status message content for different finding types.""" provider = _make_provider()