mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-09 21:14:22 +00:00
feat(scaleway): add new provider (#11166)
This commit is contained in:
@@ -17,7 +17,7 @@ prowler_command = "prowler"
|
||||
|
||||
# capsys
|
||||
# https://docs.pytest.org/en/7.1.x/how-to/capture-stdout-stderr.html
|
||||
prowler_default_usage_error = "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,googleworkspace,okta,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,vercel,dashboard,iac,image,llm} ..."
|
||||
prowler_default_usage_error = "usage: prowler [-h] [--version] {aws,azure,gcp,kubernetes,m365,github,googleworkspace,okta,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,scaleway,vercel,dashboard,iac,image,llm} ..."
|
||||
|
||||
|
||||
def mock_get_available_providers():
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from prowler.providers.scaleway.models import (
|
||||
ScalewayIdentityInfo,
|
||||
ScalewaySession,
|
||||
)
|
||||
from prowler.providers.scaleway.services.iam.iam_service import (
|
||||
ScalewayAPIKey,
|
||||
ScalewayUser,
|
||||
)
|
||||
|
||||
# Scaleway Identity
|
||||
ORGANIZATION_ID = "b4ce0bfc-38fc-4c53-8757-548be64add26"
|
||||
ROOT_USER_ID = "00000000-0000-0000-0000-000000000001"
|
||||
MEMBER_USER_ID = "00000000-0000-0000-0000-000000000002"
|
||||
APPLICATION_ID = "00000000-0000-0000-0000-000000000003"
|
||||
BEARER_EMAIL = "pedro@prowler.com"
|
||||
|
||||
# Scaleway Credentials
|
||||
ACCESS_KEY = "SCWAE000000000000000"
|
||||
SECRET_KEY = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
# API Key Constants
|
||||
ROOT_API_KEY = "SCWROOT00000000000000"
|
||||
USER_API_KEY = "SCWUSER00000000000000"
|
||||
APP_API_KEY = "SCWAPP000000000000000"
|
||||
|
||||
|
||||
def set_mocked_scaleway_provider(
|
||||
access_key: str = ACCESS_KEY,
|
||||
secret_key: str = SECRET_KEY,
|
||||
identity: ScalewayIdentityInfo = None,
|
||||
audit_config: dict = None,
|
||||
):
|
||||
"""Create a mocked ScalewayProvider for testing."""
|
||||
provider = MagicMock()
|
||||
provider.type = "scaleway"
|
||||
provider.session = ScalewaySession(
|
||||
access_key=access_key,
|
||||
secret_key=secret_key,
|
||||
organization_id=ORGANIZATION_ID,
|
||||
default_project_id=None,
|
||||
default_region="fr-par",
|
||||
client=MagicMock(),
|
||||
)
|
||||
provider.identity = identity or ScalewayIdentityInfo(
|
||||
organization_id=ORGANIZATION_ID,
|
||||
bearer_id=ROOT_USER_ID,
|
||||
bearer_type="user",
|
||||
bearer_email=BEARER_EMAIL,
|
||||
account_root_user_id=ROOT_USER_ID,
|
||||
)
|
||||
provider.audit_config = audit_config or {}
|
||||
provider.fixer_config = {}
|
||||
|
||||
return provider
|
||||
|
||||
|
||||
def make_user(
|
||||
user_id: str = ROOT_USER_ID,
|
||||
email: str = BEARER_EMAIL,
|
||||
account_root_user_id: str = ROOT_USER_ID,
|
||||
mfa: bool = True,
|
||||
) -> ScalewayUser:
|
||||
return ScalewayUser(
|
||||
id=user_id,
|
||||
email=email,
|
||||
username=email.split("@")[0] if email else None,
|
||||
organization_id=ORGANIZATION_ID,
|
||||
account_root_user_id=account_root_user_id,
|
||||
mfa=mfa,
|
||||
type_="owner" if user_id == account_root_user_id else "member",
|
||||
status="activated",
|
||||
)
|
||||
|
||||
|
||||
def make_api_key(
|
||||
access_key: str = USER_API_KEY,
|
||||
user_id: str = MEMBER_USER_ID,
|
||||
application_id: str = None,
|
||||
description: str = "test key",
|
||||
expires_at: str = None,
|
||||
) -> ScalewayAPIKey:
|
||||
return ScalewayAPIKey(
|
||||
access_key=access_key,
|
||||
description=description,
|
||||
user_id=user_id,
|
||||
application_id=application_id,
|
||||
default_project_id=None,
|
||||
editable=True,
|
||||
managed=False,
|
||||
creation_ip=None,
|
||||
created_at="2026-01-01T00:00:00Z",
|
||||
updated_at="2026-01-01T00:00:00Z",
|
||||
expires_at=expires_at,
|
||||
)
|
||||
@@ -0,0 +1,106 @@
|
||||
import os
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from prowler.providers.scaleway.exceptions.exceptions import (
|
||||
ScalewayAuthenticationError,
|
||||
ScalewayCredentialsError,
|
||||
ScalewayIdentityError,
|
||||
)
|
||||
from prowler.providers.scaleway.models import ScalewaySession
|
||||
from prowler.providers.scaleway.scaleway_provider import ScalewayProvider
|
||||
from tests.providers.scaleway.scaleway_fixtures import (
|
||||
ACCESS_KEY,
|
||||
BEARER_EMAIL,
|
||||
ORGANIZATION_ID,
|
||||
ROOT_USER_ID,
|
||||
SECRET_KEY,
|
||||
)
|
||||
|
||||
|
||||
class Test_ScalewayProvider_setup_session:
|
||||
def test_missing_access_key_raises_credentials_error(self):
|
||||
with mock.patch.dict(
|
||||
os.environ, {"SCW_ACCESS_KEY": "", "SCW_SECRET_KEY": ""}, clear=False
|
||||
):
|
||||
os.environ.pop("SCW_ACCESS_KEY", None)
|
||||
os.environ.pop("SCW_SECRET_KEY", None)
|
||||
with pytest.raises(ScalewayCredentialsError):
|
||||
ScalewayProvider.setup_session()
|
||||
|
||||
def test_returns_session_with_credentials(self):
|
||||
session = ScalewayProvider.setup_session(
|
||||
access_key=ACCESS_KEY,
|
||||
secret_key=SECRET_KEY,
|
||||
organization_id=ORGANIZATION_ID,
|
||||
)
|
||||
assert isinstance(session, ScalewaySession)
|
||||
assert session.access_key == ACCESS_KEY
|
||||
assert session.organization_id == ORGANIZATION_ID
|
||||
assert session.default_region == "fr-par"
|
||||
|
||||
|
||||
class Test_ScalewayProvider_setup_identity:
|
||||
def _build_session(self):
|
||||
return ScalewaySession(
|
||||
access_key=ACCESS_KEY,
|
||||
secret_key=SECRET_KEY,
|
||||
organization_id=ORGANIZATION_ID,
|
||||
default_region="fr-par",
|
||||
client=mock.MagicMock(),
|
||||
)
|
||||
|
||||
def test_resolves_user_bearer_identity(self):
|
||||
session = self._build_session()
|
||||
api_key = mock.MagicMock(user_id=ROOT_USER_ID, application_id=None)
|
||||
user = mock.MagicMock(
|
||||
email=BEARER_EMAIL,
|
||||
organization_id=ORGANIZATION_ID,
|
||||
account_root_user_id=ROOT_USER_ID,
|
||||
)
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.scaleway.scaleway_provider.IamV1Alpha1API"
|
||||
) as iam_cls:
|
||||
iam = iam_cls.return_value
|
||||
iam.get_api_key.return_value = api_key
|
||||
iam.get_user.return_value = user
|
||||
|
||||
identity = ScalewayProvider.setup_identity(session)
|
||||
|
||||
assert identity.organization_id == ORGANIZATION_ID
|
||||
assert identity.bearer_type == "user"
|
||||
assert identity.bearer_id == ROOT_USER_ID
|
||||
assert identity.bearer_email == BEARER_EMAIL
|
||||
assert identity.account_root_user_id == ROOT_USER_ID
|
||||
|
||||
def test_missing_organization_raises_identity_error(self):
|
||||
session = self._build_session()
|
||||
session.organization_id = None
|
||||
api_key = mock.MagicMock(user_id=None, application_id="app-id")
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.scaleway.scaleway_provider.IamV1Alpha1API"
|
||||
) as iam_cls:
|
||||
iam = iam_cls.return_value
|
||||
iam.get_api_key.return_value = api_key
|
||||
|
||||
with pytest.raises(ScalewayIdentityError):
|
||||
ScalewayProvider.setup_identity(session)
|
||||
|
||||
|
||||
class Test_ScalewayProvider_validate_credentials:
|
||||
def test_invalid_credentials_raise_authentication_error(self):
|
||||
session = ScalewaySession(
|
||||
access_key=ACCESS_KEY,
|
||||
secret_key=SECRET_KEY,
|
||||
organization_id=ORGANIZATION_ID,
|
||||
client=mock.MagicMock(),
|
||||
)
|
||||
with mock.patch(
|
||||
"prowler.providers.scaleway.scaleway_provider.IamV1Alpha1API"
|
||||
) as iam_cls:
|
||||
iam_cls.return_value.get_api_key.side_effect = Exception("expired")
|
||||
with pytest.raises(ScalewayAuthenticationError):
|
||||
ScalewayProvider.validate_credentials(session)
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
from unittest import mock
|
||||
|
||||
from tests.providers.scaleway.scaleway_fixtures import (
|
||||
APP_API_KEY,
|
||||
APPLICATION_ID,
|
||||
MEMBER_USER_ID,
|
||||
ORGANIZATION_ID,
|
||||
ROOT_API_KEY,
|
||||
ROOT_USER_ID,
|
||||
USER_API_KEY,
|
||||
make_api_key,
|
||||
set_mocked_scaleway_provider,
|
||||
)
|
||||
|
||||
|
||||
def _patch_clients(iam_client_mock):
|
||||
"""Patch both the provider and the iam_client singleton."""
|
||||
return [
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_scaleway_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned.iam_client",
|
||||
new=iam_client_mock,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class Test_iam_api_keys_no_root_owned:
|
||||
def test_no_api_keys_returns_empty_findings(self):
|
||||
iam_client = mock.MagicMock()
|
||||
iam_client.users_loaded = True
|
||||
iam_client.api_keys_loaded = True
|
||||
iam_client.account_root_user_id = ROOT_USER_ID
|
||||
iam_client.api_keys = []
|
||||
iam_client.organization_id = ORGANIZATION_ID
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_scaleway_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned.iam_client",
|
||||
new=iam_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned import (
|
||||
iam_api_keys_no_root_owned,
|
||||
)
|
||||
|
||||
result = iam_api_keys_no_root_owned().execute()
|
||||
assert result == []
|
||||
|
||||
def test_root_api_key_fails(self):
|
||||
iam_client = mock.MagicMock()
|
||||
iam_client.users_loaded = True
|
||||
iam_client.api_keys_loaded = True
|
||||
iam_client.account_root_user_id = ROOT_USER_ID
|
||||
iam_client.api_keys = [
|
||||
make_api_key(access_key=ROOT_API_KEY, user_id=ROOT_USER_ID)
|
||||
]
|
||||
iam_client.organization_id = ORGANIZATION_ID
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_scaleway_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned.iam_client",
|
||||
new=iam_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned import (
|
||||
iam_api_keys_no_root_owned,
|
||||
)
|
||||
|
||||
result = iam_api_keys_no_root_owned().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].resource_id == ROOT_API_KEY
|
||||
assert ROOT_USER_ID in result[0].status_extended
|
||||
|
||||
def test_user_api_key_passes(self):
|
||||
iam_client = mock.MagicMock()
|
||||
iam_client.users_loaded = True
|
||||
iam_client.api_keys_loaded = True
|
||||
iam_client.account_root_user_id = ROOT_USER_ID
|
||||
iam_client.api_keys = [
|
||||
make_api_key(access_key=USER_API_KEY, user_id=MEMBER_USER_ID)
|
||||
]
|
||||
iam_client.organization_id = ORGANIZATION_ID
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_scaleway_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned.iam_client",
|
||||
new=iam_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned import (
|
||||
iam_api_keys_no_root_owned,
|
||||
)
|
||||
|
||||
result = iam_api_keys_no_root_owned().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].resource_id == USER_API_KEY
|
||||
|
||||
def test_application_api_key_passes(self):
|
||||
iam_client = mock.MagicMock()
|
||||
iam_client.users_loaded = True
|
||||
iam_client.api_keys_loaded = True
|
||||
iam_client.account_root_user_id = ROOT_USER_ID
|
||||
iam_client.api_keys = [
|
||||
make_api_key(
|
||||
access_key=APP_API_KEY, user_id=None, application_id=APPLICATION_ID
|
||||
)
|
||||
]
|
||||
iam_client.organization_id = ORGANIZATION_ID
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_scaleway_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned.iam_client",
|
||||
new=iam_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned import (
|
||||
iam_api_keys_no_root_owned,
|
||||
)
|
||||
|
||||
result = iam_api_keys_no_root_owned().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
|
||||
def test_users_load_failure_returns_manual(self):
|
||||
iam_client = mock.MagicMock()
|
||||
iam_client.users_loaded = False
|
||||
iam_client.api_keys_loaded = True
|
||||
iam_client.account_root_user_id = None
|
||||
iam_client.api_keys = [
|
||||
make_api_key(access_key=ROOT_API_KEY, user_id=ROOT_USER_ID)
|
||||
]
|
||||
iam_client.organization_id = ORGANIZATION_ID
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_scaleway_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned.iam_client",
|
||||
new=iam_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned import (
|
||||
iam_api_keys_no_root_owned,
|
||||
)
|
||||
|
||||
result = iam_api_keys_no_root_owned().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "MANUAL"
|
||||
assert "Could not retrieve" in result[0].status_extended
|
||||
|
||||
def test_root_user_unresolved_returns_manual(self):
|
||||
# Data loaded fine but account_root_user_id could not be resolved
|
||||
# (e.g. application-scoped key). A root-owned key must NOT slip
|
||||
# through as PASS — the check degrades to MANUAL instead.
|
||||
iam_client = mock.MagicMock()
|
||||
iam_client.users_loaded = True
|
||||
iam_client.api_keys_loaded = True
|
||||
iam_client.account_root_user_id = None
|
||||
iam_client.api_keys = [
|
||||
make_api_key(access_key=ROOT_API_KEY, user_id=ROOT_USER_ID)
|
||||
]
|
||||
iam_client.organization_id = ORGANIZATION_ID
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_scaleway_provider(),
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned.iam_client",
|
||||
new=iam_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.scaleway.services.iam.iam_api_keys_no_root_owned.iam_api_keys_no_root_owned import (
|
||||
iam_api_keys_no_root_owned,
|
||||
)
|
||||
|
||||
result = iam_api_keys_no_root_owned().execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "MANUAL"
|
||||
assert "account root user" in result[0].status_extended
|
||||
@@ -0,0 +1,138 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.scaleway.models import ScalewayIdentityInfo
|
||||
from prowler.providers.scaleway.services.iam.iam_service import IAM
|
||||
from tests.providers.scaleway.scaleway_fixtures import (
|
||||
APPLICATION_ID,
|
||||
MEMBER_USER_ID,
|
||||
ORGANIZATION_ID,
|
||||
ROOT_USER_ID,
|
||||
USER_API_KEY,
|
||||
set_mocked_scaleway_provider,
|
||||
)
|
||||
|
||||
|
||||
def _application_identity() -> ScalewayIdentityInfo:
|
||||
"""Identity produced by an application-scoped API key: the IAM API
|
||||
never exposes account_root_user_id for an application bearer."""
|
||||
return ScalewayIdentityInfo(
|
||||
organization_id=ORGANIZATION_ID,
|
||||
bearer_id=APPLICATION_ID,
|
||||
bearer_type="application",
|
||||
bearer_email=None,
|
||||
account_root_user_id=None,
|
||||
)
|
||||
|
||||
|
||||
def _mock_user(
|
||||
user_id: str, account_root_user_id: str = ROOT_USER_ID, email: str = "u@example.com"
|
||||
):
|
||||
user = mock.MagicMock()
|
||||
user.id = user_id
|
||||
user.email = email
|
||||
user.username = email.split("@")[0]
|
||||
user.organization_id = ORGANIZATION_ID
|
||||
user.account_root_user_id = account_root_user_id
|
||||
user.mfa = True
|
||||
user.type_ = "owner" if user_id == account_root_user_id else "member"
|
||||
user.status = "activated"
|
||||
return user
|
||||
|
||||
|
||||
def _mock_api_key(access_key: str, user_id: str = None, application_id: str = None):
|
||||
key = mock.MagicMock()
|
||||
key.access_key = access_key
|
||||
key.description = "test"
|
||||
key.user_id = user_id
|
||||
key.application_id = application_id
|
||||
key.default_project_id = None
|
||||
key.editable = True
|
||||
key.managed = False
|
||||
key.creation_ip = None
|
||||
key.created_at = None
|
||||
key.updated_at = None
|
||||
key.expires_at = None
|
||||
return key
|
||||
|
||||
|
||||
class Test_IAM_service:
|
||||
def test_loads_users_and_api_keys(self):
|
||||
provider = set_mocked_scaleway_provider()
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_service.IamV1Alpha1API"
|
||||
) as iam_cls:
|
||||
api = iam_cls.return_value
|
||||
api.list_users_all.return_value = [
|
||||
_mock_user(ROOT_USER_ID),
|
||||
_mock_user(MEMBER_USER_ID, email="m@example.com"),
|
||||
]
|
||||
api.list_api_keys_all.return_value = [
|
||||
_mock_api_key(USER_API_KEY, user_id=MEMBER_USER_ID),
|
||||
_mock_api_key("SCWAPP", application_id=APPLICATION_ID),
|
||||
]
|
||||
|
||||
iam = IAM(provider)
|
||||
|
||||
assert iam.users_loaded is True
|
||||
assert iam.api_keys_loaded is True
|
||||
assert iam.account_root_user_id == ROOT_USER_ID
|
||||
assert len(iam.users) == 2
|
||||
assert len(iam.api_keys) == 2
|
||||
|
||||
def test_marks_users_unloaded_on_error(self):
|
||||
provider = set_mocked_scaleway_provider()
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_service.IamV1Alpha1API"
|
||||
) as iam_cls:
|
||||
api = iam_cls.return_value
|
||||
api.list_users_all.side_effect = Exception("denied")
|
||||
api.list_api_keys_all.return_value = []
|
||||
|
||||
iam = IAM(provider)
|
||||
|
||||
assert iam.users_loaded is False
|
||||
assert iam.api_keys_loaded is True
|
||||
# account_root_user_id comes from the audit identity, not the user
|
||||
# list, so a failed user listing must not blind the root-key check.
|
||||
assert iam.account_root_user_id == ROOT_USER_ID
|
||||
|
||||
def test_application_key_resolves_root_user_from_user_list(self):
|
||||
# Application-scoped API key: identity.account_root_user_id is None,
|
||||
# so it must be recovered from the loaded user list. Otherwise the
|
||||
# root-key check would silently PASS root-owned keys.
|
||||
provider = set_mocked_scaleway_provider(identity=_application_identity())
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_service.IamV1Alpha1API"
|
||||
) as iam_cls:
|
||||
api = iam_cls.return_value
|
||||
api.list_users_all.return_value = [
|
||||
_mock_user(ROOT_USER_ID),
|
||||
_mock_user(MEMBER_USER_ID, email="m@example.com"),
|
||||
]
|
||||
api.list_api_keys_all.return_value = []
|
||||
|
||||
iam = IAM(provider)
|
||||
|
||||
assert iam.account_root_user_id == ROOT_USER_ID
|
||||
|
||||
def test_account_root_user_id_none_when_unresolvable(self):
|
||||
# Application key + no user record exposes account_root_user_id:
|
||||
# nothing to fall back to, so it stays None and the root-key check
|
||||
# will degrade to MANUAL downstream.
|
||||
provider = set_mocked_scaleway_provider(identity=_application_identity())
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.scaleway.services.iam.iam_service.IamV1Alpha1API"
|
||||
) as iam_cls:
|
||||
api = iam_cls.return_value
|
||||
api.list_users_all.return_value = [
|
||||
_mock_user(MEMBER_USER_ID, account_root_user_id=None)
|
||||
]
|
||||
api.list_api_keys_all.return_value = []
|
||||
|
||||
iam = IAM(provider)
|
||||
|
||||
assert iam.account_root_user_id is None
|
||||
Reference in New Issue
Block a user