Skip to content

feat(api): support regionless OCI credentials#11741

Open
HugoPBrito wants to merge 7 commits into
masterfrom
feat/oci-regionless-api-chain-11565
Open

feat(api): support regionless OCI credentials#11741
HugoPBrito wants to merge 7 commits into
masterfrom
feat/oci-regionless-api-chain-11565

Conversation

@HugoPBrito

@HugoPBrito HugoPBrito commented Jun 30, 2026

Copy link
Copy Markdown
Member

Context

OCI provider setup should support credentials without requiring users to provide region filters. Region discovery should be handled by the SDK.

Description

This PR updates API validation, provider initialization, schema metadata, and migration coverage so OCI secrets can omit region fields. The API no longer introduces regions as a replacement field. The existing region field is kept only as deprecated legacy compatibility, while new regionless payloads rely on SDK region discovery.

Existing stored regions values are removed by the migration because that field is no longer part of the API contract. Existing legacy region values are preserved for backward compatibility.

Changed files:

File Change
api/CHANGELOG.md Adds the API changelog entry.
api/src/backend/api/migrations/0097_remove_oraclecloud_secret_regions.py Removes OCI secret regions from persisted secret data.
api/src/backend/api/tests/test_migrations.py Adds migration coverage.
api/src/backend/api/tests/test_serializers.py Adds serializer coverage.
api/src/backend/api/tests/test_utils.py Adds utility coverage.
api/src/backend/api/tests/test_views.py Adds endpoint coverage.
api/src/backend/api/utils.py Updates OCI provider initialization behavior.
api/src/backend/api/v1/serializer_utils/providers.py Updates OCI credential schema metadata.
api/src/backend/api/v1/serializers.py Updates OCI credential validation.
pyproject.toml Adds API Vulture ignore entries required by this test slice.

Steps to review

  1. Review the API diff against the SDK slice.
  2. Confirm the API changes match the API portion of feat: support regionless OCI provider setup #11565.
  3. Confirm the UI slice builds on this PR.

Validation previously run for this slice:

uv run --project api pytest ... -k oraclecloud

Checklist

Community Checklist
  • This feature/issue is listed in here or roadmap.prowler.com
  • Is it assigned to me, if not, request it via the issue/feature in here or Prowler Community Slack

SDK/CLI

  • Are there new checks included in this PR? No
    • If so, do we need to update permissions for the provider? Please review this carefully.

UI

  • All issue/task requirements work as expected on the UI
  • If this PR adds or updates npm dependencies, include package-health evidence (maintenance, popularity, known vulnerabilities, license, release age) and explain why existing/native alternatives are insufficient.
  • Screenshots/Video of the functionality flow (if applicable) - Mobile (X < 640px)
  • Screenshots/Video of the functionality flow (if applicable) - Table (640px > X < 1024px)
  • Screenshots/Video of the functionality flow (if applicable) - Desktop (X > 1024px)
  • Ensure new entries are added to CHANGELOG.md, if applicable.

API

  • All issue/task requirements work as expected on the API
  • Endpoint response output (if applicable)
  • EXPLAIN ANALYZE output for new/modified queries or indexes (if applicable)
  • Performance test results (if applicable)
  • Any other relevant evidence of the implementation (if applicable)
  • Verify if API specs need to be regenerated.
  • Check if version updates are required (e.g., specs, uv, etc.).
  • Ensure new entries are added to CHANGELOG.md, if applicable.

License

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Chain Context

Field Value
Chain OCI regionless provider setup split from #11565
Tracker PR #11565
Position 3 of 4
Base feat/oci-regionless-sdk-chain-11565
Depends on #11740
Follow-up #11742
Review budget 684 / 400
Starts at SDK regionless OCI provider setup
Ends with API regionless OCI credential support

Chain Overview

master
 └── #11739 Platform CI guard
      └── #11740 SDK regionless OCI setup
           └── 📍 #11741 API regionless OCI credentials
                └── #11742 UI regionless OCI credentials

Scope

Autonomy

  • CI is expected to pass for this PR branch
  • This PR has one deliverable scope
  • This PR can be rolled back without unrelated changes
  • Tests, docs, or manual verification cover this unit

Summary by CodeRabbit

  • New Features
    • Oracle Cloud API key credentials can now be saved without a region filter; the system will discover and scan subscribed regions automatically.
    • OCI credential validation now supports either providing a key file or pasting key content, with updated schema guidance.
  • Bug Fixes
    • Existing legacy OCI secrets are migrated to remove stored region filters, so migrated providers scan all subscribed regions by default.
    • Connection checks now succeed even when no explicit region is provided.

@HugoPBrito HugoPBrito requested review from a team as code owners June 30, 2026 14:12
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8c318552-92d0-431d-84f3-a687a07923b0

📥 Commits

Reviewing files that changed from the base of the PR and between 2b4ee51 and 50a6283.

📒 Files selected for processing (2)
  • api/src/backend/api/tests/test_views.py
  • api/src/backend/api/v1/serializers.py

📝 Walkthrough

Walkthrough

This PR makes Oracle Cloud API key region handling optional across serializer validation, schema generation, provider kwargs, provider session setup, and existing-secret migration. It also adds E2E secret preflight handling for forks and expands Vulture ignore names.

Changes

Oracle Cloud optional region support

Layer / File(s) Summary
Serializer and schema changes for optional region
api/src/backend/api/v1/serializers.py, api/src/backend/api/v1/serializer_utils/providers.py, api/src/backend/api/tests/test_serializers.py
OracleCloudProviderSecret.region becomes optional and deprecated, regions is rejected, key_file or key_content is required, and the generated OCI schema matches those rules with test coverage.
Provider kwargs normalization helpers
api/src/backend/api/utils.py, api/src/backend/api/tests/test_utils.py
OracleCloud provider kwargs now go through dedicated normalization helpers for scan-time region handling and connection-test bootstrap region fallback, with tests for regionless and legacy-region secrets.
OraclecloudProvider session, identity, and region discovery
prowler/providers/oraclecloud/oraclecloud_provider.py, tests/providers/oraclecloud/oraclecloud_provider_test.py, prowler/CHANGELOG.md
The provider adds a bootstrap region default, relaxes API-key setup requirements without a region field, changes fallback behavior when region discovery fails, and updates provider tests and changelog text.
Secret migration and API tests
api/src/backend/api/migrations/0097_remove_oraclecloud_secret_regions.py, api/src/backend/api/tests/test_migrations.py, api/src/backend/api/tests/test_views.py, api/CHANGELOG.md
A migration removes stored regions from OracleCloud secrets, migration/API tests validate the new payload shapes and update flow, and related fixtures and changelog notes are updated.

Estimated code review effort: 4 (Complex) | ~60 minutes

CI Workflow and Lint Config

Layer / File(s) Summary
E2E workflow secret preflight check
.github/workflows/ui-e2e-tests-v2.yml
Adds fork detection and required-secret presence checks before running E2E tests, skipping for forks and failing for internal PRs when secrets are missing.
Vulture ignore list expansion
pyproject.toml
Expands the ignore_names list to suppress additional false-positive unused-code warnings.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant OracleCloudProviderSecret
  participant get_prowler_provider_kwargs
  participant OraclecloudProvider
  participant OCI_SDK

  Client->>OracleCloudProviderSecret: submit secret payload
  OracleCloudProviderSecret->>OracleCloudProviderSecret: validate() region and regions
  OracleCloudProviderSecret->>get_prowler_provider_kwargs: normalized secret
  get_prowler_provider_kwargs->>OraclecloudProvider: build provider kwargs
  OraclecloudProvider->>OCI_SDK: setup_session(region or bootstrap region)
  OraclecloudProvider->>OCI_SDK: get_regions_to_audit()
  OCI_SDK-->>OraclecloudProvider: subscribed regions or error
  alt discovery fails and single explicit region
    OraclecloudProvider->>OraclecloudProvider: fallback to explicit region as home region
  else discovery fails and no/multiple regions
    OraclecloudProvider-->>Client: raise OCISetUpSessionError
  end
Loading

Possibly related PRs

Suggested reviewers: AdriiiPRodri, danibarranqueroo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed It clearly summarizes the main change: OCI API credentials can now omit persisted region filters.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/oci-regionless-api-chain-11565
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/oci-regionless-api-chain-11565

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

{"required": ["key_file"]},
{"required": ["key_content"]},
],
"not": {"required": ["region", "regions"]},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it mandatory to submit region(s) or can I choose not to submit any?

If it's mandatory use this:

"oneOf": [ { "required": ["region"] }, { "required": ["regions"] } ]

If we choose to not submit any and is valid, the PR is perfect :)

Comment on lines +292 to +302
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about something like this?
Avoids silent collisions

`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:
    # Extract the list from the new format
    regions = prowler_provider_kwargs.pop("regions")
    
    # Defensive programming: purge the legacy key if it somehow bypassed the serializer.
    # Using .pop(..., None) ensures it doesn't raise an error if the key doesn't exist.
    prowler_provider_kwargs.pop("region", None)
    
    # Assign the final set required by Prowler
    prowler_provider_kwargs["region"] = set(regions)
    
elif "region" in prowler_provider_kwargs:
    # If only the legacy format is present, wrap it in a set
    prowler_provider_kwargs["region"] = {prowler_provider_kwargs["region"]}

return prowler_provider_kwargs`

Comment thread api/src/backend/api/v1/serializers.py Outdated
raise serializers.ValidationError(
{"regions": "Regions cannot contain duplicate values."}
)
attrs["regions"] = regions

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this cleanup is not saved. validate_secret_based_on_provider() validates the serializer, but doesn't use serializer.validated_data, so the endpoint can store the region with spaces.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 50a6283c5a.

validate_secret_based_on_provider() now returns the nested serializer validated_data, and create/update assign it back to validated_attrs["secret"] before saving. That means legacy region cleanup is persisted instead of only being validated.

I also updated the provider-secret create/update tests to submit " us-ashburn-1 " and verify the stored secret keeps "us-ashburn-1".

if "region" not in secret and "regions" not in secret:
continue

secret.pop("region", None)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we confirm this case? If an existing OCI provider had region and cannot list regions, removing region moves it to regionless mode and it may fail.

Base automatically changed from feat/oci-regionless-sdk-chain-11565 to ci/oci-regionless-platform-11565 July 6, 2026 13:16
@HugoPBrito HugoPBrito changed the base branch from ci/oci-regionless-platform-11565 to master July 6, 2026 13:18
@HugoPBrito HugoPBrito requested a review from a team as a code owner July 6, 2026 13:18
@github-actions github-actions Bot added github_actions Pull requests that update GitHub Actions code component/api review-django-migrations This PR contains changes in Django migrations provider/oci Issues/PRs related with the OCI provider has-conflicts The PR has conflicts that needs to be resolved. labels Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Conflicts Detected

Merge conflict with the base branch. This PR cannot be merged cleanly. Update your branch with the latest base (rebase or merge) and resolve the conflicts.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
api/src/backend/api/utils.py (1)

292-320: 🩺 Stability & Availability | 🟠 Major

Legacy regions (plural) key not defensively handled.

Neither _normalize_oraclecloud_provider_kwargs nor _normalize_oraclecloud_connection_test_kwargs strip/convert a stray regions key. If any stored secret still has regions (e.g. pre-migration data, or a rolling-deploy window before migration 0097 runs), it will be forwarded verbatim via **prowler_provider_kwargs/**oraclecloud_kwargs into OraclecloudProvider(...) / test_connection(...), neither of which accept a regions kwarg — causing an unhandled TypeError and a hard failure for that provider's scans/connection tests.

This is the same concern raised in a prior review with a concrete suggested fix (pop regions, fall back to it, and defensively purge stray region), which does not appear to have been incorporated.

🛡️ Proposed defensive fix
 def _normalize_oraclecloud_provider_kwargs(secret: dict) -> dict:
     """Normalize external OCI secret fields into SDK provider kwargs."""
     prowler_provider_kwargs = secret.copy()
 
-    if "region" in prowler_provider_kwargs:
+    if "regions" in prowler_provider_kwargs:
+        prowler_provider_kwargs["region"] = set(
+            prowler_provider_kwargs.pop("regions")
+        )
+    elif "region" in prowler_provider_kwargs:
         prowler_provider_kwargs["region"] = {prowler_provider_kwargs["region"]}
 
     return prowler_provider_kwargs
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/backend/api/utils.py` around lines 292 - 320, The OCI normalization
helpers still pass a legacy regions key through to downstream calls, which can
break Oracle Cloud scans and connection tests. Update
_normalize_oraclecloud_provider_kwargs and
_normalize_oraclecloud_connection_test_kwargs to defensively remove regions,
treat it as a fallback for region when needed, and ensure only the accepted
region kwarg is forwarded to OraclecloudProvider and test_connection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/src/backend/api/utils.py`:
- Around line 302-320: The OCI test-connection normalization in
_normalize_oraclecloud_connection_test_kwargs duplicates the provider bootstrap
region literal, which can drift from OraclecloudProvider._bootstrap_region.
Update this helper to source the fallback region from
OraclecloudProvider._bootstrap_region instead of hardcoding "us-ashburn-1", and
make sure the import/reference is used wherever the fallback is applied so the
API stays aligned with the provider default.

---

Duplicate comments:
In `@api/src/backend/api/utils.py`:
- Around line 292-320: The OCI normalization helpers still pass a legacy regions
key through to downstream calls, which can break Oracle Cloud scans and
connection tests. Update _normalize_oraclecloud_provider_kwargs and
_normalize_oraclecloud_connection_test_kwargs to defensively remove regions,
treat it as a fallback for region when needed, and ensure only the accepted
region kwarg is forwarded to OraclecloudProvider and test_connection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 18404c0d-f8d3-45a9-8b6e-066ef1cef882

📥 Commits

Reviewing files that changed from the base of the PR and between 7b5d724 and 2b4ee51.

📒 Files selected for processing (14)
  • .github/workflows/ui-e2e-tests-v2.yml
  • api/CHANGELOG.md
  • api/src/backend/api/migrations/0097_remove_oraclecloud_secret_regions.py
  • api/src/backend/api/tests/test_migrations.py
  • api/src/backend/api/tests/test_serializers.py
  • api/src/backend/api/tests/test_utils.py
  • api/src/backend/api/tests/test_views.py
  • api/src/backend/api/utils.py
  • api/src/backend/api/v1/serializer_utils/providers.py
  • api/src/backend/api/v1/serializers.py
  • prowler/CHANGELOG.md
  • prowler/providers/oraclecloud/oraclecloud_provider.py
  • pyproject.toml
  • tests/providers/oraclecloud/oraclecloud_provider_test.py

Comment on lines +302 to +320
def _normalize_oraclecloud_connection_test_kwargs(secret: dict) -> dict:
"""Normalize external OCI secret fields into test_connection kwargs."""
prowler_provider_kwargs = secret.copy()

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded bootstrap region duplicates OraclecloudProvider._bootstrap_region.

"us-ashburn-1" is a literal copy of the provider's _bootstrap_region class attribute. If that constant ever changes, this API helper silently diverges from the SDK default.

♻️ Reference the provider constant instead of duplicating the literal
+    from prowler.providers.oraclecloud.oraclecloud_provider import (
+        OraclecloudProvider,
+    )
+
     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"
+        prowler_provider_kwargs["region"] = OraclecloudProvider._bootstrap_region
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _normalize_oraclecloud_connection_test_kwargs(secret: dict) -> dict:
"""Normalize external OCI secret fields into test_connection kwargs."""
prowler_provider_kwargs = secret.copy()
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 _normalize_oraclecloud_connection_test_kwargs(secret: dict) -> dict:
"""Normalize external OCI secret fields into test_connection kwargs."""
prowler_provider_kwargs = secret.copy()
from prowler.providers.oraclecloud.oraclecloud_provider import (
OraclecloudProvider,
)
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"] = OraclecloudProvider._bootstrap_region
return prowler_provider_kwargs
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/backend/api/utils.py` around lines 302 - 320, The OCI test-connection
normalization in _normalize_oraclecloud_connection_test_kwargs duplicates the
provider bootstrap region literal, which can drift from
OraclecloudProvider._bootstrap_region. Update this helper to source the fallback
region from OraclecloudProvider._bootstrap_region instead of hardcoding
"us-ashburn-1", and make sure the import/reference is used wherever the fallback
is applied so the API stays aligned with the provider default.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/api github_actions Pull requests that update GitHub Actions code has-conflicts The PR has conflicts that needs to be resolved. provider/oci Issues/PRs related with the OCI provider review-django-migrations This PR contains changes in Django migrations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants