mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-03 00:25:50 +00:00
feat(secrey-sync): Hashicorp Vault Secret Sync (and minor app connection fixes)
This commit is contained in:
@@ -2002,6 +2002,10 @@ export const SecretSyncs = {
|
|||||||
WINDMILL: {
|
WINDMILL: {
|
||||||
workspace: "The Windmill workspace to sync secrets to.",
|
workspace: "The Windmill workspace to sync secrets to.",
|
||||||
path: "The Windmill workspace path to sync secrets to."
|
path: "The Windmill workspace path to sync secrets to."
|
||||||
|
},
|
||||||
|
HC_VAULT: {
|
||||||
|
mount: "The Hashicorp Vault Secrets Engine Mount to sync secrets to.",
|
||||||
|
path: "The Hashicorp Vault path to sync secrets to."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import {
|
||||||
|
CreateHCVaultSyncSchema,
|
||||||
|
HCVaultSyncSchema,
|
||||||
|
UpdateHCVaultSyncSchema
|
||||||
|
} from "@app/services/secret-sync/hc-vault";
|
||||||
|
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||||
|
|
||||||
|
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
|
||||||
|
|
||||||
|
export const registerHCVaultSyncRouter = async (server: FastifyZodProvider) =>
|
||||||
|
registerSyncSecretsEndpoints({
|
||||||
|
destination: SecretSync.HCVault,
|
||||||
|
server,
|
||||||
|
responseSchema: HCVaultSyncSchema,
|
||||||
|
createSchema: CreateHCVaultSyncSchema,
|
||||||
|
updateSchema: UpdateHCVaultSyncSchema
|
||||||
|
});
|
||||||
@@ -8,6 +8,7 @@ import { registerCamundaSyncRouter } from "./camunda-sync-router";
|
|||||||
import { registerDatabricksSyncRouter } from "./databricks-sync-router";
|
import { registerDatabricksSyncRouter } from "./databricks-sync-router";
|
||||||
import { registerGcpSyncRouter } from "./gcp-sync-router";
|
import { registerGcpSyncRouter } from "./gcp-sync-router";
|
||||||
import { registerGitHubSyncRouter } from "./github-sync-router";
|
import { registerGitHubSyncRouter } from "./github-sync-router";
|
||||||
|
import { registerHCVaultSyncRouter } from "./hc-vault-sync-router";
|
||||||
import { registerHumanitecSyncRouter } from "./humanitec-sync-router";
|
import { registerHumanitecSyncRouter } from "./humanitec-sync-router";
|
||||||
import { registerTerraformCloudSyncRouter } from "./terraform-cloud-sync-router";
|
import { registerTerraformCloudSyncRouter } from "./terraform-cloud-sync-router";
|
||||||
import { registerVercelSyncRouter } from "./vercel-sync-router";
|
import { registerVercelSyncRouter } from "./vercel-sync-router";
|
||||||
@@ -27,5 +28,6 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
|
|||||||
[SecretSync.TerraformCloud]: registerTerraformCloudSyncRouter,
|
[SecretSync.TerraformCloud]: registerTerraformCloudSyncRouter,
|
||||||
[SecretSync.Camunda]: registerCamundaSyncRouter,
|
[SecretSync.Camunda]: registerCamundaSyncRouter,
|
||||||
[SecretSync.Vercel]: registerVercelSyncRouter,
|
[SecretSync.Vercel]: registerVercelSyncRouter,
|
||||||
[SecretSync.Windmill]: registerWindmillSyncRouter
|
[SecretSync.Windmill]: registerWindmillSyncRouter,
|
||||||
|
[SecretSync.HCVault]: registerHCVaultSyncRouter
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secr
|
|||||||
import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks";
|
import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks";
|
||||||
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
|
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
|
||||||
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
|
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
|
||||||
|
import { HCVaultSyncListItemSchema, HCVaultSyncSchema } from "@app/services/secret-sync/hc-vault";
|
||||||
import { HumanitecSyncListItemSchema, HumanitecSyncSchema } from "@app/services/secret-sync/humanitec";
|
import { HumanitecSyncListItemSchema, HumanitecSyncSchema } from "@app/services/secret-sync/humanitec";
|
||||||
import { TerraformCloudSyncListItemSchema, TerraformCloudSyncSchema } from "@app/services/secret-sync/terraform-cloud";
|
import { TerraformCloudSyncListItemSchema, TerraformCloudSyncSchema } from "@app/services/secret-sync/terraform-cloud";
|
||||||
import { VercelSyncListItemSchema, VercelSyncSchema } from "@app/services/secret-sync/vercel";
|
import { VercelSyncListItemSchema, VercelSyncSchema } from "@app/services/secret-sync/vercel";
|
||||||
@@ -39,7 +40,8 @@ const SecretSyncSchema = z.discriminatedUnion("destination", [
|
|||||||
TerraformCloudSyncSchema,
|
TerraformCloudSyncSchema,
|
||||||
CamundaSyncSchema,
|
CamundaSyncSchema,
|
||||||
VercelSyncSchema,
|
VercelSyncSchema,
|
||||||
WindmillSyncSchema
|
WindmillSyncSchema,
|
||||||
|
HCVaultSyncSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
|
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
|
||||||
@@ -54,7 +56,8 @@ const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
|
|||||||
TerraformCloudSyncListItemSchema,
|
TerraformCloudSyncListItemSchema,
|
||||||
CamundaSyncListItemSchema,
|
CamundaSyncListItemSchema,
|
||||||
VercelSyncListItemSchema,
|
VercelSyncListItemSchema,
|
||||||
WindmillSyncListItemSchema
|
WindmillSyncListItemSchema,
|
||||||
|
HCVaultSyncListItemSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {
|
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
|||||||
[AppConnection.MsSql]: "Microsoft SQL Server",
|
[AppConnection.MsSql]: "Microsoft SQL Server",
|
||||||
[AppConnection.Camunda]: "Camunda",
|
[AppConnection.Camunda]: "Camunda",
|
||||||
[AppConnection.Windmill]: "Windmill",
|
[AppConnection.Windmill]: "Windmill",
|
||||||
[AppConnection.Auth0]: "Auth0"
|
[AppConnection.Auth0]: "Auth0",
|
||||||
|
[AppConnection.HCVault]: "Hashicorp Vault"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -91,9 +91,9 @@ export const listHCVaultMounts = async (appConnection: THCVaultConnection) => {
|
|||||||
|
|
||||||
const mounts: string[] = [];
|
const mounts: string[] = [];
|
||||||
|
|
||||||
// Filter for "kv" type only
|
// Filter for "kv" version 2 type only
|
||||||
Object.entries(data.data).forEach(([path, mount]) => {
|
Object.entries(data.data).forEach(([path, mount]) => {
|
||||||
if (mount.type === "kv") {
|
if (mount.type === "kv" && mount.options?.version === "2") {
|
||||||
mounts.push(path);
|
mounts.push(path);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ export type THCVaultConnectionConfig = DiscriminativePick<THCVaultConnectionInpu
|
|||||||
export type THCVaultMountResponse = {
|
export type THCVaultMountResponse = {
|
||||||
data: {
|
data: {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
|
options: {
|
||||||
|
version?: string | null;
|
||||||
|
} | null;
|
||||||
type: string; // We're only interested in "kv" types
|
type: string; // We're only interested in "kv" types
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 HC_VAULT_SYNC_LIST_OPTION: TSecretSyncListItem = {
|
||||||
|
name: "Hashicorp Vault",
|
||||||
|
destination: SecretSync.HCVault,
|
||||||
|
connection: AppConnection.HCVault,
|
||||||
|
canImportSecrets: true
|
||||||
|
};
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import { request } from "@app/lib/config/request";
|
||||||
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
|
import { getHCVaultAccessToken } from "@app/services/app-connection/hc-vault";
|
||||||
|
import {
|
||||||
|
THCVaultListVariables,
|
||||||
|
THCVaultListVariablesResponse,
|
||||||
|
THCVaultSyncWithCredentials,
|
||||||
|
TPostHCVaultVariable
|
||||||
|
} from "@app/services/secret-sync/hc-vault/hc-vault-sync-types";
|
||||||
|
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||||
|
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
|
const listHCVaultVariables = async ({ instanceUrl, mount, accessToken, path }: THCVaultListVariables) => {
|
||||||
|
const { data } = await request.get<THCVaultListVariablesResponse>(
|
||||||
|
`${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"X-Vault-Token": accessToken
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return data.data.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hashicorp Vault updates all variables in one batch. This is to respect their versioning
|
||||||
|
const updateHCVaultVariables = async ({ path, instanceUrl, accessToken, mount, data }: TPostHCVaultVariable) =>
|
||||||
|
request.post(
|
||||||
|
`${instanceUrl}/v1/${removeTrailingSlash(mount)}/data/${path}`,
|
||||||
|
{
|
||||||
|
data
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"X-Vault-Token": accessToken,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const HCVaultSyncFns = {
|
||||||
|
syncSecrets: async (secretSync: THCVaultSyncWithCredentials, secretMap: TSecretMap) => {
|
||||||
|
const {
|
||||||
|
connection,
|
||||||
|
destinationConfig: { mount, path },
|
||||||
|
syncOptions: { disableSecretDeletion }
|
||||||
|
} = secretSync;
|
||||||
|
|
||||||
|
const accessToken = await getHCVaultAccessToken(connection);
|
||||||
|
const { instanceUrl } = connection.credentials;
|
||||||
|
|
||||||
|
const variables = await listHCVaultVariables({ instanceUrl, accessToken, mount, path });
|
||||||
|
let tainted = false;
|
||||||
|
|
||||||
|
for await (const entry of Object.entries(secretMap)) {
|
||||||
|
const [key, { value }] = entry;
|
||||||
|
if (value !== variables[key]) {
|
||||||
|
variables[key] = value;
|
||||||
|
tainted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disableSecretDeletion) return;
|
||||||
|
|
||||||
|
for await (const [key] of Object.entries(variables)) {
|
||||||
|
if (!(key in secretMap)) {
|
||||||
|
delete variables[key];
|
||||||
|
tainted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update variables if there was a change detected
|
||||||
|
if (!tainted) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateHCVaultVariables({ accessToken, instanceUrl, mount, path, data: variables });
|
||||||
|
} catch (error) {
|
||||||
|
throw new SecretSyncError({
|
||||||
|
error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeSecrets: async (secretSync: THCVaultSyncWithCredentials, secretMap: TSecretMap) => {
|
||||||
|
const {
|
||||||
|
connection,
|
||||||
|
destinationConfig: { mount, path }
|
||||||
|
} = secretSync;
|
||||||
|
|
||||||
|
const accessToken = await getHCVaultAccessToken(connection);
|
||||||
|
const { instanceUrl } = connection.credentials;
|
||||||
|
|
||||||
|
const variables = await listHCVaultVariables({ instanceUrl, accessToken, mount, path });
|
||||||
|
|
||||||
|
for await (const [key] of Object.entries(variables)) {
|
||||||
|
if (key in secretMap) {
|
||||||
|
delete variables[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateHCVaultVariables({ accessToken, instanceUrl, mount, path, data: variables });
|
||||||
|
} catch (error) {
|
||||||
|
throw new SecretSyncError({
|
||||||
|
error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSecrets: async (secretSync: THCVaultSyncWithCredentials) => {
|
||||||
|
const {
|
||||||
|
connection,
|
||||||
|
destinationConfig: { mount, path }
|
||||||
|
} = secretSync;
|
||||||
|
|
||||||
|
const accessToken = await getHCVaultAccessToken(connection);
|
||||||
|
const { instanceUrl } = connection.credentials;
|
||||||
|
|
||||||
|
const variables = await listHCVaultVariables({
|
||||||
|
instanceUrl,
|
||||||
|
accessToken,
|
||||||
|
mount,
|
||||||
|
path
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.fromEntries(Object.entries(variables).map(([key, value]) => [key, { value }]));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { SecretSyncs } from "@app/lib/api-docs";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||||
|
import {
|
||||||
|
BaseSecretSyncSchema,
|
||||||
|
GenericCreateSecretSyncFieldsSchema,
|
||||||
|
GenericUpdateSecretSyncFieldsSchema
|
||||||
|
} from "@app/services/secret-sync/secret-sync-schemas";
|
||||||
|
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
|
const HCVaultSyncDestinationConfigSchema = z.object({
|
||||||
|
mount: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Secrets Engine Mount required")
|
||||||
|
.describe(SecretSyncs.DESTINATION_CONFIG.HC_VAULT.mount),
|
||||||
|
path: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Path required")
|
||||||
|
.transform((val) => val.trim().replace(/^\/+|\/+$/g, "")) // removes leading/trailing slashes
|
||||||
|
.refine((val) => /^([a-zA-Z0-9._-]+\/)*[a-zA-Z0-9._-]+$/.test(val), {
|
||||||
|
message:
|
||||||
|
"Invalid Vault path format. Use alphanumerics, dots, dashes, underscores, and single slashes between segments."
|
||||||
|
})
|
||||||
|
.describe(SecretSyncs.DESTINATION_CONFIG.HC_VAULT.path)
|
||||||
|
});
|
||||||
|
|
||||||
|
const HCVaultSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
|
||||||
|
|
||||||
|
export const HCVaultSyncSchema = BaseSecretSyncSchema(SecretSync.HCVault, HCVaultSyncOptionsConfig).extend({
|
||||||
|
destination: z.literal(SecretSync.HCVault),
|
||||||
|
destinationConfig: HCVaultSyncDestinationConfigSchema
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CreateHCVaultSyncSchema = GenericCreateSecretSyncFieldsSchema(
|
||||||
|
SecretSync.HCVault,
|
||||||
|
HCVaultSyncOptionsConfig
|
||||||
|
).extend({
|
||||||
|
destinationConfig: HCVaultSyncDestinationConfigSchema
|
||||||
|
});
|
||||||
|
|
||||||
|
export const UpdateHCVaultSyncSchema = GenericUpdateSecretSyncFieldsSchema(
|
||||||
|
SecretSync.HCVault,
|
||||||
|
HCVaultSyncOptionsConfig
|
||||||
|
).extend({
|
||||||
|
destinationConfig: HCVaultSyncDestinationConfigSchema.optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const HCVaultSyncListItemSchema = z.object({
|
||||||
|
name: z.literal("Hashicorp Vault"),
|
||||||
|
connection: z.literal(AppConnection.HCVault),
|
||||||
|
destination: z.literal(SecretSync.HCVault),
|
||||||
|
canImportSecrets: z.literal(true)
|
||||||
|
});
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { THCVaultConnection } from "@app/services/app-connection/hc-vault";
|
||||||
|
|
||||||
|
import { CreateHCVaultSyncSchema, HCVaultSyncListItemSchema, HCVaultSyncSchema } from "./hc-vault-sync-schemas";
|
||||||
|
|
||||||
|
export type THCVaultSync = z.infer<typeof HCVaultSyncSchema>;
|
||||||
|
|
||||||
|
export type THCVaultSyncInput = z.infer<typeof CreateHCVaultSyncSchema>;
|
||||||
|
|
||||||
|
export type THCVaultSyncListItem = z.infer<typeof HCVaultSyncListItemSchema>;
|
||||||
|
|
||||||
|
export type THCVaultSyncWithCredentials = THCVaultSync & {
|
||||||
|
connection: THCVaultConnection;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type THCVaultListVariablesResponse = {
|
||||||
|
data: {
|
||||||
|
data: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type THCVaultListVariables = {
|
||||||
|
accessToken: string;
|
||||||
|
instanceUrl: string;
|
||||||
|
mount: string;
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TPostHCVaultVariable = THCVaultListVariables & {
|
||||||
|
data: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TDeleteHCVaultVariable = THCVaultListVariables;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export * from "./hc-vault-sync-constants";
|
||||||
|
export * from "./hc-vault-sync-fns";
|
||||||
|
export * from "./hc-vault-sync-schemas";
|
||||||
|
export * from "./hc-vault-sync-types";
|
||||||
@@ -10,7 +10,8 @@ export enum SecretSync {
|
|||||||
TerraformCloud = "terraform-cloud",
|
TerraformCloud = "terraform-cloud",
|
||||||
Camunda = "camunda",
|
Camunda = "camunda",
|
||||||
Vercel = "vercel",
|
Vercel = "vercel",
|
||||||
Windmill = "windmill"
|
Windmill = "windmill",
|
||||||
|
HCVault = "hashicorp-vault"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SecretSyncInitialSyncBehavior {
|
export enum SecretSyncInitialSyncBehavior {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { AZURE_KEY_VAULT_SYNC_LIST_OPTION, azureKeyVaultSyncFactory } from "./az
|
|||||||
import { CAMUNDA_SYNC_LIST_OPTION, camundaSyncFactory } from "./camunda";
|
import { CAMUNDA_SYNC_LIST_OPTION, camundaSyncFactory } from "./camunda";
|
||||||
import { GCP_SYNC_LIST_OPTION } from "./gcp";
|
import { GCP_SYNC_LIST_OPTION } from "./gcp";
|
||||||
import { GcpSyncFns } from "./gcp/gcp-sync-fns";
|
import { GcpSyncFns } from "./gcp/gcp-sync-fns";
|
||||||
|
import { HC_VAULT_SYNC_LIST_OPTION, HCVaultSyncFns } from "./hc-vault";
|
||||||
import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec";
|
import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec";
|
||||||
import { HumanitecSyncFns } from "./humanitec/humanitec-sync-fns";
|
import { HumanitecSyncFns } from "./humanitec/humanitec-sync-fns";
|
||||||
import { TERRAFORM_CLOUD_SYNC_LIST_OPTION, TerraformCloudSyncFns } from "./terraform-cloud";
|
import { TERRAFORM_CLOUD_SYNC_LIST_OPTION, TerraformCloudSyncFns } from "./terraform-cloud";
|
||||||
@@ -43,7 +44,8 @@ const SECRET_SYNC_LIST_OPTIONS: Record<SecretSync, TSecretSyncListItem> = {
|
|||||||
[SecretSync.TerraformCloud]: TERRAFORM_CLOUD_SYNC_LIST_OPTION,
|
[SecretSync.TerraformCloud]: TERRAFORM_CLOUD_SYNC_LIST_OPTION,
|
||||||
[SecretSync.Camunda]: CAMUNDA_SYNC_LIST_OPTION,
|
[SecretSync.Camunda]: CAMUNDA_SYNC_LIST_OPTION,
|
||||||
[SecretSync.Vercel]: VERCEL_SYNC_LIST_OPTION,
|
[SecretSync.Vercel]: VERCEL_SYNC_LIST_OPTION,
|
||||||
[SecretSync.Windmill]: WINDMILL_SYNC_LIST_OPTION
|
[SecretSync.Windmill]: WINDMILL_SYNC_LIST_OPTION,
|
||||||
|
[SecretSync.HCVault]: HC_VAULT_SYNC_LIST_OPTION
|
||||||
};
|
};
|
||||||
|
|
||||||
export const listSecretSyncOptions = () => {
|
export const listSecretSyncOptions = () => {
|
||||||
@@ -140,6 +142,8 @@ export const SecretSyncFns = {
|
|||||||
return VercelSyncFns.syncSecrets(secretSync, secretMap);
|
return VercelSyncFns.syncSecrets(secretSync, secretMap);
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
return WindmillSyncFns.syncSecrets(secretSync, secretMap);
|
return WindmillSyncFns.syncSecrets(secretSync, secretMap);
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
return HCVaultSyncFns.syncSecrets(secretSync, secretMap);
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||||
@@ -199,6 +203,9 @@ export const SecretSyncFns = {
|
|||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
secretMap = await WindmillSyncFns.getSecrets(secretSync);
|
secretMap = await WindmillSyncFns.getSecrets(secretSync);
|
||||||
break;
|
break;
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
secretMap = await HCVaultSyncFns.getSecrets(secretSync);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled sync destination for get secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
`Unhandled sync destination for get secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||||
@@ -252,6 +259,8 @@ export const SecretSyncFns = {
|
|||||||
return VercelSyncFns.removeSecrets(secretSync, secretMap);
|
return VercelSyncFns.removeSecrets(secretSync, secretMap);
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
return WindmillSyncFns.removeSecrets(secretSync, secretMap);
|
return WindmillSyncFns.removeSecrets(secretSync, secretMap);
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
return HCVaultSyncFns.removeSecrets(secretSync, secretMap);
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
|
|||||||
[SecretSync.TerraformCloud]: "Terraform Cloud",
|
[SecretSync.TerraformCloud]: "Terraform Cloud",
|
||||||
[SecretSync.Camunda]: "Camunda",
|
[SecretSync.Camunda]: "Camunda",
|
||||||
[SecretSync.Vercel]: "Vercel",
|
[SecretSync.Vercel]: "Vercel",
|
||||||
[SecretSync.Windmill]: "Windmill"
|
[SecretSync.Windmill]: "Windmill",
|
||||||
|
[SecretSync.HCVault]: "Hashicorp Vault"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
||||||
@@ -28,5 +29,6 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
|||||||
[SecretSync.TerraformCloud]: AppConnection.TerraformCloud,
|
[SecretSync.TerraformCloud]: AppConnection.TerraformCloud,
|
||||||
[SecretSync.Camunda]: AppConnection.Camunda,
|
[SecretSync.Camunda]: AppConnection.Camunda,
|
||||||
[SecretSync.Vercel]: AppConnection.Vercel,
|
[SecretSync.Vercel]: AppConnection.Vercel,
|
||||||
[SecretSync.Windmill]: AppConnection.Windmill
|
[SecretSync.Windmill]: AppConnection.Windmill,
|
||||||
|
[SecretSync.HCVault]: AppConnection.HCVault
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ import {
|
|||||||
TAzureKeyVaultSyncWithCredentials
|
TAzureKeyVaultSyncWithCredentials
|
||||||
} from "./azure-key-vault";
|
} from "./azure-key-vault";
|
||||||
import { TGcpSync, TGcpSyncInput, TGcpSyncListItem, TGcpSyncWithCredentials } from "./gcp";
|
import { TGcpSync, TGcpSyncInput, TGcpSyncListItem, TGcpSyncWithCredentials } from "./gcp";
|
||||||
|
import {
|
||||||
|
THCVaultSync,
|
||||||
|
THCVaultSyncInput,
|
||||||
|
THCVaultSyncListItem,
|
||||||
|
THCVaultSyncWithCredentials
|
||||||
|
} from "./hc-vault/hc-vault-sync-types";
|
||||||
import {
|
import {
|
||||||
THumanitecSync,
|
THumanitecSync,
|
||||||
THumanitecSyncInput,
|
THumanitecSyncInput,
|
||||||
@@ -81,7 +87,8 @@ export type TSecretSync =
|
|||||||
| TTerraformCloudSync
|
| TTerraformCloudSync
|
||||||
| TCamundaSync
|
| TCamundaSync
|
||||||
| TVercelSync
|
| TVercelSync
|
||||||
| TWindmillSync;
|
| TWindmillSync
|
||||||
|
| THCVaultSync;
|
||||||
|
|
||||||
export type TSecretSyncWithCredentials =
|
export type TSecretSyncWithCredentials =
|
||||||
| TAwsParameterStoreSyncWithCredentials
|
| TAwsParameterStoreSyncWithCredentials
|
||||||
@@ -95,7 +102,8 @@ export type TSecretSyncWithCredentials =
|
|||||||
| TTerraformCloudSyncWithCredentials
|
| TTerraformCloudSyncWithCredentials
|
||||||
| TCamundaSyncWithCredentials
|
| TCamundaSyncWithCredentials
|
||||||
| TVercelSyncWithCredentials
|
| TVercelSyncWithCredentials
|
||||||
| TWindmillSyncWithCredentials;
|
| TWindmillSyncWithCredentials
|
||||||
|
| THCVaultSyncWithCredentials;
|
||||||
|
|
||||||
export type TSecretSyncInput =
|
export type TSecretSyncInput =
|
||||||
| TAwsParameterStoreSyncInput
|
| TAwsParameterStoreSyncInput
|
||||||
@@ -109,7 +117,8 @@ export type TSecretSyncInput =
|
|||||||
| TTerraformCloudSyncInput
|
| TTerraformCloudSyncInput
|
||||||
| TCamundaSyncInput
|
| TCamundaSyncInput
|
||||||
| TVercelSyncInput
|
| TVercelSyncInput
|
||||||
| TWindmillSyncInput;
|
| TWindmillSyncInput
|
||||||
|
| THCVaultSyncInput;
|
||||||
|
|
||||||
export type TSecretSyncListItem =
|
export type TSecretSyncListItem =
|
||||||
| TAwsParameterStoreSyncListItem
|
| TAwsParameterStoreSyncListItem
|
||||||
@@ -123,7 +132,8 @@ export type TSecretSyncListItem =
|
|||||||
| TTerraformCloudSyncListItem
|
| TTerraformCloudSyncListItem
|
||||||
| TCamundaSyncListItem
|
| TCamundaSyncListItem
|
||||||
| TVercelSyncListItem
|
| TVercelSyncListItem
|
||||||
| TWindmillSyncListItem;
|
| TWindmillSyncListItem
|
||||||
|
| THCVaultSyncListItem;
|
||||||
|
|
||||||
export type TSyncOptionsConfig = {
|
export type TSyncOptionsConfig = {
|
||||||
canImportSecrets: boolean;
|
canImportSecrets: boolean;
|
||||||
|
|||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||||
|
import { SingleValue } from "react-select";
|
||||||
|
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
|
import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField";
|
||||||
|
import { FilterableSelect, FormControl, Input, Tooltip } from "@app/components/v2";
|
||||||
|
import { useHCVaultConnectionListMounts } from "@app/hooks/api/appConnections/hc-vault";
|
||||||
|
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||||
|
|
||||||
|
import { TSecretSyncForm } from "../schemas";
|
||||||
|
|
||||||
|
export const HCVaultSyncFields = () => {
|
||||||
|
const { control, setValue } = useFormContext<
|
||||||
|
TSecretSyncForm & { destination: SecretSync.HCVault }
|
||||||
|
>();
|
||||||
|
|
||||||
|
const connectionId = useWatch({ name: "connection.id", control });
|
||||||
|
|
||||||
|
const { data: mounts, isLoading: isMountsLoading } = useHCVaultConnectionListMounts(
|
||||||
|
connectionId,
|
||||||
|
{
|
||||||
|
enabled: Boolean(connectionId)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SecretSyncConnectionField
|
||||||
|
onChange={() => {
|
||||||
|
setValue("destinationConfig.mount", "");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="destinationConfig.mount"
|
||||||
|
control={control}
|
||||||
|
render={({ field: { onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
label="Secrets Engine Mount"
|
||||||
|
helperText={
|
||||||
|
<Tooltip
|
||||||
|
className="max-w-md"
|
||||||
|
content="Ensure the Secrets Engine mount exists and that your App Role / Access Token has permission to access it. Infisical only supports version 2 KV Secrets Engine mounts."
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span>Don't see the mount you're looking for?</span>{" "}
|
||||||
|
<FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-400" />
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FilterableSelect
|
||||||
|
menuPlacement="top"
|
||||||
|
isLoading={isMountsLoading && Boolean(connectionId)}
|
||||||
|
isDisabled={!connectionId}
|
||||||
|
onChange={(option) =>
|
||||||
|
onChange((option as SingleValue<{ value: string }>)?.value ?? null)
|
||||||
|
}
|
||||||
|
options={mounts?.map((v) => ({ label: v, value: v }))}
|
||||||
|
placeholder="Select a Secrets Engine Mount..."
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="destinationConfig.path"
|
||||||
|
control={control}
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
tooltipClassName="max-w-sm"
|
||||||
|
tooltipText="The Secrets Engine mount path where secrets should be synced to."
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
label="Path"
|
||||||
|
>
|
||||||
|
<Input value={value} onChange={onChange} placeholder="dev/example" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
+3
@@ -11,6 +11,7 @@ import { CamundaSyncFields } from "./CamundaSyncFields";
|
|||||||
import { DatabricksSyncFields } from "./DatabricksSyncFields";
|
import { DatabricksSyncFields } from "./DatabricksSyncFields";
|
||||||
import { GcpSyncFields } from "./GcpSyncFields";
|
import { GcpSyncFields } from "./GcpSyncFields";
|
||||||
import { GitHubSyncFields } from "./GitHubSyncFields";
|
import { GitHubSyncFields } from "./GitHubSyncFields";
|
||||||
|
import { HCVaultSyncFields } from "./HCVaultSyncFields";
|
||||||
import { HumanitecSyncFields } from "./HumanitecSyncFields";
|
import { HumanitecSyncFields } from "./HumanitecSyncFields";
|
||||||
import { TerraformCloudSyncFields } from "./TerraformCloudSyncFields";
|
import { TerraformCloudSyncFields } from "./TerraformCloudSyncFields";
|
||||||
import { VercelSyncFields } from "./VercelSyncFields";
|
import { VercelSyncFields } from "./VercelSyncFields";
|
||||||
@@ -46,6 +47,8 @@ export const SecretSyncDestinationFields = () => {
|
|||||||
return <VercelSyncFields />;
|
return <VercelSyncFields />;
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
return <WindmillSyncFields />;
|
return <WindmillSyncFields />;
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
return <HCVaultSyncFields />;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled Destination Config Field: ${destination}`);
|
throw new Error(`Unhandled Destination Config Field: ${destination}`);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -43,6 +43,7 @@ export const SecretSyncOptionsFields = ({ hideInitialSync }: Props) => {
|
|||||||
case SecretSync.Camunda:
|
case SecretSync.Camunda:
|
||||||
case SecretSync.Vercel:
|
case SecretSync.Vercel:
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
|
case SecretSync.HCVault:
|
||||||
AdditionalSyncOptionsFieldsComponent = null;
|
AdditionalSyncOptionsFieldsComponent = null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
import { useFormContext } from "react-hook-form";
|
||||||
|
|
||||||
|
import { TSecretSyncForm } from "@app/components/secret-syncs/forms/schemas";
|
||||||
|
import { GenericFieldLabel } from "@app/components/v2";
|
||||||
|
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||||
|
|
||||||
|
export const HCVaultSyncReviewFields = () => {
|
||||||
|
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.HCVault }>();
|
||||||
|
const mount = watch("destinationConfig.mount");
|
||||||
|
const path = watch("destinationConfig.path");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<GenericFieldLabel label="Secrets Engine Mount">{mount}</GenericFieldLabel>
|
||||||
|
<GenericFieldLabel label="Path">{path}</GenericFieldLabel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
+4
@@ -21,6 +21,7 @@ import { CamundaSyncReviewFields } from "./CamundaSyncReviewFields";
|
|||||||
import { DatabricksSyncReviewFields } from "./DatabricksSyncReviewFields";
|
import { DatabricksSyncReviewFields } from "./DatabricksSyncReviewFields";
|
||||||
import { GcpSyncReviewFields } from "./GcpSyncReviewFields";
|
import { GcpSyncReviewFields } from "./GcpSyncReviewFields";
|
||||||
import { GitHubSyncReviewFields } from "./GitHubSyncReviewFields";
|
import { GitHubSyncReviewFields } from "./GitHubSyncReviewFields";
|
||||||
|
import { HCVaultSyncReviewFields } from "./HCVaultSyncReviewFields";
|
||||||
import { HumanitecSyncReviewFields } from "./HumanitecSyncReviewFields";
|
import { HumanitecSyncReviewFields } from "./HumanitecSyncReviewFields";
|
||||||
import { TerraformCloudSyncReviewFields } from "./TerraformCloudSyncReviewFields";
|
import { TerraformCloudSyncReviewFields } from "./TerraformCloudSyncReviewFields";
|
||||||
import { VercelSyncReviewFields } from "./VercelSyncReviewFields";
|
import { VercelSyncReviewFields } from "./VercelSyncReviewFields";
|
||||||
@@ -88,6 +89,9 @@ export const SecretSyncReviewFields = () => {
|
|||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
DestinationFieldsComponent = <WindmillSyncReviewFields />;
|
DestinationFieldsComponent = <WindmillSyncReviewFields />;
|
||||||
break;
|
break;
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
DestinationFieldsComponent = <HCVaultSyncReviewFields />;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled Destination Review Fields: ${destination}`);
|
throw new Error(`Unhandled Destination Review Fields: ${destination}`);
|
||||||
}
|
}
|
||||||
|
|||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { BaseSecretSyncSchema } from "@app/components/secret-syncs/forms/schemas/base-secret-sync-schema";
|
||||||
|
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||||
|
|
||||||
|
export const HCVaultSyncDestinationSchema = BaseSecretSyncSchema().merge(
|
||||||
|
z.object({
|
||||||
|
destination: z.literal(SecretSync.HCVault),
|
||||||
|
destinationConfig: z.object({
|
||||||
|
mount: z.string().trim().min(1, "Secrets Engine Mount required"),
|
||||||
|
path: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Path required")
|
||||||
|
.transform((val) => val.trim().replace(/^\/+|\/+$/g, "")) // removes leading/trailing slashes
|
||||||
|
.refine((val) => /^([a-zA-Z0-9._-]+\/)*[a-zA-Z0-9._-]+$/.test(val), {
|
||||||
|
message:
|
||||||
|
"Invalid Vault path format. Use alphanumerics, dots, dashes, underscores, and single slashes between segments."
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
);
|
||||||
@@ -8,6 +8,7 @@ import { CamundaSyncDestinationSchema } from "./camunda-sync-destination-schema"
|
|||||||
import { DatabricksSyncDestinationSchema } from "./databricks-sync-destination-schema";
|
import { DatabricksSyncDestinationSchema } from "./databricks-sync-destination-schema";
|
||||||
import { GcpSyncDestinationSchema } from "./gcp-sync-destination-schema";
|
import { GcpSyncDestinationSchema } from "./gcp-sync-destination-schema";
|
||||||
import { GitHubSyncDestinationSchema } from "./github-sync-destination-schema";
|
import { GitHubSyncDestinationSchema } from "./github-sync-destination-schema";
|
||||||
|
import { HCVaultSyncDestinationSchema } from "./hc-vault-sync-destination-schema";
|
||||||
import { HumanitecSyncDestinationSchema } from "./humanitec-sync-destination-schema";
|
import { HumanitecSyncDestinationSchema } from "./humanitec-sync-destination-schema";
|
||||||
import { TerraformCloudSyncDestinationSchema } from "./terraform-cloud-destination-schema";
|
import { TerraformCloudSyncDestinationSchema } from "./terraform-cloud-destination-schema";
|
||||||
import { VercelSyncDestinationSchema } from "./vercel-sync-destination-schema";
|
import { VercelSyncDestinationSchema } from "./vercel-sync-destination-schema";
|
||||||
@@ -25,7 +26,8 @@ const SecretSyncUnionSchema = z.discriminatedUnion("destination", [
|
|||||||
TerraformCloudSyncDestinationSchema,
|
TerraformCloudSyncDestinationSchema,
|
||||||
CamundaSyncDestinationSchema,
|
CamundaSyncDestinationSchema,
|
||||||
VercelSyncDestinationSchema,
|
VercelSyncDestinationSchema,
|
||||||
WindmillSyncDestinationSchema
|
WindmillSyncDestinationSchema,
|
||||||
|
HCVaultSyncDestinationSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const SecretSyncFormSchema = SecretSyncUnionSchema;
|
export const SecretSyncFormSchema = SecretSyncUnionSchema;
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ import {
|
|||||||
DatabricksConnectionMethod,
|
DatabricksConnectionMethod,
|
||||||
GcpConnectionMethod,
|
GcpConnectionMethod,
|
||||||
GitHubConnectionMethod,
|
GitHubConnectionMethod,
|
||||||
|
HCVaultConnectionMethod,
|
||||||
HumanitecConnectionMethod,
|
HumanitecConnectionMethod,
|
||||||
MsSqlConnectionMethod,
|
MsSqlConnectionMethod,
|
||||||
PostgresConnectionMethod,
|
PostgresConnectionMethod,
|
||||||
TAppConnection,
|
TAppConnection,
|
||||||
TerraformCloudConnectionMethod,
|
TerraformCloudConnectionMethod,
|
||||||
VercelConnectionMethod,
|
VercelConnectionMethod,
|
||||||
WindmillConnectionMethod,
|
WindmillConnectionMethod
|
||||||
HCVaultConnectionMethod
|
|
||||||
} from "@app/hooks/api/appConnections/types";
|
} from "@app/hooks/api/appConnections/types";
|
||||||
|
|
||||||
export const APP_CONNECTION_MAP: Record<
|
export const APP_CONNECTION_MAP: Record<
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ export const SECRET_SYNC_MAP: Record<SecretSync, { name: string; image: string }
|
|||||||
[SecretSync.Windmill]: {
|
[SecretSync.Windmill]: {
|
||||||
name: "Windmill",
|
name: "Windmill",
|
||||||
image: "Windmill.png"
|
image: "Windmill.png"
|
||||||
|
},
|
||||||
|
[SecretSync.HCVault]: {
|
||||||
|
name: "Hashicorp Vault",
|
||||||
|
image: "Vault.png"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,7 +58,8 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
|||||||
[SecretSync.TerraformCloud]: AppConnection.TerraformCloud,
|
[SecretSync.TerraformCloud]: AppConnection.TerraformCloud,
|
||||||
[SecretSync.Camunda]: AppConnection.Camunda,
|
[SecretSync.Camunda]: AppConnection.Camunda,
|
||||||
[SecretSync.Vercel]: AppConnection.Vercel,
|
[SecretSync.Vercel]: AppConnection.Vercel,
|
||||||
[SecretSync.Windmill]: AppConnection.Windmill
|
[SecretSync.Windmill]: AppConnection.Windmill,
|
||||||
|
[SecretSync.HCVault]: AppConnection.HCVault
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP: Record<
|
export const SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP: Record<
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export * from "./queries";
|
export * from "./queries";
|
||||||
export * from "./types";
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const hcVaultConnectionKeys = {
|
|||||||
[...hcVaultConnectionKeys.all, "mounts", connectionId] as const
|
[...hcVaultConnectionKeys.all, "mounts", connectionId] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useHCVaultConnectionListWorkspaces = (
|
export const useHCVaultConnectionListMounts = (
|
||||||
connectionId: string,
|
connectionId: string,
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseQueryOptions<
|
UseQueryOptions<
|
||||||
@@ -26,7 +26,7 @@ export const useHCVaultConnectionListWorkspaces = (
|
|||||||
queryKey: hcVaultConnectionKeys.listMounts(connectionId),
|
queryKey: hcVaultConnectionKeys.listMounts(connectionId),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await apiRequest.get<string[]>(
|
const { data } = await apiRequest.get<string[]>(
|
||||||
`/api/v1/app-connections/hc-vault/${connectionId}/mounts`
|
`/api/v1/app-connections/hashicorp-vault/${connectionId}/mounts`
|
||||||
);
|
);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ export * from "./camunda-connection";
|
|||||||
export * from "./databricks-connection";
|
export * from "./databricks-connection";
|
||||||
export * from "./gcp-connection";
|
export * from "./gcp-connection";
|
||||||
export * from "./github-connection";
|
export * from "./github-connection";
|
||||||
|
export * from "./hc-vault-connection";
|
||||||
export * from "./humanitec-connection";
|
export * from "./humanitec-connection";
|
||||||
export * from "./mssql-connection";
|
export * from "./mssql-connection";
|
||||||
export * from "./postgres-connection";
|
export * from "./postgres-connection";
|
||||||
export * from "./terraform-cloud-connection";
|
export * from "./terraform-cloud-connection";
|
||||||
export * from "./vercel-connection";
|
export * from "./vercel-connection";
|
||||||
export * from "./windmill-connection";
|
export * from "./windmill-connection";
|
||||||
export * from "./hc-vault-connection";
|
|
||||||
|
|
||||||
export type TAppConnection =
|
export type TAppConnection =
|
||||||
| TAwsConnection
|
| TAwsConnection
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ export enum SecretSync {
|
|||||||
TerraformCloud = "terraform-cloud",
|
TerraformCloud = "terraform-cloud",
|
||||||
Camunda = "camunda",
|
Camunda = "camunda",
|
||||||
Vercel = "vercel",
|
Vercel = "vercel",
|
||||||
Windmill = "windmill"
|
Windmill = "windmill",
|
||||||
|
HCVault = "hashicorp-vault"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SecretSyncStatus {
|
export enum SecretSyncStatus {
|
||||||
|
|||||||
@@ -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 THCVaultSync = TRootSecretSync & {
|
||||||
|
destination: SecretSync.HCVault;
|
||||||
|
destinationConfig: {
|
||||||
|
mount: string;
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
connection: {
|
||||||
|
app: AppConnection.HCVault;
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ import { TCamundaSync } from "./camunda-sync";
|
|||||||
import { TDatabricksSync } from "./databricks-sync";
|
import { TDatabricksSync } from "./databricks-sync";
|
||||||
import { TGcpSync } from "./gcp-sync";
|
import { TGcpSync } from "./gcp-sync";
|
||||||
import { TGitHubSync } from "./github-sync";
|
import { TGitHubSync } from "./github-sync";
|
||||||
|
import { THCVaultSync } from "./hc-vault-sync";
|
||||||
import { THumanitecSync } from "./humanitec-sync";
|
import { THumanitecSync } from "./humanitec-sync";
|
||||||
import { TTerraformCloudSync } from "./terraform-cloud-sync";
|
import { TTerraformCloudSync } from "./terraform-cloud-sync";
|
||||||
import { TVercelSync } from "./vercel-sync";
|
import { TVercelSync } from "./vercel-sync";
|
||||||
@@ -32,7 +33,8 @@ export type TSecretSync =
|
|||||||
| TTerraformCloudSync
|
| TTerraformCloudSync
|
||||||
| TCamundaSync
|
| TCamundaSync
|
||||||
| TVercelSync
|
| TVercelSync
|
||||||
| TWindmillSync;
|
| TWindmillSync
|
||||||
|
| THCVaultSync;
|
||||||
|
|
||||||
export type TListSecretSyncs = { secretSyncs: TSecretSync[] };
|
export type TListSecretSyncs = { secretSyncs: TSecretSync[] };
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -17,13 +17,13 @@ import { CamundaConnectionForm } from "./CamundaConnectionForm";
|
|||||||
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
|
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
|
||||||
import { GcpConnectionForm } from "./GcpConnectionForm";
|
import { GcpConnectionForm } from "./GcpConnectionForm";
|
||||||
import { GitHubConnectionForm } from "./GitHubConnectionForm";
|
import { GitHubConnectionForm } from "./GitHubConnectionForm";
|
||||||
|
import { HCVaultConnectionForm } from "./HCVaultConnectionForm";
|
||||||
import { HumanitecConnectionForm } from "./HumanitecConnectionForm";
|
import { HumanitecConnectionForm } from "./HumanitecConnectionForm";
|
||||||
import { MsSqlConnectionForm } from "./MsSqlConnectionForm";
|
import { MsSqlConnectionForm } from "./MsSqlConnectionForm";
|
||||||
import { PostgresConnectionForm } from "./PostgresConnectionForm";
|
import { PostgresConnectionForm } from "./PostgresConnectionForm";
|
||||||
import { TerraformCloudConnectionForm } from "./TerraformCloudConnectionForm";
|
import { TerraformCloudConnectionForm } from "./TerraformCloudConnectionForm";
|
||||||
import { VercelConnectionForm } from "./VercelConnectionForm";
|
import { VercelConnectionForm } from "./VercelConnectionForm";
|
||||||
import { WindmillConnectionForm } from "./WindmillConnectionForm";
|
import { WindmillConnectionForm } from "./WindmillConnectionForm";
|
||||||
import { HCVaultConnectionForm } from "./HCVaultConnectionForm";
|
|
||||||
|
|
||||||
type FormProps = {
|
type FormProps = {
|
||||||
onComplete: (appConnection: TAppConnection) => void;
|
onComplete: (appConnection: TAppConnection) => void;
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
import { THCVaultSync } from "@app/hooks/api/secretSyncs/types/hc-vault-sync";
|
||||||
|
|
||||||
|
import { getSecretSyncDestinationColValues } from "../helpers";
|
||||||
|
import { SecretSyncTableCell } from "../SecretSyncTableCell";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
secretSync: THCVaultSync;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HCVaultSyncDestinationCol = ({ secretSync }: Props) => {
|
||||||
|
const { primaryText, secondaryText } = getSecretSyncDestinationColValues(secretSync);
|
||||||
|
|
||||||
|
return <SecretSyncTableCell primaryText={primaryText} secondaryText={secondaryText} />;
|
||||||
|
};
|
||||||
+3
@@ -8,6 +8,7 @@ import { CamundaSyncDestinationCol } from "./CamundaSyncDestinationCol";
|
|||||||
import { DatabricksSyncDestinationCol } from "./DatabricksSyncDestinationCol";
|
import { DatabricksSyncDestinationCol } from "./DatabricksSyncDestinationCol";
|
||||||
import { GcpSyncDestinationCol } from "./GcpSyncDestinationCol";
|
import { GcpSyncDestinationCol } from "./GcpSyncDestinationCol";
|
||||||
import { GitHubSyncDestinationCol } from "./GitHubSyncDestinationCol";
|
import { GitHubSyncDestinationCol } from "./GitHubSyncDestinationCol";
|
||||||
|
import { HCVaultSyncDestinationCol } from "./HCVaultSyncDestinationCol";
|
||||||
import { HumanitecSyncDestinationCol } from "./HumanitecSyncDestinationCol";
|
import { HumanitecSyncDestinationCol } from "./HumanitecSyncDestinationCol";
|
||||||
import { TerraformCloudSyncDestinationCol } from "./TerraformCloudSyncDestinationCol";
|
import { TerraformCloudSyncDestinationCol } from "./TerraformCloudSyncDestinationCol";
|
||||||
import { VercelSyncDestinationCol } from "./VercelSyncDestinationCol";
|
import { VercelSyncDestinationCol } from "./VercelSyncDestinationCol";
|
||||||
@@ -43,6 +44,8 @@ export const SecretSyncDestinationCol = ({ secretSync }: Props) => {
|
|||||||
return <VercelSyncDestinationCol secretSync={secretSync} />;
|
return <VercelSyncDestinationCol secretSync={secretSync} />;
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
return <WindmillSyncDestinationCol secretSync={secretSync} />;
|
return <WindmillSyncDestinationCol secretSync={secretSync} />;
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
return <HCVaultSyncDestinationCol secretSync={secretSync} />;
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unhandled Secret Sync Destination Col: ${(secretSync as TSecretSync).destination}`
|
`Unhandled Secret Sync Destination Col: ${(secretSync as TSecretSync).destination}`
|
||||||
|
|||||||
+4
@@ -94,6 +94,10 @@ export const getSecretSyncDestinationColValues = (secretSync: TSecretSync) => {
|
|||||||
primaryText = destinationConfig.workspace;
|
primaryText = destinationConfig.workspace;
|
||||||
secondaryText = destinationConfig.path;
|
secondaryText = destinationConfig.path;
|
||||||
break;
|
break;
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
primaryText = destinationConfig.mount;
|
||||||
|
secondaryText = destinationConfig.path;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled Destination Col Values ${destination}`);
|
throw new Error(`Unhandled Destination Col Values ${destination}`);
|
||||||
}
|
}
|
||||||
|
|||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
import { GenericFieldLabel } from "@app/components/secret-syncs";
|
||||||
|
import { THCVaultSync } from "@app/hooks/api/secretSyncs/types/hc-vault-sync";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
secretSync: THCVaultSync;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const HCVaultSyncDestinationSection = ({ secretSync }: Props) => {
|
||||||
|
const {
|
||||||
|
destinationConfig: { path, mount }
|
||||||
|
} = secretSync;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<GenericFieldLabel label="Secrets Engine Mount">{mount}</GenericFieldLabel>
|
||||||
|
<GenericFieldLabel label="Path">{path}</GenericFieldLabel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
+4
@@ -18,6 +18,7 @@ import { CamundaSyncDestinationSection } from "./CamundaSyncDestinationSection";
|
|||||||
import { DatabricksSyncDestinationSection } from "./DatabricksSyncDestinationSection";
|
import { DatabricksSyncDestinationSection } from "./DatabricksSyncDestinationSection";
|
||||||
import { GcpSyncDestinationSection } from "./GcpSyncDestinationSection";
|
import { GcpSyncDestinationSection } from "./GcpSyncDestinationSection";
|
||||||
import { GitHubSyncDestinationSection } from "./GitHubSyncDestinationSection";
|
import { GitHubSyncDestinationSection } from "./GitHubSyncDestinationSection";
|
||||||
|
import { HCVaultSyncDestinationSection } from "./HCVaultSyncDestinationSection";
|
||||||
import { HumanitecSyncDestinationSection } from "./HumanitecSyncDestinationSection";
|
import { HumanitecSyncDestinationSection } from "./HumanitecSyncDestinationSection";
|
||||||
import { TerraformCloudSyncDestinationSection } from "./TerraformCloudSyncDestinationSection";
|
import { TerraformCloudSyncDestinationSection } from "./TerraformCloudSyncDestinationSection";
|
||||||
import { VercelSyncDestinationSection } from "./VercelSyncDestinationSection";
|
import { VercelSyncDestinationSection } from "./VercelSyncDestinationSection";
|
||||||
@@ -73,6 +74,9 @@ export const SecretSyncDestinationSection = ({ secretSync, onEditDestination }:
|
|||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
DestinationComponents = <WindmillSyncDestinationSection secretSync={secretSync} />;
|
DestinationComponents = <WindmillSyncDestinationSection secretSync={secretSync} />;
|
||||||
break;
|
break;
|
||||||
|
case SecretSync.HCVault:
|
||||||
|
DestinationComponents = <HCVaultSyncDestinationSection secretSync={secretSync} />;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled Destination Section components: ${destination}`);
|
throw new Error(`Unhandled Destination Section components: ${destination}`);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -52,6 +52,7 @@ export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) =
|
|||||||
case SecretSync.Camunda:
|
case SecretSync.Camunda:
|
||||||
case SecretSync.Vercel:
|
case SecretSync.Vercel:
|
||||||
case SecretSync.Windmill:
|
case SecretSync.Windmill:
|
||||||
|
case SecretSync.HCVault:
|
||||||
AdditionalSyncOptionsComponent = null;
|
AdditionalSyncOptionsComponent = null;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user