app connection + finishing touches

This commit is contained in:
x032205
2025-05-20 13:25:15 -04:00
parent 966294bd0e
commit 1efdb31037
31 changed files with 319 additions and 66 deletions
@@ -26,3 +26,8 @@ export enum SecretSyncImportBehavior {
PrioritizeSource = "prioritize-source",
PrioritizeDestination = "prioritize-destination"
}
export enum SecretSyncPlanType {
Enterprise = "enterprise",
Regular = "regular"
}
@@ -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",
@@ -36,3 +36,21 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.TeamCity]: AppConnection.TeamCity,
[SecretSync.OCIVault]: AppConnection.OCI
};
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,8 +5,10 @@ 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 { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue";
import { decryptAppConnectionCredentials } from "@app/services/app-connection/app-connection-fns";
@@ -29,11 +31,12 @@ import { TSecretSyncDALFactory } from "@app/services/secret-sync/secret-sync-dal
import {
SecretSync,
SecretSyncImportBehavior,
SecretSyncInitialSyncBehavior
SecretSyncInitialSyncBehavior,
SecretSyncPlanType
} 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 { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
import { SECRET_SYNC_NAME_MAP, SECRET_SYNC_PLAN_MAP } from "@app/services/secret-sync/secret-sync-maps";
import {
SecretSyncAction,
SecretSyncStatus,
@@ -93,6 +96,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 +137,8 @@ export const secretSyncQueueFactory = ({
secretVersionTagDAL,
secretVersionV2BridgeDAL,
secretVersionTagV2BridgeDAL,
resourceMetadataDAL
resourceMetadataDAL,
licenseService
}: TSecretSyncQueueFactoryDep) => {
const appCfg = getConfig();
@@ -323,7 +328,22 @@ export const secretSyncQueueFactory = ({
secretSync: TSecretSyncWithCredentials,
importBehavior: SecretSyncImportBehavior
): Promise<TSecretMap> => {
const { projectId, environment, folder } = secretSync;
const {
projectId,
environment,
folder,
destination,
connection: { orgId }
} = secretSync;
// Enterprise Check
if (SECRET_SYNC_PLAN_MAP[destination] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message: "Failed to import secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
});
}
if (!environment || !folder)
throw new Error(
@@ -400,6 +420,15 @@ export const secretSyncQueueFactory = ({
if (!secretSync) throw new Error(`Cannot find secret sync with ID ${syncId}`);
// Enterprise Check
if (SECRET_SYNC_PLAN_MAP[secretSync.destination as SecretSync] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(secretSync.connection.orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message: "Failed to sync secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
});
}
await secretSyncDAL.updateById(syncId, {
syncStatus: SecretSyncStatus.Running
});
@@ -659,6 +688,16 @@ export const secretSyncQueueFactory = ({
if (!secretSync) throw new Error(`Cannot find secret sync with ID ${syncId}`);
// Enterprise Check
if (SECRET_SYNC_PLAN_MAP[secretSync.destination as SecretSync] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(secretSync.connection.orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message:
"Failed to access secret sync 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 {
@@ -15,7 +16,7 @@ import { OrgServiceActor } from "@app/lib/types";
import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service";
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 { SecretSync, SecretSyncPlanType } from "@app/services/secret-sync/secret-sync-enums";
import { listSecretSyncOptions } from "@app/services/secret-sync/secret-sync-fns";
import {
SecretSyncStatus,
@@ -34,7 +35,7 @@ import {
import { TSecretImportDALFactory } from "../secret-import/secret-import-dal";
import { TSecretSyncDALFactory } from "./secret-sync-dal";
import { SECRET_SYNC_CONNECTION_MAP, SECRET_SYNC_NAME_MAP } from "./secret-sync-maps";
import { SECRET_SYNC_CONNECTION_MAP, SECRET_SYNC_NAME_MAP, SECRET_SYNC_PLAN_MAP } from "./secret-sync-maps";
import { TSecretSyncQueueFactory } from "./secret-sync-queue";
type TSecretSyncServiceFactoryDep = {
@@ -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,16 @@ export const secretSyncServiceFactory = ({
{ projectId, secretPath, environment, ...params }: TCreateSecretSyncDTO,
actor: OrgServiceActor
) => {
// Enterprise check
if (SECRET_SYNC_PLAN_MAP[params.destination] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(actor.orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message:
"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 +273,16 @@ export const secretSyncServiceFactory = ({
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID ${syncId}`
});
// Enterprise check
if (SECRET_SYNC_PLAN_MAP[secretSync.destination as SecretSync] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(actor.orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message:
"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 +431,16 @@ export const secretSyncServiceFactory = ({
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
});
// Enterprise check
if (SECRET_SYNC_PLAN_MAP[secretSync.destination as SecretSync] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(actor.orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message:
"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 +496,16 @@ export const secretSyncServiceFactory = ({
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
});
// Enterprise check
if (SECRET_SYNC_PLAN_MAP[secretSync.destination as SecretSync] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(actor.orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message:
"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 +555,16 @@ export const secretSyncServiceFactory = ({
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
});
// Enterprise check
if (SECRET_SYNC_PLAN_MAP[secretSync.destination as SecretSync] === SecretSyncPlanType.Enterprise) {
const plan = await licenseService.getPlan(actor.orgId);
if (!plan.enterpriseSecretSyncs)
throw new BadRequestError({
message:
"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,