feat: updated ui to reflect secret import and approval

This commit is contained in:
Akhil Mohan
2024-05-31 23:10:01 +05:30
committed by =
parent c9d6c5c5f7
commit 51c1487ed1
17 changed files with 103 additions and 47 deletions
+3 -1
View File
@@ -677,7 +677,9 @@ export const registerRoutes = async (
secretApprovalPolicyService,
secretBlindIndexDAL,
secretApprovalRequestDAL,
secretApprovalRequestSecretDAL
secretApprovalRequestSecretDAL,
secretQueueService,
snapshotService
});
const secretRotationQueue = secretRotationQueueFactory({
telemetryService,
@@ -79,7 +79,7 @@ export const fnSecretsFromImports = async ({
let secretsFromDeeperImports: TSecretImportSecrets[] = [];
if (deeperImports.length) {
secretsFromDeeperImports = await fnSecretsFromImports({
allowedImports: deeperImports,
allowedImports: deeperImports.filter(({ isReplication }) => !isReplication),
secretImportDAL,
folderDAL,
secretDAL,
@@ -8,6 +8,7 @@ import { TProjectDALFactory } from "../project/project-dal";
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
import { TSecretDALFactory } from "../secret/secret-dal";
import { TSecretQueueFactory } from "../secret/secret-queue";
import { SecretOperations } from "../secret/secret-types";
import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal";
import { TSecretImportDALFactory } from "./secret-import-dal";
import { fnSecretsFromImports } from "./secret-import-fns";
@@ -26,7 +27,7 @@ type TSecretImportServiceFactoryDep = {
projectDAL: Pick<TProjectDALFactory, "checkProjectUpgradeStatus">;
projectEnvDAL: TProjectEnvDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets">;
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets" | "replicateSecrets">;
};
const ERR_SEC_IMP_NOT_FOUND = new BadRequestError({ message: "Secret import not found" });
@@ -53,7 +54,7 @@ export const secretImportServiceFactory = ({
isReplication,
path
}: TCreateSecretImportDTO) => {
const { permission } = await permissionService.getProjectPermission(
const { permission, membership } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
@@ -108,12 +109,27 @@ export const secretImportServiceFactory = ({
);
});
await secretQueueService.syncSecrets({
secretPath: secImport.importPath,
projectId,
environmentSlug: importEnv.slug,
excludeReplication: true
});
if (secImport.isReplication) {
const importedSecrets = await secretDAL.find({ folderId: sourceFolder?.id });
await secretQueueService.replicateSecrets({
secretPath: secImport.importPath,
projectId,
environmentSlug: importEnv.slug,
pickOnlyImportIds: [secImport.id],
folderId: sourceFolder?.id as string,
secrets: importedSecrets.map(({ id, version }) => ({ operation: SecretOperations.Create, version, id })),
// TODO(akhilmhdh): approval based replication this will fail for identity
membershipId: membership?.id as string,
environmentId: importEnv.id
});
} else {
await secretQueueService.syncSecrets({
secretPath: secImport.importPath,
projectId,
environmentSlug: importEnv.slug,
excludeReplication: true
});
}
return { ...secImport, importEnv };
};
@@ -283,7 +299,7 @@ export const secretImportServiceFactory = ({
if (!folder) return [];
// this will already order by position
// so anything based on this order will also be in right position
const secretImports = await secretImportDAL.find({ folderId: folder.id });
const secretImports = await secretImportDAL.find({ folderId: folder.id, isReplication: false });
const allowedImports = secretImports.filter(({ importEnv, importPath }) =>
permission.can(
@@ -64,12 +64,15 @@ export const secretReplicationServiceFactory = ({
}: TSecretReplicationServiceFactoryDep) => {
queueService.start(QueueName.SecretReplication, async (job) => {
logger.info(job.data, "Replication started");
const { secrets, folderId, secretPath, environmentId, projectId, membershipId } = job.data;
const secretImports = await secretImportDAL.find({
const { secrets, folderId, secretPath, environmentId, projectId, membershipId, pickOnlyImportIds } = job.data;
let secretImports = await secretImportDAL.find({
importPath: secretPath,
importEnv: environmentId,
isReplication: true
});
secretImports = pickOnlyImportIds
? secretImports.filter(({ id }) => pickOnlyImportIds?.includes(id))
: secretImports;
if (!secretImports.length || !secrets.length) return;
// unfiltered secrets to be replicated
+27 -18
View File
@@ -143,6 +143,18 @@ export const secretQueueFactory = ({
});
};
const replicateSecrets = async (dto: TSyncSecretsDTO) => {
await queueService.queue(QueueName.SecretReplication, QueueJobs.SecretReplication, dto, {
attempts: 3,
backoff: {
type: "exponential",
delay: 2000
},
removeOnComplete: true,
removeOnFail: true
});
};
const removeSecretReminder = async (dto: TRemoveSecretReminderDTO) => {
const appCfg = getConfig();
await queueService.stopRepeatableJob(
@@ -361,22 +373,17 @@ export const secretQueueFactory = ({
}
);
await syncIntegrations({ secretPath, projectId, environment });
if (!excludeReplication) {
await queueService.queue(
QueueName.SecretReplication,
QueueJobs.SecretReplication,
{ environmentId, projectId, secretPath, folderId, secrets, membershipId },
{
attempts: 3,
backoff: {
type: "exponential",
delay: 2000
},
removeOnComplete: true,
removeOnFail: true
}
);
}
if (!excludeReplication)
await replicateSecrets({
environmentId,
projectId,
secretPath,
folderId,
secrets,
membershipId,
excludeReplication,
environmentSlug: environment
});
});
queueService.start(QueueName.IntegrationSync, async (job) => {
@@ -394,7 +401,8 @@ export const secretQueueFactory = ({
const linkSourceDto = {
projectId,
importEnv: folder.environment.id,
importPath: secretPath
importPath: secretPath,
isReplication: false
};
const imports = await secretImportDAL.find(linkSourceDto);
@@ -598,6 +606,7 @@ export const secretQueueFactory = ({
syncIntegrations,
addSecretReminder,
removeSecretReminder,
handleSecretReminder
handleSecretReminder,
replicateSecrets
};
};
@@ -550,7 +550,8 @@ export const secretServiceFactory = ({
if (includeImports) {
const secretImports = await secretImportDAL.findByFolderIds(paths.map((p) => p.folderId));
const allowedImports = secretImports.filter(({ importEnv, importPath }) =>
const allowedImports = secretImports.filter(({ importEnv, importPath, isReplication }) =>
!isReplication &&
// if its service token allow full access over imported one
actor === ActorType.SERVICE
? true
@@ -655,7 +656,7 @@ export const secretServiceFactory = ({
// then search for imported secrets
// here we consider the import order also thus starting from bottom
if (!secret && includeImports) {
const secretImports = await secretImportDAL.find({ folderId });
const secretImports = await secretImportDAL.find({ folderId, isReplication: false });
const allowedImports = secretImports.filter(({ importEnv, importPath }) =>
// if its service token allow full access over imported one
actor === ActorType.SERVICE
@@ -389,6 +389,8 @@ export type TSyncSecretsDTO<T extends boolean = false> = {
environmentId: string;
folderId: string;
membershipId: string;
// used for import creation to trigger replication
pickOnlyImportIds?: string[];
secrets: {
operation: SecretOperations;
id: string;