mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-29 14:54:30 +00:00
fix(oci): use home region for identity bootstrap (#12909)
Co-authored-by: Pedro Martín <pedromarting3@gmail.com>
This commit is contained in:
1 parent
f23b38a269
commit
01d7df6fce
26 files changed
+383
-60
No files matched your search
@@ -0,0 +1 @@
|
||||
Required home region selector in the OCI credentials form, so tenancies not subscribed to us-ashburn-1 can connect
|
||||
+31
@@ -4,6 +4,9 @@ import {
|
||||
WizardInputField,
|
||||
WizardTextareaField,
|
||||
} from "@/components/providers/workflow/forms/fields";
|
||||
import { Combobox } from "@/components/shadcn/combobox";
|
||||
import { FormControl, FormField, FormMessage } from "@/components/shadcn/form";
|
||||
import { OCI_REGION_GROUPS } from "@/lib/provider-credentials/oci-regions";
|
||||
import { ProviderCredentialFields } from "@/lib/provider-credentials/provider-credential-fields";
|
||||
import { OCICredentials } from "@/types";
|
||||
|
||||
@@ -48,6 +51,34 @@ export const OracleCloudCredentialsForm = ({
|
||||
variant="bordered"
|
||||
isRequired
|
||||
/>
|
||||
<FormField
|
||||
control={control}
|
||||
name={ProviderCredentialFields.OCI_REGION}
|
||||
render={({ field }) => (
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<span className="text-text-neutral-tertiary text-xs font-light tracking-tight">
|
||||
Home Region<span className="text-text-error-primary">*</span>
|
||||
</span>
|
||||
<FormControl>
|
||||
<Combobox
|
||||
aria-label="Home Region"
|
||||
value={field.value ?? ""}
|
||||
onValueChange={field.onChange}
|
||||
groups={OCI_REGION_GROUPS}
|
||||
placeholder="Select your tenancy home region"
|
||||
searchPlaceholder="Search region..."
|
||||
emptyMessage="No region found."
|
||||
contentClassName="z-[60] sm:w-(--radix-popover-trigger-width) sm:max-w-none"
|
||||
/>
|
||||
</FormControl>
|
||||
<span className="text-text-neutral-tertiary text-xs">
|
||||
Shown in the OCI Console under Tenancy Details. Used only to
|
||||
validate the credentials: all subscribed regions are scanned.
|
||||
</span>
|
||||
<FormMessage className="text-text-error-primary max-w-full text-xs" />
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<WizardTextareaField
|
||||
control={control}
|
||||
name={ProviderCredentialFields.OCI_KEY_CONTENT}
|
||||
|
||||
@@ -181,6 +181,7 @@ export const useCredentialsForm = ({
|
||||
[ProviderCredentialFields.OCI_FINGERPRINT]: "",
|
||||
[ProviderCredentialFields.OCI_KEY_CONTENT]: "",
|
||||
[ProviderCredentialFields.OCI_TENANCY]: providerUid || "",
|
||||
[ProviderCredentialFields.OCI_REGION]: "",
|
||||
[ProviderCredentialFields.OCI_PASS_PHRASE]: "",
|
||||
};
|
||||
case "mongodbatlas":
|
||||
|
||||
@@ -389,6 +389,10 @@ 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,
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import type { ComboboxGroup } from "@/components/shadcn/combobox";
|
||||
|
||||
// Keep in sync with OCI_REGIONS in prowler/providers/oraclecloud/config.py
|
||||
const OCI_COMMERCIAL_REGIONS = [
|
||||
"af-casablanca-1",
|
||||
"af-johannesburg-1",
|
||||
"ap-batam-1",
|
||||
"ap-chuncheon-1",
|
||||
"ap-hyderabad-1",
|
||||
"ap-kulai-2",
|
||||
"ap-melbourne-1",
|
||||
"ap-mumbai-1",
|
||||
"ap-osaka-1",
|
||||
"ap-seoul-1",
|
||||
"ap-singapore-1",
|
||||
"ap-singapore-2",
|
||||
"ap-sydney-1",
|
||||
"ap-tokyo-1",
|
||||
"ca-montreal-1",
|
||||
"ca-toronto-1",
|
||||
"eu-amsterdam-1",
|
||||
"eu-frankfurt-1",
|
||||
"eu-madrid-1",
|
||||
"eu-madrid-3",
|
||||
"eu-marseille-1",
|
||||
"eu-milan-1",
|
||||
"eu-paris-1",
|
||||
"eu-stockholm-1",
|
||||
"eu-turin-1",
|
||||
"eu-zurich-1",
|
||||
"il-jerusalem-1",
|
||||
"me-abudhabi-1",
|
||||
"me-dubai-1",
|
||||
"me-jeddah-1",
|
||||
"me-riyadh-1",
|
||||
"mx-monterrey-1",
|
||||
"mx-queretaro-1",
|
||||
"sa-bogota-1",
|
||||
"sa-santiago-1",
|
||||
"sa-saopaulo-1",
|
||||
"sa-valparaiso-1",
|
||||
"sa-vinhedo-1",
|
||||
"uk-cardiff-1",
|
||||
"uk-london-1",
|
||||
"us-ashburn-1",
|
||||
"us-chicago-1",
|
||||
"us-phoenix-1",
|
||||
"us-sanjose-1",
|
||||
];
|
||||
|
||||
const OCI_GOVERNMENT_REGIONS = [
|
||||
{ value: "us-langley-1", label: "us-langley-1 (US Gov West)" },
|
||||
{ value: "us-luke-1", label: "us-luke-1 (US Gov East)" },
|
||||
{ value: "us-gov-ashburn-1", label: "us-gov-ashburn-1 (US DoD East)" },
|
||||
{ value: "us-gov-chicago-1", label: "us-gov-chicago-1 (US DoD North)" },
|
||||
{ value: "us-gov-phoenix-1", label: "us-gov-phoenix-1 (US DoD West)" },
|
||||
];
|
||||
|
||||
export const OCI_REGION_GROUPS: ComboboxGroup[] = [
|
||||
{
|
||||
heading: "Commercial",
|
||||
options: OCI_COMMERCIAL_REGIONS.map((region) => ({
|
||||
value: region,
|
||||
label: region,
|
||||
})),
|
||||
},
|
||||
{ heading: "Government", options: OCI_GOVERNMENT_REGIONS },
|
||||
];
|
||||
|
||||
export const OCI_REGION_VALUES = OCI_REGION_GROUPS.flatMap((group) =>
|
||||
group.options.map((option) => option.value),
|
||||
);
|
||||
@@ -224,6 +224,7 @@ export interface OCIProviderCredential {
|
||||
userId?: string;
|
||||
fingerprint?: string;
|
||||
keyContent?: string;
|
||||
homeRegion?: string;
|
||||
}
|
||||
|
||||
// AlibabaCloud credential options
|
||||
@@ -365,6 +366,7 @@ export class ProvidersPage extends BasePage {
|
||||
readonly ociUserIdInput: Locator;
|
||||
readonly ociFingerprintInput: Locator;
|
||||
readonly ociKeyContentInput: Locator;
|
||||
readonly ociHomeRegionCombobox: Locator;
|
||||
|
||||
// AlibabaCloud provider form elements
|
||||
readonly alibabacloudAccountIdInput: Locator;
|
||||
@@ -510,6 +512,9 @@ export class ProvidersPage extends BasePage {
|
||||
this.ociKeyContentInput = page.getByRole("textbox", {
|
||||
name: /Private Key Content/i,
|
||||
});
|
||||
this.ociHomeRegionCombobox = page.getByRole("combobox", {
|
||||
name: /Home Region/i,
|
||||
});
|
||||
|
||||
// AlibabaCloud provider form inputs
|
||||
this.alibabacloudAccountIdInput = page.getByRole("textbox", {
|
||||
@@ -1284,6 +1289,12 @@ export class ProvidersPage extends BasePage {
|
||||
if (credentials.keyContent) {
|
||||
await this.ociKeyContentInput.fill(credentials.keyContent);
|
||||
}
|
||||
if (credentials.homeRegion) {
|
||||
await this.ociHomeRegionCombobox.click();
|
||||
await this.page
|
||||
.locator(`[role="option"][data-value="${credentials.homeRegion}"]`)
|
||||
.click();
|
||||
}
|
||||
}
|
||||
|
||||
async verifyOCICredentialsPageLoaded(): Promise<void> {
|
||||
@@ -1294,6 +1305,7 @@ export class ProvidersPage extends BasePage {
|
||||
await expect(this.ociUserIdInput).toBeVisible();
|
||||
await expect(this.ociFingerprintInput).toBeVisible();
|
||||
await expect(this.ociKeyContentInput).toBeVisible();
|
||||
await expect(this.ociHomeRegionCombobox).toBeVisible();
|
||||
}
|
||||
|
||||
async verifyOCIUpdateCredentialsPageLoaded(): Promise<void> {
|
||||
@@ -1304,6 +1316,7 @@ export class ProvidersPage extends BasePage {
|
||||
await expect(this.ociUserIdInput).toBeVisible();
|
||||
await expect(this.ociFingerprintInput).toBeVisible();
|
||||
await expect(this.ociKeyContentInput).toBeVisible();
|
||||
await expect(this.ociHomeRegionCombobox).toBeVisible();
|
||||
}
|
||||
|
||||
async selectAlibabaCloudProvider(): Promise<void> {
|
||||
|
||||
@@ -611,7 +611,7 @@
|
||||
**Preconditions:**
|
||||
|
||||
- Admin user authentication required (admin.auth.setup setup)
|
||||
- Environment variables configured: E2E_OCI_TENANCY_ID, E2E_OCI_USER_ID, E2E_OCI_FINGERPRINT, E2E_OCI_KEY_CONTENT
|
||||
- Environment variables configured: E2E_OCI_TENANCY_ID, E2E_OCI_USER_ID, E2E_OCI_FINGERPRINT, E2E_OCI_KEY_CONTENT, E2E_OCI_REGION (optional, defaults to us-ashburn-1)
|
||||
- Remove any existing provider with the same Tenancy ID before starting the test
|
||||
- This test must be run serially and never in parallel with other tests, as it requires the Tenancy ID not to be already registered beforehand.
|
||||
|
||||
@@ -622,7 +622,7 @@
|
||||
3. Select OCI provider type
|
||||
4. Fill provider details (tenancy ID and alias)
|
||||
5. Verify OCI credentials page is loaded
|
||||
6. Fill OCI credentials (user ID, fingerprint, key content)
|
||||
6. Fill OCI credentials (user ID, fingerprint, key content, home region)
|
||||
7. Confirm provider connection without launching a scan
|
||||
8. Verify return to Providers page
|
||||
9. Verify provider exists in Providers table
|
||||
@@ -640,7 +640,7 @@
|
||||
- Connect account page displays OCI option
|
||||
- Provider details form accepts tenancy ID and alias
|
||||
- OCI credentials page loads
|
||||
- Credentials form accepts all required fields (user ID, fingerprint, key content)
|
||||
- Credentials form accepts all required fields (user ID, fingerprint, key content, home region)
|
||||
- Launch step appears
|
||||
- Successful return to Providers page after closing the launch step
|
||||
- Provider exists in Providers table (verified by tenancy ID)
|
||||
@@ -670,7 +670,7 @@
|
||||
**Preconditions:**
|
||||
|
||||
- Admin user authentication required (admin.auth.setup setup)
|
||||
- Environment variables configured: E2E_OCI_TENANCY_ID, E2E_OCI_USER_ID, E2E_OCI_FINGERPRINT, E2E_OCI_KEY_CONTENT
|
||||
- Environment variables configured: E2E_OCI_TENANCY_ID, E2E_OCI_USER_ID, E2E_OCI_FINGERPRINT, E2E_OCI_KEY_CONTENT, E2E_OCI_REGION (optional, defaults to us-ashburn-1)
|
||||
- An OCI provider with the specified Tenancy ID must already exist (run PROVIDER-E2E-012 first)
|
||||
- This test must be run serially and never in parallel with other tests
|
||||
|
||||
@@ -682,7 +682,7 @@
|
||||
4. Click "Update Credentials" option
|
||||
5. Verify update credentials page is loaded
|
||||
6. Verify OCI credentials form fields are visible (confirms providerUid is loaded)
|
||||
7. Fill OCI credentials (user ID, fingerprint, key content)
|
||||
7. Fill OCI credentials (user ID, fingerprint, key content, home region)
|
||||
8. Click Next to submit
|
||||
9. Verify successful navigation to test connection page
|
||||
|
||||
|
||||
@@ -954,6 +954,7 @@ 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 homeRegion = process.env.E2E_OCI_REGION ?? "us-ashburn-1";
|
||||
|
||||
// Setup before each test
|
||||
test.beforeEach(async ({ page }) => {
|
||||
@@ -995,6 +996,7 @@ test.describe("Add Provider", () => {
|
||||
userId: userId,
|
||||
fingerprint: fingerprint,
|
||||
keyContent: keyContent,
|
||||
homeRegion: homeRegion,
|
||||
};
|
||||
|
||||
// Navigate to providers page
|
||||
@@ -1439,6 +1441,7 @@ 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 homeRegion = process.env.E2E_OCI_REGION ?? "us-ashburn-1";
|
||||
|
||||
// Setup before each test
|
||||
test.beforeEach(async ({ page }) => {
|
||||
@@ -1465,6 +1468,7 @@ test.describe("Update Provider Credentials", () => {
|
||||
userId: userId,
|
||||
fingerprint: fingerprint,
|
||||
keyContent: keyContent,
|
||||
homeRegion: homeRegion,
|
||||
};
|
||||
|
||||
// Navigate to providers page
|
||||
|
||||
@@ -281,6 +281,7 @@ 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;
|
||||
};
|
||||
|
||||
Vendored
+1
@@ -151,6 +151,7 @@ declare global {
|
||||
E2E_OCI_USER_ID?: string;
|
||||
E2E_OCI_FINGERPRINT?: string;
|
||||
E2E_OCI_KEY_CONTENT?: string;
|
||||
E2E_OCI_REGION?: string;
|
||||
|
||||
// E2E Alibaba Cloud
|
||||
E2E_ALIBABACLOUD_ACCOUNT_ID?: string;
|
||||
|
||||
@@ -307,11 +307,33 @@ describe("addCredentialsFormSchema - oraclecloud", () => {
|
||||
[ProviderCredentialFields.OCI_TENANCY]: "ocid1.tenancy.oc1..example",
|
||||
} as const;
|
||||
|
||||
it("accepts OCI API key credentials without region", () => {
|
||||
it("rejects OCI API key credentials without a home region", () => {
|
||||
const schema = addCredentialsFormSchema("oraclecloud");
|
||||
|
||||
const result = schema.safeParse(BASE_OCI_VALUES);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects an unknown OCI home region", () => {
|
||||
const schema = addCredentialsFormSchema("oraclecloud");
|
||||
|
||||
const result = schema.safeParse({
|
||||
...BASE_OCI_VALUES,
|
||||
[ProviderCredentialFields.OCI_REGION]: "mars-north-1",
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it("accepts OCI API key credentials with a home region", () => {
|
||||
const schema = addCredentialsFormSchema("oraclecloud");
|
||||
|
||||
const result = schema.safeParse({
|
||||
...BASE_OCI_VALUES,
|
||||
[ProviderCredentialFields.OCI_REGION]: "me-abudhabi-1",
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import yaml from "js-yaml";
|
||||
import { z } from "zod";
|
||||
|
||||
import { OCI_REGION_VALUES } from "@/lib/provider-credentials/oci-regions";
|
||||
import { ProviderCredentialFields } from "@/lib/provider-credentials/provider-credential-fields";
|
||||
import { validateMutelistYaml, validateYaml } from "@/lib/yaml";
|
||||
import { MAX_SAML_ADDITIONAL_EMAIL_DOMAINS } from "@/types/saml";
|
||||
@@ -325,6 +326,14 @@ export const addCredentialsFormSchema = (
|
||||
[ProviderCredentialFields.OCI_TENANCY]: z
|
||||
.string()
|
||||
.min(1, "Tenancy OCID is required"),
|
||||
[ProviderCredentialFields.OCI_REGION]: z
|
||||
.string()
|
||||
.refine(
|
||||
(region) => OCI_REGION_VALUES.includes(region),
|
||||
{
|
||||
error: "Home region is required",
|
||||
},
|
||||
),
|
||||
[ProviderCredentialFields.OCI_PASS_PHRASE]: z
|
||||
.union([z.string(), z.literal("")])
|
||||
.optional(),
|
||||
|
||||
Reference in new issue
Block a user