mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 11:27:47 +00:00
feat: added subscription plan to secret replication
This commit is contained in:
@@ -16,6 +16,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
|||||||
environmentLimit: null,
|
environmentLimit: null,
|
||||||
environmentsUsed: 0,
|
environmentsUsed: 0,
|
||||||
dynamicSecret: false,
|
dynamicSecret: false,
|
||||||
|
secretReplication: false,
|
||||||
secretVersioning: true,
|
secretVersioning: true,
|
||||||
pitRecovery: false,
|
pitRecovery: false,
|
||||||
ipAllowlisting: false,
|
ipAllowlisting: false,
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export type TFeatureSet = {
|
|||||||
has_used_trial: true;
|
has_used_trial: true;
|
||||||
secretApproval: false;
|
secretApproval: false;
|
||||||
secretRotation: true;
|
secretRotation: true;
|
||||||
|
secretReplication: false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TOrgPlansTableDTO = {
|
export type TOrgPlansTableDTO = {
|
||||||
|
|||||||
@@ -590,6 +590,7 @@ export const registerRoutes = async (
|
|||||||
secretVersionTagDAL
|
secretVersionTagDAL
|
||||||
});
|
});
|
||||||
const secretImportService = secretImportServiceFactory({
|
const secretImportService = secretImportServiceFactory({
|
||||||
|
licenseService,
|
||||||
projectEnvDAL,
|
projectEnvDAL,
|
||||||
folderDAL,
|
folderDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
@@ -30,6 +31,7 @@ type TSecretImportServiceFactoryDep = {
|
|||||||
projectEnvDAL: TProjectEnvDALFactory;
|
projectEnvDAL: TProjectEnvDALFactory;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets" | "replicateSecrets">;
|
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets" | "replicateSecrets">;
|
||||||
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ERR_SEC_IMP_NOT_FOUND = new BadRequestError({ message: "Secret import not found" });
|
const ERR_SEC_IMP_NOT_FOUND = new BadRequestError({ message: "Secret import not found" });
|
||||||
@@ -43,7 +45,8 @@ export const secretImportServiceFactory = ({
|
|||||||
folderDAL,
|
folderDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
secretDAL,
|
secretDAL,
|
||||||
secretQueueService
|
secretQueueService,
|
||||||
|
licenseService
|
||||||
}: TSecretImportServiceFactoryDep) => {
|
}: TSecretImportServiceFactoryDep) => {
|
||||||
const createImport = async ({
|
const createImport = async ({
|
||||||
environment,
|
environment,
|
||||||
@@ -78,6 +81,14 @@ export const secretImportServiceFactory = ({
|
|||||||
secretPath: data.path
|
secretPath: data.path
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
if (isReplication) {
|
||||||
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
|
if (!plan.secretReplication) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to create secret replication due to plan restriction. Upgrade plan to create replication."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await projectDAL.checkProjectUpgradeStatus(projectId);
|
await projectDAL.checkProjectUpgradeStatus(projectId);
|
||||||
|
|
||||||
@@ -273,6 +284,13 @@ export const secretImportServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
|
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
|
if (!plan.secretReplication) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to create secret replication due to plan restriction. Upgrade plan to create replication."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
|
||||||
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Update import" });
|
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Update import" });
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export type SubscriptionPlan = {
|
|||||||
scim: boolean;
|
scim: boolean;
|
||||||
ldap: boolean;
|
ldap: boolean;
|
||||||
groups: boolean;
|
groups: boolean;
|
||||||
|
secretReplication: boolean;
|
||||||
status:
|
status:
|
||||||
| "incomplete"
|
| "incomplete"
|
||||||
| "incomplete_expired"
|
| "incomplete_expired"
|
||||||
|
|||||||
@@ -482,6 +482,7 @@ export const ActionBar = ({
|
|||||||
environment={environment}
|
environment={environment}
|
||||||
workspaceId={workspaceId}
|
workspaceId={workspaceId}
|
||||||
secretPath={secretPath}
|
secretPath={secretPath}
|
||||||
|
onUpgradePlan={() => handlePopUpOpen("upgradePlan")}
|
||||||
isOpen={popUp.addSecretImport.isOpen}
|
isOpen={popUp.addSecretImport.isOpen}
|
||||||
onClose={() => handlePopUpClose("addSecretImport")}
|
onClose={() => handlePopUpClose("addSecretImport")}
|
||||||
onTogglePopUp={(isOpen) => handlePopUpToggle("addSecretImport", isOpen)}
|
onTogglePopUp={(isOpen) => handlePopUpToggle("addSecretImport", isOpen)}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
SelectItem
|
SelectItem
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
|
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
|
||||||
import { useWorkspace } from "@app/context";
|
import { useSubscription, useWorkspace } from "@app/context";
|
||||||
import { useCreateSecretImport } from "@app/hooks/api";
|
import { useCreateSecretImport } from "@app/hooks/api";
|
||||||
|
|
||||||
const typeSchema = z.object({
|
const typeSchema = z.object({
|
||||||
@@ -38,6 +38,7 @@ type Props = {
|
|||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onTogglePopUp: (isOpen: boolean) => void;
|
onTogglePopUp: (isOpen: boolean) => void;
|
||||||
|
onUpgradePlan: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateSecretImportForm = ({
|
export const CreateSecretImportForm = ({
|
||||||
@@ -46,7 +47,8 @@ export const CreateSecretImportForm = ({
|
|||||||
secretPath = "/",
|
secretPath = "/",
|
||||||
isOpen,
|
isOpen,
|
||||||
onClose,
|
onClose,
|
||||||
onTogglePopUp
|
onTogglePopUp,
|
||||||
|
onUpgradePlan
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -58,6 +60,7 @@ export const CreateSecretImportForm = ({
|
|||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const environments = currentWorkspace?.environments || [];
|
const environments = currentWorkspace?.environments || [];
|
||||||
const selectedEnvironment = watch("environment");
|
const selectedEnvironment = watch("environment");
|
||||||
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const { mutateAsync: createSecretImport } = useCreateSecretImport();
|
const { mutateAsync: createSecretImport } = useCreateSecretImport();
|
||||||
|
|
||||||
@@ -67,6 +70,11 @@ export const CreateSecretImportForm = ({
|
|||||||
isReplication
|
isReplication
|
||||||
}: TFormSchema) => {
|
}: TFormSchema) => {
|
||||||
try {
|
try {
|
||||||
|
if (isReplication && !subscription?.secretReplication) {
|
||||||
|
onUpgradePlan();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await createSecretImport({
|
await createSecretImport({
|
||||||
environment,
|
environment,
|
||||||
projectId: workspaceId,
|
projectId: workspaceId,
|
||||||
|
|||||||
Reference in New Issue
Block a user