mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-08-19 09:30:21 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eab6d00482 | ||
|
|
e4c8624203 | ||
|
|
6ac1bd821c |
@@ -39,6 +39,7 @@ All notable changes to the **Prowler API** are documented in this file.
|
||||
|
||||
- Gunicorn worker timeout raised from the 30s default to 120s, so long-running requests are no longer killed prematurely [(#11631)](https://github.com/prowler-cloud/prowler/pull/11631)
|
||||
- Sentry now drops ASGI's `RequestAborted` errors from health-check probe disconnects on `/health/live` [(#11632)](https://github.com/prowler-cloud/prowler/pull/11632)
|
||||
- OCI provider secrets can now omit `region` and `regions`; existing OCI secrets are migrated to remove stored region filters, so migrated providers discover and scan all subscribed regions by default while legacy single-region and explicit multi-region filters remain supported for new payloads [(#11565)](https://github.com/prowler-cloud/prowler/pull/11565)
|
||||
- Gunicorn keep-alive timeout now exceeds the load balancer idle timeout, stopping 502s from reused connections [(#11647)](https://github.com/prowler-cloud/prowler/pull/11647)
|
||||
- API runs under the Uvicorn worker so keep-alive outlives the load balancer idle timeout, fixing Gunicorn's intermittent 502s [(#11663)](https://github.com/prowler-cloud/prowler/pull/11663)
|
||||
- SAML logins no longer wipe a user's roles when the IdP does not send the `userType` attribute; existing roles are kept, and when `userType` names a role that does not exist it is now created with read-only access (visibility over all providers, no management permissions) instead of no permissions at all [(#11520)](https://github.com/prowler-cloud/prowler/pull/11520)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import json
|
||||
|
||||
from api.db_utils import rls_transaction
|
||||
from cryptography.fernet import Fernet
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def remove_oraclecloud_secret_regions(apps, schema_editor):
|
||||
Tenant = apps.get_model("api", "Tenant")
|
||||
ProviderSecret = apps.get_model("api", "ProviderSecret")
|
||||
db_alias = schema_editor.connection.alias
|
||||
fernet = Fernet(settings.SECRETS_ENCRYPTION_KEY.encode())
|
||||
|
||||
for tenant in Tenant.objects.using(db_alias).all().iterator():
|
||||
with rls_transaction(str(tenant.id), using=db_alias):
|
||||
provider_secrets = ProviderSecret._base_manager.using(db_alias).filter(
|
||||
provider__provider="oraclecloud"
|
||||
)
|
||||
|
||||
for provider_secret in provider_secrets.iterator():
|
||||
encrypted_secret = provider_secret._secret
|
||||
if isinstance(encrypted_secret, memoryview):
|
||||
encrypted_secret = encrypted_secret.tobytes()
|
||||
elif isinstance(encrypted_secret, str):
|
||||
encrypted_secret = encrypted_secret.encode()
|
||||
|
||||
secret = json.loads(fernet.decrypt(encrypted_secret).decode())
|
||||
if "region" not in secret and "regions" not in secret:
|
||||
continue
|
||||
|
||||
secret.pop("region", None)
|
||||
secret.pop("regions", None)
|
||||
provider_secret._secret = fernet.encrypt(json.dumps(secret).encode())
|
||||
provider_secret.save(update_fields=["_secret"], using=db_alias)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("api", "0096_attack_paths_scan_is_migrated"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
remove_oraclecloud_secret_regions,
|
||||
reverse_code=migrations.RunPython.noop,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,52 @@
|
||||
from importlib import import_module
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from api.models import ProviderSecret
|
||||
from django.apps import apps
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestRemoveOraclecloudSecretRegionsMigration:
|
||||
def test_removes_region_fields_from_oraclecloud_secrets_only(
|
||||
self, providers_fixture
|
||||
):
|
||||
oraclecloud_provider = providers_fixture[6]
|
||||
aws_provider = providers_fixture[0]
|
||||
oraclecloud_secret = ProviderSecret.objects.create(
|
||||
tenant_id=oraclecloud_provider.tenant_id,
|
||||
provider=oraclecloud_provider,
|
||||
secret_type=ProviderSecret.TypeChoices.STATIC,
|
||||
secret={
|
||||
"user": "ocid1.user.oc1..fake",
|
||||
"fingerprint": "00:11:22:33:44:55:66:77",
|
||||
"key_content": "fake-base64-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..fake",
|
||||
"region": "us-ashburn-1",
|
||||
"regions": ["us-phoenix-1"],
|
||||
},
|
||||
)
|
||||
oraclecloud_provider.is_deleted = True
|
||||
oraclecloud_provider.save(update_fields=["is_deleted"])
|
||||
aws_secret = ProviderSecret.objects.create(
|
||||
tenant_id=aws_provider.tenant_id,
|
||||
provider=aws_provider,
|
||||
secret_type=ProviderSecret.TypeChoices.STATIC,
|
||||
secret={
|
||||
"aws_access_key_id": "fake-access-key-id",
|
||||
"aws_secret_access_key": "fake-secret-access-key",
|
||||
"region": "us-east-1",
|
||||
},
|
||||
)
|
||||
migration = import_module(
|
||||
"api.migrations.0097_remove_oraclecloud_secret_regions"
|
||||
)
|
||||
schema_editor = SimpleNamespace(connection=SimpleNamespace(alias="default"))
|
||||
|
||||
migration.remove_oraclecloud_secret_regions(apps, schema_editor)
|
||||
|
||||
oraclecloud_secret = ProviderSecret.all_objects.get(pk=oraclecloud_secret.pk)
|
||||
aws_secret.refresh_from_db()
|
||||
assert "region" not in oraclecloud_secret.secret
|
||||
assert "regions" not in oraclecloud_secret.secret
|
||||
assert aws_secret.secret["region"] == "us-east-1"
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
from api.v1.serializer_utils.integrations import S3ConfigSerializer
|
||||
from api.v1.serializers import ImageProviderSecret
|
||||
from api.v1.serializers import ImageProviderSecret, OracleCloudProviderSecret
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
|
||||
@@ -132,3 +132,77 @@ class TestImageProviderSecret:
|
||||
serializer = ImageProviderSecret(data={"registry_password": "pass"})
|
||||
assert not serializer.is_valid()
|
||||
assert "non_field_errors" in serializer.errors
|
||||
|
||||
|
||||
class TestOracleCloudProviderSecret:
|
||||
def valid_secret(self, **overrides):
|
||||
secret = {
|
||||
"user": "ocid1.user.oc1..aaaaaaaexample",
|
||||
"fingerprint": "aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
"key_content": "fake-base64-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
"regions": ["us-ashburn-1"],
|
||||
}
|
||||
secret.update(overrides)
|
||||
return secret
|
||||
|
||||
def test_accepts_regions_list(self):
|
||||
serializer = OracleCloudProviderSecret(data=self.valid_secret())
|
||||
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
assert serializer.validated_data["regions"] == ["us-ashburn-1"]
|
||||
|
||||
def test_accepts_regions_list_trims_values(self):
|
||||
serializer = OracleCloudProviderSecret(
|
||||
data=self.valid_secret(regions=[" us-ashburn-1 "])
|
||||
)
|
||||
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
assert serializer.validated_data["regions"] == ["us-ashburn-1"]
|
||||
|
||||
def test_accepts_legacy_region_string(self):
|
||||
secret = self.valid_secret(region="us-phoenix-1")
|
||||
secret.pop("regions")
|
||||
serializer = OracleCloudProviderSecret(data=secret)
|
||||
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
assert serializer.validated_data["region"] == "us-phoenix-1"
|
||||
|
||||
def test_accepts_legacy_region_string_trims_value(self):
|
||||
secret = self.valid_secret(region=" us-phoenix-1 ")
|
||||
secret.pop("regions")
|
||||
serializer = OracleCloudProviderSecret(data=secret)
|
||||
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
assert serializer.validated_data["region"] == "us-phoenix-1"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"regions",
|
||||
[
|
||||
[],
|
||||
[""],
|
||||
["us-ashburn-1", " "],
|
||||
["us-ashburn-1", "us-ashburn-1"],
|
||||
["us-ashburn-1", " us-ashburn-1 "],
|
||||
],
|
||||
)
|
||||
def test_rejects_invalid_regions_list(self, regions):
|
||||
serializer = OracleCloudProviderSecret(data=self.valid_secret(regions=regions))
|
||||
|
||||
assert not serializer.is_valid()
|
||||
|
||||
def test_accepts_missing_regions_and_region(self):
|
||||
secret = self.valid_secret()
|
||||
secret.pop("regions")
|
||||
serializer = OracleCloudProviderSecret(data=secret)
|
||||
|
||||
assert serializer.is_valid(), serializer.errors
|
||||
assert "region" not in serializer.validated_data
|
||||
assert "regions" not in serializer.validated_data
|
||||
|
||||
def test_rejects_both_regions_and_legacy_region(self):
|
||||
serializer = OracleCloudProviderSecret(
|
||||
data=self.valid_secret(region="us-phoenix-1")
|
||||
)
|
||||
|
||||
assert not serializer.is_valid()
|
||||
|
||||
@@ -171,6 +171,59 @@ class TestInitializeProwlerProvider:
|
||||
key="value", mutelist_content={"key": "value"}
|
||||
)
|
||||
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
def test_initialize_oraclecloud_provider_normalizes_regions_list(
|
||||
self, mock_return_prowler_provider
|
||||
):
|
||||
provider = MagicMock()
|
||||
provider.provider = Provider.ProviderChoices.ORACLECLOUD.value
|
||||
provider.secret.secret = {"regions": ["us-phoenix-1", "us-ashburn-1"]}
|
||||
mock_return_prowler_provider.return_value = MagicMock()
|
||||
|
||||
initialize_prowler_provider(provider)
|
||||
|
||||
mock_return_prowler_provider.return_value.assert_called_once_with(
|
||||
region={"us-phoenix-1", "us-ashburn-1"}
|
||||
)
|
||||
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
def test_initialize_oraclecloud_provider_preserves_legacy_region_string(
|
||||
self, mock_return_prowler_provider
|
||||
):
|
||||
provider = MagicMock()
|
||||
provider.provider = Provider.ProviderChoices.ORACLECLOUD.value
|
||||
provider.secret.secret = {"region": "us-ashburn-1"}
|
||||
mock_return_prowler_provider.return_value = MagicMock()
|
||||
|
||||
initialize_prowler_provider(provider)
|
||||
|
||||
mock_return_prowler_provider.return_value.assert_called_once_with(
|
||||
region={"us-ashburn-1"}
|
||||
)
|
||||
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
def test_initialize_oraclecloud_provider_without_region_omits_scan_filter(
|
||||
self, mock_return_prowler_provider
|
||||
):
|
||||
provider = MagicMock()
|
||||
provider.provider = Provider.ProviderChoices.ORACLECLOUD.value
|
||||
provider.secret.secret = {
|
||||
"user": "ocid1.user.oc1..fake",
|
||||
"fingerprint": "00:11:22:33:44:55:66:77",
|
||||
"key_content": "fake-base64-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..fake",
|
||||
}
|
||||
mock_return_prowler_provider.return_value = MagicMock()
|
||||
|
||||
initialize_prowler_provider(provider)
|
||||
|
||||
mock_return_prowler_provider.return_value.assert_called_once_with(
|
||||
user="ocid1.user.oc1..fake",
|
||||
fingerprint="00:11:22:33:44:55:66:77",
|
||||
key_content="fake-base64-key-content",
|
||||
tenancy="ocid1.tenancy.oc1..fake",
|
||||
)
|
||||
|
||||
|
||||
class TestProwlerProviderConnectionTest:
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
@@ -185,6 +238,68 @@ class TestProwlerProviderConnectionTest:
|
||||
key="value", provider_id="1234567890", raise_on_exception=False
|
||||
)
|
||||
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
def test_oraclecloud_connection_test_uses_deterministic_region_string(
|
||||
self, mock_return_prowler_provider
|
||||
):
|
||||
provider = MagicMock()
|
||||
provider.uid = "ocid1.tenancy.oc1..aaaaaaaexample"
|
||||
provider.provider = Provider.ProviderChoices.ORACLECLOUD.value
|
||||
provider.secret.secret = {"regions": ["us-phoenix-1", "us-ashburn-1"]}
|
||||
mock_return_prowler_provider.return_value = MagicMock()
|
||||
|
||||
prowler_provider_connection_test(provider)
|
||||
|
||||
mock_return_prowler_provider.return_value.test_connection.assert_called_once_with(
|
||||
region="us-ashburn-1",
|
||||
provider_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
raise_on_exception=False,
|
||||
)
|
||||
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
def test_oraclecloud_connection_test_ignores_empty_regions_list(
|
||||
self, mock_return_prowler_provider
|
||||
):
|
||||
provider = MagicMock()
|
||||
provider.uid = "ocid1.tenancy.oc1..aaaaaaaexample"
|
||||
provider.provider = Provider.ProviderChoices.ORACLECLOUD.value
|
||||
provider.secret.secret = {"regions": []}
|
||||
mock_return_prowler_provider.return_value = MagicMock()
|
||||
|
||||
prowler_provider_connection_test(provider)
|
||||
|
||||
mock_return_prowler_provider.return_value.test_connection.assert_called_once_with(
|
||||
provider_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
raise_on_exception=False,
|
||||
)
|
||||
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
def test_oraclecloud_connection_test_uses_direct_credentials_without_region(
|
||||
self, mock_return_prowler_provider
|
||||
):
|
||||
provider = MagicMock()
|
||||
provider.uid = "ocid1.tenancy.oc1..aaaaaaaexample"
|
||||
provider.provider = Provider.ProviderChoices.ORACLECLOUD.value
|
||||
provider.secret.secret = {
|
||||
"user": "ocid1.user.oc1..aaaaaaaexample",
|
||||
"fingerprint": "00:11:22:33:44:55:66:77",
|
||||
"key_content": "fake-base64-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
}
|
||||
mock_return_prowler_provider.return_value = MagicMock()
|
||||
|
||||
prowler_provider_connection_test(provider)
|
||||
|
||||
mock_return_prowler_provider.return_value.test_connection.assert_called_once_with(
|
||||
user="ocid1.user.oc1..aaaaaaaexample",
|
||||
fingerprint="00:11:22:33:44:55:66:77",
|
||||
key_content="fake-base64-key-content",
|
||||
tenancy="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
region="us-ashburn-1",
|
||||
provider_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
raise_on_exception=False,
|
||||
)
|
||||
|
||||
@pytest.mark.django_db
|
||||
@patch("api.utils.return_prowler_provider")
|
||||
def test_prowler_provider_connection_test_without_secret(
|
||||
@@ -380,6 +495,29 @@ class TestGetProwlerProviderKwargs:
|
||||
expected_result = {**secret_dict, "region": {"us-ashburn-1"}}
|
||||
assert result == expected_result
|
||||
|
||||
def test_get_prowler_provider_kwargs_oraclecloud_without_region_keeps_secret_regionless(
|
||||
self,
|
||||
):
|
||||
secret_dict = {
|
||||
"user": "ocid1.user.oc1..fake",
|
||||
"fingerprint": "00:11:22:33:44:55:66:77",
|
||||
"key_content": "fake-base64-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..fake",
|
||||
}
|
||||
secret_mock = MagicMock()
|
||||
secret_mock.secret = secret_dict
|
||||
|
||||
provider = MagicMock()
|
||||
provider.provider = Provider.ProviderChoices.ORACLECLOUD.value
|
||||
provider.secret = secret_mock
|
||||
provider.uid = "ocid1.tenancy.oc1..fake"
|
||||
|
||||
result = get_prowler_provider_kwargs(provider)
|
||||
|
||||
assert result == secret_dict
|
||||
assert "region" not in result
|
||||
assert "regions" not in result
|
||||
|
||||
def test_get_prowler_provider_kwargs_with_mutelist(self):
|
||||
provider_uid = "provider_uid"
|
||||
secret_dict = {"key": "value"}
|
||||
|
||||
@@ -2796,6 +2796,52 @@ class TestProviderGroupViewSet:
|
||||
|
||||
@pytest.mark.django_db
|
||||
class TestProviderSecretViewSet:
|
||||
@staticmethod
|
||||
def _get_oraclecloud_provider(providers_fixture):
|
||||
return next(
|
||||
provider
|
||||
for provider in providers_fixture
|
||||
if provider.provider == Provider.ProviderChoices.ORACLECLOUD.value
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _oraclecloud_secret(**overrides):
|
||||
secret = {
|
||||
"user": "ocid1.user.oc1..aaaaaaaakldibrbov4ubh25aqdeiroklxjngwka7u6w7no3glmdq3n5sxtkq",
|
||||
"fingerprint": "aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
"key_content": "test-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..aaaaaaaa3dwoazoox4q7wrvriywpokp5grlhgnkwtyt6dmwyou7no6mdmzda",
|
||||
}
|
||||
secret.update(overrides)
|
||||
return secret
|
||||
|
||||
def _create_oraclecloud_secret(
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
secret,
|
||||
name="OCI Secret",
|
||||
):
|
||||
provider = self._get_oraclecloud_provider(providers_fixture)
|
||||
data = {
|
||||
"data": {
|
||||
"type": "provider-secrets",
|
||||
"attributes": {
|
||||
"name": name,
|
||||
"secret_type": ProviderSecret.TypeChoices.STATIC,
|
||||
"secret": secret,
|
||||
},
|
||||
"relationships": {
|
||||
"provider": {"data": {"type": "providers", "id": str(provider.id)}}
|
||||
},
|
||||
}
|
||||
}
|
||||
return authenticated_client.post(
|
||||
reverse("providersecret-list"),
|
||||
data=json.dumps(data),
|
||||
content_type="application/vnd.api+json",
|
||||
)
|
||||
|
||||
def test_provider_secrets_list(self, authenticated_client, provider_secret_fixture):
|
||||
response = authenticated_client.get(reverse("providersecret-list"))
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
@@ -2931,9 +2977,8 @@ class TestProviderSecretViewSet:
|
||||
{
|
||||
"user": "ocid1.user.oc1..aaaaaaaakldibrbov4ubh25aqdeiroklxjngwka7u6w7no3glmdq3n5sxtkq",
|
||||
"fingerprint": "aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
"key_content": "-----BEGIN RSA PRIVATE KEY-----\ntest-key-content\n-----END RSA PRIVATE KEY-----",
|
||||
"key_content": "test-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..aaaaaaaa3dwoazoox4q7wrvriywpokp5grlhgnkwtyt6dmwyou7no6mdmzda",
|
||||
"region": "us-ashburn-1",
|
||||
},
|
||||
),
|
||||
# OCI with API key credentials (with key_file)
|
||||
@@ -2945,7 +2990,18 @@ class TestProviderSecretViewSet:
|
||||
"fingerprint": "aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
"key_file": "/path/to/oci_api_key.pem",
|
||||
"tenancy": "ocid1.tenancy.oc1..aaaaaaaa3dwoazoox4q7wrvriywpokp5grlhgnkwtyt6dmwyou7no6mdmzda",
|
||||
"region": "us-ashburn-1",
|
||||
},
|
||||
),
|
||||
# OCI with explicit region filters
|
||||
(
|
||||
Provider.ProviderChoices.ORACLECLOUD.value,
|
||||
ProviderSecret.TypeChoices.STATIC,
|
||||
{
|
||||
"user": "ocid1.user.oc1..aaaaaaaakldibrbov4ubh25aqdeiroklxjngwka7u6w7no3glmdq3n5sxtkq",
|
||||
"fingerprint": "aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
"key_content": "test-key-content",
|
||||
"tenancy": "ocid1.tenancy.oc1..aaaaaaaa3dwoazoox4q7wrvriywpokp5grlhgnkwtyt6dmwyou7no6mdmzda",
|
||||
"regions": ["us-ashburn-1", "us-phoenix-1"],
|
||||
},
|
||||
),
|
||||
# OCI with API key credentials (with passphrase)
|
||||
@@ -2955,9 +3011,8 @@ class TestProviderSecretViewSet:
|
||||
{
|
||||
"user": "ocid1.user.oc1..aaaaaaaakldibrbov4ubh25aqdeiroklxjngwka7u6w7no3glmdq3n5sxtkq",
|
||||
"fingerprint": "aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
"key_content": "-----BEGIN RSA PRIVATE KEY-----\ntest-encrypted-key\n-----END RSA PRIVATE KEY-----",
|
||||
"key_content": "test-encrypted-key",
|
||||
"tenancy": "ocid1.tenancy.oc1..aaaaaaaa3dwoazoox4q7wrvriywpokp5grlhgnkwtyt6dmwyou7no6mdmzda",
|
||||
"region": "us-ashburn-1",
|
||||
"pass_phrase": "my-secure-passphrase",
|
||||
},
|
||||
),
|
||||
@@ -3110,6 +3165,160 @@ class TestProviderSecretViewSet:
|
||||
== data["data"]["relationships"]["provider"]["data"]["id"]
|
||||
)
|
||||
|
||||
def test_provider_secrets_create_oraclecloud_without_regions_stores_neither(
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
):
|
||||
response = self._create_oraclecloud_secret(
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
self._oraclecloud_secret(),
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
provider_secret = ProviderSecret.objects.get()
|
||||
assert "region" not in provider_secret.secret
|
||||
assert "regions" not in provider_secret.secret
|
||||
|
||||
def test_provider_secrets_create_oraclecloud_with_regions_stores_regions(
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
):
|
||||
response = self._create_oraclecloud_secret(
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
self._oraclecloud_secret(regions=["us-ashburn-1", "us-phoenix-1"]),
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
provider_secret = ProviderSecret.objects.get()
|
||||
assert provider_secret.secret["regions"] == ["us-ashburn-1", "us-phoenix-1"]
|
||||
assert "region" not in provider_secret.secret
|
||||
|
||||
def test_provider_secrets_create_oraclecloud_rejects_region_and_regions(
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
):
|
||||
response = self._create_oraclecloud_secret(
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
self._oraclecloud_secret(region="us-ashburn-1", regions=["us-phoenix-1"]),
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
errors = response.json()["errors"]
|
||||
assert errors[0]["status"] == "400"
|
||||
assert errors[0]["code"] == "invalid"
|
||||
assert errors[0]["source"]["pointer"] == "/data/attributes/secret/region"
|
||||
|
||||
def test_provider_secrets_update_oraclecloud_without_regions_stores_neither(
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
):
|
||||
create_response = self._create_oraclecloud_secret(
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
self._oraclecloud_secret(regions=["us-ashburn-1"]),
|
||||
)
|
||||
provider_secret = ProviderSecret.objects.get(
|
||||
id=create_response.json()["data"]["id"]
|
||||
)
|
||||
data = {
|
||||
"data": {
|
||||
"type": "provider-secrets",
|
||||
"id": str(provider_secret.id),
|
||||
"attributes": {"secret": self._oraclecloud_secret()},
|
||||
}
|
||||
}
|
||||
|
||||
response = authenticated_client.patch(
|
||||
reverse("providersecret-detail", kwargs={"pk": provider_secret.id}),
|
||||
data=json.dumps(data),
|
||||
content_type="application/vnd.api+json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
provider_secret.refresh_from_db()
|
||||
assert "region" not in provider_secret.secret
|
||||
assert "regions" not in provider_secret.secret
|
||||
|
||||
def test_provider_secrets_update_oraclecloud_with_regions_stores_regions(
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
):
|
||||
create_response = self._create_oraclecloud_secret(
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
self._oraclecloud_secret(),
|
||||
)
|
||||
provider_secret = ProviderSecret.objects.get(
|
||||
id=create_response.json()["data"]["id"]
|
||||
)
|
||||
data = {
|
||||
"data": {
|
||||
"type": "provider-secrets",
|
||||
"id": str(provider_secret.id),
|
||||
"attributes": {
|
||||
"secret": self._oraclecloud_secret(
|
||||
regions=["us-ashburn-1", "us-phoenix-1"]
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
response = authenticated_client.patch(
|
||||
reverse("providersecret-detail", kwargs={"pk": provider_secret.id}),
|
||||
data=json.dumps(data),
|
||||
content_type="application/vnd.api+json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
provider_secret.refresh_from_db()
|
||||
assert provider_secret.secret["regions"] == ["us-ashburn-1", "us-phoenix-1"]
|
||||
assert "region" not in provider_secret.secret
|
||||
|
||||
def test_provider_secrets_update_oraclecloud_rejects_region_and_regions(
|
||||
self,
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
):
|
||||
create_response = self._create_oraclecloud_secret(
|
||||
authenticated_client,
|
||||
providers_fixture,
|
||||
self._oraclecloud_secret(),
|
||||
)
|
||||
provider_secret = ProviderSecret.objects.get(
|
||||
id=create_response.json()["data"]["id"]
|
||||
)
|
||||
data = {
|
||||
"data": {
|
||||
"type": "provider-secrets",
|
||||
"id": str(provider_secret.id),
|
||||
"attributes": {
|
||||
"secret": self._oraclecloud_secret(
|
||||
region="us-ashburn-1", regions=["us-phoenix-1"]
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
response = authenticated_client.patch(
|
||||
reverse("providersecret-detail", kwargs={"pk": provider_secret.id}),
|
||||
data=json.dumps(data),
|
||||
content_type="application/vnd.api+json",
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
errors = response.json()["errors"]
|
||||
assert errors[0]["status"] == "400"
|
||||
assert errors[0]["code"] == "invalid"
|
||||
assert errors[0]["source"]["pointer"] == "/data/attributes/secret/region"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"attributes, error_code, error_pointer",
|
||||
(
|
||||
@@ -4069,7 +4278,7 @@ class TestScanViewSet:
|
||||
|
||||
monkeypatch.setattr(
|
||||
"api.v1.views.env",
|
||||
type("env", (), {"str": lambda self, *args, **kwargs: "test-bucket"})(),
|
||||
type("env", (), {"str": lambda self, *_args, **_kwargs: "test-bucket"})(),
|
||||
)
|
||||
|
||||
presigned_url = (
|
||||
@@ -4175,7 +4384,7 @@ class TestScanViewSet:
|
||||
|
||||
monkeypatch.setattr(
|
||||
"api.v1.views.TaskSerializer",
|
||||
lambda *args, **kwargs: type("S", (), {"data": dummy}),
|
||||
lambda *_args, **_kwargs: type("S", (), {"data": dummy}),
|
||||
)
|
||||
|
||||
framework = get_compliance_frameworks(scan.provider.provider)[0]
|
||||
@@ -4233,7 +4442,7 @@ class TestScanViewSet:
|
||||
|
||||
monkeypatch.setattr(
|
||||
"api.v1.views.env",
|
||||
type("env", (), {"str": lambda self, *args, **kwargs: "test-bucket"})(),
|
||||
type("env", (), {"str": lambda self, *_args, **_kwargs: "test-bucket"})(),
|
||||
)
|
||||
|
||||
match_key = "path/compliance/mitre_attack_aws.csv"
|
||||
@@ -4275,7 +4484,7 @@ class TestScanViewSet:
|
||||
|
||||
monkeypatch.setattr(
|
||||
"api.v1.views.env",
|
||||
type("env", (), {"str": lambda self, *args, **kwargs: "test-bucket"})(),
|
||||
type("env", (), {"str": lambda self, *_args, **_kwargs: "test-bucket"})(),
|
||||
)
|
||||
|
||||
old_key = "path/compliance/prowler-output-aws-20240101000000_cis_1.4_aws.csv"
|
||||
@@ -4356,7 +4565,7 @@ class TestScanViewSet:
|
||||
|
||||
monkeypatch.setattr(
|
||||
"api.v1.views.env",
|
||||
type("env", (), {"str": lambda self, *args, **kwargs: "test-bucket"})(),
|
||||
type("env", (), {"str": lambda self, *_args, **_kwargs: "test-bucket"})(),
|
||||
)
|
||||
|
||||
class FakeS3Client:
|
||||
@@ -4546,8 +4755,10 @@ class TestScanViewSet:
|
||||
inserted_at=base + timedelta(hours=1)
|
||||
)
|
||||
|
||||
mock_task_serializer.side_effect = lambda instance, *a, **k: SimpleNamespace(
|
||||
data={"id": str(instance.id), "state": StateChoices.EXECUTING}
|
||||
mock_task_serializer.side_effect = lambda instance, *_args, **_kwargs: (
|
||||
SimpleNamespace(
|
||||
data={"id": str(instance.id), "state": StateChoices.EXECUTING}
|
||||
)
|
||||
)
|
||||
|
||||
url = reverse("scan-report", kwargs={"pk": scan.id})
|
||||
|
||||
@@ -242,12 +242,6 @@ def get_prowler_provider_kwargs(
|
||||
**prowler_provider_kwargs,
|
||||
"filter_accounts": [provider.uid],
|
||||
}
|
||||
elif provider.provider == Provider.ProviderChoices.ORACLECLOUD.value:
|
||||
if isinstance(prowler_provider_kwargs.get("region"), str):
|
||||
prowler_provider_kwargs = {
|
||||
**prowler_provider_kwargs,
|
||||
"region": {prowler_provider_kwargs["region"]},
|
||||
}
|
||||
elif provider.provider == Provider.ProviderChoices.OPENSTACK.value:
|
||||
# clouds_yaml_content, clouds_yaml_cloud and provider_id are validated
|
||||
# in the provider itself, so it's not needed here.
|
||||
@@ -278,6 +272,11 @@ def get_prowler_provider_kwargs(
|
||||
**{k: v for k, v in prowler_provider_kwargs.items() if v},
|
||||
}
|
||||
|
||||
elif provider.provider == Provider.ProviderChoices.ORACLECLOUD.value:
|
||||
prowler_provider_kwargs = _normalize_oraclecloud_provider_kwargs(
|
||||
prowler_provider_kwargs
|
||||
)
|
||||
|
||||
if mutelist_processor:
|
||||
mutelist_content = mutelist_processor.configuration.get("Mutelist", {})
|
||||
# IaC and Image providers don't support mutelist (both use Trivy's built-in logic)
|
||||
@@ -290,6 +289,44 @@ def get_prowler_provider_kwargs(
|
||||
return prowler_provider_kwargs
|
||||
|
||||
|
||||
def _normalize_oraclecloud_provider_kwargs(secret: dict) -> dict:
|
||||
"""Normalize external OCI secret fields into SDK provider kwargs."""
|
||||
prowler_provider_kwargs = secret.copy()
|
||||
|
||||
if "regions" in prowler_provider_kwargs:
|
||||
regions = prowler_provider_kwargs.pop("regions")
|
||||
prowler_provider_kwargs["region"] = set(regions)
|
||||
elif "region" in prowler_provider_kwargs:
|
||||
prowler_provider_kwargs["region"] = {prowler_provider_kwargs["region"]}
|
||||
|
||||
return prowler_provider_kwargs
|
||||
|
||||
|
||||
def _normalize_oraclecloud_connection_test_kwargs(secret: dict) -> dict:
|
||||
"""Normalize external OCI secret fields into test_connection kwargs."""
|
||||
prowler_provider_kwargs = secret.copy()
|
||||
|
||||
if "regions" in prowler_provider_kwargs:
|
||||
regions = prowler_provider_kwargs.pop("regions")
|
||||
if regions:
|
||||
prowler_provider_kwargs["region"] = sorted(regions)[0]
|
||||
|
||||
if (
|
||||
"region" not in prowler_provider_kwargs
|
||||
and prowler_provider_kwargs.get("user")
|
||||
and prowler_provider_kwargs.get("fingerprint")
|
||||
and prowler_provider_kwargs.get("tenancy")
|
||||
and (
|
||||
prowler_provider_kwargs.get("key_content")
|
||||
or prowler_provider_kwargs.get("key_file")
|
||||
)
|
||||
):
|
||||
# Connection validation needs one OCI endpoint, but scans remain unfiltered.
|
||||
prowler_provider_kwargs["region"] = "us-ashburn-1"
|
||||
|
||||
return prowler_provider_kwargs
|
||||
|
||||
|
||||
def initialize_prowler_provider(
|
||||
provider: Provider,
|
||||
mutelist_processor: Processor | None = None,
|
||||
@@ -392,6 +429,15 @@ def prowler_provider_connection_test(provider: Provider) -> Connection:
|
||||
if prowler_provider_kwargs.get("registry_token"):
|
||||
image_kwargs["registry_token"] = prowler_provider_kwargs["registry_token"]
|
||||
return prowler_provider.test_connection(**image_kwargs)
|
||||
elif provider.provider == Provider.ProviderChoices.ORACLECLOUD.value:
|
||||
oraclecloud_kwargs = _normalize_oraclecloud_connection_test_kwargs(
|
||||
prowler_provider_kwargs
|
||||
)
|
||||
return prowler_provider.test_connection(
|
||||
**oraclecloud_kwargs,
|
||||
provider_id=provider.uid,
|
||||
raise_on_exception=False,
|
||||
)
|
||||
else:
|
||||
return prowler_provider.test_connection(
|
||||
**prowler_provider_kwargs,
|
||||
|
||||
@@ -296,14 +296,27 @@ from rest_framework_json_api import serializers
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"description": "The OCI region identifier (e.g., us-ashburn-1, us-phoenix-1).",
|
||||
"description": "Legacy optional single OCI region filter. "
|
||||
"Deprecated; use regions for explicit scan scope filters.",
|
||||
},
|
||||
"regions": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {"type": "string", "minLength": 1},
|
||||
"description": "Optional explicit OCI regions to audit. Omit to audit all "
|
||||
"subscribed OCI regions discovered from the tenancy.",
|
||||
},
|
||||
"pass_phrase": {
|
||||
"type": "string",
|
||||
"description": "The passphrase for the private key, if encrypted.",
|
||||
},
|
||||
},
|
||||
"required": ["user", "fingerprint", "tenancy", "region"],
|
||||
"required": ["user", "fingerprint", "tenancy"],
|
||||
"anyOf": [
|
||||
{"required": ["key_file"]},
|
||||
{"required": ["key_content"]},
|
||||
],
|
||||
"not": {"required": ["region", "regions"]},
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
|
||||
@@ -1739,9 +1739,51 @@ class OracleCloudProviderSecret(serializers.Serializer):
|
||||
key_file = serializers.CharField(required=False)
|
||||
key_content = serializers.CharField(required=False)
|
||||
tenancy = serializers.CharField()
|
||||
region = serializers.CharField()
|
||||
regions = serializers.ListField(
|
||||
child=serializers.CharField(allow_blank=False),
|
||||
allow_empty=False,
|
||||
required=False,
|
||||
help_text="OCI regions to audit. Canonical field for new payloads.",
|
||||
)
|
||||
region = serializers.CharField(
|
||||
required=False,
|
||||
help_text="Legacy single OCI region. Deprecated; use regions instead.",
|
||||
)
|
||||
pass_phrase = serializers.CharField(required=False)
|
||||
|
||||
def validate(self, attrs):
|
||||
has_regions = "regions" in attrs
|
||||
has_region = "region" in attrs
|
||||
|
||||
if has_regions and has_region:
|
||||
raise serializers.ValidationError(
|
||||
{"region": "Provide either regions or legacy region, not both."}
|
||||
)
|
||||
|
||||
if "key_file" not in attrs and "key_content" not in attrs:
|
||||
raise serializers.ValidationError(
|
||||
{"key_file": "Either key_file or key_content must be provided."}
|
||||
)
|
||||
|
||||
if has_regions:
|
||||
regions = [region.strip() for region in attrs["regions"]]
|
||||
if any(not region for region in regions):
|
||||
raise serializers.ValidationError(
|
||||
{"regions": "Regions cannot contain blank values."}
|
||||
)
|
||||
if len(regions) != len(set(regions)):
|
||||
raise serializers.ValidationError(
|
||||
{"regions": "Regions cannot contain duplicate values."}
|
||||
)
|
||||
attrs["regions"] = regions
|
||||
elif has_region:
|
||||
region = attrs["region"].strip()
|
||||
if not region:
|
||||
raise serializers.ValidationError({"region": "Region cannot be blank."})
|
||||
attrs["region"] = region
|
||||
|
||||
return attrs
|
||||
|
||||
class Meta:
|
||||
resource_name = "provider-secrets"
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- Compliance frameworks contributed by several external packages under the same provider are now merged instead of overwritten, so every entry-point directory a provider contributes is discovered [(#11578)](https://github.com/prowler-cloud/prowler/pull/11578)
|
||||
- Azure PostgreSQL flexible server collection no longer drops the remaining servers in a subscription when one server fails to collect; the `connection_throttle.enable` parameter (removed in PostgreSQL 16+) is treated as absent only when the Azure SDK reports it as not found, so unexpected lookup failures are not silently reported as throttling disabled [(#11595)](https://github.com/prowler-cloud/prowler/pull/11595)
|
||||
- Azure `keyvault_logging_enabled` now accepts Key Vault diagnostic settings that enable the explicit `AuditEvent` category, avoiding false failures when Azure returns category-based logs without category groups [(#11660)](https://github.com/prowler-cloud/prowler/pull/11660)
|
||||
- GitHub default branch protection checks now evaluate repository rulesets in addition to classic branch protection, avoiding false positives for repositories that enforce protection through rulesets [(#11723)](https://github.com/prowler-cloud/prowler/pull/11723)
|
||||
- Okta, Alibaba Cloud and OpenStack scan-config sections are now validated against a registered schema instead of being silently accepted, so their configurable thresholds (session/idle timeouts, retention days, image-sharing and secret-scanning settings) log a warning and fall back to the built-in default whenever a value is out of range [(#11725)](https://github.com/prowler-cloud/prowler/pull/11725)
|
||||
|
||||
---
|
||||
@@ -127,6 +126,10 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
- A broken built-in provider no longer aborts the CLI when a different provider was invoked [(#11618)](https://github.com/prowler-cloud/prowler/pull/11618)
|
||||
- GCP organization scans with `--organization-id` no longer silently fall back to the credentials' host project when the Cloud Asset API call fails [(#11280)](https://github.com/prowler-cloud/prowler/pull/11280)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- Oracle Cloud API key authentication now uses an internal bootstrap region when no explicit scan region filter is provided [(#11565)](https://github.com/prowler-cloud/prowler/pull/11565)
|
||||
|
||||
---
|
||||
|
||||
## [5.30.0] (Prowler v5.30.0)
|
||||
|
||||
@@ -68,12 +68,13 @@ class OraclecloudProvider(Provider):
|
||||
_mutelist: OCIMutelist
|
||||
audit_metadata: Audit_Metadata
|
||||
_home_region: str = "us-ashburn-1"
|
||||
_bootstrap_region: str = "us-ashburn-1"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
oci_config_file: str = None,
|
||||
profile: str = None,
|
||||
region: set = set(),
|
||||
region: set = None,
|
||||
compartment_ids: list = None,
|
||||
config_path: str = None,
|
||||
config_content: dict = None,
|
||||
@@ -131,8 +132,11 @@ class OraclecloudProvider(Provider):
|
||||
|
||||
# Check if the configuration is scanning a single region
|
||||
single_region = None
|
||||
if region:
|
||||
single_region = list(region)[0] if len(region) == 1 else None
|
||||
if isinstance(region, str):
|
||||
single_region = region
|
||||
elif region:
|
||||
single_region = sorted(region)[0]
|
||||
bootstrap_region = single_region or self._bootstrap_region
|
||||
|
||||
# Setup OCI Session
|
||||
logger.info("Setting up OCI session ...")
|
||||
@@ -145,7 +149,7 @@ class OraclecloudProvider(Provider):
|
||||
key_file=key_file,
|
||||
key_content=key_content,
|
||||
tenancy=tenancy,
|
||||
region=single_region,
|
||||
region=bootstrap_region,
|
||||
pass_phrase=pass_phrase,
|
||||
)
|
||||
|
||||
@@ -155,7 +159,7 @@ class OraclecloudProvider(Provider):
|
||||
logger.info("Validating OCI credentials ...")
|
||||
self._identity = self.set_identity(
|
||||
session=self._session,
|
||||
region=single_region,
|
||||
region=bootstrap_region,
|
||||
compartment_ids=compartment_ids,
|
||||
)
|
||||
logger.info("OCI credentials validated")
|
||||
@@ -165,7 +169,13 @@ class OraclecloudProvider(Provider):
|
||||
# Determine the tenancy home region from the full subscription list, independent of
|
||||
# the --region filter, so tenancy-level APIs (e.g. the Audit configuration) always
|
||||
# target the home region instead of a filtered, non-home region.
|
||||
all_subscribed_regions = self.get_regions_to_audit()
|
||||
try:
|
||||
all_subscribed_regions = self.get_regions_to_audit()
|
||||
except OCISetUpSessionError:
|
||||
if single_region and len(self._regions) == 1:
|
||||
all_subscribed_regions = self._regions
|
||||
else:
|
||||
raise
|
||||
self._home_region = next(
|
||||
(region.key for region in all_subscribed_regions if region.is_home_region),
|
||||
self._regions[0].key if self._regions else "us-ashburn-1",
|
||||
@@ -284,7 +294,7 @@ class OraclecloudProvider(Provider):
|
||||
signer = None
|
||||
|
||||
# If API key credentials are provided directly, create config from them
|
||||
if user and fingerprint and tenancy and region:
|
||||
if user and fingerprint and tenancy:
|
||||
import base64
|
||||
|
||||
logger.info("Using API key credentials from direct parameters")
|
||||
@@ -294,7 +304,7 @@ class OraclecloudProvider(Provider):
|
||||
"user": user,
|
||||
"fingerprint": fingerprint,
|
||||
"tenancy": tenancy,
|
||||
"region": region,
|
||||
"region": region or OraclecloudProvider._bootstrap_region,
|
||||
}
|
||||
|
||||
# Handle private key
|
||||
@@ -565,6 +575,12 @@ class OraclecloudProvider(Provider):
|
||||
"""
|
||||
regions = []
|
||||
|
||||
explicit_regions = None
|
||||
if isinstance(region_set, str):
|
||||
explicit_regions = {region_set}
|
||||
elif region_set:
|
||||
explicit_regions = set(region_set)
|
||||
|
||||
# Audit all subscribed regions
|
||||
try:
|
||||
# Create identity client with proper authentication handling
|
||||
@@ -581,11 +597,9 @@ class OraclecloudProvider(Provider):
|
||||
).data
|
||||
|
||||
# Check if auditing specific region or all
|
||||
regions_check = (
|
||||
region_set
|
||||
if region_set
|
||||
else [sub.region_name for sub in region_subscriptions]
|
||||
)
|
||||
regions_check = explicit_regions or [
|
||||
sub.region_name for sub in region_subscriptions
|
||||
]
|
||||
|
||||
for region_sub in region_subscriptions:
|
||||
if region_sub.region_name in regions_check:
|
||||
@@ -600,11 +614,21 @@ class OraclecloudProvider(Provider):
|
||||
)
|
||||
logger.info(f"Found {len(regions)} subscribed regions")
|
||||
except Exception as error:
|
||||
if not explicit_regions or len(explicit_regions) != 1:
|
||||
raise OCISetUpSessionError(
|
||||
original_exception=error,
|
||||
message=(
|
||||
"Could not retrieve OCI subscribed regions. "
|
||||
"Configure an explicit region to preserve legacy single-region scans, "
|
||||
"or fix the credentials/permissions required to list region subscriptions."
|
||||
),
|
||||
) from error
|
||||
|
||||
config_region = next(iter(explicit_regions))
|
||||
logger.warning(
|
||||
f"Could not retrieve region subscriptions: {error}. Using configured region."
|
||||
f"Could not retrieve region subscriptions: {error}. "
|
||||
f"Using explicitly configured region {config_region}."
|
||||
)
|
||||
# Fallback to configured region
|
||||
config_region = self._session.config.get("region", "us-ashburn-1")
|
||||
regions.append(
|
||||
OCIRegion(
|
||||
key=config_region,
|
||||
@@ -855,7 +879,7 @@ class OraclecloudProvider(Provider):
|
||||
session = None
|
||||
|
||||
# If API key credentials are provided directly, create config from them
|
||||
if user and fingerprint and tenancy and region:
|
||||
if user and fingerprint and tenancy:
|
||||
import base64
|
||||
|
||||
logger.info("Using API key credentials from direct parameters")
|
||||
@@ -865,7 +889,7 @@ class OraclecloudProvider(Provider):
|
||||
"user": user,
|
||||
"fingerprint": fingerprint,
|
||||
"tenancy": tenancy,
|
||||
"region": region,
|
||||
"region": region or OraclecloudProvider._bootstrap_region,
|
||||
}
|
||||
|
||||
# Handle private key
|
||||
@@ -914,7 +938,7 @@ class OraclecloudProvider(Provider):
|
||||
|
||||
identity = OraclecloudProvider.set_identity(
|
||||
session=session,
|
||||
region=region,
|
||||
region=region or OraclecloudProvider._bootstrap_region,
|
||||
)
|
||||
|
||||
# Validate provider_id if provided
|
||||
|
||||
+14
-1
@@ -377,4 +377,17 @@ override-dependencies = ["okta==3.4.2"]
|
||||
# (e.g. mock_sensitive_args in tests/lib/cli/redact_test.py)
|
||||
# - view : DRF BasePermission.has_object_permission(self, request, view, obj)
|
||||
# framework-required signature param in skills/django-drf template assets
|
||||
ignore_names = ["mock_*", "view"]
|
||||
ignore_names = [
|
||||
"Prefix",
|
||||
"backfill_scan_metadata_fixture",
|
||||
"create_provider_group_relationship",
|
||||
"expected_scanner_args",
|
||||
"field_to_check",
|
||||
"finding_groups_title_variants_fixture",
|
||||
"latest_scan_finding_with_categories",
|
||||
"mock_*",
|
||||
"provider_compliance_scores_fixture",
|
||||
"scan_summaries_fixture",
|
||||
"tenant_compliance_summary_fixture",
|
||||
"view"
|
||||
]
|
||||
|
||||
@@ -5,6 +5,7 @@ import pytest
|
||||
from prowler.providers.oraclecloud.exceptions.exceptions import (
|
||||
OCIAuthenticationError,
|
||||
OCIInvalidConfigError,
|
||||
OCISetUpSessionError,
|
||||
)
|
||||
from prowler.providers.oraclecloud.models import OCIIdentityInfo, OCIRegion, OCISession
|
||||
from prowler.providers.oraclecloud.oraclecloud_provider import OraclecloudProvider
|
||||
@@ -200,6 +201,41 @@ MIIEpQIBAAKCAQEA0Z3VS5JJcds3xfn/ygWyF8n0sMcD/QHWCJ7yGSEtLN2T
|
||||
|
||||
assert connection.is_connected is True
|
||||
|
||||
def test_test_connection_direct_credentials_without_region_uses_bootstrap_region(
|
||||
self,
|
||||
):
|
||||
"""Direct API key auth should not fall back to config-file auth without a region."""
|
||||
import base64
|
||||
|
||||
valid_key = (
|
||||
"-----BEGIN RSA PRIVATE KEY-----\nfake\n-----END RSA PRIVATE KEY-----"
|
||||
)
|
||||
encoded_key = base64.b64encode(valid_key.encode("utf-8")).decode("utf-8")
|
||||
|
||||
with (
|
||||
patch("oci.config.validate_config") as mock_validate_config,
|
||||
patch("oci.identity.IdentityClient") as mock_identity_client,
|
||||
):
|
||||
mock_tenancy = MagicMock()
|
||||
mock_tenancy.name = "test-tenancy"
|
||||
mock_response = MagicMock()
|
||||
mock_response.data = mock_tenancy
|
||||
mock_client_instance = MagicMock()
|
||||
mock_client_instance.get_tenancy.return_value = mock_response
|
||||
mock_identity_client.return_value = mock_client_instance
|
||||
|
||||
connection = OraclecloudProvider.test_connection(
|
||||
key_content=encoded_key,
|
||||
user="ocid1.user.oc1..aaaaaaaexample",
|
||||
fingerprint="aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
tenancy="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
provider_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
raise_on_exception=False,
|
||||
)
|
||||
|
||||
assert connection.is_connected is True
|
||||
assert mock_validate_config.call_args.args[0]["region"] == "us-ashburn-1"
|
||||
|
||||
|
||||
class TestOraclecloudProviderInit:
|
||||
"""Tests for OraclecloudProvider initialization"""
|
||||
@@ -256,6 +292,159 @@ class TestOraclecloudProviderInit:
|
||||
assert provider.home_region == "us-ashburn-1"
|
||||
mock_set_global.assert_called_once_with(provider)
|
||||
|
||||
def test_init_with_multiple_regions_uses_deterministic_session_region(self):
|
||||
mock_session = OCISession(
|
||||
config={"region": "us-ashburn-1"}, signer=None, profile="DEFAULT"
|
||||
)
|
||||
mock_identity = OCIIdentityInfo(
|
||||
tenancy_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
tenancy_name="test-tenancy",
|
||||
user_id="ocid1.user.oc1..aaaaaaaexample",
|
||||
region="us-ashburn-1",
|
||||
profile="DEFAULT",
|
||||
audited_regions=set(),
|
||||
audited_compartments=[],
|
||||
)
|
||||
audited_regions = [
|
||||
OCIRegion(key="us-ashburn-1", name="us-ashburn-1", is_home_region=True),
|
||||
OCIRegion(key="us-phoenix-1", name="us-phoenix-1", is_home_region=False),
|
||||
]
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.setup_session",
|
||||
return_value=mock_session,
|
||||
) as mock_setup_session,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.set_identity",
|
||||
return_value=mock_identity,
|
||||
) as mock_set_identity,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.get_regions_to_audit",
|
||||
return_value=audited_regions,
|
||||
) as mock_get_regions_to_audit,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.get_compartments_to_audit",
|
||||
return_value=["ocid1.compartment.oc1..aaaaaaaexample"],
|
||||
),
|
||||
patch("prowler.providers.common.provider.Provider.set_global_provider"),
|
||||
):
|
||||
provider = OraclecloudProvider(
|
||||
region={"us-phoenix-1", "us-ashburn-1"},
|
||||
user="ocid1.user.oc1..aaaaaaaexample",
|
||||
fingerprint="aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
key_content="fake-base64-key-content",
|
||||
tenancy="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
config_content={"dummy": True},
|
||||
mutelist_content={"Accounts": {}},
|
||||
)
|
||||
|
||||
assert mock_setup_session.call_args.kwargs["region"] == "us-ashburn-1"
|
||||
assert mock_set_identity.call_args.kwargs["region"] == "us-ashburn-1"
|
||||
assert mock_get_regions_to_audit.call_args_list[0].args == (
|
||||
{"us-phoenix-1", "us-ashburn-1"},
|
||||
)
|
||||
assert provider.regions == audited_regions
|
||||
|
||||
def test_init_with_legacy_region_string_uses_full_region_for_identity(self):
|
||||
mock_session = OCISession(
|
||||
config={"region": "us-ashburn-1"}, signer=None, profile="DEFAULT"
|
||||
)
|
||||
mock_identity = OCIIdentityInfo(
|
||||
tenancy_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
tenancy_name="test-tenancy",
|
||||
user_id="ocid1.user.oc1..aaaaaaaexample",
|
||||
region="us-ashburn-1",
|
||||
profile="DEFAULT",
|
||||
audited_regions=set(),
|
||||
audited_compartments=[],
|
||||
)
|
||||
audited_regions = [
|
||||
OCIRegion(key="us-ashburn-1", name="us-ashburn-1", is_home_region=True),
|
||||
]
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.setup_session",
|
||||
return_value=mock_session,
|
||||
) as mock_setup_session,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.set_identity",
|
||||
return_value=mock_identity,
|
||||
) as mock_set_identity,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.get_regions_to_audit",
|
||||
return_value=audited_regions,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.get_compartments_to_audit",
|
||||
return_value=["ocid1.compartment.oc1..aaaaaaaexample"],
|
||||
),
|
||||
patch("prowler.providers.common.provider.Provider.set_global_provider"),
|
||||
):
|
||||
OraclecloudProvider(
|
||||
region="us-ashburn-1",
|
||||
user="ocid1.user.oc1..aaaaaaaexample",
|
||||
fingerprint="aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
key_content="fake-base64-key-content",
|
||||
tenancy="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
config_content={"dummy": True},
|
||||
mutelist_content={"Accounts": {}},
|
||||
)
|
||||
|
||||
assert mock_setup_session.call_args.kwargs["region"] == "us-ashburn-1"
|
||||
assert mock_set_identity.call_args.kwargs["region"] == "us-ashburn-1"
|
||||
|
||||
def test_init_without_region_uses_bootstrap_region_without_scan_filter(self):
|
||||
mock_session = OCISession(
|
||||
config={"region": "us-ashburn-1"}, signer=None, profile="DEFAULT"
|
||||
)
|
||||
mock_identity = OCIIdentityInfo(
|
||||
tenancy_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
tenancy_name="test-tenancy",
|
||||
user_id="ocid1.user.oc1..aaaaaaaexample",
|
||||
region="us-ashburn-1",
|
||||
profile="DEFAULT",
|
||||
audited_regions=set(),
|
||||
audited_compartments=[],
|
||||
)
|
||||
all_subscribed_regions = [
|
||||
OCIRegion(key="us-ashburn-1", name="us-ashburn-1", is_home_region=True),
|
||||
OCIRegion(key="us-phoenix-1", name="us-phoenix-1", is_home_region=False),
|
||||
]
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.setup_session",
|
||||
return_value=mock_session,
|
||||
) as mock_setup_session,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.set_identity",
|
||||
return_value=mock_identity,
|
||||
) as mock_set_identity,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.get_regions_to_audit",
|
||||
return_value=all_subscribed_regions,
|
||||
) as mock_get_regions_to_audit,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.get_compartments_to_audit",
|
||||
return_value=["ocid1.compartment.oc1..aaaaaaaexample"],
|
||||
),
|
||||
patch("prowler.providers.common.provider.Provider.set_global_provider"),
|
||||
):
|
||||
provider = OraclecloudProvider(
|
||||
user="ocid1.user.oc1..aaaaaaaexample",
|
||||
fingerprint="aa:bb:cc:dd:ee:ff:00:11:22:33:44:55:66:77:88:99",
|
||||
key_content="fake-base64-key-content",
|
||||
tenancy="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
config_content={"dummy": True},
|
||||
mutelist_content={"Accounts": {}},
|
||||
)
|
||||
|
||||
assert mock_setup_session.call_args.kwargs["region"] == "us-ashburn-1"
|
||||
assert mock_set_identity.call_args.kwargs["region"] == "us-ashburn-1"
|
||||
assert mock_get_regions_to_audit.call_args_list[0].args == (None,)
|
||||
assert provider.regions == all_subscribed_regions
|
||||
|
||||
def test_home_region_uses_full_subscription_list_not_region_filter(self):
|
||||
"""Home region must come from the full subscription list, not the --region filter.
|
||||
|
||||
@@ -313,3 +502,105 @@ class TestOraclecloudProviderInit:
|
||||
|
||||
assert provider.regions == audited_regions
|
||||
assert provider.home_region == "us-ashburn-1"
|
||||
|
||||
def test_init_with_legacy_single_region_preserves_fallback_for_home_region(self):
|
||||
mock_session = OCISession(
|
||||
config={"region": "us-phoenix-1"}, signer=None, profile="DEFAULT"
|
||||
)
|
||||
mock_identity = OCIIdentityInfo(
|
||||
tenancy_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
tenancy_name="test-tenancy",
|
||||
user_id="ocid1.user.oc1..aaaaaaaexample",
|
||||
region="us-phoenix-1",
|
||||
profile="DEFAULT",
|
||||
audited_regions=set(),
|
||||
audited_compartments=[],
|
||||
)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.setup_session",
|
||||
return_value=mock_session,
|
||||
),
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.set_identity",
|
||||
return_value=mock_identity,
|
||||
),
|
||||
patch("oci.identity.IdentityClient") as mock_identity_client,
|
||||
patch(
|
||||
"prowler.providers.oraclecloud.oraclecloud_provider.OraclecloudProvider.get_compartments_to_audit",
|
||||
return_value=["ocid1.compartment.oc1..aaaaaaaexample"],
|
||||
),
|
||||
patch("prowler.providers.common.provider.Provider.set_global_provider"),
|
||||
):
|
||||
mock_identity_client.return_value.list_region_subscriptions.side_effect = (
|
||||
Exception("discovery failed")
|
||||
)
|
||||
|
||||
provider = OraclecloudProvider(
|
||||
region="us-phoenix-1",
|
||||
config_content={"dummy": True},
|
||||
mutelist_content={"Accounts": {}},
|
||||
)
|
||||
|
||||
assert [region.key for region in provider.regions] == ["us-phoenix-1"]
|
||||
assert provider.home_region == "us-phoenix-1"
|
||||
|
||||
|
||||
class TestGetRegionsToAudit:
|
||||
def _provider_with_identity(self):
|
||||
provider = OraclecloudProvider.__new__(OraclecloudProvider)
|
||||
provider._session = OCISession(
|
||||
config={"region": "us-ashburn-1"}, signer=None, profile="DEFAULT"
|
||||
)
|
||||
provider._identity = OCIIdentityInfo(
|
||||
tenancy_id="ocid1.tenancy.oc1..aaaaaaaexample",
|
||||
tenancy_name="test-tenancy",
|
||||
user_id="ocid1.user.oc1..aaaaaaaexample",
|
||||
region="us-ashburn-1",
|
||||
profile="DEFAULT",
|
||||
audited_regions=set(),
|
||||
audited_compartments=[],
|
||||
)
|
||||
return provider
|
||||
|
||||
def test_regionless_scan_raises_when_region_subscription_discovery_fails(self):
|
||||
provider = self._provider_with_identity()
|
||||
|
||||
with patch("oci.identity.IdentityClient") as mock_identity_client:
|
||||
mock_identity_client.return_value.list_region_subscriptions.side_effect = (
|
||||
Exception("discovery failed")
|
||||
)
|
||||
|
||||
with pytest.raises(OCISetUpSessionError) as exc_info:
|
||||
provider.get_regions_to_audit()
|
||||
|
||||
assert "Could not retrieve OCI subscribed regions" in str(exc_info.value)
|
||||
|
||||
def test_single_explicit_region_falls_back_when_region_subscription_discovery_fails(
|
||||
self,
|
||||
):
|
||||
provider = self._provider_with_identity()
|
||||
|
||||
with patch("oci.identity.IdentityClient") as mock_identity_client:
|
||||
mock_identity_client.return_value.list_region_subscriptions.side_effect = (
|
||||
Exception("discovery failed")
|
||||
)
|
||||
|
||||
regions = provider.get_regions_to_audit("us-phoenix-1")
|
||||
|
||||
assert len(regions) == 1
|
||||
assert regions[0].key == "us-phoenix-1"
|
||||
|
||||
def test_multiple_explicit_regions_raise_when_region_subscription_discovery_fails(
|
||||
self,
|
||||
):
|
||||
provider = self._provider_with_identity()
|
||||
|
||||
with patch("oci.identity.IdentityClient") as mock_identity_client:
|
||||
mock_identity_client.return_value.list_region_subscriptions.side_effect = (
|
||||
Exception("discovery failed")
|
||||
)
|
||||
|
||||
with pytest.raises(OCISetUpSessionError):
|
||||
provider.get_regions_to_audit({"us-ashburn-1", "us-phoenix-1"})
|
||||
|
||||
@@ -28,6 +28,10 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
|
||||
- Controlled `402` and `403` Server Action error messages for alert seed and mutation flows [(#11629)](https://github.com/prowler-cloud/prowler/pull/11629)
|
||||
|
||||
### 🔄 Changed
|
||||
|
||||
- OCI provider setup no longer requires a region in the credentials form [(#11565)](https://github.com/prowler-cloud/prowler/pull/11565)
|
||||
|
||||
### 🐞 Fixed
|
||||
|
||||
- Attack Paths now shows distinct messages while a scan is queued, running, or building its graph — plus a separate "couldn't load scans" error — instead of always showing "No scans available" [(#11512)](https://github.com/prowler-cloud/prowler/pull/11512)
|
||||
|
||||
-10
@@ -48,16 +48,6 @@ export const OracleCloudCredentialsForm = ({
|
||||
variant="bordered"
|
||||
isRequired
|
||||
/>
|
||||
<WizardInputField
|
||||
control={control}
|
||||
name={ProviderCredentialFields.OCI_REGION}
|
||||
type="text"
|
||||
label="Region"
|
||||
labelPlacement="inside"
|
||||
placeholder="e.g. us-ashburn-1"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
/>
|
||||
<WizardTextareaField
|
||||
control={control}
|
||||
name={ProviderCredentialFields.OCI_KEY_CONTENT}
|
||||
|
||||
@@ -180,7 +180,6 @@ export const useCredentialsForm = ({
|
||||
[ProviderCredentialFields.OCI_FINGERPRINT]: "",
|
||||
[ProviderCredentialFields.OCI_KEY_CONTENT]: "",
|
||||
[ProviderCredentialFields.OCI_TENANCY]: providerUid || "",
|
||||
[ProviderCredentialFields.OCI_REGION]: "",
|
||||
[ProviderCredentialFields.OCI_PASS_PHRASE]: "",
|
||||
};
|
||||
case "mongodbatlas":
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
vi.mock("@/lib", () => ({
|
||||
filterEmptyValues: (obj: Record<string, unknown>) =>
|
||||
Object.fromEntries(
|
||||
Object.entries(obj).filter(([, value]) => {
|
||||
if (value === 0 || value === false) return true;
|
||||
if (value === null || value === undefined) return false;
|
||||
if (typeof value === "string" && value.trim() === "") return false;
|
||||
if (Array.isArray(value) && value.length === 0) return false;
|
||||
|
||||
return true;
|
||||
}),
|
||||
),
|
||||
getFormValue: (formData: FormData, field: string) => formData.get(field),
|
||||
}));
|
||||
|
||||
import { buildOracleCloudSecret } from "./build-credentials";
|
||||
import { ProviderCredentialFields } from "./provider-credential-fields";
|
||||
|
||||
describe("buildOracleCloudSecret", () => {
|
||||
it("omits region filters for the basic credentials flow", () => {
|
||||
const formData = new FormData();
|
||||
formData.set(ProviderCredentialFields.OCI_USER, "ocid1.user.oc1..example");
|
||||
formData.set(ProviderCredentialFields.OCI_FINGERPRINT, "fingerprint");
|
||||
formData.set(ProviderCredentialFields.OCI_KEY_CONTENT, "private-key");
|
||||
|
||||
const secret = buildOracleCloudSecret(
|
||||
formData,
|
||||
"ocid1.tenancy.oc1..example",
|
||||
);
|
||||
|
||||
expect(secret).toMatchObject({
|
||||
user: "ocid1.user.oc1..example",
|
||||
fingerprint: "fingerprint",
|
||||
tenancy: "ocid1.tenancy.oc1..example",
|
||||
});
|
||||
expect(secret).not.toHaveProperty("region");
|
||||
expect(secret).not.toHaveProperty("regions");
|
||||
});
|
||||
});
|
||||
@@ -385,10 +385,6 @@ export const buildOracleCloudSecret = (
|
||||
[ProviderCredentialFields.OCI_TENANCY]:
|
||||
providerUid ||
|
||||
getFormValue(formData, ProviderCredentialFields.OCI_TENANCY),
|
||||
[ProviderCredentialFields.OCI_REGION]: getFormValue(
|
||||
formData,
|
||||
ProviderCredentialFields.OCI_REGION,
|
||||
),
|
||||
[ProviderCredentialFields.OCI_PASS_PHRASE]: getFormValue(
|
||||
formData,
|
||||
ProviderCredentialFields.OCI_PASS_PHRASE,
|
||||
|
||||
@@ -224,7 +224,6 @@ export interface OCIProviderCredential {
|
||||
userId?: string;
|
||||
fingerprint?: string;
|
||||
keyContent?: string;
|
||||
region?: string;
|
||||
}
|
||||
|
||||
// AlibabaCloud credential options
|
||||
@@ -366,7 +365,6 @@ export class ProvidersPage extends BasePage {
|
||||
readonly ociUserIdInput: Locator;
|
||||
readonly ociFingerprintInput: Locator;
|
||||
readonly ociKeyContentInput: Locator;
|
||||
readonly ociRegionInput: Locator;
|
||||
|
||||
// AlibabaCloud provider form elements
|
||||
readonly alibabacloudAccountIdInput: Locator;
|
||||
@@ -510,7 +508,6 @@ export class ProvidersPage extends BasePage {
|
||||
this.ociKeyContentInput = page.getByRole("textbox", {
|
||||
name: /Private Key Content/i,
|
||||
});
|
||||
this.ociRegionInput = page.getByRole("textbox", { name: /Region/i });
|
||||
|
||||
// AlibabaCloud provider form inputs
|
||||
this.alibabacloudAccountIdInput = page.getByRole("textbox", {
|
||||
@@ -1300,9 +1297,6 @@ export class ProvidersPage extends BasePage {
|
||||
if (credentials.keyContent) {
|
||||
await this.ociKeyContentInput.fill(credentials.keyContent);
|
||||
}
|
||||
if (credentials.region) {
|
||||
await this.ociRegionInput.fill(credentials.region);
|
||||
}
|
||||
}
|
||||
|
||||
async verifyOCICredentialsPageLoaded(): Promise<void> {
|
||||
@@ -1313,7 +1307,6 @@ export class ProvidersPage extends BasePage {
|
||||
await expect(this.ociUserIdInput).toBeVisible();
|
||||
await expect(this.ociFingerprintInput).toBeVisible();
|
||||
await expect(this.ociKeyContentInput).toBeVisible();
|
||||
await expect(this.ociRegionInput).toBeVisible();
|
||||
}
|
||||
|
||||
async verifyOCIUpdateCredentialsPageLoaded(): Promise<void> {
|
||||
@@ -1324,7 +1317,6 @@ export class ProvidersPage extends BasePage {
|
||||
await expect(this.ociUserIdInput).toBeVisible();
|
||||
await expect(this.ociFingerprintInput).toBeVisible();
|
||||
await expect(this.ociKeyContentInput).toBeVisible();
|
||||
await expect(this.ociRegionInput).toBeVisible();
|
||||
}
|
||||
|
||||
async selectAlibabaCloudProvider(): Promise<void> {
|
||||
|
||||
@@ -1029,12 +1029,10 @@ test.describe("Add Provider", () => {
|
||||
const userId = process.env.E2E_OCI_USER_ID ?? "";
|
||||
const fingerprint = process.env.E2E_OCI_FINGERPRINT ?? "";
|
||||
const keyContent = process.env.E2E_OCI_KEY_CONTENT ?? "";
|
||||
const region = process.env.E2E_OCI_REGION ?? "";
|
||||
|
||||
// Setup before each test
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.skip(
|
||||
!tenancyId || !userId || !fingerprint || !keyContent || !region,
|
||||
!tenancyId || !userId || !fingerprint || !keyContent,
|
||||
"OCI E2E env vars are not set",
|
||||
);
|
||||
providersPage = new ProvidersPage(page);
|
||||
@@ -1071,7 +1069,6 @@ test.describe("Add Provider", () => {
|
||||
userId: userId,
|
||||
fingerprint: fingerprint,
|
||||
keyContent: keyContent,
|
||||
region: region,
|
||||
};
|
||||
|
||||
// Navigate to providers page
|
||||
@@ -1516,12 +1513,10 @@ test.describe("Update Provider Credentials", () => {
|
||||
const userId = process.env.E2E_OCI_USER_ID ?? "";
|
||||
const fingerprint = process.env.E2E_OCI_FINGERPRINT ?? "";
|
||||
const keyContent = process.env.E2E_OCI_KEY_CONTENT ?? "";
|
||||
const region = process.env.E2E_OCI_REGION ?? "";
|
||||
|
||||
// Setup before each test
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.skip(
|
||||
!tenancyId || !userId || !fingerprint || !keyContent || !region,
|
||||
!tenancyId || !userId || !fingerprint || !keyContent,
|
||||
"OCI E2E env vars are not set",
|
||||
);
|
||||
providersPage = new ProvidersPage(page);
|
||||
@@ -1543,7 +1538,6 @@ test.describe("Update Provider Credentials", () => {
|
||||
userId: userId,
|
||||
fingerprint: fingerprint,
|
||||
keyContent: keyContent,
|
||||
region: region,
|
||||
};
|
||||
|
||||
// Navigate to providers page
|
||||
|
||||
@@ -315,7 +315,6 @@ export type OCICredentials = {
|
||||
[ProviderCredentialFields.OCI_FINGERPRINT]: string;
|
||||
[ProviderCredentialFields.OCI_KEY_CONTENT]: string;
|
||||
[ProviderCredentialFields.OCI_TENANCY]: string;
|
||||
[ProviderCredentialFields.OCI_REGION]: string;
|
||||
[ProviderCredentialFields.OCI_PASS_PHRASE]?: string;
|
||||
[ProviderCredentialFields.PROVIDER_ID]: string;
|
||||
};
|
||||
|
||||
@@ -262,9 +262,6 @@ export const addCredentialsFormSchema = (
|
||||
[ProviderCredentialFields.OCI_TENANCY]: z
|
||||
.string()
|
||||
.min(1, "Tenancy OCID is required"),
|
||||
[ProviderCredentialFields.OCI_REGION]: z
|
||||
.string()
|
||||
.min(1, "Region is required"),
|
||||
[ProviderCredentialFields.OCI_PASS_PHRASE]: z
|
||||
.union([z.string(), z.literal("")])
|
||||
.optional(),
|
||||
|
||||
Reference in New Issue
Block a user