mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-03-22 03:08:23 +00:00
feat(openstack): add image service with 6 checks (#10096)
This commit is contained in:
committed by
GitHub
parent
8eddb48b16
commit
b21ded6d46
@@ -0,0 +1,231 @@
|
||||
"""Tests for image_hw_mem_encryption_enabled check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.image.image_service import ImageResource
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_image_hw_mem_encryption_enabled:
|
||||
def test_no_images(self):
|
||||
"""Test when no images exist."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled import (
|
||||
image_hw_mem_encryption_enabled,
|
||||
)
|
||||
|
||||
check = image_hw_mem_encryption_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_image_hw_mem_encryption_enabled(self):
|
||||
"""Test PASS when hw_mem_encryption is True."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-1",
|
||||
name="encrypted-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=True,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled import (
|
||||
image_hw_mem_encryption_enabled,
|
||||
)
|
||||
|
||||
check = image_hw_mem_encryption_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image encrypted-image (img-1) has hardware memory encryption enabled."
|
||||
)
|
||||
assert result[0].resource_id == "img-1"
|
||||
assert result[0].resource_name == "encrypted-image"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
|
||||
def test_image_encryption_not_set(self):
|
||||
"""Test FAIL when hw_mem_encryption is None."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-2",
|
||||
name="unencrypted-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled import (
|
||||
image_hw_mem_encryption_enabled,
|
||||
)
|
||||
|
||||
check = image_hw_mem_encryption_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image unencrypted-image (img-2) does not have hardware memory encryption enabled."
|
||||
)
|
||||
|
||||
def test_image_encryption_false(self):
|
||||
"""Test FAIL when hw_mem_encryption is False."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-3",
|
||||
name="no-encrypt-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=False,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled import (
|
||||
image_hw_mem_encryption_enabled,
|
||||
)
|
||||
|
||||
check = image_hw_mem_encryption_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
|
||||
def test_multiple_images_mixed(self):
|
||||
"""Test mixed results with encrypted and unencrypted images."""
|
||||
image_client = mock.MagicMock()
|
||||
base = dict(
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-enc", name="encrypted", hw_mem_encryption=True, **base
|
||||
),
|
||||
ImageResource(
|
||||
id="img-noenc", name="unencrypted", hw_mem_encryption=None, **base
|
||||
),
|
||||
ImageResource(
|
||||
id="img-false", name="false-enc", hw_mem_encryption=False, **base
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_hw_mem_encryption_enabled.image_hw_mem_encryption_enabled import (
|
||||
image_hw_mem_encryption_enabled,
|
||||
)
|
||||
|
||||
check = image_hw_mem_encryption_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 3
|
||||
assert result[0].status == "PASS"
|
||||
assert result[1].status == "FAIL"
|
||||
assert result[2].status == "FAIL"
|
||||
@@ -0,0 +1,192 @@
|
||||
"""Tests for image_not_publicly_visible check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.image.image_service import ImageResource
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_image_not_publicly_visible:
|
||||
def test_no_images(self):
|
||||
"""Test when no images exist."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible import (
|
||||
image_not_publicly_visible,
|
||||
)
|
||||
|
||||
check = image_not_publicly_visible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_image_private(self):
|
||||
"""Test PASS when image is private."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-1",
|
||||
name="private-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible import (
|
||||
image_not_publicly_visible,
|
||||
)
|
||||
|
||||
check = image_not_publicly_visible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image private-image (img-1) is not publicly visible (visibility=private)."
|
||||
)
|
||||
assert result[0].resource_id == "img-1"
|
||||
assert result[0].resource_name == "private-image"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
|
||||
def test_image_public(self):
|
||||
"""Test FAIL when image is public."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-2",
|
||||
name="public-image",
|
||||
status="active",
|
||||
visibility="public",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible import (
|
||||
image_not_publicly_visible,
|
||||
)
|
||||
|
||||
check = image_not_publicly_visible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image public-image (img-2) is publicly visible to all tenants."
|
||||
)
|
||||
assert result[0].resource_id == "img-2"
|
||||
assert result[0].resource_name == "public-image"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
|
||||
def test_multiple_images_mixed(self):
|
||||
"""Test mixed results with public, private, shared, and community images."""
|
||||
image_client = mock.MagicMock()
|
||||
base = dict(
|
||||
status="active",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
image_client.images = [
|
||||
ImageResource(id="img-pub", name="public-img", visibility="public", **base),
|
||||
ImageResource(
|
||||
id="img-priv", name="private-img", visibility="private", **base
|
||||
),
|
||||
ImageResource(
|
||||
id="img-shared", name="shared-img", visibility="shared", **base
|
||||
),
|
||||
ImageResource(
|
||||
id="img-comm", name="community-img", visibility="community", **base
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_publicly_visible.image_not_publicly_visible import (
|
||||
image_not_publicly_visible,
|
||||
)
|
||||
|
||||
check = image_not_publicly_visible()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 4
|
||||
assert result[0].status == "FAIL" # public
|
||||
assert result[1].status == "PASS" # private
|
||||
assert result[2].status == "PASS" # shared
|
||||
assert result[3].status == "PASS" # community
|
||||
@@ -0,0 +1,417 @@
|
||||
"""Tests for image_not_shared_with_multiple_projects check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.image.image_service import (
|
||||
ImageMember,
|
||||
ImageResource,
|
||||
)
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_image_not_shared_with_multiple_projects:
|
||||
def test_no_images(self):
|
||||
"""Test when no images exist."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = []
|
||||
image_client.audit_config = {}
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_image_not_shared(self):
|
||||
"""Test PASS when image is not shared."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.audit_config = {}
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-1",
|
||||
name="private-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image private-image (img-1) is not shared (visibility=private)."
|
||||
)
|
||||
assert result[0].resource_id == "img-1"
|
||||
|
||||
def test_image_shared_within_threshold(self):
|
||||
"""Test PASS when shared image has accepted members within threshold."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.audit_config = {}
|
||||
members = [
|
||||
ImageMember(member_id=f"project-{i}", status="accepted") for i in range(3)
|
||||
]
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-2",
|
||||
name="shared-image",
|
||||
status="active",
|
||||
visibility="shared",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=members,
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image shared-image (img-2) is shared with 3 accepted projects, within the threshold of 5."
|
||||
)
|
||||
|
||||
def test_image_shared_at_threshold(self):
|
||||
"""Test PASS when accepted members exactly equal threshold."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.audit_config = {}
|
||||
members = [
|
||||
ImageMember(member_id=f"project-{i}", status="accepted") for i in range(5)
|
||||
]
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-3",
|
||||
name="threshold-image",
|
||||
status="active",
|
||||
visibility="shared",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=members,
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image threshold-image (img-3) is shared with 5 accepted projects, within the threshold of 5."
|
||||
)
|
||||
|
||||
def test_image_shared_above_threshold(self):
|
||||
"""Test FAIL when accepted members exceed threshold."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.audit_config = {}
|
||||
members = [
|
||||
ImageMember(member_id=f"project-{i}", status="accepted") for i in range(8)
|
||||
]
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-4",
|
||||
name="overshared-image",
|
||||
status="active",
|
||||
visibility="shared",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=members,
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image overshared-image (img-4) is shared with 8 accepted projects, exceeding the threshold of 5."
|
||||
)
|
||||
|
||||
def test_pending_members_not_counted(self):
|
||||
"""Test that pending and rejected members are not counted."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.audit_config = {}
|
||||
members = [
|
||||
ImageMember(member_id="project-1", status="accepted"),
|
||||
ImageMember(member_id="project-2", status="pending"),
|
||||
ImageMember(member_id="project-3", status="rejected"),
|
||||
ImageMember(member_id="project-4", status="pending"),
|
||||
ImageMember(member_id="project-5", status="accepted"),
|
||||
ImageMember(member_id="project-6", status="pending"),
|
||||
ImageMember(member_id="project-7", status="pending"),
|
||||
ImageMember(member_id="project-8", status="pending"),
|
||||
ImageMember(member_id="project-9", status="pending"),
|
||||
ImageMember(member_id="project-10", status="pending"),
|
||||
]
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-5",
|
||||
name="pending-members-image",
|
||||
status="active",
|
||||
visibility="shared",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=members,
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image pending-members-image (img-5) is shared with 2 accepted projects, within the threshold of 5."
|
||||
)
|
||||
|
||||
def test_custom_threshold_via_audit_config(self):
|
||||
"""Test custom threshold from audit_config."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.audit_config = {"image_sharing_threshold": 2}
|
||||
members = [
|
||||
ImageMember(member_id=f"project-{i}", status="accepted") for i in range(3)
|
||||
]
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-6",
|
||||
name="custom-threshold-image",
|
||||
status="active",
|
||||
visibility="shared",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=members,
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image custom-threshold-image (img-6) is shared with 3 accepted projects, exceeding the threshold of 2."
|
||||
)
|
||||
|
||||
def test_multiple_images_mixed(self):
|
||||
"""Test mixed results with shared and non-shared images."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.audit_config = {}
|
||||
base = dict(
|
||||
status="active",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-priv",
|
||||
name="private",
|
||||
visibility="private",
|
||||
members=[],
|
||||
**base,
|
||||
),
|
||||
ImageResource(
|
||||
id="img-over",
|
||||
name="overshared",
|
||||
visibility="shared",
|
||||
members=[
|
||||
ImageMember(member_id=f"p-{i}", status="accepted") for i in range(6)
|
||||
],
|
||||
**base,
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_not_shared_with_multiple_projects.image_not_shared_with_multiple_projects import (
|
||||
image_not_shared_with_multiple_projects,
|
||||
)
|
||||
|
||||
check = image_not_shared_with_multiple_projects()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS" # private
|
||||
assert result[1].status == "FAIL" # overshared
|
||||
@@ -0,0 +1,180 @@
|
||||
"""Tests for image_protected_status_enabled check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.image.image_service import ImageResource
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_image_protected_status_enabled:
|
||||
def test_no_images(self):
|
||||
"""Test when no images exist."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled import (
|
||||
image_protected_status_enabled,
|
||||
)
|
||||
|
||||
check = image_protected_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_image_protected(self):
|
||||
"""Test PASS when image is protected."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-1",
|
||||
name="protected-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=True,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled import (
|
||||
image_protected_status_enabled,
|
||||
)
|
||||
|
||||
check = image_protected_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image protected-image (img-1) has deletion protection enabled."
|
||||
)
|
||||
assert result[0].resource_id == "img-1"
|
||||
assert result[0].resource_name == "protected-image"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
|
||||
def test_image_not_protected(self):
|
||||
"""Test FAIL when image is not protected."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-2",
|
||||
name="unprotected-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled import (
|
||||
image_protected_status_enabled,
|
||||
)
|
||||
|
||||
check = image_protected_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image unprotected-image (img-2) does not have deletion protection enabled."
|
||||
)
|
||||
assert result[0].resource_id == "img-2"
|
||||
|
||||
def test_multiple_images_mixed(self):
|
||||
"""Test mixed results with protected and unprotected images."""
|
||||
image_client = mock.MagicMock()
|
||||
base = dict(
|
||||
status="active",
|
||||
visibility="private",
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
image_client.images = [
|
||||
ImageResource(id="img-p", name="protected", protected=True, **base),
|
||||
ImageResource(id="img-u", name="unprotected", protected=False, **base),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_protected_status_enabled.image_protected_status_enabled import (
|
||||
image_protected_status_enabled,
|
||||
)
|
||||
|
||||
check = image_protected_status_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert result[1].status == "FAIL"
|
||||
@@ -0,0 +1,277 @@
|
||||
"""Tests for image_secure_boot_enabled check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.image.image_service import ImageResource
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_image_secure_boot_enabled:
|
||||
def test_no_images(self):
|
||||
"""Test when no images exist."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled import (
|
||||
image_secure_boot_enabled,
|
||||
)
|
||||
|
||||
check = image_secure_boot_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_image_secure_boot_required(self):
|
||||
"""Test PASS when os_secure_boot is 'required'."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-1",
|
||||
name="secure-boot-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot="required",
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled import (
|
||||
image_secure_boot_enabled,
|
||||
)
|
||||
|
||||
check = image_secure_boot_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image secure-boot-image (img-1) has Secure Boot set to required."
|
||||
)
|
||||
assert result[0].resource_id == "img-1"
|
||||
assert result[0].resource_name == "secure-boot-image"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
|
||||
def test_image_secure_boot_not_set(self):
|
||||
"""Test FAIL when os_secure_boot is None."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-2",
|
||||
name="no-secureboot-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled import (
|
||||
image_secure_boot_enabled,
|
||||
)
|
||||
|
||||
check = image_secure_boot_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image no-secureboot-image (img-2) does not have Secure Boot set to required (os_secure_boot=None)."
|
||||
)
|
||||
|
||||
def test_image_secure_boot_optional(self):
|
||||
"""Test FAIL when os_secure_boot is 'optional'."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-3",
|
||||
name="optional-secureboot",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot="optional",
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled import (
|
||||
image_secure_boot_enabled,
|
||||
)
|
||||
|
||||
check = image_secure_boot_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
|
||||
def test_image_secure_boot_disabled(self):
|
||||
"""Test FAIL when os_secure_boot is 'disabled'."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-4",
|
||||
name="disabled-secureboot",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot="disabled",
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled import (
|
||||
image_secure_boot_enabled,
|
||||
)
|
||||
|
||||
check = image_secure_boot_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
|
||||
def test_multiple_images_mixed(self):
|
||||
"""Test mixed results with various secure boot settings."""
|
||||
image_client = mock.MagicMock()
|
||||
base = dict(
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-req", name="required", os_secure_boot="required", **base
|
||||
),
|
||||
ImageResource(
|
||||
id="img-opt", name="optional", os_secure_boot="optional", **base
|
||||
),
|
||||
ImageResource(
|
||||
id="img-dis", name="disabled", os_secure_boot="disabled", **base
|
||||
),
|
||||
ImageResource(id="img-none", name="none-set", os_secure_boot=None, **base),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_secure_boot_enabled.image_secure_boot_enabled import (
|
||||
image_secure_boot_enabled,
|
||||
)
|
||||
|
||||
check = image_secure_boot_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 4
|
||||
assert result[0].status == "PASS" # required
|
||||
assert result[1].status == "FAIL" # optional
|
||||
assert result[2].status == "FAIL" # disabled
|
||||
assert result[3].status == "FAIL" # None
|
||||
593
tests/providers/openstack/services/image/image_service_test.py
Normal file
593
tests/providers/openstack/services/image/image_service_test.py
Normal file
@@ -0,0 +1,593 @@
|
||||
"""Tests for OpenStack Image service."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from openstack import exceptions as openstack_exceptions
|
||||
|
||||
from prowler.providers.openstack.services.image.image_service import (
|
||||
Image,
|
||||
ImageMember,
|
||||
ImageResource,
|
||||
)
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class TestImageService:
|
||||
"""Test suite for Image service."""
|
||||
|
||||
def test_image_service_initialization(self):
|
||||
"""Test Image service initializes correctly."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
with patch.object(Image, "_list_images", return_value=[]):
|
||||
image_service = Image(provider)
|
||||
|
||||
assert image_service.service_name == "Image"
|
||||
assert image_service.provider == provider
|
||||
assert image_service.connection == provider.connection
|
||||
assert image_service.regional_connections == provider.regional_connections
|
||||
assert image_service.audited_regions == [OPENSTACK_REGION]
|
||||
assert image_service.region == OPENSTACK_REGION
|
||||
assert image_service.project_id == OPENSTACK_PROJECT_ID
|
||||
assert image_service.images == []
|
||||
|
||||
def test_image_list_images_success(self):
|
||||
"""Test listing images successfully."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-1"
|
||||
mock_img.name = "ubuntu-22.04"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = True
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = ["production"]
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert isinstance(image_service.images[0], ImageResource)
|
||||
assert image_service.images[0].id == "img-1"
|
||||
assert image_service.images[0].name == "ubuntu-22.04"
|
||||
assert image_service.images[0].status == "active"
|
||||
assert image_service.images[0].visibility == "private"
|
||||
assert image_service.images[0].protected is True
|
||||
assert image_service.images[0].tags == ["production"]
|
||||
assert image_service.images[0].members == []
|
||||
|
||||
def test_image_list_images_with_signature(self):
|
||||
"""Test listing images with signature properties."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-signed"
|
||||
mock_img.name = "signed-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = "abc123sig"
|
||||
mock_img.img_signature_hash_method = "SHA-256"
|
||||
mock_img.img_signature_key_type = "RSA-PSS"
|
||||
mock_img.img_signature_certificate_uuid = "cert-uuid-123"
|
||||
mock_img.hw_mem_encryption = True
|
||||
mock_img.needs_secure_boot = "required"
|
||||
mock_img.os_secure_boot = "required"
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
img = image_service.images[0]
|
||||
assert img.img_signature == "abc123sig"
|
||||
assert img.img_signature_hash_method == "SHA-256"
|
||||
assert img.img_signature_key_type == "RSA-PSS"
|
||||
assert img.img_signature_certificate_uuid == "cert-uuid-123"
|
||||
assert img.hw_mem_encryption is True
|
||||
assert img.os_secure_boot == "required"
|
||||
|
||||
def test_image_list_images_shared_with_members(self):
|
||||
"""Test listing shared images fetches members."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-shared"
|
||||
mock_img.name = "shared-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "shared"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
mock_member = MagicMock()
|
||||
mock_member.member_id = "project-2"
|
||||
mock_member.id = "project-2"
|
||||
mock_member.status = "accepted"
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
provider.connection.image.members.return_value = [mock_member]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert len(image_service.images[0].members) == 1
|
||||
assert isinstance(image_service.images[0].members[0], ImageMember)
|
||||
assert image_service.images[0].members[0].member_id == "project-2"
|
||||
assert image_service.images[0].members[0].status == "accepted"
|
||||
provider.connection.image.members.assert_called_once_with("img-shared")
|
||||
|
||||
def test_image_list_images_private_no_member_fetch(self):
|
||||
"""Test that private images do not trigger member listing."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-private"
|
||||
mock_img.name = "private-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].members == []
|
||||
provider.connection.image.members.assert_not_called()
|
||||
|
||||
def test_image_list_images_empty(self):
|
||||
"""Test listing images when none exist."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
provider.connection.image.images.return_value = []
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert image_service.images == []
|
||||
|
||||
def test_image_list_images_sdk_exception(self):
|
||||
"""Test handling SDKException when listing images."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
provider.connection.image.images.side_effect = (
|
||||
openstack_exceptions.SDKException("API error")
|
||||
)
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert image_service.images == []
|
||||
|
||||
def test_image_list_images_generic_exception(self):
|
||||
"""Test handling generic Exception when listing images."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
provider.connection.image.images.side_effect = Exception("Unexpected error")
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert image_service.images == []
|
||||
|
||||
def test_image_list_image_members_sdk_exception(self):
|
||||
"""Test handling SDKException when listing image members."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-shared-err"
|
||||
mock_img.name = "shared-error-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "shared"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
provider.connection.image.members.side_effect = (
|
||||
openstack_exceptions.SDKException("Members API error")
|
||||
)
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].members == []
|
||||
|
||||
def test_image_hw_mem_encryption_false_not_overridden_by_properties(self):
|
||||
"""Test that hw_mem_encryption=False is preserved, not overridden by properties dict."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-enc-false"
|
||||
mock_img.name = "encryption-false-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = False
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {"hw_mem_encryption": "true"}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].hw_mem_encryption is False
|
||||
|
||||
def test_image_os_secure_boot_disabled_not_overridden_by_properties(self):
|
||||
"""Test that os_secure_boot='disabled' is preserved, not overridden by properties dict."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-boot-disabled"
|
||||
mock_img.name = "boot-disabled-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = "disabled"
|
||||
mock_img.os_secure_boot = "disabled"
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {"os_secure_boot": "required"}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].os_secure_boot == "disabled"
|
||||
|
||||
def test_image_signature_empty_string_not_overridden_by_properties(self):
|
||||
"""Test that empty string signature attrs are preserved, not overridden by properties."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-sig-empty"
|
||||
mock_img.name = "sig-empty-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = ""
|
||||
mock_img.img_signature_hash_method = ""
|
||||
mock_img.img_signature_key_type = ""
|
||||
mock_img.img_signature_certificate_uuid = ""
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {
|
||||
"img_signature": "should-not-override",
|
||||
"img_signature_hash_method": "should-not-override",
|
||||
"img_signature_key_type": "should-not-override",
|
||||
"img_signature_certificate_uuid": "should-not-override",
|
||||
}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
img = image_service.images[0]
|
||||
assert img.img_signature == ""
|
||||
assert img.img_signature_hash_method == ""
|
||||
assert img.img_signature_key_type == ""
|
||||
assert img.img_signature_certificate_uuid == ""
|
||||
|
||||
def test_image_properties_fallback_when_attrs_are_none(self):
|
||||
"""Test that properties dict is used as fallback when image attrs are None."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-fallback"
|
||||
mock_img.name = "fallback-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {
|
||||
"img_signature": "prop-sig",
|
||||
"img_signature_hash_method": "SHA-256",
|
||||
"img_signature_key_type": "RSA-PSS",
|
||||
"img_signature_certificate_uuid": "cert-from-props",
|
||||
"hw_mem_encryption": "true",
|
||||
"os_secure_boot": "required",
|
||||
}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
img = image_service.images[0]
|
||||
assert img.img_signature == "prop-sig"
|
||||
assert img.img_signature_hash_method == "SHA-256"
|
||||
assert img.img_signature_key_type == "RSA-PSS"
|
||||
assert img.img_signature_certificate_uuid == "cert-from-props"
|
||||
assert img.hw_mem_encryption is True
|
||||
assert img.os_secure_boot == "required"
|
||||
|
||||
def test_image_needs_secure_boot_sdk_attr_resolved(self):
|
||||
"""Test that needs_secure_boot (SDK attr) is used when os_secure_boot is absent."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-sdk-boot"
|
||||
mock_img.name = "sdk-boot-image"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = "required"
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
provider.connection.image.images.return_value = [mock_img]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].os_secure_boot == "required"
|
||||
|
||||
def test_image_list_images_multi_region(self):
|
||||
"""Test listing images across multiple regions."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_conn_uk1 = MagicMock()
|
||||
mock_conn_de1 = MagicMock()
|
||||
|
||||
provider.regional_connections = {"UK1": mock_conn_uk1, "DE1": mock_conn_de1}
|
||||
|
||||
mock_img_uk = MagicMock()
|
||||
mock_img_uk.id = "img-uk"
|
||||
mock_img_uk.name = "ubuntu-uk"
|
||||
mock_img_uk.status = "active"
|
||||
mock_img_uk.visibility = "private"
|
||||
mock_img_uk.is_protected = False
|
||||
mock_img_uk.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img_uk.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img_uk.img_signature = None
|
||||
mock_img_uk.img_signature_hash_method = None
|
||||
mock_img_uk.img_signature_key_type = None
|
||||
mock_img_uk.img_signature_certificate_uuid = None
|
||||
mock_img_uk.hw_mem_encryption = None
|
||||
mock_img_uk.needs_secure_boot = None
|
||||
mock_img_uk.os_secure_boot = None
|
||||
mock_img_uk.tags = []
|
||||
mock_img_uk.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img_uk.properties = {}
|
||||
|
||||
mock_img_de = MagicMock()
|
||||
mock_img_de.id = "img-de"
|
||||
mock_img_de.name = "ubuntu-de"
|
||||
mock_img_de.status = "active"
|
||||
mock_img_de.visibility = "private"
|
||||
mock_img_de.is_protected = False
|
||||
mock_img_de.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img_de.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img_de.img_signature = None
|
||||
mock_img_de.img_signature_hash_method = None
|
||||
mock_img_de.img_signature_key_type = None
|
||||
mock_img_de.img_signature_certificate_uuid = None
|
||||
mock_img_de.hw_mem_encryption = None
|
||||
mock_img_de.needs_secure_boot = None
|
||||
mock_img_de.os_secure_boot = None
|
||||
mock_img_de.tags = []
|
||||
mock_img_de.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img_de.properties = {}
|
||||
|
||||
mock_conn_uk1.image.images.return_value = [mock_img_uk]
|
||||
mock_conn_de1.image.images.return_value = [mock_img_de]
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 2
|
||||
uk_img = next(i for i in image_service.images if i.id == "img-uk")
|
||||
de_img = next(i for i in image_service.images if i.id == "img-de")
|
||||
assert uk_img.region == "UK1"
|
||||
assert de_img.region == "DE1"
|
||||
|
||||
def test_image_list_images_multi_region_partial_failure(self):
|
||||
"""Test that a failing region doesn't prevent other regions from being listed."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_conn_ok = MagicMock()
|
||||
mock_conn_fail = MagicMock()
|
||||
|
||||
provider.regional_connections = {"UK1": mock_conn_ok, "DE1": mock_conn_fail}
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-uk"
|
||||
mock_img.name = "ubuntu-uk"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
mock_conn_ok.image.images.return_value = [mock_img]
|
||||
mock_conn_fail.image.images.side_effect = openstack_exceptions.SDKException(
|
||||
"API error in DE1"
|
||||
)
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].id == "img-uk"
|
||||
assert image_service.images[0].region == "UK1"
|
||||
|
||||
def test_image_list_images_multi_region_one_empty(self):
|
||||
"""Test multi-region where one region has images and the other is empty."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_conn_uk1 = MagicMock()
|
||||
mock_conn_de1 = MagicMock()
|
||||
|
||||
provider.regional_connections = {"UK1": mock_conn_uk1, "DE1": mock_conn_de1}
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-uk"
|
||||
mock_img.name = "ubuntu-uk"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "private"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
mock_conn_uk1.image.images.return_value = [mock_img]
|
||||
mock_conn_de1.image.images.return_value = []
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].id == "img-uk"
|
||||
assert image_service.images[0].region == "UK1"
|
||||
|
||||
def test_image_list_images_multi_region_shared_with_members(self):
|
||||
"""Test listing shared images fetches members using the correct regional connection."""
|
||||
provider = set_mocked_openstack_provider()
|
||||
|
||||
mock_conn_uk1 = MagicMock()
|
||||
mock_conn_de1 = MagicMock()
|
||||
|
||||
provider.regional_connections = {"UK1": mock_conn_uk1, "DE1": mock_conn_de1}
|
||||
|
||||
mock_img = MagicMock()
|
||||
mock_img.id = "img-shared-uk"
|
||||
mock_img.name = "shared-uk"
|
||||
mock_img.status = "active"
|
||||
mock_img.visibility = "shared"
|
||||
mock_img.is_protected = False
|
||||
mock_img.owner_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.owner = OPENSTACK_PROJECT_ID
|
||||
mock_img.img_signature = None
|
||||
mock_img.img_signature_hash_method = None
|
||||
mock_img.img_signature_key_type = None
|
||||
mock_img.img_signature_certificate_uuid = None
|
||||
mock_img.hw_mem_encryption = None
|
||||
mock_img.needs_secure_boot = None
|
||||
mock_img.os_secure_boot = None
|
||||
mock_img.tags = []
|
||||
mock_img.project_id = OPENSTACK_PROJECT_ID
|
||||
mock_img.properties = {}
|
||||
|
||||
mock_member = MagicMock()
|
||||
mock_member.member_id = "project-2"
|
||||
mock_member.id = "project-2"
|
||||
mock_member.status = "accepted"
|
||||
|
||||
mock_conn_uk1.image.images.return_value = [mock_img]
|
||||
mock_conn_uk1.image.members.return_value = [mock_member]
|
||||
mock_conn_de1.image.images.return_value = []
|
||||
|
||||
image_service = Image(provider)
|
||||
|
||||
assert len(image_service.images) == 1
|
||||
assert image_service.images[0].region == "UK1"
|
||||
assert len(image_service.images[0].members) == 1
|
||||
assert image_service.images[0].members[0].member_id == "project-2"
|
||||
mock_conn_uk1.image.members.assert_called_once_with("img-shared-uk")
|
||||
@@ -0,0 +1,280 @@
|
||||
"""Tests for image_signature_verification_enabled check."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.openstack.services.image.image_service import ImageResource
|
||||
from tests.providers.openstack.openstack_fixtures import (
|
||||
OPENSTACK_PROJECT_ID,
|
||||
OPENSTACK_REGION,
|
||||
set_mocked_openstack_provider,
|
||||
)
|
||||
|
||||
|
||||
class Test_image_signature_verification_enabled:
|
||||
def test_no_images(self):
|
||||
"""Test when no images exist."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled import (
|
||||
image_signature_verification_enabled,
|
||||
)
|
||||
|
||||
check = image_signature_verification_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
def test_image_fully_signed(self):
|
||||
"""Test PASS when all four signature properties are set."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-1",
|
||||
name="signed-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature="abc123sig",
|
||||
img_signature_hash_method="SHA-256",
|
||||
img_signature_key_type="RSA-PSS",
|
||||
img_signature_certificate_uuid="cert-uuid-123",
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled import (
|
||||
image_signature_verification_enabled,
|
||||
)
|
||||
|
||||
check = image_signature_verification_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image signed-image (img-1) has all signature verification properties configured."
|
||||
)
|
||||
assert result[0].resource_id == "img-1"
|
||||
assert result[0].resource_name == "signed-image"
|
||||
assert result[0].region == OPENSTACK_REGION
|
||||
|
||||
def test_image_no_signatures(self):
|
||||
"""Test FAIL when no signature properties are set."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-2",
|
||||
name="unsigned-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled import (
|
||||
image_signature_verification_enabled,
|
||||
)
|
||||
|
||||
check = image_signature_verification_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Image unsigned-image (img-2) does not have all signature verification properties configured."
|
||||
)
|
||||
|
||||
def test_image_partial_signatures(self):
|
||||
"""Test FAIL when only some signature properties are set."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-3",
|
||||
name="partial-sig-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature="abc123sig",
|
||||
img_signature_hash_method="SHA-256",
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled import (
|
||||
image_signature_verification_enabled,
|
||||
)
|
||||
|
||||
check = image_signature_verification_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
|
||||
def test_image_empty_string_signatures(self):
|
||||
"""Test FAIL when signature properties are empty strings."""
|
||||
image_client = mock.MagicMock()
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-4",
|
||||
name="empty-sig-image",
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
img_signature="",
|
||||
img_signature_hash_method="",
|
||||
img_signature_key_type="",
|
||||
img_signature_certificate_uuid="",
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled import (
|
||||
image_signature_verification_enabled,
|
||||
)
|
||||
|
||||
check = image_signature_verification_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
|
||||
def test_multiple_images_mixed(self):
|
||||
"""Test mixed results with signed and unsigned images."""
|
||||
image_client = mock.MagicMock()
|
||||
base = dict(
|
||||
status="active",
|
||||
visibility="private",
|
||||
protected=False,
|
||||
owner=OPENSTACK_PROJECT_ID,
|
||||
hw_mem_encryption=None,
|
||||
os_secure_boot=None,
|
||||
members=[],
|
||||
tags=[],
|
||||
project_id=OPENSTACK_PROJECT_ID,
|
||||
region=OPENSTACK_REGION,
|
||||
)
|
||||
image_client.images = [
|
||||
ImageResource(
|
||||
id="img-signed",
|
||||
name="signed",
|
||||
img_signature="sig",
|
||||
img_signature_hash_method="SHA-256",
|
||||
img_signature_key_type="RSA-PSS",
|
||||
img_signature_certificate_uuid="cert-uuid",
|
||||
**base,
|
||||
),
|
||||
ImageResource(
|
||||
id="img-unsigned",
|
||||
name="unsigned",
|
||||
img_signature=None,
|
||||
img_signature_hash_method=None,
|
||||
img_signature_key_type=None,
|
||||
img_signature_certificate_uuid=None,
|
||||
**base,
|
||||
),
|
||||
]
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_openstack_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled.image_client",
|
||||
new=image_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.openstack.services.image.image_signature_verification_enabled.image_signature_verification_enabled import (
|
||||
image_signature_verification_enabled,
|
||||
)
|
||||
|
||||
check = image_signature_verification_enabled()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert result[1].status == "FAIL"
|
||||
Reference in New Issue
Block a user