feat: gcp secret sync management

This commit is contained in:
Sheen Capadngan
2025-01-25 03:01:10 +08:00
parent 58f51411c0
commit 753c28a2d3
34 changed files with 467 additions and 22 deletions

View File

@@ -1,13 +1,18 @@
import z from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateGcpConnectionSchema,
SanitizedGcpConnectionSchema,
UpdateGcpConnectionSchema
} from "@app/services/app-connection/gcp";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerGcpConnectionRouter = async (server: FastifyZodProvider) =>
export const registerGcpConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.GCP,
server,
@@ -15,3 +20,29 @@ export const registerGcpConnectionRouter = async (server: FastifyZodProvider) =>
createSchema: CreateGcpConnectionSchema,
updateSchema: UpdateGcpConnectionSchema
});
// The below endpoints are not exposed and for Infisical App use
server.route({
method: "GET",
url: `/:connectionId/secret-manager-projects`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z.object({ id: z.string(), name: z.string() }).array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const projects = await server.services.appConnection.gcp.listSecretManagerProjects(connectionId, req.permission);
return projects;
}
});
};

View File

@@ -0,0 +1,13 @@
import { CreateGcpSyncSchema, GcpSyncSchema, UpdateGcpSyncSchema } from "@app/services/secret-sync/gcp";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerGcpSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.GCP,
server,
responseSchema: GcpSyncSchema,
createSchema: CreateGcpSyncSchema,
updateSchema: UpdateGcpSyncSchema
});

View File

@@ -1,11 +1,13 @@
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerAwsParameterStoreSyncRouter } from "./aws-parameter-store-sync-router";
import { registerGcpSyncRouter } from "./gcp-sync-router";
import { registerGitHubSyncRouter } from "./github-sync-router";
export * from "./secret-sync-router";
export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: FastifyZodProvider) => Promise<void>> = {
[SecretSync.AWSParameterStore]: registerAwsParameterStoreSyncRouter,
[SecretSync.GitHub]: registerGitHubSyncRouter
[SecretSync.GitHub]: registerGitHubSyncRouter,
[SecretSync.GCP]: registerGcpSyncRouter
};

View File

@@ -9,13 +9,19 @@ import {
AwsParameterStoreSyncListItemSchema,
AwsParameterStoreSyncSchema
} from "@app/services/secret-sync/aws-parameter-store";
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
const SecretSyncSchema = z.discriminatedUnion("destination", [AwsParameterStoreSyncSchema, GitHubSyncSchema]);
const SecretSyncSchema = z.discriminatedUnion("destination", [
AwsParameterStoreSyncSchema,
GitHubSyncSchema,
GcpSyncSchema
]);
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
AwsParameterStoreSyncListItemSchema,
GitHubSyncListItemSchema
GitHubSyncListItemSchema,
GcpSyncListItemSchema
]);
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {

View File

@@ -2,5 +2,6 @@ import { AppConnection } from "./app-connection-enums";
export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
[AppConnection.AWS]: "AWS",
[AppConnection.GitHub]: "GitHub"
[AppConnection.GitHub]: "GitHub",
[AppConnection.GCP]: "GCP"
};

View File

@@ -27,6 +27,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TAppConnectionDALFactory } from "./app-connection-dal";
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
import { gcpConnectionService } from "./gcp/gcp-connection-service";
export type TAppConnectionServiceFactoryDep = {
appConnectionDAL: TAppConnectionDALFactory;
@@ -384,6 +385,7 @@ export const appConnectionServiceFactory = ({
deleteAppConnection,
connectAppConnectionById,
listAvailableAppConnectionsForUser,
github: githubConnectionService(connectAppConnectionById)
github: githubConnectionService(connectAppConnectionById),
gcp: gcpConnectionService(connectAppConnectionById)
};
};

View File

@@ -2,12 +2,20 @@ import { gaxios, Impersonated, JWT } from "google-auth-library";
import { GetAccessTokenResponse } from "google-auth-library/build/src/auth/oauth2client";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { BadRequestError, InternalServerError } from "@app/lib/errors";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
import { AppConnection } from "../app-connection-enums";
import { getAppConnectionMethodName } from "../app-connection-fns";
import { GcpConnectionMethod } from "./gcp-connection-enums";
import { TGcpConnectionConfig } from "./gcp-connection-types";
import {
GCPApp,
GCPGetProjectsRes,
GCPGetServiceRes,
TGcpConnection,
TGcpConnectionConfig
} from "./gcp-connection-types";
export const getGcpAppConnectionListItem = () => {
return {
@@ -17,9 +25,8 @@ export const getGcpAppConnectionListItem = () => {
};
};
export const validateGcpConnectionCredentials = async (appConnection: TGcpConnectionConfig) => {
export const getAuthToken = async (appConnection: TGcpConnectionConfig) => {
const appCfg = getConfig();
if (!appCfg.INF_APP_CONNECTION_GCP_SERVICE_ACCOUNT_CREDENTIAL) {
throw new InternalServerError({
message: `Environment variables have not been configured for GCP ${getAppConnectionMethodName(
@@ -67,5 +74,79 @@ export const validateGcpConnectionCredentials = async (appConnection: TGcpConnec
});
}
return tokenResponse.token;
};
export const getGcpSecretManagerProjects = async (appConnection: TGcpConnection) => {
const accessToken = await getAuthToken(appConnection);
let gcpApps: GCPApp[] = [];
const pageSize = 100;
let pageToken: string | undefined;
let hasMorePages = true;
const projects: {
name: string;
id: string;
}[] = [];
while (hasMorePages) {
const params = new URLSearchParams({
pageSize: String(pageSize),
...(pageToken ? { pageToken } : {})
});
// eslint-disable-next-line no-await-in-loop
const { data } = await request.get<GCPGetProjectsRes>(`${IntegrationUrls.GCP_API_URL}/v1/projects`, {
params,
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
});
gcpApps = gcpApps.concat(data.projects);
if (!data.nextPageToken) {
hasMorePages = false;
}
pageToken = data.nextPageToken;
}
// eslint-disable-next-line
for await (const gcpApp of gcpApps) {
try {
const res = (
await request.get<GCPGetServiceRes>(
`${IntegrationUrls.GCP_SERVICE_USAGE_URL}/v1/projects/${gcpApp.projectId}/services/${IntegrationUrls.GCP_SECRET_MANAGER_SERVICE_NAME}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
)
).data;
if (res.state === "ENABLED") {
projects.push({
name: gcpApp.name,
id: gcpApp.projectId
});
}
} catch {
// eslint-disable-next-line
continue;
}
}
return projects;
};
export const validateGcpConnectionCredentials = async (appConnection: TGcpConnectionConfig) => {
await getAuthToken(appConnection);
return appConnection.credentials;
};

View File

@@ -0,0 +1,29 @@
import { OrgServiceActor } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums";
import { getGcpSecretManagerProjects } from "./gcp-connection-fns";
import { TGcpConnection } from "./gcp-connection-types";
type TGetAppConnectionFunc = (
app: AppConnection,
connectionId: string,
actor: OrgServiceActor
) => Promise<TGcpConnection>;
export const gcpConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
const listSecretManagerProjects = async (connectionId: string, actor: OrgServiceActor) => {
const appConnection = await getAppConnection(AppConnection.GCP, connectionId, actor);
try {
const projects = await getGcpSecretManagerProjects(appConnection);
return projects;
} catch (error) {
return [];
}
};
return {
listSecretManagerProjects
};
};

View File

@@ -20,3 +20,26 @@ export type TValidateGcpConnectionCredentials = typeof ValidateGcpConnectionCred
export type TGcpConnectionConfig = DiscriminativePick<TGcpConnectionInput, "method" | "app" | "credentials"> & {
orgId: string;
};
export interface GCPApp {
projectNumber: string;
projectId: string;
lifecycleState: "ACTIVE" | "LIFECYCLE_STATE_UNSPECIFIED" | "DELETE_REQUESTED" | "DELETE_IN_PROGRESS";
name: string;
createTime: string;
parent: {
type: "organization" | "folder" | "project";
id: string;
};
}
export interface GCPGetProjectsRes {
projects: GCPApp[];
nextPageToken?: string;
}
export interface GCPGetServiceRes {
name: string;
parent: string;
state: "ENABLED" | "DISABLED" | "STATE_UNSPECIFIED";
}

View File

@@ -0,0 +1,10 @@
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { TSecretSyncListItem } from "@app/services/secret-sync/secret-sync-types";
export const GCP_SYNC_LIST_OPTION: TSecretSyncListItem = {
name: "GCP",
destination: SecretSync.GCP,
connection: AppConnection.GCP,
canImportSecrets: false
};

View File

@@ -0,0 +1,37 @@
import z from "zod";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
BaseSecretSyncSchema,
GenericCreateSecretSyncFieldsSchema,
GenericUpdateSecretSyncFieldsSchema
} from "@app/services/secret-sync/secret-sync-schemas";
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
import { SecretSync } from "../secret-sync-enums";
const GcpSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: false };
const GcpSyncDestinationConfigSchema = z.object({
projectId: z.string().min(1, "Project ID is required")
});
export const GcpSyncSchema = BaseSecretSyncSchema(SecretSync.GCP, GcpSyncOptionsConfig).extend({
destination: z.literal(SecretSync.GCP),
destinationConfig: GcpSyncDestinationConfigSchema
});
export const CreateGcpSyncSchema = GenericCreateSecretSyncFieldsSchema(SecretSync.GCP, GcpSyncOptionsConfig).extend({
destinationConfig: GcpSyncDestinationConfigSchema
});
export const UpdateGcpSyncSchema = GenericUpdateSecretSyncFieldsSchema(SecretSync.GCP, GcpSyncOptionsConfig).extend({
destinationConfig: GcpSyncDestinationConfigSchema.optional()
});
export const GcpSyncListItemSchema = z.object({
name: z.literal("GCP"),
connection: z.literal(AppConnection.GCP),
destination: z.literal(SecretSync.GCP),
canImportSecrets: z.literal(false)
});

View File

@@ -0,0 +1,15 @@
import z from "zod";
import { TGcpConnection } from "@app/services/app-connection/gcp";
import { CreateGcpSyncSchema, GcpSyncListItemSchema, GcpSyncSchema } from "./gcp-sync-schemas";
export type TGcpSyncListItem = z.infer<typeof GcpSyncListItemSchema>;
export type TGcpSync = z.infer<typeof GcpSyncSchema>;
export type TGcpSyncInput = z.infer<typeof CreateGcpSyncSchema>;
export type TGcpSyncWithCredentials = TGcpSync & {
connection: TGcpConnection;
};

View File

@@ -0,0 +1,3 @@
export * from "./gcp-sync-constants";
export * from "./gcp-sync-schemas";
export * from "./gcp-sync-types";

View File

@@ -1,6 +1,7 @@
export enum SecretSync {
AWSParameterStore = "aws-parameter-store",
GitHub = "github"
GitHub = "github",
GCP = "gcp"
}
export enum SecretSyncInitialSyncBehavior {

View File

@@ -13,9 +13,12 @@ import {
TSecretSyncWithCredentials
} from "@app/services/secret-sync/secret-sync-types";
import { GCP_SYNC_LIST_OPTION } from "./gcp";
const SECRET_SYNC_LIST_OPTIONS: Record<SecretSync, TSecretSyncListItem> = {
[SecretSync.AWSParameterStore]: AWS_PARAMETER_STORE_SYNC_LIST_OPTION,
[SecretSync.GitHub]: GITHUB_SYNC_LIST_OPTION
[SecretSync.GitHub]: GITHUB_SYNC_LIST_OPTION,
[SecretSync.GCP]: GCP_SYNC_LIST_OPTION
};
export const listSecretSyncOptions = () => {

View File

@@ -3,10 +3,12 @@ import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
[SecretSync.AWSParameterStore]: "AWS Parameter Store",
[SecretSync.GitHub]: "GitHub"
[SecretSync.GitHub]: "GitHub",
[SecretSync.GCP]: "GCP Secret Manager"
};
export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.AWSParameterStore]: AppConnection.AWS,
[SecretSync.GitHub]: AppConnection.GitHub
[SecretSync.GitHub]: AppConnection.GitHub,
[SecretSync.GCP]: AppConnection.GCP
};

View File

@@ -17,14 +17,18 @@ import {
TAwsParameterStoreSyncListItem,
TAwsParameterStoreSyncWithCredentials
} from "./aws-parameter-store";
import { TGcpSync, TGcpSyncInput, TGcpSyncListItem, TGcpSyncWithCredentials } from "./gcp";
export type TSecretSync = TAwsParameterStoreSync | TGitHubSync;
export type TSecretSync = TAwsParameterStoreSync | TGitHubSync | TGcpSync;
export type TSecretSyncWithCredentials = TAwsParameterStoreSyncWithCredentials | TGitHubSyncWithCredentials;
export type TSecretSyncWithCredentials =
| TAwsParameterStoreSyncWithCredentials
| TGitHubSyncWithCredentials
| TGcpSyncWithCredentials;
export type TSecretSyncInput = TAwsParameterStoreSyncInput | TGitHubSyncInput;
export type TSecretSyncInput = TAwsParameterStoreSyncInput | TGitHubSyncInput | TGcpSyncInput;
export type TSecretSyncListItem = TAwsParameterStoreSyncListItem | TGitHubSyncListItem;
export type TSecretSyncListItem = TAwsParameterStoreSyncListItem | TGitHubSyncListItem | TGcpSyncListItem;
export type TSyncOptionsConfig = {
canImportSecrets: boolean;

View File

@@ -0,0 +1,51 @@
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { SingleValue } from "react-select";
import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField";
import { FilterableSelect, FormControl } from "@app/components/v2";
import { useGcpConnectionListProjects } from "@app/hooks/api/appConnections/gcp/queries";
import { TGitHubConnectionEnvironment } from "@app/hooks/api/appConnections/github";
import { SecretSync } from "@app/hooks/api/secretSyncs";
import { TSecretSyncForm } from "../schemas";
export const GcpSyncFields = () => {
const { control, setValue } = useFormContext<TSecretSyncForm & { destination: SecretSync.GCP }>();
const connectionId = useWatch({ name: "connection.id", control });
const { data: projects, isPending } = useGcpConnectionListProjects(connectionId, {
enabled: Boolean(connectionId)
});
return (
<>
<SecretSyncConnectionField
onChange={() => {
setValue("destinationConfig.projectId", "");
}}
/>
<Controller
name="destinationConfig.projectId"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message} label="Project">
<FilterableSelect
menuPlacement="top"
isLoading={isPending && Boolean(connectionId)}
isDisabled={!connectionId}
value={projects?.find((project) => project.id === value) ?? null}
onChange={(option) =>
onChange((option as SingleValue<TGitHubConnectionEnvironment>)?.id ?? null)
}
options={projects}
placeholder="Select a GCP project..."
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id.toString()}
/>
</FormControl>
)}
/>
</>
);
};

View File

@@ -4,6 +4,7 @@ import { SecretSync } from "@app/hooks/api/secretSyncs";
import { TSecretSyncForm } from "../schemas";
import { AwsParameterStoreSyncFields } from "./AwsParameterStoreSyncFields";
import { GcpSyncFields } from "./GcpSyncFields";
import { GitHubSyncFields } from "./GitHubSyncFields";
export const SecretSyncDestinationFields = () => {
@@ -16,6 +17,8 @@ export const SecretSyncDestinationFields = () => {
return <AwsParameterStoreSyncFields />;
case SecretSync.GitHub:
return <GitHubSyncFields />;
case SecretSync.GCP:
return <GcpSyncFields />;
default:
throw new Error(`Unhandled Destination Config Field: ${destination}`);
}

View File

@@ -0,0 +1,12 @@
import { useFormContext } from "react-hook-form";
import { SecretSyncLabel } from "@app/components/secret-syncs";
import { TSecretSyncForm } from "@app/components/secret-syncs/forms/schemas";
import { SecretSync } from "@app/hooks/api/secretSyncs";
export const GcpSyncReviewFields = () => {
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.GCP }>();
const projectId = watch("destinationConfig.projectId");
return <SecretSyncLabel label="Project ID">{projectId}</SecretSyncLabel>;
};

View File

@@ -8,6 +8,7 @@ import { SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP, SECRET_SYNC_MAP } from "@app/hel
import { SecretSync } from "@app/hooks/api/secretSyncs";
import { AwsParameterStoreSyncReviewFields } from "./AwsParameterStoreSyncReviewFields";
import { GcpSyncReviewFields } from "./GcpSyncReviewFIelds";
import { GitHubSyncReviewFields } from "./GitHubSyncReviewFields";
export const SecretSyncReviewFields = () => {
@@ -38,6 +39,9 @@ export const SecretSyncReviewFields = () => {
case SecretSync.GitHub:
DestinationFieldsComponent = <GitHubSyncReviewFields />;
break;
case SecretSync.GCP:
DestinationFieldsComponent = <GcpSyncReviewFields />;
break;
default:
throw new Error(`Unhandled Destination Review Fields: ${destination}`);
}

View File

@@ -0,0 +1,10 @@
import { z } from "zod";
import { SecretSync } from "@app/hooks/api/secretSyncs";
export const GcpSyncDestinationSchema = z.object({
destination: z.literal(SecretSync.GCP),
destinationConfig: z.object({
projectId: z.string().min(1, "Project ID required")
})
});

View File

@@ -5,6 +5,7 @@ import { SecretSyncInitialSyncBehavior } from "@app/hooks/api/secretSyncs";
import { slugSchema } from "@app/lib/schemas";
import { AwsParameterStoreSyncDestinationSchema } from "./aws-parameter-store-sync-destination-schema";
import { GcpSyncDestinationSchema } from "./gcp-sync-destination-schema";
const BaseSecretSyncSchema = z.object({
name: slugSchema({ field: "Name" }),
@@ -31,7 +32,8 @@ const BaseSecretSyncSchema = z.object({
const SecretSyncUnionSchema = z.discriminatedUnion("destination", [
AwsParameterStoreSyncDestinationSchema,
GitHubSyncDestinationSchema
GitHubSyncDestinationSchema,
GcpSyncDestinationSchema
]);
export const SecretSyncFormSchema = SecretSyncUnionSchema.and(BaseSecretSyncSchema);

View File

@@ -7,12 +7,14 @@ import {
export const SECRET_SYNC_MAP: Record<SecretSync, { name: string; image: string }> = {
[SecretSync.AWSParameterStore]: { name: "Parameter Store", image: "Amazon Web Services.png" },
[SecretSync.GitHub]: { name: "GitHub", image: "GitHub.png" }
[SecretSync.GitHub]: { name: "GitHub", image: "GitHub.png" },
[SecretSync.GCP]: { name: "GCP Secret Manager", image: "Google Cloud Platform.png" }
};
export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.AWSParameterStore]: AppConnection.AWS,
[SecretSync.GitHub]: AppConnection.GitHub
[SecretSync.GitHub]: AppConnection.GitHub,
[SecretSync.GCP]: AppConnection.GCP
};
export const SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP: Record<

View File

@@ -0,0 +1,37 @@
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { appConnectionKeys } from "../queries";
import { TGcpProject } from "./types";
const gcpConnectionKeys = {
all: [...appConnectionKeys.all, "gcp"] as const,
listProjects: (connectionId: string) =>
[...gcpConnectionKeys.all, "projects", connectionId] as const
};
export const useGcpConnectionListProjects = (
connectionId: string,
options?: Omit<
UseQueryOptions<
TGcpProject[],
unknown,
TGcpProject[],
ReturnType<typeof gcpConnectionKeys.listProjects>
>,
"queryKey" | "queryFn"
>
) => {
return useQuery({
queryKey: gcpConnectionKeys.listProjects(connectionId),
queryFn: async () => {
const { data } = await apiRequest.get<TGcpProject[]>(
`/api/v1/app-connections/gcp/${connectionId}/secret-manager-projects`
);
return data;
},
...options
});
};

View File

@@ -0,0 +1,4 @@
export type TGcpProject = {
id: string;
name: string;
};

View File

@@ -1,6 +1,7 @@
export enum SecretSync {
AWSParameterStore = "aws-parameter-store",
GitHub = "github"
GitHub = "github",
GCP = "gcp"
}
export enum SecretSyncStatus {

View File

@@ -0,0 +1,15 @@
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 TGcpSync = TRootSecretSync & {
destination: SecretSync.GCP;
destinationConfig: {
projectId: string;
};
connection: {
app: AppConnection.GCP;
name: string;
id: string;
};
};

View File

@@ -3,13 +3,15 @@ import { TAwsParameterStoreSync } from "@app/hooks/api/secretSyncs/types/aws-par
import { TGitHubSync } from "@app/hooks/api/secretSyncs/types/github-sync";
import { DiscriminativePick } from "@app/types";
import { TGcpSync } from "./gcp-sync";
export type TSecretSyncOption = {
name: string;
destination: SecretSync;
canImportSecrets: boolean;
};
export type TSecretSync = TAwsParameterStoreSync | TGitHubSync;
export type TSecretSync = TAwsParameterStoreSync | TGitHubSync | TGcpSync;
export type TListSecretSyncs = { secretSyncs: TSecretSync[] };

View File

@@ -0,0 +1,14 @@
import { TGcpSync } from "@app/hooks/api/secretSyncs/types/gcp-sync";
import { getSecretSyncDestinationColValues } from "../helpers";
import { SecretSyncTableCell } from "../SecretSyncTableCell";
type Props = {
secretSync: TGcpSync;
};
export const GcpSyncDestinationCol = ({ secretSync }: Props) => {
const { primaryText, secondaryText } = getSecretSyncDestinationColValues(secretSync);
return <SecretSyncTableCell primaryText={primaryText} secondaryText={secondaryText} />;
};

View File

@@ -1,6 +1,7 @@
import { SecretSync, TSecretSync } from "@app/hooks/api/secretSyncs";
import { AwsParameterStoreSyncDestinationCol } from "./AwsParameterStoreSyncDestinationCol";
import { GcpSyncDestinationCol } from "./GcpSyncDestinationCol";
import { GitHubSyncDestinationCol } from "./GitHubSyncDestinationCol";
type Props = {
@@ -13,6 +14,8 @@ export const SecretSyncDestinationCol = ({ secretSync }: Props) => {
return <AwsParameterStoreSyncDestinationCol secretSync={secretSync} />;
case SecretSync.GitHub:
return <GitHubSyncDestinationCol secretSync={secretSync} />;
case SecretSync.GCP:
return <GcpSyncDestinationCol secretSync={secretSync} />;
default:
throw new Error(
`Unhandled Secret Sync Destination Col: ${(secretSync as TSecretSync).destination}`

View File

@@ -39,6 +39,9 @@ export const getSecretSyncDestinationColValues = (secretSync: TSecretSync) => {
throw new Error(`Unhandled GitHub Scope Destination Col Values ${destination}`);
}
break;
case SecretSync.GCP:
primaryText = destinationConfig.projectId;
break;
default:
throw new Error(`Unhandled Destination Col Values ${destination}`);
}

View File

@@ -0,0 +1,14 @@
import { SecretSyncLabel } from "@app/components/secret-syncs";
import { TGcpSync } from "@app/hooks/api/secretSyncs/types/gcp-sync";
type Props = {
secretSync: TGcpSync;
};
export const GcpSyncDestinationSection = ({ secretSync }: Props) => {
const {
destinationConfig: { projectId }
} = secretSync;
return <SecretSyncLabel label="Project ID">{projectId}</SecretSyncLabel>;
};

View File

@@ -12,6 +12,8 @@ import { SecretSync, TSecretSync } from "@app/hooks/api/secretSyncs";
import { AwsParameterStoreSyncDestinationSection } from "@app/pages/secret-manager/SecretSyncDetailsByIDPage/components/SecretSyncDestinationSection/AwsParameterStoreSyncDestinationSection";
import { GitHubSyncDestinationSection } from "@app/pages/secret-manager/SecretSyncDetailsByIDPage/components/SecretSyncDestinationSection/GitHubSyncDestinationSection";
import { GcpSyncDestinationSection } from "./GcpSyncDestinationSection";
type Props = {
secretSync: TSecretSync;
onEditDestination: VoidFunction;
@@ -30,6 +32,9 @@ export const SecretSyncDestinationSection = ({ secretSync, onEditDestination }:
case SecretSync.GitHub:
DestinationComponents = <GitHubSyncDestinationSection secretSync={secretSync} />;
break;
case SecretSync.GCP:
DestinationComponents = <GcpSyncDestinationSection secretSync={secretSync} />;
break;
default:
throw new Error(`Unhandled Destination Section components: ${destination}`);
}