mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 03:31:27 +00:00
feature secret rotations v2
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
export enum SecretRotation {
|
||||
PostgresCredentials = "postgres-credentials",
|
||||
MsSqlCredentials = "mssql-credentials"
|
||||
}
|
||||
|
||||
export enum SecretRotationStatus {
|
||||
Success = "success",
|
||||
Failed = "failed"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./enums";
|
||||
export * from "./queries";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,91 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { dashboardKeys } from "@app/hooks/api/dashboard/queries";
|
||||
import {
|
||||
TCreateSecretRotationV2DTO,
|
||||
TDeleteSecretRotationV2DTO,
|
||||
TRotateSecretRotationV2DTO,
|
||||
TSecretRotationV2Response,
|
||||
TUpdateSecretRotationV2DTO
|
||||
} from "@app/hooks/api/secretRotationsV2/types";
|
||||
|
||||
export const useCreateSecretRotationV2 = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ type, ...params }: TCreateSecretRotationV2DTO) => {
|
||||
const { data } = await apiRequest.post<TSecretRotationV2Response>(
|
||||
`/api/v2/secret-rotations/${type}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.secretRotation;
|
||||
},
|
||||
onSuccess: (_, { projectId, secretPath }) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath })
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateSecretRotationV2 = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ type, rotationId, ...params }: TUpdateSecretRotationV2DTO) => {
|
||||
const { data } = await apiRequest.patch<TSecretRotationV2Response>(
|
||||
`/api/v2/secret-rotations/${type}/${rotationId}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.secretRotation;
|
||||
},
|
||||
onSuccess: (_, { projectId, secretPath }) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath })
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export const useRotateSecretRotationV2 = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ type, rotationId }: TRotateSecretRotationV2DTO) => {
|
||||
const { data } = await apiRequest.post<TSecretRotationV2Response>(
|
||||
`/api/v2/secret-rotations/${type}/${rotationId}/rotate-secrets`
|
||||
);
|
||||
|
||||
return data.secretRotation;
|
||||
},
|
||||
onSuccess: (_, { projectId, secretPath }) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath })
|
||||
}),
|
||||
onError: (_, { projectId, secretPath }) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath })
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteSecretRotationV2 = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
type,
|
||||
rotationId,
|
||||
deleteSecrets,
|
||||
revokeGeneratedCredentials
|
||||
}: TDeleteSecretRotationV2DTO) => {
|
||||
const { data } = await apiRequest.delete<TSecretRotationV2Response>(
|
||||
`/api/v2/secret-rotations/${type}/${rotationId}`,
|
||||
{ params: { deleteSecrets, revokeGeneratedCredentials } }
|
||||
);
|
||||
|
||||
return data.secretRotation;
|
||||
},
|
||||
onSuccess: (_, { projectId, secretPath }) =>
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath })
|
||||
})
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { SecretRotation } from "@app/hooks/api/secretRotationsV2/enums";
|
||||
import {
|
||||
TListSecretRotationV2Options,
|
||||
TSecretRotationV2Option,
|
||||
TViewSecretRotationGeneratedCredentialsResponse,
|
||||
TViewSecretRotationV2GeneratedCredentialsDTO
|
||||
} from "@app/hooks/api/secretRotationsV2/types";
|
||||
|
||||
export const secretRotationV2Keys = {
|
||||
all: ["secret-rotations-v2"] as const,
|
||||
options: () => [...secretRotationV2Keys.all, "options"] as const,
|
||||
viewGeneratedCredentials: ({ type, rotationId }: TViewSecretRotationV2GeneratedCredentialsDTO) =>
|
||||
[...secretRotationV2Keys.all, type, rotationId] as const
|
||||
};
|
||||
|
||||
export const useSecretRotationV2Options = (
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretRotationV2Option[],
|
||||
unknown,
|
||||
TSecretRotationV2Option[],
|
||||
ReturnType<typeof secretRotationV2Keys.options>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretRotationV2Keys.options(),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretRotationV2Options>(
|
||||
"/api/v2/secret-rotations/options"
|
||||
);
|
||||
|
||||
return data.secretRotationOptions;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useSecretRotationV2Option = (type: SecretRotation) => {
|
||||
const { data: rotationOptions, isPending } = useSecretRotationV2Options();
|
||||
const rotationOption = rotationOptions?.find((option) => option.type === type);
|
||||
|
||||
return { rotationOption, isPending };
|
||||
};
|
||||
|
||||
export const useViewSecretRotationV2GeneratedCredentials = (
|
||||
{ rotationId, type }: TViewSecretRotationV2GeneratedCredentialsDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TViewSecretRotationGeneratedCredentialsResponse,
|
||||
unknown,
|
||||
TViewSecretRotationGeneratedCredentialsResponse,
|
||||
ReturnType<typeof secretRotationV2Keys.viewGeneratedCredentials>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretRotationV2Keys.viewGeneratedCredentials({ rotationId, type }),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TViewSecretRotationGeneratedCredentialsResponse>(
|
||||
`/api/v2/secret-rotations/${type}/${rotationId}/generated-credentials`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { SecretRotation } from "@app/hooks/api/secretRotationsV2";
|
||||
import {
|
||||
TMsSqlCredentialsRotation,
|
||||
TMsSqlCredentialsRotationGeneratedCredentialsResponse
|
||||
} from "@app/hooks/api/secretRotationsV2/types/mssql-credentials-rotation";
|
||||
import {
|
||||
TPostgresCredentialsRotation,
|
||||
TPostgresCredentialsRotationGeneratedCredentialsResponse
|
||||
} from "@app/hooks/api/secretRotationsV2/types/postgres-credentials-rotation";
|
||||
import { TSqlOptionTemplate } from "@app/hooks/api/secretRotationsV2/types/shared";
|
||||
import { SecretV3RawSanitized } from "@app/hooks/api/secrets/types";
|
||||
import { DiscriminativePick } from "@app/types";
|
||||
|
||||
export type TSecretRotationV2 = (TPostgresCredentialsRotation | TMsSqlCredentialsRotation) & {
|
||||
secrets: (SecretV3RawSanitized | null)[];
|
||||
};
|
||||
|
||||
export type TSecretRotationV2Option = {
|
||||
name: string;
|
||||
type: SecretRotation;
|
||||
connection: AppConnection;
|
||||
template: TSqlOptionTemplate;
|
||||
};
|
||||
|
||||
export type TListSecretRotationV2Options = { secretRotationOptions: TSecretRotationV2Option[] };
|
||||
|
||||
export type TSecretRotationV2Response = { secretRotation: TSecretRotationV2 };
|
||||
|
||||
export type TViewSecretRotationGeneratedCredentialsResponse =
|
||||
| TPostgresCredentialsRotationGeneratedCredentialsResponse
|
||||
| TMsSqlCredentialsRotationGeneratedCredentialsResponse;
|
||||
|
||||
export type TCreateSecretRotationV2DTO = DiscriminativePick<
|
||||
TSecretRotationV2,
|
||||
| "name"
|
||||
| "parameters"
|
||||
| "secretsMapping"
|
||||
| "description"
|
||||
| "connectionId"
|
||||
| "type"
|
||||
| "isAutoRotationEnabled"
|
||||
| "rotationInterval"
|
||||
| "rotateAtUtc"
|
||||
> & { environment: string; secretPath: string; projectId: string };
|
||||
|
||||
export type TUpdateSecretRotationV2DTO = Partial<
|
||||
Omit<TCreateSecretRotationV2DTO, "type" | "secretPath" | "projectId">
|
||||
> & {
|
||||
type: SecretRotation;
|
||||
rotationId: string;
|
||||
// required for query invalidation
|
||||
projectId: string;
|
||||
secretPath: string;
|
||||
};
|
||||
|
||||
export type TRotateSecretRotationV2DTO = {
|
||||
rotationId: string;
|
||||
type: SecretRotation;
|
||||
// required for query invalidation
|
||||
secretPath: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TDeleteSecretRotationV2DTO = TRotateSecretRotationV2DTO & {
|
||||
revokeGeneratedCredentials: boolean;
|
||||
deleteSecrets: boolean;
|
||||
};
|
||||
|
||||
export type TViewSecretRotationV2GeneratedCredentialsDTO = {
|
||||
rotationId: string;
|
||||
type: SecretRotation;
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { SecretRotation } from "@app/hooks/api/secretRotationsV2";
|
||||
import {
|
||||
TSecretRotationV2Base,
|
||||
TSecretRotationV2GeneratedCredentialsResponseBase,
|
||||
TSqlCredentialsRotationGeneratedCredentials,
|
||||
TSqlCredentialsRotationProperties
|
||||
} from "@app/hooks/api/secretRotationsV2/types/shared";
|
||||
|
||||
export type TMsSqlCredentialsRotation = TSecretRotationV2Base & {
|
||||
type: SecretRotation.MsSqlCredentials;
|
||||
} & TSqlCredentialsRotationProperties;
|
||||
|
||||
export type TMsSqlCredentialsRotationGeneratedCredentialsResponse =
|
||||
TSecretRotationV2GeneratedCredentialsResponseBase<
|
||||
SecretRotation.MsSqlCredentials,
|
||||
TSqlCredentialsRotationGeneratedCredentials
|
||||
>;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { SecretRotation } from "@app/hooks/api/secretRotationsV2";
|
||||
import {
|
||||
TSecretRotationV2Base,
|
||||
TSecretRotationV2GeneratedCredentialsResponseBase,
|
||||
TSqlCredentialsRotationGeneratedCredentials,
|
||||
TSqlCredentialsRotationProperties
|
||||
} from "@app/hooks/api/secretRotationsV2/types/shared";
|
||||
|
||||
export type TPostgresCredentialsRotation = TSecretRotationV2Base & {
|
||||
type: SecretRotation.PostgresCredentials;
|
||||
} & TSqlCredentialsRotationProperties;
|
||||
|
||||
export type TPostgresCredentialsRotationGeneratedCredentialsResponse =
|
||||
TSecretRotationV2GeneratedCredentialsResponseBase<
|
||||
SecretRotation.PostgresCredentials,
|
||||
TSqlCredentialsRotationGeneratedCredentials
|
||||
>;
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./secret-rotation-base";
|
||||
export * from "./sql-credentials-rotation";
|
||||
@@ -0,0 +1,53 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { SecretRotationStatus } from "@app/hooks/api/secretRotationsV2";
|
||||
|
||||
export type TSecretRotationV2Base = {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
folderId: string;
|
||||
connectionId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
rotationInterval: number;
|
||||
rotateAtUtc: {
|
||||
hours: number;
|
||||
minutes: number;
|
||||
};
|
||||
projectId: string;
|
||||
rotationStatus: SecretRotationStatus | null;
|
||||
lastRotationJobId: string | null;
|
||||
lastRotatedAt: string;
|
||||
lastRotationAttemptedAt: string;
|
||||
lastRotationMessage?: string | null;
|
||||
connection: {
|
||||
app: AppConnection;
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
environment: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
folder: {
|
||||
id: string;
|
||||
path: string;
|
||||
};
|
||||
} & (
|
||||
| {
|
||||
nextRotationAt: string;
|
||||
isAutoRotationEnabled: true;
|
||||
}
|
||||
| {
|
||||
nextRotationAt?: null;
|
||||
isAutoRotationEnabled: false;
|
||||
}
|
||||
);
|
||||
|
||||
export type TSecretRotationV2GeneratedCredentialsResponseBase<U, T> = {
|
||||
activeIndex: 0 | 1;
|
||||
generatedCredentials: [T, T | undefined];
|
||||
type: U;
|
||||
rotationId: string;
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
export type TSqlCredentialsRotationProperties = {
|
||||
parameters: {
|
||||
username1: string;
|
||||
username2: string;
|
||||
};
|
||||
secretsMapping: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type TSqlOptionTemplate = {
|
||||
secretsMapping: TSqlCredentialsRotationProperties["secretsMapping"];
|
||||
createUserStatement: string;
|
||||
};
|
||||
|
||||
export type TSqlCredentialsRotationGeneratedCredentials = {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
Reference in New Issue
Block a user