mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-17 02:47:35 +00:00
Merge branch 'main' into feat/showWarningOnImportedSecretDeletion
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
ProjectPermissionSecretActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/ee/services/permission/project-permission";
|
||||
import { SecretRotationV2Schema } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema";
|
||||
import { DASHBOARD } from "@app/lib/api-docs";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { removeTrailingSlash } from "@app/lib/fn";
|
||||
@@ -101,12 +102,30 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
includeSecrets: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeSecrets),
|
||||
includeFolders: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeFolders),
|
||||
includeImports: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeImports),
|
||||
includeSecretRotations: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeSecretRotations),
|
||||
includeDynamicSecrets: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeDynamicSecrets)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
folders: SecretFoldersSchema.extend({ environment: z.string() }).array().optional(),
|
||||
dynamicSecrets: SanitizedDynamicSecretSchema.extend({ environment: z.string() }).array().optional(),
|
||||
secretRotations: z
|
||||
.intersection(
|
||||
SecretRotationV2Schema,
|
||||
z.object({
|
||||
secrets: secretRawSchema
|
||||
.extend({
|
||||
secretValueHidden: z.boolean(),
|
||||
secretPath: z.string().optional(),
|
||||
secretMetadata: ResourceMetadataSchema.optional(),
|
||||
tags: SanitizedTagSchema.array().optional()
|
||||
})
|
||||
.nullable()
|
||||
.array()
|
||||
})
|
||||
)
|
||||
.array()
|
||||
.optional(),
|
||||
secrets: secretRawSchema
|
||||
.extend({
|
||||
secretValueHidden: z.boolean(),
|
||||
@@ -127,6 +146,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
totalDynamicSecretCount: z.number().optional(),
|
||||
totalSecretCount: z.number().optional(),
|
||||
totalImportCount: z.number().optional(),
|
||||
totalSecretRotationCount: z.number().optional(),
|
||||
totalCount: z.number()
|
||||
})
|
||||
}
|
||||
@@ -144,7 +164,8 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
includeFolders,
|
||||
includeSecrets,
|
||||
includeImports,
|
||||
includeDynamicSecrets
|
||||
includeDynamicSecrets,
|
||||
includeSecretRotations
|
||||
} = req.query;
|
||||
|
||||
const environments = req.query.environments.split(",");
|
||||
@@ -166,11 +187,15 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
let dynamicSecrets:
|
||||
| Awaited<ReturnType<typeof server.services.dynamicSecret.listDynamicSecretsByEnvs>>
|
||||
| undefined;
|
||||
let secretRotations:
|
||||
| Awaited<ReturnType<typeof server.services.secretRotationV2.getDashboardSecretRotations>>
|
||||
| undefined;
|
||||
|
||||
let totalFolderCount: number | undefined;
|
||||
let totalDynamicSecretCount: number | undefined;
|
||||
let totalSecretCount: number | undefined;
|
||||
let totalImportCount: number | undefined;
|
||||
let totalSecretRotationCount: number | undefined;
|
||||
|
||||
if (includeImports) {
|
||||
totalImportCount = await server.services.secretImport.getProjectImportMultiEnvCount({
|
||||
@@ -322,6 +347,56 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (includeSecretRotations) {
|
||||
totalSecretRotationCount = await server.services.secretRotationV2.getDashboardSecretRotationCount(
|
||||
{
|
||||
projectId,
|
||||
search,
|
||||
environments,
|
||||
secretPath
|
||||
},
|
||||
req.permission
|
||||
);
|
||||
|
||||
if (remainingLimit > 0 && totalSecretRotationCount > adjustedOffset) {
|
||||
secretRotations = await server.services.secretRotationV2.getDashboardSecretRotations(
|
||||
{
|
||||
projectId,
|
||||
search,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
environments,
|
||||
secretPath,
|
||||
limit: remainingLimit,
|
||||
offset: adjustedOffset
|
||||
},
|
||||
req.permission
|
||||
);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRET_ROTATIONS,
|
||||
metadata: {
|
||||
count: secretRotations.length,
|
||||
rotationIds: secretRotations.map((rotation) => rotation.id),
|
||||
secretPath,
|
||||
environment: environments.join(",")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// get the count of unique secret rotation names to properly adjust remaining limit
|
||||
const uniqueSecretRotationCount = new Set(secretRotations.map((rotation) => rotation.name)).size;
|
||||
|
||||
remainingLimit -= uniqueSecretRotationCount;
|
||||
adjustedOffset = 0;
|
||||
} else {
|
||||
adjustedOffset = Math.max(0, adjustedOffset - totalSecretRotationCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (includeSecrets) {
|
||||
// this is the unique count, ie duplicate secrets across envs only count as 1
|
||||
totalSecretCount = await server.services.secret.getSecretsCountMultiEnv({
|
||||
@@ -353,38 +428,44 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
offset: adjustedOffset,
|
||||
isInternal: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for await (const environment of environments) {
|
||||
const secretCountFromEnv = secrets.filter((secret) => secret.environment === environment).length;
|
||||
if (secrets?.length || secretRotations?.length) {
|
||||
for await (const environment of environments) {
|
||||
const secretCountFromEnv =
|
||||
(secrets?.filter((secret) => secret.environment === environment).length ?? 0) +
|
||||
(secretRotations
|
||||
?.filter((rotation) => rotation.environment.slug === environment)
|
||||
.flatMap((rotation) => rotation.secrets.filter((secret) => Boolean(secret))).length ?? 0);
|
||||
|
||||
if (secretCountFromEnv) {
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRETS,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
numberOfSecrets: secretCountFromEnv
|
||||
}
|
||||
if (secretCountFromEnv) {
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRETS,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
numberOfSecrets: secretCountFromEnv
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (getUserAgentType(req.headers["user-agent"]) !== UserAgentType.K8_OPERATOR) {
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secretCountFromEnv,
|
||||
workspaceId: projectId,
|
||||
environment,
|
||||
secretPath,
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
|
||||
if (getUserAgentType(req.headers["user-agent"]) !== UserAgentType.K8_OPERATOR) {
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secretCountFromEnv,
|
||||
workspaceId: projectId,
|
||||
environment,
|
||||
secretPath,
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,12 +476,18 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
dynamicSecrets,
|
||||
secrets,
|
||||
imports,
|
||||
secretRotations,
|
||||
totalFolderCount,
|
||||
totalDynamicSecretCount,
|
||||
totalImportCount,
|
||||
totalSecretCount,
|
||||
totalSecretRotationCount,
|
||||
totalCount:
|
||||
(totalFolderCount ?? 0) + (totalDynamicSecretCount ?? 0) + (totalSecretCount ?? 0) + (totalImportCount ?? 0)
|
||||
(totalFolderCount ?? 0) +
|
||||
(totalDynamicSecretCount ?? 0) +
|
||||
(totalSecretCount ?? 0) +
|
||||
(totalImportCount ?? 0) +
|
||||
(totalSecretRotationCount ?? 0)
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -445,7 +532,8 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
includeSecrets: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeSecrets),
|
||||
includeFolders: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeFolders),
|
||||
includeDynamicSecrets: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeDynamicSecrets),
|
||||
includeImports: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeImports)
|
||||
includeImports: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeImports),
|
||||
includeSecretRotations: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeSecretRotations)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -457,6 +545,23 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
.optional(),
|
||||
folders: SecretFoldersSchema.array().optional(),
|
||||
dynamicSecrets: SanitizedDynamicSecretSchema.array().optional(),
|
||||
secretRotations: z
|
||||
.intersection(
|
||||
SecretRotationV2Schema,
|
||||
z.object({
|
||||
secrets: secretRawSchema
|
||||
.extend({
|
||||
secretValueHidden: z.boolean(),
|
||||
secretPath: z.string().optional(),
|
||||
secretMetadata: ResourceMetadataSchema.optional(),
|
||||
tags: SanitizedTagSchema.array().optional()
|
||||
})
|
||||
.nullable()
|
||||
.array()
|
||||
})
|
||||
)
|
||||
.array()
|
||||
.optional(),
|
||||
secrets: secretRawSchema
|
||||
.extend({
|
||||
secretValueHidden: z.boolean(),
|
||||
@@ -470,7 +575,6 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
totalFolderCount: z.number().optional(),
|
||||
totalDynamicSecretCount: z.number().optional(),
|
||||
totalSecretCount: z.number().optional(),
|
||||
totalCount: z.number(),
|
||||
importedBy: z
|
||||
.object({
|
||||
envName: z.string(),
|
||||
@@ -482,7 +586,9 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
.array()
|
||||
})
|
||||
.array()
|
||||
.optional()
|
||||
.optional(),
|
||||
totalSecretRotationCount: z.number().optional(),
|
||||
totalCount: z.number()
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -500,7 +606,8 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
includeFolders,
|
||||
includeSecrets,
|
||||
includeDynamicSecrets,
|
||||
includeImports
|
||||
includeImports,
|
||||
includeSecretRotations
|
||||
} = req.query;
|
||||
|
||||
if (!projectId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" });
|
||||
@@ -519,11 +626,15 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
let folders: Awaited<ReturnType<typeof server.services.folder.getFolders>> | undefined;
|
||||
let secrets: Awaited<ReturnType<typeof server.services.secret.getSecretsRaw>>["secrets"] | undefined;
|
||||
let dynamicSecrets: Awaited<ReturnType<typeof server.services.dynamicSecret.listDynamicSecretsByEnv>> | undefined;
|
||||
let secretRotations:
|
||||
| Awaited<ReturnType<typeof server.services.secretRotationV2.getDashboardSecretRotations>>
|
||||
| undefined;
|
||||
|
||||
let totalImportCount: number | undefined;
|
||||
let totalFolderCount: number | undefined;
|
||||
let totalDynamicSecretCount: number | undefined;
|
||||
let totalSecretCount: number | undefined;
|
||||
let totalSecretRotationCount: number | undefined;
|
||||
|
||||
if (includeImports) {
|
||||
totalImportCount = await server.services.secretImport.getProjectImportCount({
|
||||
@@ -606,6 +717,53 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (includeSecretRotations) {
|
||||
totalSecretRotationCount = await server.services.secretRotationV2.getDashboardSecretRotationCount(
|
||||
{
|
||||
projectId,
|
||||
search,
|
||||
environments: [environment],
|
||||
secretPath
|
||||
},
|
||||
req.permission
|
||||
);
|
||||
|
||||
if (remainingLimit > 0 && totalSecretRotationCount > adjustedOffset) {
|
||||
secretRotations = await server.services.secretRotationV2.getDashboardSecretRotations(
|
||||
{
|
||||
projectId,
|
||||
search,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
environments: [environment],
|
||||
secretPath,
|
||||
limit: remainingLimit,
|
||||
offset: adjustedOffset
|
||||
},
|
||||
req.permission
|
||||
);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRET_ROTATIONS,
|
||||
metadata: {
|
||||
count: secretRotations.length,
|
||||
rotationIds: secretRotations.map((rotation) => rotation.id),
|
||||
secretPath,
|
||||
environment
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
remainingLimit -= secretRotations.length;
|
||||
adjustedOffset = 0;
|
||||
} else {
|
||||
adjustedOffset = Math.max(0, adjustedOffset - totalSecretRotationCount);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (includeDynamicSecrets) {
|
||||
totalDynamicSecretCount = await server.services.dynamicSecret.getDynamicSecretCount({
|
||||
@@ -641,7 +799,13 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
adjustedOffset = Math.max(0, adjustedOffset - totalDynamicSecretCount);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (!(error instanceof ForbiddenError)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (includeSecrets) {
|
||||
totalSecretCount = await server.services.secret.getSecretsCount({
|
||||
actorId: req.permission.id,
|
||||
@@ -675,34 +839,6 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
tagSlugs: tags
|
||||
})
|
||||
).secrets;
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRETS,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
numberOfSecrets: secrets.length
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (getUserAgentType(req.headers["user-agent"]) !== UserAgentType.K8_OPERATOR) {
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secrets.length,
|
||||
workspaceId: projectId,
|
||||
environment,
|
||||
secretPath,
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -720,19 +856,58 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId
|
||||
});
|
||||
if (secrets?.length || secretRotations?.length) {
|
||||
const secretCount =
|
||||
(secrets?.length ?? 0) +
|
||||
(secretRotations?.flatMap((rotation) => rotation.secrets.filter((secret) => Boolean(secret))).length ?? 0);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRETS,
|
||||
metadata: {
|
||||
environment,
|
||||
secretPath,
|
||||
numberOfSecrets: secretCount
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (getUserAgentType(req.headers["user-agent"]) !== UserAgentType.K8_OPERATOR) {
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secretCount,
|
||||
workspaceId: projectId,
|
||||
environment,
|
||||
secretPath,
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
imports,
|
||||
folders,
|
||||
dynamicSecrets,
|
||||
secrets,
|
||||
secretRotations,
|
||||
totalImportCount,
|
||||
totalFolderCount,
|
||||
totalDynamicSecretCount,
|
||||
totalSecretCount,
|
||||
totalSecretRotationCount,
|
||||
importedBy,
|
||||
totalCount:
|
||||
(totalImportCount ?? 0) + (totalFolderCount ?? 0) + (totalDynamicSecretCount ?? 0) + (totalSecretCount ?? 0),
|
||||
importedBy
|
||||
(totalImportCount ?? 0) +
|
||||
(totalFolderCount ?? 0) +
|
||||
(totalDynamicSecretCount ?? 0) +
|
||||
(totalSecretCount ?? 0) +
|
||||
(totalSecretRotationCount ?? 0)
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -770,7 +945,8 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
tags: SanitizedTagSchema.array().optional()
|
||||
})
|
||||
.array()
|
||||
.optional()
|
||||
.optional(),
|
||||
secretRotations: SecretRotationV2Schema.array().optional()
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -834,6 +1010,17 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
req.permission
|
||||
);
|
||||
|
||||
const secretRotations = searchHasTags
|
||||
? []
|
||||
: await server.services.secretRotationV2.getQuickSearchSecretRotations(
|
||||
{
|
||||
projectId,
|
||||
folderMappings,
|
||||
filters: sharedFilters
|
||||
},
|
||||
req.permission
|
||||
);
|
||||
|
||||
for await (const environment of environments) {
|
||||
const secretCountForEnv = secrets.filter((secret) => secret.environment === environment).length;
|
||||
|
||||
@@ -866,6 +1053,24 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const secretRotationsFromEnv = secretRotations.filter((rotation) => rotation.environment.slug === environment);
|
||||
|
||||
if (secretRotationsFromEnv.length) {
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRET_ROTATIONS,
|
||||
metadata: {
|
||||
count: secretRotationsFromEnv.length,
|
||||
rotationIds: secretRotationsFromEnv.map((rotation) => rotation.id),
|
||||
secretPath,
|
||||
environment
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const sliceQuickSearch = <T>(array: T[]) => array.slice(0, 25);
|
||||
@@ -879,6 +1084,9 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
? dynamicSecrets.filter((dynamicSecret) => dynamicSecret.path.endsWith(searchPath))
|
||||
: dynamicSecrets
|
||||
),
|
||||
secretRotations: sliceQuickSearch(
|
||||
searchPath ? secretRotations.filter((rotation) => rotation.folder.path.endsWith(searchPath)) : secretRotations
|
||||
),
|
||||
folders: searchHasTags
|
||||
? []
|
||||
: sliceQuickSearch(
|
||||
|
||||
Reference in New Issue
Block a user