diff --git a/backend/src/server/routes/v1/app-connection-routers/oci-connection-router.ts b/backend/src/server/routes/v1/app-connection-routers/oci-connection-router.ts index 3398ec8a8..d78eee3d9 100644 --- a/backend/src/server/routes/v1/app-connection-routers/oci-connection-router.ts +++ b/backend/src/server/routes/v1/app-connection-routers/oci-connection-router.ts @@ -97,7 +97,7 @@ export const registerOCIConnectionRouter = async (server: FastifyZodProvider) => }), querystring: z.object({ compartmentOcid: z.string().min(1, "Compartment OCID required"), - vaultOcid: z.string().min(1, "Compartment OCID required") + vaultOcid: z.string().min(1, "Vault OCID required") }), response: { 200: z @@ -113,11 +113,11 @@ export const registerOCIConnectionRouter = async (server: FastifyZodProvider) => const { connectionId } = req.params; const { compartmentOcid, vaultOcid } = req.query; - const vaults = await server.services.appConnection.oci.listVaultKeys( + const keys = await server.services.appConnection.oci.listVaultKeys( { connectionId, compartmentOcid, vaultOcid }, req.permission ); - return vaults; + return keys; } }); }; diff --git a/backend/src/services/app-connection/oci/oci-connection-fns.ts b/backend/src/services/app-connection/oci/oci-connection-fns.ts index d48044d29..153e58c98 100644 --- a/backend/src/services/app-connection/oci/oci-connection-fns.ts +++ b/backend/src/services/app-connection/oci/oci-connection-fns.ts @@ -108,7 +108,7 @@ export const listOCIVaultKeys = async (appConnection: TOCIConnection, compartmen authenticationDetailsProvider: provider }); - keyManagementClient.endpoint = `https://${vaultIdMatch[1]}-management.kms.${appConnection.credentials.region}.oraclecloud.com`; + keyManagementClient.endpoint = `https://${vaultIdMatch[1].replace(/[^a-zA-Z0-9]/g, "")}-management.kms.${appConnection.credentials.region}.oraclecloud.com`; const keys = await keyManagementClient.listKeys({ compartmentId: compartmentOcid diff --git a/backend/src/services/app-connection/oci/oci-connection-service.ts b/backend/src/services/app-connection/oci/oci-connection-service.ts index d49d795ef..2d72135e5 100644 --- a/backend/src/services/app-connection/oci/oci-connection-service.ts +++ b/backend/src/services/app-connection/oci/oci-connection-service.ts @@ -1,3 +1,4 @@ +import { logger } from "@app/lib/logger"; import { OrgServiceActor } from "@app/lib/types"; import { AppConnection } from "../app-connection-enums"; @@ -29,6 +30,7 @@ export const ociConnectionService = (getAppConnection: TGetAppConnectionFunc) => const compartments = await listOCICompartments(appConnection); return compartments; } catch (error) { + logger.error(error, "Failed to establish connection with OCI"); return []; } }; @@ -40,6 +42,7 @@ export const ociConnectionService = (getAppConnection: TGetAppConnectionFunc) => const vaults = await listOCIVaults(appConnection, compartmentOcid); return vaults; } catch (error) { + logger.error(error, "Failed to establish connection with OCI"); return []; } }; @@ -51,9 +54,10 @@ export const ociConnectionService = (getAppConnection: TGetAppConnectionFunc) => const appConnection = await getAppConnection(AppConnection.OCI, connectionId, actor); try { - const vaults = await listOCIVaultKeys(appConnection, compartmentOcid, vaultOcid); - return vaults; + const keys = await listOCIVaultKeys(appConnection, compartmentOcid, vaultOcid); + return keys; } catch (error) { + logger.error(error, "Failed to establish connection with OCI"); return []; } }; diff --git a/backend/src/services/secret-sync/oci-vault/oci-vault-sync-schemas.ts b/backend/src/services/secret-sync/oci-vault/oci-vault-sync-schemas.ts index f2d1bb733..2b82da4ea 100644 --- a/backend/src/services/secret-sync/oci-vault/oci-vault-sync-schemas.ts +++ b/backend/src/services/secret-sync/oci-vault/oci-vault-sync-schemas.ts @@ -15,13 +15,23 @@ const OCIVaultSyncDestinationConfigSchema = z.object({ .string() .trim() .min(1, "Compartment OCID required") + .regex( + /^ocid1\.(tenancy|compartment)\.oc1\..+$/, + "Invalid Compartment OCID format. Must start with ocid1.tenancy.oc1. or ocid1.compartment.oc1." + ) .describe(SecretSyncs.DESTINATION_CONFIG.OCI_VAULT.compartmentOcid), vaultOcid: z .string() .trim() .min(1, "Vault OCID required") + .regex(/^ocid1\.vault\.oc1\..+$/, "Invalid Vault OCID format. Must start with ocid1.vault.oc1.") .describe(SecretSyncs.DESTINATION_CONFIG.OCI_VAULT.vaultOcid), - keyOcid: z.string().trim().min(1, "Key OCID required").describe(SecretSyncs.DESTINATION_CONFIG.OCI_VAULT.keyOcid) + keyOcid: z + .string() + .trim() + .min(1, "Key OCID required") + .regex(/^ocid1\.key\.oc1\..+$/, "Invalid Key OCID format. Must start with ocid1.key.oc1.") + .describe(SecretSyncs.DESTINATION_CONFIG.OCI_VAULT.keyOcid) }); const OCIVaultSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true }; diff --git a/docs/integrations/app-connections/oci.mdx b/docs/integrations/app-connections/oci.mdx index fe12d4095..ff51ce1d9 100644 --- a/docs/integrations/app-connections/oci.mdx +++ b/docs/integrations/app-connections/oci.mdx @@ -59,12 +59,12 @@ Infisical supports the use of [API Signing Key Authentication](https://docs.orac ![Select Groups](/images/app-connections/oci/select-groups.png) - The name and description can be anything. **Ensure that you assing the user created in earlier steps to this group**. + The name and description can be anything. **Ensure that you assign the user created in earlier steps to this group**. ![Create Group](/images/app-connections/oci/create-group.png) - After creating the group, take note of it's name. It will be used in later steps. + After creating the group, take note of its name. It will be used in later steps. @@ -175,7 +175,7 @@ Infisical supports the use of [API Signing Key Authentication](https://docs.orac "isPlatformManagedCredentials": false, "credentialsHash": "7c2d371dec195f82a6a0d5b41c970a229cfcaf88e894a5b6395e2dbd0280661f", "app": "oci", - "method": "access-token", + "method": "access-key", "credentials": { "userOcid": "ocid1.user.oc1..aaaaaaaagrp35tbkvvad4y2j7sug7xonua7dl2gfp4at2u5i5xj4ghnitg3a", "tenancyOcid": "ocid1.tenancy.oc1..aaaaaaaaotfma465m4zumfe2ua64mj2m5dwmlw2llh4g4dnfttnakiifonta", diff --git a/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/OCIVaultSyncFields.tsx b/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/OCIVaultSyncFields.tsx index f6e868318..26fa601f6 100644 --- a/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/OCIVaultSyncFields.tsx +++ b/frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/OCIVaultSyncFields.tsx @@ -34,7 +34,7 @@ export const OCIVaultSyncFields = () => { const { data: vaults, isLoading: isVaultsLoading } = useOCIConnectionListVaults( { connectionId, compartmentOcid: selectedCompartment }, { - enabled: Boolean(connectionId) + enabled: Boolean(connectionId && selectedCompartment) } ); @@ -43,7 +43,7 @@ export const OCIVaultSyncFields = () => { const { data: keys, isLoading: isKeysLoading } = useOCIConnectionListVaultKeys( { connectionId, compartmentOcid: selectedCompartment, vaultOcid: selectedVault }, { - enabled: Boolean(connectionId) + enabled: Boolean(connectionId && selectedCompartment && selectedVault) } ); @@ -119,7 +119,7 @@ export const OCIVaultSyncFields = () => { v.id === value) ?? null} onChange={(option) => { onChange((option as SingleValue<{ id: string }>)?.id ?? null); @@ -157,9 +157,7 @@ export const OCIVaultSyncFields = () => { v.id === value) ?? null} onChange={(option) => { onChange((option as SingleValue<{ id: string }>)?.id ?? null); diff --git a/frontend/src/components/secret-syncs/forms/schemas/oci-vault-sync-destination-schema.ts b/frontend/src/components/secret-syncs/forms/schemas/oci-vault-sync-destination-schema.ts index 54d48a59b..84eb6a362 100644 --- a/frontend/src/components/secret-syncs/forms/schemas/oci-vault-sync-destination-schema.ts +++ b/frontend/src/components/secret-syncs/forms/schemas/oci-vault-sync-destination-schema.ts @@ -7,9 +7,27 @@ export const OCIVaultSyncDestinationSchema = BaseSecretSyncSchema().merge( z.object({ destination: z.literal(SecretSync.OCIVault), destinationConfig: z.object({ - compartmentOcid: z.string().trim().min(1, "Compartment OCID required"), - vaultOcid: z.string().trim().min(1, "Vault OCID required"), - keyOcid: z.string().trim().min(1, "Key OCID required") + compartmentOcid: z + .string() + .trim() + .min(1, "Compartment OCID required") + .regex( + /^ocid1\.(tenancy|compartment)\.oc1\..+$/, + "Invalid Compartment OCID format. Must start with ocid1.tenancy.oc1. or ocid1.compartment.oc1." + ), + vaultOcid: z + .string() + .trim() + .min(1, "Vault OCID required") + .regex( + /^ocid1\.vault\.oc1\..+$/, + "Invalid Vault OCID format. Must start with ocid1.vault.oc1." + ), + keyOcid: z + .string() + .trim() + .min(1, "Key OCID required") + .regex(/^ocid1\.key\.oc1\..+$/, "Invalid Key OCID format. Must start with ocid1.key.oc1.") }) }) ); diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OCIConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OCIConnectionForm.tsx index 242fa740a..6ea355dd2 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OCIConnectionForm.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OCIConnectionForm.tsx @@ -33,8 +33,16 @@ const formSchema = z.discriminatedUnion("method", [ rootSchema.extend({ method: z.literal(OCIConnectionMethod.AccessKey), credentials: z.object({ - userOcid: z.string().trim().min(1, "User OCID required"), - tenancyOcid: z.string().trim().min(1, "Tenancy OCID required"), + userOcid: z + .string() + .trim() + .min(1, "User OCID required") + .regex(/^ocid1\.user\.oc1\.\..+$/, "Invalid User OCID format"), + tenancyOcid: z + .string() + .trim() + .min(1, "Tenancy OCID required") + .regex(/^ocid1\.tenancy\.oc1\.\..+$/, "Invalid Tenancy OCID format"), region: z.string().trim().min(1, "Region required"), fingerprint: z.string().trim().min(1, "Fingerprint required"), privateKey: z.string().trim().min(1, "Private Key required")