mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 15:31:19 +00:00
feature: secret sync base + aws parameter store & github
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
export enum SecretSync {
|
||||
AWSParameterStore = "aws-parameter-store",
|
||||
GitHub = "github"
|
||||
}
|
||||
|
||||
export enum SecretSyncStatus {
|
||||
Pending = "pending",
|
||||
Running = "running",
|
||||
Succeeded = "succeeded",
|
||||
Failed = "failed"
|
||||
}
|
||||
|
||||
export enum SecretSyncInitialSyncBehavior {
|
||||
OverwriteDestination = "overwrite-destination",
|
||||
ImportPrioritizeSource = "import-prioritize-source",
|
||||
ImportPrioritizeDestination = "import-prioritize-destination"
|
||||
}
|
||||
|
||||
export enum SecretSyncImportBehavior {
|
||||
PrioritizeSource = "prioritize-source",
|
||||
PrioritizeDestination = "prioritize-destination"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./enums";
|
||||
export * from "./mutations";
|
||||
export * from "./queries";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,116 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { secretSyncKeys } from "@app/hooks/api/secretSyncs/queries";
|
||||
import {
|
||||
TCreateSecretSyncDTO,
|
||||
TDeleteSecretSyncDTO,
|
||||
TSecretSyncResponse,
|
||||
TTriggerSecretSyncImportSecretsDTO,
|
||||
TTriggerSecretSyncRemoveSecretsDTO,
|
||||
TTriggerSecretSyncSyncSecretsDTO,
|
||||
TUpdateSecretSyncDTO
|
||||
} from "@app/hooks/api/secretSyncs/types";
|
||||
|
||||
export const useCreateSecretSync = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ destination, ...params }: TCreateSecretSyncDTO) => {
|
||||
const { data } = await apiRequest.post<TSecretSyncResponse>(
|
||||
`/api/v1/secret-syncs/${destination}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.secretSync;
|
||||
},
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: secretSyncKeys.list() })
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateSecretSync = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, destination, ...params }: TUpdateSecretSyncDTO) => {
|
||||
const { data } = await apiRequest.patch<TSecretSyncResponse>(
|
||||
`/api/v1/secret-syncs/${destination}/${syncId}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data.secretSync;
|
||||
},
|
||||
onSuccess: (_, { syncId, destination }) => {
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.list() });
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.byId(destination, syncId) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteSecretSync = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, destination }: TDeleteSecretSyncDTO) => {
|
||||
const { data } = await apiRequest.delete(`/api/v1/secret-syncs/${destination}/${syncId}`);
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { syncId, destination }) => {
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.list() });
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.byId(destination, syncId) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useTriggerSecretSyncSyncSecrets = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, destination }: TTriggerSecretSyncSyncSecretsDTO) => {
|
||||
const { data } = await apiRequest.post(
|
||||
`/api/v1/secret-syncs/${destination}/${syncId}/sync-secrets`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { syncId, destination }) => {
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.list() });
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.byId(destination, syncId) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useTriggerSecretSyncImportSecrets = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
syncId,
|
||||
destination,
|
||||
importBehavior
|
||||
}: TTriggerSecretSyncImportSecretsDTO) => {
|
||||
const { data } = await apiRequest.post(
|
||||
`/api/v1/secret-syncs/${destination}/${syncId}/import-secrets?importBehavior=${importBehavior}`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { syncId, destination }) => {
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.list() });
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.byId(destination, syncId) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useTriggerSecretSyncRemoveSecrets = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, destination }: TTriggerSecretSyncRemoveSecretsDTO) => {
|
||||
const { data } = await apiRequest.post(
|
||||
`/api/v1/secret-syncs/${destination}/${syncId}/remove-secrets`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { syncId, destination }) => {
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.list() });
|
||||
queryClient.invalidateQueries({ queryKey: secretSyncKeys.byId(destination, syncId) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { SecretSync, TSecretSyncOption } from "@app/hooks/api/secretSyncs";
|
||||
import {
|
||||
TListSecretSyncOptions,
|
||||
TListSecretSyncs,
|
||||
TSecretSync,
|
||||
TSecretSyncResponse
|
||||
} from "@app/hooks/api/secretSyncs/types";
|
||||
|
||||
export const secretSyncKeys = {
|
||||
all: ["secret-sync"] as const,
|
||||
options: () => [...secretSyncKeys.all, "options"] as const,
|
||||
list: () => [...secretSyncKeys.all, "list"] as const,
|
||||
byId: (destination: SecretSync, syncId: string) =>
|
||||
[...secretSyncKeys.all, destination, "by-id", syncId] as const
|
||||
};
|
||||
|
||||
export const useSecretSyncOptions = (
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TSecretSyncOption[],
|
||||
unknown,
|
||||
TSecretSyncOption[],
|
||||
ReturnType<typeof secretSyncKeys.options>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretSyncKeys.options(),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretSyncOptions>("/api/v1/secret-syncs/options");
|
||||
|
||||
return data.secretSyncOptions;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useSecretSyncOption = (destination: SecretSync) => {
|
||||
const { data: syncOptions, isPending } = useSecretSyncOptions();
|
||||
const syncOption = syncOptions?.find((option) => option.destination === destination);
|
||||
|
||||
return { syncOption, isPending };
|
||||
};
|
||||
|
||||
export const useListSecretSyncs = (
|
||||
projectId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<TSecretSync[], unknown, TSecretSync[], ReturnType<typeof secretSyncKeys.list>>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretSyncKeys.list(),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListSecretSyncs>("/api/v1/secret-syncs", {
|
||||
params: { projectId }
|
||||
});
|
||||
|
||||
return data.secretSyncs;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetSecretSync = (
|
||||
destination: SecretSync,
|
||||
syncId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<TSecretSync, unknown, TSecretSync, ReturnType<typeof secretSyncKeys.byId>>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: secretSyncKeys.byId(destination, syncId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TSecretSyncResponse>(
|
||||
`/api/v1/secret-syncs/${destination}/${syncId}`
|
||||
);
|
||||
|
||||
return data.secretSync;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||
import { TRootSecretSync } from "@app/hooks/api/secretSyncs/types/root-sync";
|
||||
|
||||
export type TAwsParameterStoreSync = TRootSecretSync & {
|
||||
destination: SecretSync.AWSParameterStore;
|
||||
destinationConfig: {
|
||||
path: string;
|
||||
region: string;
|
||||
};
|
||||
connection: {
|
||||
app: AppConnection.AWS;
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||
import { TRootSecretSync } from "@app/hooks/api/secretSyncs/types/root-sync";
|
||||
|
||||
export enum GitHubSyncScope {
|
||||
Organization = "organization",
|
||||
Repository = "repository",
|
||||
RepositoryEnvironment = "repository-environment"
|
||||
}
|
||||
|
||||
export enum GitHubSyncVisibility {
|
||||
All = "all",
|
||||
Private = "private",
|
||||
Selected = "selected"
|
||||
}
|
||||
|
||||
export type TGitHubSync = TRootSecretSync & {
|
||||
destination: SecretSync.GitHub;
|
||||
destinationConfig:
|
||||
| {
|
||||
scope: GitHubSyncScope.Organization;
|
||||
org: string;
|
||||
visibility: GitHubSyncVisibility;
|
||||
selectedRepositoryIds?: number[];
|
||||
}
|
||||
| {
|
||||
scope: GitHubSyncScope.Repository;
|
||||
owner: string;
|
||||
repo: string;
|
||||
}
|
||||
| {
|
||||
scope: GitHubSyncScope.RepositoryEnvironment;
|
||||
owner: string;
|
||||
repo: string;
|
||||
env: string;
|
||||
};
|
||||
connection: {
|
||||
app: AppConnection.GitHub;
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
import { SecretSync, SecretSyncImportBehavior } from "@app/hooks/api/secretSyncs";
|
||||
import { TAwsParameterStoreSync } from "@app/hooks/api/secretSyncs/types/aws-parameter-store-sync";
|
||||
import { TGitHubSync } from "@app/hooks/api/secretSyncs/types/github-sync";
|
||||
import { DiscriminativePick } from "@app/types";
|
||||
|
||||
export type TSecretSyncOption = {
|
||||
name: string;
|
||||
destination: SecretSync;
|
||||
canImportSecrets: boolean;
|
||||
};
|
||||
|
||||
export type TSecretSync = TAwsParameterStoreSync | TGitHubSync;
|
||||
|
||||
export type TListSecretSyncs = { secretSyncs: TSecretSync[] };
|
||||
|
||||
export type TListSecretSyncOptions = { secretSyncOptions: TSecretSyncOption[] };
|
||||
export type TSecretSyncResponse = { secretSync: TSecretSync };
|
||||
|
||||
export type TCreateSecretSyncDTO = DiscriminativePick<
|
||||
TSecretSync,
|
||||
| "name"
|
||||
| "destinationConfig"
|
||||
| "description"
|
||||
| "connectionId"
|
||||
| "syncOptions"
|
||||
| "destination"
|
||||
| "isEnabled"
|
||||
> & { environment: string; secretPath: string; projectId: string };
|
||||
|
||||
export type TUpdateSecretSyncDTO = Partial<
|
||||
Omit<TCreateSecretSyncDTO, "connectionId" | "destination" | "projectId">
|
||||
> & {
|
||||
destination: SecretSync;
|
||||
syncId: string;
|
||||
};
|
||||
|
||||
export type TDeleteSecretSyncDTO = {
|
||||
destination: SecretSync;
|
||||
syncId: string;
|
||||
};
|
||||
|
||||
export type TTriggerSecretSyncSyncSecretsDTO = {
|
||||
destination: SecretSync;
|
||||
syncId: string;
|
||||
};
|
||||
|
||||
export type TTriggerSecretSyncImportSecretsDTO = {
|
||||
destination: SecretSync;
|
||||
syncId: string;
|
||||
importBehavior: SecretSyncImportBehavior;
|
||||
};
|
||||
|
||||
export type TTriggerSecretSyncRemoveSecretsDTO = {
|
||||
destination: SecretSync;
|
||||
syncId: string;
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { SecretSyncInitialSyncBehavior, SecretSyncStatus } from "@app/hooks/api/secretSyncs";
|
||||
|
||||
export type TRootSecretSync = {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
version: number;
|
||||
folderId: string;
|
||||
connectionId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
isEnabled: boolean;
|
||||
projectId: string;
|
||||
syncStatus: SecretSyncStatus | null;
|
||||
lastSyncJobId: string | null;
|
||||
lastSyncedAt: Date | null;
|
||||
lastSyncMessage: string | null;
|
||||
importStatus: SecretSyncStatus | null;
|
||||
lastImportJobId: string | null;
|
||||
lastImportedAt: Date | null;
|
||||
lastImportMessage: string | null;
|
||||
removeStatus: SecretSyncStatus | null;
|
||||
lastRemoveJobId: string | null;
|
||||
lastRemovedAt: Date | null;
|
||||
lastRemoveMessage: string | null;
|
||||
syncOptions: {
|
||||
initialSyncBehavior: SecretSyncInitialSyncBehavior;
|
||||
prependPrefix?: string;
|
||||
appendSuffix?: string;
|
||||
};
|
||||
connection: {
|
||||
app: AppConnection;
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
environment: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
folder: {
|
||||
id: string;
|
||||
path: string;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user