|
7 | 7 | import pytest |
8 | 8 |
|
9 | 9 | from prowler.lib.check.models import CheckReportImage |
| 10 | +from prowler.providers.common.provider import Provider |
10 | 11 | from prowler.providers.image.exceptions.exceptions import ( |
11 | 12 | ImageInvalidConfigScannerError, |
12 | 13 | ImageInvalidNameError, |
|
20 | 21 | ImageScanError, |
21 | 22 | ImageTrivyBinaryNotFoundError, |
22 | 23 | ) |
23 | | -from prowler.providers.common.provider import Provider |
24 | 24 | from prowler.providers.image.image_provider import ImageProvider |
25 | 25 | from tests.providers.image.image_fixtures import ( |
26 | 26 | SAMPLE_IMAGE_SHA, |
@@ -345,6 +345,24 @@ def test_test_connection_registry_url(self, mock_factory): |
345 | 345 | ) |
346 | 346 | mock_adapter.list_repositories.assert_called_once() |
347 | 347 |
|
| 348 | + @patch("prowler.providers.image.image_provider.create_registry_adapter") |
| 349 | + def test_test_connection_registry_url_with_https_scheme(self, mock_factory): |
| 350 | + """Registry URL with https:// scheme is normalised before adapter creation.""" |
| 351 | + mock_adapter = MagicMock() |
| 352 | + mock_adapter.list_repositories.return_value = ["repo1"] |
| 353 | + mock_factory.return_value = mock_adapter |
| 354 | + |
| 355 | + result = ImageProvider.test_connection(image="https://my-registry.example.com") |
| 356 | + |
| 357 | + assert result.is_connected is True |
| 358 | + mock_factory.assert_called_once_with( |
| 359 | + registry_url="my-registry.example.com", |
| 360 | + username=None, |
| 361 | + password=None, |
| 362 | + token=None, |
| 363 | + ) |
| 364 | + mock_adapter.list_repositories.assert_called_once() |
| 365 | + |
348 | 366 | def test_build_status_extended(self): |
349 | 367 | """Test status message content for different finding types.""" |
350 | 368 | provider = _make_provider() |
@@ -659,6 +677,27 @@ def test_print_credentials_shows_auth_method(self): |
659 | 677 | assert "Docker login" in output |
660 | 678 |
|
661 | 679 |
|
| 680 | +class TestStripScheme: |
| 681 | + @pytest.mark.parametrize( |
| 682 | + "raw,expected", |
| 683 | + [ |
| 684 | + ("https://my-registry.example.com", "my-registry.example.com"), |
| 685 | + ("http://my-registry.example.com", "my-registry.example.com"), |
| 686 | + ("HTTPS://My-Registry.Example.Com", "My-Registry.Example.Com"), |
| 687 | + ("Http://localhost:5000", "localhost:5000"), |
| 688 | + ("my-registry.example.com", "my-registry.example.com"), |
| 689 | + ("https://", ""), |
| 690 | + ("https://https://nested.example.com", "https://nested.example.com"), |
| 691 | + ( |
| 692 | + "ftp://not-a-supported-scheme.example.com", |
| 693 | + "ftp://not-a-supported-scheme.example.com", |
| 694 | + ), |
| 695 | + ], |
| 696 | + ) |
| 697 | + def test_strip_scheme(self, raw, expected): |
| 698 | + assert ImageProvider._strip_scheme(raw) == expected |
| 699 | + |
| 700 | + |
662 | 701 | class TestExtractRegistry: |
663 | 702 | def test_docker_hub_simple(self): |
664 | 703 | assert ImageProvider._extract_registry("alpine:3.18") is None |
@@ -698,6 +737,24 @@ def test_digest_reference(self): |
698 | 737 | def test_bare_image_name(self): |
699 | 738 | assert ImageProvider._extract_registry("nginx") is None |
700 | 739 |
|
| 740 | + def test_https_scheme_bare_hostname_returns_none(self): |
| 741 | + """Bare scheme-prefixed hostname has no image path, so no registry is extracted.""" |
| 742 | + assert ( |
| 743 | + ImageProvider._extract_registry("https://my-registry.example.com") is None |
| 744 | + ) |
| 745 | + |
| 746 | + def test_http_scheme_with_port_stripped(self): |
| 747 | + assert ( |
| 748 | + ImageProvider._extract_registry("http://localhost:5000/myimage:latest") |
| 749 | + == "localhost:5000" |
| 750 | + ) |
| 751 | + |
| 752 | + def test_https_scheme_with_path_stripped(self): |
| 753 | + assert ( |
| 754 | + ImageProvider._extract_registry("https://ghcr.io/org/image:tag") |
| 755 | + == "ghcr.io" |
| 756 | + ) |
| 757 | + |
701 | 758 |
|
702 | 759 | class TestIsRegistryUrl: |
703 | 760 | def test_bare_ecr_hostname(self): |
@@ -728,6 +785,16 @@ def test_bare_image_no_tag(self): |
728 | 785 | def test_dockerhub_namespace(self): |
729 | 786 | assert not ImageProvider._is_registry_url("library/alpine") |
730 | 787 |
|
| 788 | + def test_https_scheme_bare_hostname(self): |
| 789 | + assert ImageProvider._is_registry_url("https://my-registry.example.com") |
| 790 | + |
| 791 | + def test_http_scheme_bare_hostname_with_port(self): |
| 792 | + assert ImageProvider._is_registry_url("http://my-registry.example.com:5000") |
| 793 | + |
| 794 | + def test_https_scheme_image_reference_not_registry(self): |
| 795 | + """A scheme-prefixed full image reference is still an image, not a registry URL.""" |
| 796 | + assert not ImageProvider._is_registry_url("https://ghcr.io/myorg/repo:tag") |
| 797 | + |
731 | 798 |
|
732 | 799 | class TestTestRegistryConnection: |
733 | 800 | @patch("prowler.providers.image.image_provider.create_registry_adapter") |
|
0 commit comments