mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 01:52:22 +00:00
Merge
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
export * from "./oci-vault-sync-constants";
|
||||
export * from "./oci-vault-sync-fns";
|
||||
export * from "./oci-vault-sync-schemas";
|
||||
export * from "./oci-vault-sync-types";
|
||||
@@ -1,10 +0,0 @@
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { TSecretSyncListItem } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
export const OCI_VAULT_SYNC_LIST_OPTION: TSecretSyncListItem = {
|
||||
name: "OCI Vault",
|
||||
destination: SecretSync.OCIVault,
|
||||
connection: AppConnection.OCI,
|
||||
canImportSecrets: true
|
||||
};
|
||||
@@ -1,296 +0,0 @@
|
||||
import { secrets, vault } from "oci-sdk";
|
||||
|
||||
import { delay } from "@app/lib/delay";
|
||||
import { getOCIProvider } from "@app/services/app-connection/oci";
|
||||
import {
|
||||
TCreateOCIVaultVariable,
|
||||
TDeleteOCIVaultVariable,
|
||||
TOCIVaultListVariables,
|
||||
TOCIVaultSyncWithCredentials,
|
||||
TUnmarkOCIVaultVariableFromDeletion,
|
||||
TUpdateOCIVaultVariable
|
||||
} from "@app/services/secret-sync/oci-vault/oci-vault-sync-types";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
const listOCIVaultVariables = async ({ provider, compartmentId, vaultId, onlyActive }: TOCIVaultListVariables) => {
|
||||
const vaultsClient = new vault.VaultsClient({ authenticationDetailsProvider: provider });
|
||||
const secretsClient = new secrets.SecretsClient({ authenticationDetailsProvider: provider });
|
||||
|
||||
const secretsRes = await vaultsClient.listSecrets({
|
||||
compartmentId,
|
||||
vaultId,
|
||||
lifecycleState: onlyActive ? vault.models.SecretSummary.LifecycleState.Active : undefined
|
||||
});
|
||||
|
||||
const result: Record<string, vault.models.SecretSummary & { name: string; value: string }> = {};
|
||||
|
||||
for await (const s of secretsRes.items) {
|
||||
let secretValue = "";
|
||||
|
||||
if (s.lifecycleState === vault.models.SecretSummary.LifecycleState.Active) {
|
||||
const secretBundle = await secretsClient.getSecretBundle({
|
||||
secretId: s.id
|
||||
});
|
||||
|
||||
secretValue = Buffer.from(secretBundle.secretBundle.secretBundleContent?.content || "", "base64").toString(
|
||||
"utf-8"
|
||||
);
|
||||
}
|
||||
|
||||
result[s.secretName] = {
|
||||
...s,
|
||||
name: s.secretName,
|
||||
value: secretValue
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const createOCIVaultVariable = async ({
|
||||
provider,
|
||||
compartmentId,
|
||||
vaultId,
|
||||
keyId,
|
||||
name,
|
||||
value
|
||||
}: TCreateOCIVaultVariable) => {
|
||||
if (!value) return;
|
||||
|
||||
const vaultsClient = new vault.VaultsClient({ authenticationDetailsProvider: provider });
|
||||
|
||||
return vaultsClient.createSecret({
|
||||
createSecretDetails: {
|
||||
compartmentId,
|
||||
vaultId,
|
||||
keyId,
|
||||
secretName: name,
|
||||
enableAutoGeneration: false,
|
||||
secretContent: {
|
||||
content: Buffer.from(value).toString("base64"),
|
||||
contentType: "BASE64"
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const updateOCIVaultVariable = async ({ provider, secretId, value }: TUpdateOCIVaultVariable) => {
|
||||
if (!value) return;
|
||||
|
||||
const vaultsClient = new vault.VaultsClient({ authenticationDetailsProvider: provider });
|
||||
|
||||
return vaultsClient.updateSecret({
|
||||
secretId,
|
||||
updateSecretDetails: {
|
||||
enableAutoGeneration: false,
|
||||
secretContent: {
|
||||
content: Buffer.from(value).toString("base64"),
|
||||
contentType: "BASE64"
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const deleteOCIVaultVariable = async ({ provider, secretId }: TDeleteOCIVaultVariable) => {
|
||||
const vaultsClient = new vault.VaultsClient({ authenticationDetailsProvider: provider });
|
||||
|
||||
// Schedule a secret deletion 7 days from now. OCI Vault requires a MINIMUM buffer period of 7 days
|
||||
return vaultsClient.scheduleSecretDeletion({
|
||||
secretId,
|
||||
scheduleSecretDeletionDetails: {
|
||||
timeOfDeletion: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const unmarkOCIVaultVariableFromDeletion = async ({ provider, secretId }: TUnmarkOCIVaultVariableFromDeletion) => {
|
||||
const vaultsClient = new vault.VaultsClient({ authenticationDetailsProvider: provider });
|
||||
|
||||
return vaultsClient.cancelSecretDeletion({
|
||||
secretId
|
||||
});
|
||||
};
|
||||
|
||||
export const OCIVaultSyncFns = {
|
||||
syncSecrets: async (secretSync: TOCIVaultSyncWithCredentials, secretMap: TSecretMap) => {
|
||||
const {
|
||||
connection,
|
||||
destinationConfig: { compartmentOcid, vaultOcid, keyOcid }
|
||||
} = secretSync;
|
||||
|
||||
const provider = await getOCIProvider(connection);
|
||||
const variables = await listOCIVaultVariables({ provider, compartmentId: compartmentOcid, vaultId: vaultOcid });
|
||||
|
||||
// Throw an error if any keys are updating in OCI vault to prevent skipped updates
|
||||
if (
|
||||
Object.entries(variables).some(
|
||||
([, secret]) =>
|
||||
secret.lifecycleState === vault.models.SecretSummary.LifecycleState.Updating ||
|
||||
secret.lifecycleState === vault.models.SecretSummary.LifecycleState.CancellingDeletion ||
|
||||
secret.lifecycleState === vault.models.SecretSummary.LifecycleState.Creating ||
|
||||
secret.lifecycleState === vault.models.SecretSummary.LifecycleState.Deleting ||
|
||||
secret.lifecycleState === vault.models.SecretSummary.LifecycleState.SchedulingDeletion
|
||||
)
|
||||
) {
|
||||
throw new SecretSyncError({
|
||||
error: "Cannot sync while keys are updating in OCI Vault."
|
||||
});
|
||||
}
|
||||
|
||||
// Create secrets
|
||||
for await (const entry of Object.entries(secretMap)) {
|
||||
const [key, { value }] = entry;
|
||||
|
||||
// skip secrets that don't have a value set
|
||||
if (!value) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingVariable = Object.values(variables).find((v) => v.secretName === key);
|
||||
|
||||
if (!existingVariable) {
|
||||
try {
|
||||
await createOCIVaultVariable({
|
||||
compartmentId: compartmentOcid,
|
||||
vaultId: vaultOcid,
|
||||
provider,
|
||||
keyId: keyOcid,
|
||||
name: key,
|
||||
value
|
||||
});
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
} else if (existingVariable.lifecycleState === vault.models.SecretSummary.LifecycleState.PendingDeletion) {
|
||||
// If a secret exists but is pending deletion, cancel the deletion and update the secret
|
||||
await unmarkOCIVaultVariableFromDeletion({
|
||||
provider,
|
||||
compartmentId: compartmentOcid,
|
||||
vaultId: vaultOcid,
|
||||
secretId: existingVariable.id
|
||||
});
|
||||
|
||||
const vaultsClient = new vault.VaultsClient({ authenticationDetailsProvider: provider });
|
||||
const MAX_RETRIES = 10;
|
||||
|
||||
for (let i = 0; i < MAX_RETRIES; i += 1) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await delay(5000);
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const secret = await vaultsClient.getSecret({
|
||||
secretId: existingVariable.id
|
||||
});
|
||||
|
||||
if (secret.secret.lifecycleState === vault.models.SecretSummary.LifecycleState.Active) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await updateOCIVaultVariable({
|
||||
provider,
|
||||
compartmentId: compartmentOcid,
|
||||
vaultId: vaultOcid,
|
||||
secretId: existingVariable.id,
|
||||
value
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (i === MAX_RETRIES - 1) {
|
||||
throw new SecretSyncError({
|
||||
error: "Failed to update secret after cancelling deletion.",
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update and delete secrets
|
||||
for await (const [key, variable] of Object.entries(variables)) {
|
||||
// eslint-disable-next-line no-continue
|
||||
if (!matchesSchema(key, secretSync.syncOptions.keySchema)) continue;
|
||||
|
||||
// Only update / delete active secrets
|
||||
if (variable.lifecycleState === vault.models.SecretSummary.LifecycleState.Active) {
|
||||
if (key in secretMap && secretMap[key].value.length > 0) {
|
||||
if (variable.value !== secretMap[key].value) {
|
||||
try {
|
||||
await updateOCIVaultVariable({
|
||||
compartmentId: compartmentOcid,
|
||||
vaultId: vaultOcid,
|
||||
provider,
|
||||
secretId: variable.id,
|
||||
value: secretMap[key].value
|
||||
});
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (!secretSync.syncOptions.disableSecretDeletion) {
|
||||
try {
|
||||
await deleteOCIVaultVariable({
|
||||
compartmentId: compartmentOcid,
|
||||
vaultId: vaultOcid,
|
||||
provider,
|
||||
secretId: variable.id
|
||||
});
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
removeSecrets: async (secretSync: TOCIVaultSyncWithCredentials, secretMap: TSecretMap) => {
|
||||
const {
|
||||
connection,
|
||||
destinationConfig: { compartmentOcid, vaultOcid }
|
||||
} = secretSync;
|
||||
|
||||
const provider = await getOCIProvider(connection);
|
||||
const variables = await listOCIVaultVariables({
|
||||
provider,
|
||||
compartmentId: compartmentOcid,
|
||||
vaultId: vaultOcid,
|
||||
onlyActive: true
|
||||
});
|
||||
|
||||
for await (const [key, variable] of Object.entries(variables)) {
|
||||
if (key in secretMap) {
|
||||
try {
|
||||
await deleteOCIVaultVariable({
|
||||
compartmentId: compartmentOcid,
|
||||
vaultId: vaultOcid,
|
||||
provider,
|
||||
secretId: variable.id
|
||||
});
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getSecrets: async (secretSync: TOCIVaultSyncWithCredentials) => {
|
||||
const {
|
||||
connection,
|
||||
destinationConfig: { compartmentOcid, vaultOcid }
|
||||
} = secretSync;
|
||||
|
||||
const provider = await getOCIProvider(connection);
|
||||
return listOCIVaultVariables({ provider, compartmentId: compartmentOcid, vaultId: vaultOcid, onlyActive: true });
|
||||
}
|
||||
};
|
||||
@@ -1,70 +0,0 @@
|
||||
import RE2 from "re2";
|
||||
import { z } from "zod";
|
||||
|
||||
import { SecretSyncs } from "@app/lib/api-docs";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import {
|
||||
BaseSecretSyncSchema,
|
||||
GenericCreateSecretSyncFieldsSchema,
|
||||
GenericUpdateSecretSyncFieldsSchema
|
||||
} from "@app/services/secret-sync/secret-sync-schemas";
|
||||
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
||||
|
||||
const OCIVaultSyncDestinationConfigSchema = z.object({
|
||||
compartmentOcid: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Compartment OCID required")
|
||||
.refine(
|
||||
(val) => new RE2("^ocid1\\.(tenancy|compartment)\\.oc1\\..+$").test(val),
|
||||
"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")
|
||||
.refine(
|
||||
(val) => new RE2("^ocid1\\.vault\\.oc1\\..+$").test(val),
|
||||
"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")
|
||||
.refine(
|
||||
(val) => new RE2("^ocid1\\.key\\.oc1\\..+$").test(val),
|
||||
"Invalid Key OCID format. Must start with ocid1.key.oc1."
|
||||
)
|
||||
.describe(SecretSyncs.DESTINATION_CONFIG.OCI_VAULT.keyOcid)
|
||||
});
|
||||
|
||||
const OCIVaultSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
|
||||
|
||||
export const OCIVaultSyncSchema = BaseSecretSyncSchema(SecretSync.OCIVault, OCIVaultSyncOptionsConfig).extend({
|
||||
destination: z.literal(SecretSync.OCIVault),
|
||||
destinationConfig: OCIVaultSyncDestinationConfigSchema
|
||||
});
|
||||
|
||||
export const CreateOCIVaultSyncSchema = GenericCreateSecretSyncFieldsSchema(
|
||||
SecretSync.OCIVault,
|
||||
OCIVaultSyncOptionsConfig
|
||||
).extend({
|
||||
destinationConfig: OCIVaultSyncDestinationConfigSchema
|
||||
});
|
||||
|
||||
export const UpdateOCIVaultSyncSchema = GenericUpdateSecretSyncFieldsSchema(
|
||||
SecretSync.OCIVault,
|
||||
OCIVaultSyncOptionsConfig
|
||||
).extend({
|
||||
destinationConfig: OCIVaultSyncDestinationConfigSchema.optional()
|
||||
});
|
||||
|
||||
export const OCIVaultSyncListItemSchema = z.object({
|
||||
name: z.literal("OCI Vault"),
|
||||
connection: z.literal(AppConnection.OCI),
|
||||
destination: z.literal(SecretSync.OCIVault),
|
||||
canImportSecrets: z.literal(true)
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
import { SimpleAuthenticationDetailsProvider } from "oci-sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
import { TOCIConnection } from "@app/services/app-connection/oci";
|
||||
|
||||
import { CreateOCIVaultSyncSchema, OCIVaultSyncListItemSchema, OCIVaultSyncSchema } from "./oci-vault-sync-schemas";
|
||||
|
||||
export type TOCIVaultSync = z.infer<typeof OCIVaultSyncSchema>;
|
||||
|
||||
export type TOCIVaultSyncInput = z.infer<typeof CreateOCIVaultSyncSchema>;
|
||||
|
||||
export type TOCIVaultSyncListItem = z.infer<typeof OCIVaultSyncListItemSchema>;
|
||||
|
||||
export type TOCIVaultSyncWithCredentials = TOCIVaultSync & {
|
||||
connection: TOCIConnection;
|
||||
};
|
||||
|
||||
export type TOCIVaultVariable = {
|
||||
id: string;
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TOCIVaultListVariables = {
|
||||
provider: SimpleAuthenticationDetailsProvider;
|
||||
compartmentId: string;
|
||||
vaultId: string;
|
||||
onlyActive?: boolean; // Whether to filter for only active secrets. Removes deleted / scheduled for deletion secrets
|
||||
};
|
||||
|
||||
export type TCreateOCIVaultVariable = TOCIVaultListVariables & {
|
||||
keyId: string;
|
||||
name: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TUpdateOCIVaultVariable = TOCIVaultListVariables & {
|
||||
secretId: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TDeleteOCIVaultVariable = TOCIVaultListVariables & {
|
||||
secretId: string;
|
||||
};
|
||||
|
||||
export type TUnmarkOCIVaultVariableFromDeletion = TOCIVaultListVariables & {
|
||||
secretId: string;
|
||||
};
|
||||
@@ -27,3 +27,8 @@ export enum SecretSyncImportBehavior {
|
||||
PrioritizeSource = "prioritize-source",
|
||||
PrioritizeDestination = "prioritize-destination"
|
||||
}
|
||||
|
||||
export enum SecretSyncPlanType {
|
||||
Enterprise = "enterprise",
|
||||
Regular = "regular"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { AxiosError } from "axios";
|
||||
import RE2 from "re2";
|
||||
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { OCI_VAULT_SYNC_LIST_OPTION, OCIVaultSyncFns } from "@app/ee/services/secret-sync/oci-vault";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import {
|
||||
AWS_PARAMETER_STORE_SYNC_LIST_OPTION,
|
||||
AwsParameterStoreSyncFns
|
||||
@@ -11,7 +14,7 @@ import {
|
||||
} from "@app/services/secret-sync/aws-secrets-manager";
|
||||
import { DATABRICKS_SYNC_LIST_OPTION, databricksSyncFactory } from "@app/services/secret-sync/databricks";
|
||||
import { GITHUB_SYNC_LIST_OPTION, GithubSyncFns } from "@app/services/secret-sync/github";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSync, SecretSyncPlanType } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import {
|
||||
TSecretMap,
|
||||
@@ -30,7 +33,7 @@ import { GcpSyncFns } from "./gcp/gcp-sync-fns";
|
||||
import { HC_VAULT_SYNC_LIST_OPTION, HCVaultSyncFns } from "./hc-vault";
|
||||
import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec";
|
||||
import { HumanitecSyncFns } from "./humanitec/humanitec-sync-fns";
|
||||
import { OCI_VAULT_SYNC_LIST_OPTION, OCIVaultSyncFns } from "./oci-vault";
|
||||
import { SECRET_SYNC_PLAN_MAP } from "./secret-sync-maps";
|
||||
import { TEAMCITY_SYNC_LIST_OPTION, TeamCitySyncFns } from "./teamcity";
|
||||
import { TERRAFORM_CLOUD_SYNC_LIST_OPTION, TerraformCloudSyncFns } from "./terraform-cloud";
|
||||
import { VERCEL_SYNC_LIST_OPTION, VercelSyncFns } from "./vercel";
|
||||
@@ -336,3 +339,18 @@ export const parseSyncErrorMessage = (err: unknown): string => {
|
||||
? errorMessage
|
||||
: `${errorMessage.substring(0, MAX_MESSAGE_LENGTH - 3)}...`;
|
||||
};
|
||||
|
||||
export const enterpriseSyncCheck = async (
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">,
|
||||
secretSync: SecretSync,
|
||||
orgId: string,
|
||||
errorMessage: string
|
||||
) => {
|
||||
if (SECRET_SYNC_PLAN_MAP[secretSync] === SecretSyncPlanType.Enterprise) {
|
||||
const plan = await licenseService.getPlan(orgId);
|
||||
if (!plan.enterpriseSecretSyncs)
|
||||
throw new BadRequestError({
|
||||
message: errorMessage
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSync, SecretSyncPlanType } from "@app/services/secret-sync/secret-sync-enums";
|
||||
|
||||
export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
|
||||
[SecretSync.AWSParameterStore]: "AWS Parameter Store",
|
||||
@@ -38,3 +38,21 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
||||
[SecretSync.OCIVault]: AppConnection.OCI,
|
||||
[SecretSync.OnePass]: AppConnection.OnePass
|
||||
};
|
||||
|
||||
export const SECRET_SYNC_PLAN_MAP: Record<SecretSync, SecretSyncPlanType> = {
|
||||
[SecretSync.AWSParameterStore]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.AWSSecretsManager]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.GitHub]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.GCPSecretManager]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.AzureKeyVault]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.AzureAppConfiguration]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Databricks]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Humanitec]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.TerraformCloud]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Camunda]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Vercel]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Windmill]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.HCVault]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.TeamCity]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.OCIVault]: SecretSyncPlanType.Enterprise
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Job } from "bullmq";
|
||||
import { ProjectMembershipRole, SecretType } from "@app/db/schemas";
|
||||
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { KeyStorePrefixes, TKeyStoreFactory } from "@app/keystore/keystore";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { logger } from "@app/lib/logger";
|
||||
@@ -32,7 +33,7 @@ import {
|
||||
SecretSyncInitialSyncBehavior
|
||||
} from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { parseSyncErrorMessage, SecretSyncFns } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { enterpriseSyncCheck, parseSyncErrorMessage, SecretSyncFns } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||
import {
|
||||
SecretSyncAction,
|
||||
@@ -93,6 +94,7 @@ type TSecretSyncQueueFactoryDep = {
|
||||
secretVersionV2BridgeDAL: Pick<TSecretVersionV2DALFactory, "insertMany" | "findLatestVersionMany">;
|
||||
secretVersionTagV2BridgeDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">;
|
||||
resourceMetadataDAL: Pick<TResourceMetadataDALFactory, "insertMany" | "delete">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
type SecretSyncActionJob = Job<
|
||||
@@ -133,7 +135,8 @@ export const secretSyncQueueFactory = ({
|
||||
secretVersionTagDAL,
|
||||
secretVersionV2BridgeDAL,
|
||||
secretVersionTagV2BridgeDAL,
|
||||
resourceMetadataDAL
|
||||
resourceMetadataDAL,
|
||||
licenseService
|
||||
}: TSecretSyncQueueFactoryDep) => {
|
||||
const appCfg = getConfig();
|
||||
|
||||
@@ -323,7 +326,20 @@ export const secretSyncQueueFactory = ({
|
||||
secretSync: TSecretSyncWithCredentials,
|
||||
importBehavior: SecretSyncImportBehavior
|
||||
): Promise<TSecretMap> => {
|
||||
const { projectId, environment, folder } = secretSync;
|
||||
const {
|
||||
projectId,
|
||||
environment,
|
||||
folder,
|
||||
destination,
|
||||
connection: { orgId }
|
||||
} = secretSync;
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
destination,
|
||||
orgId,
|
||||
"Failed to import secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
if (!environment || !folder)
|
||||
throw new Error(
|
||||
@@ -400,6 +416,13 @@ export const secretSyncQueueFactory = ({
|
||||
|
||||
if (!secretSync) throw new Error(`Cannot find secret sync with ID ${syncId}`);
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
secretSync.connection.orgId,
|
||||
"Failed to sync secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
await secretSyncDAL.updateById(syncId, {
|
||||
syncStatus: SecretSyncStatus.Running
|
||||
});
|
||||
@@ -659,6 +682,13 @@ export const secretSyncQueueFactory = ({
|
||||
|
||||
if (!secretSync) throw new Error(`Cannot find secret sync with ID ${syncId}`);
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
secretSync.connection.orgId,
|
||||
"Failed to remove secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
await secretSyncDAL.updateById(syncId, {
|
||||
removeStatus: SecretSyncStatus.Running
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
|
||||
import { ActionProjectType } from "@app/db/schemas";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { throwIfMissingSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import {
|
||||
@@ -16,7 +17,7 @@ import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-c
|
||||
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
||||
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { listSecretSyncOptions } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { enterpriseSyncCheck, listSecretSyncOptions } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import {
|
||||
SecretSyncStatus,
|
||||
TCreateSecretSyncDTO,
|
||||
@@ -49,6 +50,7 @@ type TSecretSyncServiceFactoryDep = {
|
||||
TSecretSyncQueueFactory,
|
||||
"queueSecretSyncSyncSecretsById" | "queueSecretSyncImportSecretsById" | "queueSecretSyncRemoveSecretsById"
|
||||
>;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
export type TSecretSyncServiceFactory = ReturnType<typeof secretSyncServiceFactory>;
|
||||
@@ -61,7 +63,8 @@ export const secretSyncServiceFactory = ({
|
||||
appConnectionService,
|
||||
projectBotService,
|
||||
secretSyncQueue,
|
||||
keyStore
|
||||
keyStore,
|
||||
licenseService
|
||||
}: TSecretSyncServiceFactoryDep) => {
|
||||
const listSecretSyncsByProjectId = async (
|
||||
{ projectId, destination }: TListSecretSyncsByProjectId,
|
||||
@@ -191,6 +194,13 @@ export const secretSyncServiceFactory = ({
|
||||
{ projectId, secretPath, environment, ...params }: TCreateSecretSyncDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
params.destination,
|
||||
actor.orgId,
|
||||
"Failed to create secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission: projectPermission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -260,6 +270,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID ${syncId}`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to update secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -408,6 +425,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to trigger secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -463,6 +487,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to trigger secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -512,6 +543,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to trigger secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { Job } from "bullmq";
|
||||
|
||||
import { AuditLogInfo } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import {
|
||||
TOCIVaultSync,
|
||||
TOCIVaultSyncInput,
|
||||
TOCIVaultSyncListItem,
|
||||
TOCIVaultSyncWithCredentials
|
||||
} from "@app/ee/services/secret-sync/oci-vault";
|
||||
import { QueueJobs } from "@app/queue";
|
||||
import { ResourceMetadataDTO } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||
import {
|
||||
@@ -73,7 +79,6 @@ import {
|
||||
THumanitecSyncListItem,
|
||||
THumanitecSyncWithCredentials
|
||||
} from "./humanitec";
|
||||
import { TOCIVaultSync, TOCIVaultSyncInput, TOCIVaultSyncListItem, TOCIVaultSyncWithCredentials } from "./oci-vault";
|
||||
import {
|
||||
TTeamCitySync,
|
||||
TTeamCitySyncInput,
|
||||
|
||||
Reference in New Issue
Block a user