mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 06:35:21 +00:00
Merge branch 'main' into secret-rotations-v2-feature
This commit is contained in:
@@ -1818,7 +1818,8 @@ export const certificateAuthorityServiceFactory = ({
|
||||
certificateChain: `${issuingCaCertificate}\n${caCertChain}`.trim(),
|
||||
issuingCaCertificate,
|
||||
serialNumber,
|
||||
ca
|
||||
ca,
|
||||
commonName: cn
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -423,7 +423,7 @@ export const projectMembershipServiceFactory = ({
|
||||
const usernamesAndEmails = [...emails, ...usernames];
|
||||
|
||||
const projectMembers = await projectMembershipDAL.findMembershipsByUsername(projectId, [
|
||||
...new Set(usernamesAndEmails.map((element) => element.toLowerCase()))
|
||||
...new Set(usernamesAndEmails.map((element) => element))
|
||||
]);
|
||||
|
||||
if (projectMembers.length !== usernamesAndEmails.length) {
|
||||
|
||||
@@ -402,7 +402,8 @@ export const secretFolderServiceFactory = ({
|
||||
orderDirection,
|
||||
limit,
|
||||
offset,
|
||||
recursive
|
||||
recursive,
|
||||
lastSecretModified
|
||||
}: TGetFolderDTO) => {
|
||||
// folder list is allowed to be read by anyone
|
||||
// permission to check does user has access
|
||||
@@ -425,7 +426,16 @@ export const secretFolderServiceFactory = ({
|
||||
const recursiveFolders = await folderDAL.findByEnvsDeep({ parentIds: [parentFolder.id] });
|
||||
// remove the parent folder
|
||||
return recursiveFolders
|
||||
.filter((folder) => folder.id !== parentFolder.id)
|
||||
.filter((folder) => {
|
||||
if (lastSecretModified) {
|
||||
if (!folder.lastSecretModified) return false;
|
||||
|
||||
if (folder.lastSecretModified < new Date(lastSecretModified)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return folder.id !== parentFolder.id;
|
||||
})
|
||||
.map((folder) => ({
|
||||
...folder,
|
||||
relativePath: folder.path
|
||||
@@ -445,6 +455,11 @@ export const secretFolderServiceFactory = ({
|
||||
offset
|
||||
}
|
||||
);
|
||||
if (lastSecretModified) {
|
||||
return folders.filter((el) =>
|
||||
el.lastSecretModified ? el.lastSecretModified >= new Date(lastSecretModified) : false
|
||||
);
|
||||
}
|
||||
return folders;
|
||||
};
|
||||
|
||||
@@ -619,10 +634,29 @@ export const secretFolderServiceFactory = ({
|
||||
const relevantFolders = folders.filter((folder) => folder.envId === env.id);
|
||||
const foldersMap = Object.fromEntries(relevantFolders.map((folder) => [folder.id, folder]));
|
||||
|
||||
const foldersWithPath = relevantFolders.map((folder) => ({
|
||||
...folder,
|
||||
path: buildFolderPath(folder, foldersMap)
|
||||
}));
|
||||
const foldersWithPath = relevantFolders
|
||||
.map((folder) => {
|
||||
try {
|
||||
return {
|
||||
...folder,
|
||||
path: buildFolderPath(folder, foldersMap)
|
||||
};
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Boolean) as {
|
||||
path: string;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
envId: string;
|
||||
version?: number | null | undefined;
|
||||
parentId?: string | null | undefined;
|
||||
isReserved?: boolean | undefined;
|
||||
description?: string | undefined;
|
||||
}[];
|
||||
|
||||
return [env.slug, { ...env, folders: foldersWithPath }];
|
||||
})
|
||||
|
||||
@@ -46,6 +46,7 @@ export type TGetFolderDTO = {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
recursive?: boolean;
|
||||
lastSecretModified?: string;
|
||||
} & TProjectPermission;
|
||||
|
||||
export type TGetFolderByIdDTO = {
|
||||
|
||||
@@ -356,7 +356,7 @@ export const fnSecretBulkDelete = async ({
|
||||
interface FolderMap {
|
||||
[parentId: string]: TSecretFolders[];
|
||||
}
|
||||
const buildHierarchy = (folders: TSecretFolders[]): FolderMap => {
|
||||
export const buildHierarchy = (folders: TSecretFolders[]): FolderMap => {
|
||||
const map: FolderMap = {};
|
||||
map.null = []; // Initialize mapping for root directory
|
||||
|
||||
@@ -371,7 +371,7 @@ const buildHierarchy = (folders: TSecretFolders[]): FolderMap => {
|
||||
return map;
|
||||
};
|
||||
|
||||
const generatePaths = (
|
||||
export const generatePaths = (
|
||||
map: FolderMap,
|
||||
parentId: string = "null",
|
||||
basePath: string = "",
|
||||
|
||||
@@ -45,10 +45,12 @@ import { fnSecretsV2FromImports } from "../secret-import/secret-import-fns";
|
||||
import { TSecretTagDALFactory } from "../secret-tag/secret-tag-dal";
|
||||
import { TSecretV2BridgeDALFactory } from "./secret-v2-bridge-dal";
|
||||
import {
|
||||
buildHierarchy,
|
||||
expandSecretReferencesFactory,
|
||||
fnSecretBulkDelete,
|
||||
fnSecretBulkInsert,
|
||||
fnSecretBulkUpdate,
|
||||
generatePaths,
|
||||
getAllSecretReferences,
|
||||
recursivelyGetSecretPaths,
|
||||
reshapeBridgeSecret
|
||||
@@ -2663,7 +2665,8 @@ export const secretV2BridgeServiceFactory = ({
|
||||
actorId,
|
||||
actor,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
actorOrgId,
|
||||
recursive
|
||||
}: TGetAccessibleSecretsDTO) => {
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor,
|
||||
@@ -2678,10 +2681,38 @@ export const secretV2BridgeServiceFactory = ({
|
||||
secretPath
|
||||
});
|
||||
|
||||
const folders = [];
|
||||
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
||||
if (!folder) return { secrets: [] };
|
||||
folders.push({ ...folder, parentId: null });
|
||||
|
||||
const secrets = await secretDAL.findByFolderIds([folder.id]);
|
||||
const env = await projectEnvDAL.findOne({
|
||||
projectId,
|
||||
slug: environment
|
||||
});
|
||||
|
||||
if (!env) {
|
||||
throw new NotFoundError({
|
||||
message: `Environment with slug '${environment}' in project with ID ${projectId} not found`
|
||||
});
|
||||
}
|
||||
|
||||
if (recursive) {
|
||||
const subFolders = await folderDAL.find({
|
||||
envId: env.id,
|
||||
isReserved: false
|
||||
});
|
||||
folders.push(...subFolders);
|
||||
}
|
||||
|
||||
if (folders.length === 0) return { secrets: [] };
|
||||
|
||||
const folderMap = buildHierarchy(folders);
|
||||
const paths = Object.fromEntries(
|
||||
generatePaths(folderMap).map(({ folderId, path }) => [folderId, path === "/" ? path : path.substring(1)])
|
||||
);
|
||||
|
||||
const secrets = await secretDAL.findByFolderIds(folders.map((f) => f.id));
|
||||
|
||||
const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||
type: KmsDataKey.SecretManager,
|
||||
@@ -2693,7 +2724,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
if (
|
||||
!hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretPath: paths[el.folderId],
|
||||
secretName: el.key,
|
||||
secretTags: el.tags.map((i) => i.slug)
|
||||
})
|
||||
@@ -2704,7 +2735,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
if (filterByAction === ProjectPermissionSecretActions.ReadValue) {
|
||||
return hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretPath: paths[el.folderId],
|
||||
secretName: el.key,
|
||||
secretTags: el.tags.map((i) => i.slug)
|
||||
});
|
||||
@@ -2717,7 +2748,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
filterByAction === ProjectPermissionSecretActions.DescribeSecret &&
|
||||
!hasSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.ReadValue, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretPath: paths[secret.folderId],
|
||||
secretName: secret.key,
|
||||
secretTags: secret.tags.map((i) => i.slug)
|
||||
});
|
||||
@@ -2725,7 +2756,7 @@ export const secretV2BridgeServiceFactory = ({
|
||||
return reshapeBridgeSecret(
|
||||
projectId,
|
||||
environment,
|
||||
secretPath,
|
||||
paths[secret.folderId],
|
||||
{
|
||||
...secret,
|
||||
value: secret.encryptedValue
|
||||
|
||||
@@ -356,5 +356,6 @@ export type TGetAccessibleSecretsDTO = {
|
||||
environment: string;
|
||||
projectId: string;
|
||||
secretPath: string;
|
||||
recursive?: boolean;
|
||||
filterByAction: ProjectPermissionSecretActions.DescribeSecret | ProjectPermissionSecretActions.ReadValue;
|
||||
} & TProjectPermission;
|
||||
|
||||
@@ -646,6 +646,10 @@ export const secretQueueFactory = ({
|
||||
}
|
||||
);
|
||||
|
||||
const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath);
|
||||
if (!folder) return;
|
||||
await folderDAL.updateById(folder.id, { lastSecretModified: new Date() });
|
||||
|
||||
await secretSyncQueue.queueSecretSyncsSyncSecretsByPath({ projectId, environmentSlug: environment, secretPath });
|
||||
|
||||
await syncIntegrations({ secretPath, projectId, environment, deDupeQueue, isManual: false });
|
||||
|
||||
@@ -1321,7 +1321,8 @@ export const secretServiceFactory = ({
|
||||
actorOrgId,
|
||||
actorAuthMethod,
|
||||
environment,
|
||||
filterByAction
|
||||
filterByAction,
|
||||
recursive
|
||||
}: TGetAccessibleSecretsDTO) => {
|
||||
const { shouldUseSecretV2Bridge } = await projectBotService.getBotKey(projectId);
|
||||
|
||||
@@ -1340,7 +1341,8 @@ export const secretServiceFactory = ({
|
||||
actor,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod
|
||||
actorAuthMethod,
|
||||
recursive
|
||||
});
|
||||
|
||||
return secrets;
|
||||
|
||||
@@ -184,6 +184,7 @@ export enum SecretsOrderBy {
|
||||
export type TGetAccessibleSecretsDTO = {
|
||||
secretPath: string;
|
||||
environment: string;
|
||||
recursive?: boolean;
|
||||
filterByAction: ProjectPermissionSecretActions.DescribeSecret | ProjectPermissionSecretActions.ReadValue;
|
||||
} & TProjectPermission;
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ export enum PostHogEventTypes {
|
||||
SecretRequestCreated = "Secret Request Created",
|
||||
SecretRequestDeleted = "Secret Request Deleted",
|
||||
SignSshKey = "Sign SSH Key",
|
||||
IssueSshCreds = "Issue SSH Credentials"
|
||||
IssueSshCreds = "Issue SSH Credentials",
|
||||
SignCert = "Sign PKI Certificate",
|
||||
IssueCert = "Issue PKI Certificate"
|
||||
}
|
||||
|
||||
export type TSecretModifiedEvent = {
|
||||
@@ -159,6 +161,26 @@ export type TIssueSshCredsEvent = {
|
||||
};
|
||||
};
|
||||
|
||||
export type TSignCertificateEvent = {
|
||||
event: PostHogEventTypes.SignCert;
|
||||
properties: {
|
||||
caId?: string;
|
||||
certificateTemplateId?: string;
|
||||
commonName: string;
|
||||
userAgent?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type TIssueCertificateEvent = {
|
||||
event: PostHogEventTypes.IssueCert;
|
||||
properties: {
|
||||
caId?: string;
|
||||
certificateTemplateId?: string;
|
||||
commonName: string;
|
||||
userAgent?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type TPostHogEvent = { distinctId: string } & (
|
||||
| TSecretModifiedEvent
|
||||
| TAdminInitEvent
|
||||
@@ -173,4 +195,6 @@ export type TPostHogEvent = { distinctId: string } & (
|
||||
| TSecretRequestDeletedEvent
|
||||
| TSignSshKeyEvent
|
||||
| TIssueSshCredsEvent
|
||||
| TSignCertificateEvent
|
||||
| TIssueCertificateEvent
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user