feat: chef secret-sync

This commit is contained in:
Piyush Gupta
2025-10-30 20:06:04 +05:30
parent fd010fe823
commit 30c0cfb8c2
36 changed files with 767 additions and 124 deletions
+4
View File
@@ -2626,6 +2626,10 @@ export const SecretSyncs = {
siteName: "The name of the Netlify site to sync secrets to.",
siteId: "The ID of the Netlify site to sync secrets to.",
context: "The Netlify context to sync secrets to."
},
CHEF: {
dataBagName: "The name of the Chef data bag to sync secrets to.",
dataBagItemName: "The name of the Chef data bag item to sync secrets to."
}
}
};
@@ -1,15 +1,15 @@
// import z from "zod";
import z from "zod";
// import { readLimit } from "@app/server/config/rateLimiter";
// import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
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 {
CreateChefConnectionSchema,
SanitizedChefConnectionSchema,
UpdateChefConnectionSchema
} from "@app/services/app-connection/chef";
import { AuthMode } from "@app/services/auth/auth-type";
// import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerChefConnectionRouter = async (server: FastifyZodProvider) => {
@@ -21,64 +21,65 @@ export const registerChefConnectionRouter = async (server: FastifyZodProvider) =
updateSchema: UpdateChefConnectionSchema
});
// server.route({
// method: "GET",
// url: `/:connectionId/data-bags`,
// 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 dataBags = await server.services.appConnection.chef.listDataBags(connectionId, req.permission);
server.route({
method: "GET",
url: `/:connectionId/data-bags`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const dataBags = await server.services.appConnection.chef.listDataBags(connectionId, req.permission);
// return dataBags;
// }
// });
return dataBags;
}
});
// server.route({
// method: "GET",
// url: `/:connectionId/data-bags/:dataBagName/items`,
// config: {
// rateLimit: readLimit
// },
// schema: {
// params: z.object({
// connectionId: z.string().uuid(),
// dataBagName: z.string()
// }),
// response: {
// 200: z
// .object({
// id: z.string(),
// name: z.string()
// })
// .array()
// }
// },
// onRequest: verifyAuth([AuthMode.JWT]),
// handler: async (req) => {
// const { connectionId, dataBagName } = req.params;
// const dataBagItems = await server.services.appConnection.chef.listDataBagItems(
// connectionId,
// dataBagName,
// req.permission
// );
server.route({
method: "GET",
url: `/:connectionId/data-bag-items`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
querystring: z.object({
dataBagName: z.string()
}),
response: {
200: z
.object({
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const { dataBagName } = req.query;
const dataBagItems = await server.services.appConnection.chef.listDataBagItems(
connectionId,
dataBagName,
req.permission
);
// return dataBagItems;
// }
// });
return dataBagItems;
}
});
};
@@ -0,0 +1,13 @@
import { ChefSyncSchema, CreateChefSyncSchema, UpdateChefSyncSchema } from "@app/services/secret-sync/chef";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerChefSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.Chef,
server,
responseSchema: ChefSyncSchema,
createSchema: CreateChefSyncSchema,
updateSchema: UpdateChefSyncSchema
});
@@ -10,6 +10,7 @@ import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router";
import { registerBitbucketSyncRouter } from "./bitbucket-sync-router";
import { registerCamundaSyncRouter } from "./camunda-sync-router";
import { registerChecklySyncRouter } from "./checkly-sync-router";
import { registerChefSyncRouter } from "./chef-sync-router";
import { registerCloudflarePagesSyncRouter } from "./cloudflare-pages-sync-router";
import { registerCloudflareWorkersSyncRouter } from "./cloudflare-workers-sync-router";
import { registerDatabricksSyncRouter } from "./databricks-sync-router";
@@ -65,5 +66,6 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
[SecretSync.DigitalOceanAppPlatform]: registerDigitalOceanAppPlatformSyncRouter,
[SecretSync.Netlify]: registerNetlifySyncRouter,
[SecretSync.Bitbucket]: registerBitbucketSyncRouter,
[SecretSync.LaravelForge]: registerLaravelForgeSyncRouter
[SecretSync.LaravelForge]: registerLaravelForgeSyncRouter,
[SecretSync.Chef]: registerChefSyncRouter
};
@@ -24,6 +24,7 @@ import { AzureKeyVaultSyncListItemSchema, AzureKeyVaultSyncSchema } from "@app/s
import { BitbucketSyncListItemSchema, BitbucketSyncSchema } from "@app/services/secret-sync/bitbucket";
import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secret-sync/camunda";
import { ChecklySyncListItemSchema, ChecklySyncSchema } from "@app/services/secret-sync/checkly/checkly-sync-schemas";
import { ChefSyncListItemSchema, ChefSyncSchema } from "@app/services/secret-sync/chef";
import {
CloudflarePagesSyncListItemSchema,
CloudflarePagesSyncSchema
@@ -86,7 +87,8 @@ const SecretSyncSchema = z.discriminatedUnion("destination", [
DigitalOceanAppPlatformSyncSchema,
NetlifySyncSchema,
BitbucketSyncSchema,
LaravelForgeSyncSchema
LaravelForgeSyncSchema,
ChefSyncSchema
]);
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
@@ -120,7 +122,8 @@ const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
SupabaseSyncListItemSchema,
NetlifySyncListItemSchema,
BitbucketSyncListItemSchema,
LaravelForgeSyncListItemSchema
LaravelForgeSyncListItemSchema,
ChefSyncListItemSchema
]);
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {
@@ -7,9 +7,10 @@ import { removeTrailingSlash } from "@app/lib/fn";
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
import { TChefDataBagItemContent } from "../../secret-sync/chef/chef-sync-types";
import { AppConnection } from "../app-connection-enums";
import { ChefConnectionMethod } from "./chef-connection-enums";
import { TChefConnection, TChefConnectionConfig, TChefDataBag } from "./chef-connection-types";
import { TChefConnection, TChefConnectionConfig, TChefDataBag, TChefDataBagItem } from "./chef-connection-types";
export const getChefServerUrl = async (serverUrl?: string) => {
const chefServerUrl = serverUrl ? removeTrailingSlash(serverUrl) : IntegrationUrls.CHEF_API_URL;
@@ -120,40 +121,6 @@ export const getChefConnectionListItem = () => {
};
};
export const listChefDataBags = async (appConnection: TChefConnection): Promise<TChefDataBag[]> => {
const {
credentials: { serverUrl, userName, privateKey }
} = appConnection;
try {
const path = "/data";
const body = "";
const hostServerUrl = await getChefServerUrl(serverUrl);
const headers = getChefAuthHeaders("GET", path, body, userName, privateKey);
const res = await request.get<Record<string, string>>(`${hostServerUrl}${path}`, {
headers
});
// Chef returns data bags as an object with keys being data bag names
return Object.keys(res.data).map((name) => ({
name,
id: name
}));
} catch (error) {
if (error instanceof AxiosError) {
// throw new BadRequestError({
// message: `Failed to list Chef data bags: ${error.response?.data?.error || error.message}`
// });
}
throw new BadRequestError({
message: "Unable to list Chef data bags"
});
}
};
export const validateChefConnectionCredentials = async (config: TChefConnectionConfig) => {
const { credentials: inputCredentials } = config;
@@ -181,16 +148,13 @@ export const validateChefConnectionCredentials = async (config: TChefConnectionC
return inputCredentials;
};
export const listChefDataBagItems = async (
appConnection: TChefConnection,
dataBagName: string
): Promise<TChefDataBag[]> => {
export const listChefDataBags = async (appConnection: TChefConnection): Promise<TChefDataBag[]> => {
const {
credentials: { serverUrl, userName, privateKey }
credentials: { serverUrl, userName, privateKey, orgName }
} = appConnection;
try {
const path = `/data/${dataBagName}`;
const path = `/organizations/${orgName}/data`;
const body = "";
const hostServerUrl = await getChefServerUrl(serverUrl);
@@ -201,10 +165,43 @@ export const listChefDataBagItems = async (
headers
});
// Chef returns data bag items as an object with keys being item names
return Object.keys(res.data).map((name) => ({
name,
id: name
name
}));
} catch (error) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to list Chef data bags: ${error.message || "Unknown error"}`
});
}
throw new BadRequestError({
message: "Unable to list Chef data bags"
});
}
};
export const listChefDataBagItems = async (
appConnection: TChefConnection,
dataBagName: string
): Promise<TChefDataBagItem[]> => {
const {
credentials: { serverUrl, userName, privateKey, orgName }
} = appConnection;
try {
const path = `/organizations/${orgName}/data/${dataBagName}`;
const body = "";
const hostServerUrl = await getChefServerUrl(serverUrl);
const headers = getChefAuthHeaders("GET", path, body, userName, privateKey);
const res = await request.get<Record<string, string>>(`${hostServerUrl}${path}`, {
headers
});
return Object.keys(res.data).map((name) => ({
name
}));
} catch (error) {
if (error instanceof AxiosError) {
@@ -217,3 +214,87 @@ export const listChefDataBagItems = async (
});
}
};
type TGetChefDataBagItem = {
serverUrl?: string;
userName: string;
privateKey: string;
orgName: string;
dataBagName: string;
dataBagItemName: string;
};
export const getChefDataBagItem = async ({
serverUrl,
userName,
privateKey,
orgName,
dataBagName,
dataBagItemName
}: TGetChefDataBagItem): Promise<TChefDataBagItemContent> => {
try {
const path = `/organizations/${orgName}/data/${dataBagName}/${dataBagItemName}`;
const body = "";
const hostServerUrl = await getChefServerUrl(serverUrl);
const headers = getChefAuthHeaders("GET", path, body, userName, privateKey);
const res = await request.get<TChefDataBagItemContent>(`${hostServerUrl}${path}`, {
headers
});
return res.data;
} catch (error) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to get Chef data bag item: ${error.message || "Unknown error"}`
});
}
throw new BadRequestError({
message: "Unable to get Chef data bag item"
});
}
};
type TUpdateChefDataBagItem = {
serverUrl?: string;
userName: string;
privateKey: string;
orgName: string;
dataBagName: string;
dataBagItemName: string;
data: TChefDataBagItemContent;
};
export const updateChefDataBagItem = async ({
serverUrl,
userName,
privateKey,
orgName,
dataBagName,
dataBagItemName,
data
}: TUpdateChefDataBagItem): Promise<void> => {
try {
const path = `/organizations/${orgName}/data/${dataBagName}/${dataBagItemName}`;
const body = JSON.stringify(data);
const hostServerUrl = await getChefServerUrl(serverUrl);
const headers = getChefAuthHeaders("PUT", path, body, userName, privateKey);
await request.put(`${hostServerUrl}${path}`, data, {
headers
});
} catch (error) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to update Chef data bag item: ${error.message || "Unknown error"}`
});
}
throw new BadRequestError({
message: "Unable to update Chef data bag item"
});
}
};
@@ -18,15 +18,13 @@ export type TChefConnectionInput = z.infer<typeof CreateChefConnectionSchema> &
export type TValidateChefConnectionCredentialsSchema = typeof ValidateChefConnectionCredentialsSchema;
export type TChefConnectionConfig = DiscriminativePick<TChefConnectionInput, "method" | "app" | "credentials"> & {
orgId: string;
orgName: string;
};
export type TChefDataBag = {
name: string;
id: string;
};
export type TChefDataBagItem = {
name: string;
id: string;
};
@@ -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 CHEF_SYNC_LIST_OPTION: TSecretSyncListItem = {
name: "Chef",
destination: SecretSync.Chef,
connection: AppConnection.Chef,
canImportSecrets: true
};
@@ -0,0 +1,143 @@
import { getChefDataBagItem, updateChefDataBagItem } from "@app/services/app-connection/chef";
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
import { ChefSecret, TChefDataBagItemContent, TChefSyncWithCredentials, TGetChefSecrets } from "./chef-sync-types";
const getChefSecretsRaw = async ({
serverUrl,
userName,
privateKey,
orgName,
dataBagName,
dataBagItemName
}: TGetChefSecrets): Promise<TChefDataBagItemContent> => {
const dataBagItem = await getChefDataBagItem({
serverUrl,
userName,
privateKey,
orgName,
dataBagName,
dataBagItemName
});
// Ensure the data bag item has an id field
if (!dataBagItem.id) {
dataBagItem.id = dataBagItemName;
}
return dataBagItem;
};
const getChefSecrets = async (secretSync: TChefSyncWithCredentials): Promise<ChefSecret[]> => {
const {
connection,
destinationConfig: { dataBagName, dataBagItemName }
} = secretSync;
const { serverUrl, userName, privateKey, orgName } = connection.credentials;
const dataBagItem = await getChefSecretsRaw({
serverUrl,
orgName,
userName,
privateKey,
dataBagName,
dataBagItemName
});
// Convert data bag item to key-value pairs
// Exclude the 'id' field as it's metadata
const secrets: ChefSecret[] = [];
Object.entries(dataBagItem).forEach(([key, value]) => {
if (key !== "id" && value !== null && value !== undefined) {
secrets.push({ key, value: String(value) });
}
});
return secrets;
};
const updateChefSecrets = async (
secretSync: TChefSyncWithCredentials,
secrets: Record<string, string | number | boolean>
) => {
const {
connection,
destinationConfig: { dataBagName, dataBagItemName }
} = secretSync;
const { serverUrl, userName, privateKey, orgName } = connection.credentials;
// Chef data bag items must have an 'id' field
const dataBagItemContent: TChefDataBagItemContent = {
id: dataBagItemName,
...secrets
};
await updateChefDataBagItem({
serverUrl,
orgName,
userName,
privateKey,
dataBagName,
dataBagItemName,
data: dataBagItemContent
});
};
export const ChefSyncFns = {
async syncSecrets(secretSync: TChefSyncWithCredentials, secretMap: TSecretMap) {
const {
environment,
syncOptions: { disableSecretDeletion, keySchema }
} = secretSync;
const secrets = await getChefSecrets(secretSync);
// Create a map of the existing secrets
const updatedSecretsMap = new Map(secrets.map((secret) => [secret.key, secret.value]));
// Add/update new secrets
for (const [key, { value }] of Object.entries(secretMap)) {
updatedSecretsMap.set(key, value);
}
// Delete secrets if not disabled
if (!disableSecretDeletion) {
secrets.forEach((secret) => {
if (!matchesSchema(secret.key, environment?.slug || "", keySchema)) return;
if (!secretMap[secret.key]) {
updatedSecretsMap.delete(secret.key);
}
});
}
// Convert map to object for Chef API
const updatedSecrets = Object.fromEntries(updatedSecretsMap.entries());
await updateChefSecrets(secretSync, updatedSecrets);
},
async getSecrets(secretSync: TChefSyncWithCredentials): Promise<TSecretMap> {
const secrets = await getChefSecrets(secretSync);
return Object.fromEntries(secrets.map((secret) => [secret.key, { value: secret.value }]));
},
async removeSecrets(secretSync: TChefSyncWithCredentials, secretMap: TSecretMap) {
const existingSecrets = await getChefSecrets(secretSync);
const newSecrets = existingSecrets.filter((secret) => !Object.hasOwn(secretMap, secret.key));
// If nothing changed, return early
if (newSecrets.length === existingSecrets.length) {
return;
}
// Convert to object for Chef API
const updatedSecrets = Object.fromEntries(newSecrets.map((secret) => [secret.key, secret.value]));
await updateChefSecrets(secretSync, updatedSecrets);
}
};
@@ -0,0 +1,46 @@
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 ChefSyncDestinationConfigSchema = z.object({
dataBagName: z
.string()
.min(1, "Data Bag Name is required")
.max(256, "Data Bag Name cannot exceed 256 characters")
.describe(SecretSyncs.DESTINATION_CONFIG.CHEF.dataBagName),
dataBagItemName: z
.string()
.min(1, "Data Bag Item Name is required")
.max(256, "Data Bag Item Name cannot exceed 256 characters")
.describe(SecretSyncs.DESTINATION_CONFIG.CHEF.dataBagItemName)
});
const ChefSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
export const ChefSyncSchema = BaseSecretSyncSchema(SecretSync.Chef, ChefSyncOptionsConfig).extend({
destination: z.literal(SecretSync.Chef),
destinationConfig: ChefSyncDestinationConfigSchema
});
export const CreateChefSyncSchema = GenericCreateSecretSyncFieldsSchema(SecretSync.Chef, ChefSyncOptionsConfig).extend({
destinationConfig: ChefSyncDestinationConfigSchema
});
export const UpdateChefSyncSchema = GenericUpdateSecretSyncFieldsSchema(SecretSync.Chef, ChefSyncOptionsConfig).extend({
destinationConfig: ChefSyncDestinationConfigSchema.optional()
});
export const ChefSyncListItemSchema = z.object({
name: z.literal("Chef"),
connection: z.literal(AppConnection.Chef),
destination: z.literal(SecretSync.Chef),
canImportSecrets: z.literal(true)
});
@@ -0,0 +1,34 @@
import z from "zod";
import { TChefConnection } from "@app/services/app-connection/chef";
import { ChefSyncListItemSchema, ChefSyncSchema, CreateChefSyncSchema } from "./chef-sync-schemas";
export type TChefSyncListItem = z.infer<typeof ChefSyncListItemSchema>;
export type TChefSync = z.infer<typeof ChefSyncSchema>;
export type TChefSyncInput = z.infer<typeof CreateChefSyncSchema>;
export type TChefSyncWithCredentials = TChefSync & {
connection: TChefConnection;
};
export type TGetChefSecrets = {
serverUrl?: string;
userName: string;
privateKey: string;
orgName: string;
dataBagName: string;
dataBagItemName: string;
};
export type TChefDataBagItemContent = {
id: string;
[key: string]: string | number | boolean | null;
};
export type ChefSecret = {
key: string;
value: string;
};
@@ -0,0 +1,4 @@
export * from "./chef-sync-constants";
export * from "./chef-sync-fns";
export * from "./chef-sync-schemas";
export * from "./chef-sync-types";
@@ -29,7 +29,8 @@ export enum SecretSync {
DigitalOceanAppPlatform = "digital-ocean-app-platform",
Netlify = "netlify",
Bitbucket = "bitbucket",
LaravelForge = "laravel-forge"
LaravelForge = "laravel-forge",
Chef = "chef"
}
export enum SecretSyncInitialSyncBehavior {
@@ -34,6 +34,7 @@ import { BITBUCKET_SYNC_LIST_OPTION, BitbucketSyncFns } from "./bitbucket";
import { CAMUNDA_SYNC_LIST_OPTION, camundaSyncFactory } from "./camunda";
import { CHECKLY_SYNC_LIST_OPTION } from "./checkly/checkly-sync-constants";
import { ChecklySyncFns } from "./checkly/checkly-sync-fns";
import { CHEF_SYNC_LIST_OPTION, ChefSyncFns } from "./chef";
import { CLOUDFLARE_PAGES_SYNC_LIST_OPTION } from "./cloudflare-pages/cloudflare-pages-constants";
import { CloudflarePagesSyncFns } from "./cloudflare-pages/cloudflare-pages-fns";
import { CLOUDFLARE_WORKERS_SYNC_LIST_OPTION, CloudflareWorkersSyncFns } from "./cloudflare-workers";
@@ -49,8 +50,7 @@ import { HC_VAULT_SYNC_LIST_OPTION, HCVaultSyncFns } from "./hc-vault";
import { HEROKU_SYNC_LIST_OPTION, HerokuSyncFns } from "./heroku";
import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec";
import { HumanitecSyncFns } from "./humanitec/humanitec-sync-fns";
import { LARAVEL_FORGE_SYNC_LIST_OPTION } from "./laravel-forge";
import { LaravelForgeSyncFns } from "./laravel-forge/laravel-forge-sync-fns";
import { LARAVEL_FORGE_SYNC_LIST_OPTION, LaravelForgeSyncFns } from "./laravel-forge";
import { NETLIFY_SYNC_LIST_OPTION, NetlifySyncFns } from "./netlify";
import { RAILWAY_SYNC_LIST_OPTION } from "./railway/railway-sync-constants";
import { RailwaySyncFns } from "./railway/railway-sync-fns";
@@ -94,7 +94,8 @@ const SECRET_SYNC_LIST_OPTIONS: Record<SecretSync, TSecretSyncListItem> = {
[SecretSync.DigitalOceanAppPlatform]: DIGITAL_OCEAN_APP_PLATFORM_SYNC_LIST_OPTION,
[SecretSync.Netlify]: NETLIFY_SYNC_LIST_OPTION,
[SecretSync.Bitbucket]: BITBUCKET_SYNC_LIST_OPTION,
[SecretSync.LaravelForge]: LARAVEL_FORGE_SYNC_LIST_OPTION
[SecretSync.LaravelForge]: LARAVEL_FORGE_SYNC_LIST_OPTION,
[SecretSync.Chef]: CHEF_SYNC_LIST_OPTION
};
export const listSecretSyncOptions = () => {
@@ -282,6 +283,8 @@ export const SecretSyncFns = {
return BitbucketSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.LaravelForge:
return LaravelForgeSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Chef:
return ChefSyncFns.syncSecrets(secretSync, schemaSecretMap);
default:
throw new Error(
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
@@ -401,6 +404,9 @@ export const SecretSyncFns = {
case SecretSync.LaravelForge:
secretMap = await LaravelForgeSyncFns.getSecrets(secretSync);
break;
case SecretSync.Chef:
secretMap = await ChefSyncFns.getSecrets(secretSync);
break;
default:
throw new Error(
`Unhandled sync destination for get secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
@@ -496,6 +502,8 @@ export const SecretSyncFns = {
return BitbucketSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.LaravelForge:
return LaravelForgeSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Chef:
return ChefSyncFns.removeSecrets(secretSync, schemaSecretMap);
default:
throw new Error(
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
@@ -33,7 +33,8 @@ export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
[SecretSync.DigitalOceanAppPlatform]: "Digital Ocean App Platform",
[SecretSync.Netlify]: "Netlify",
[SecretSync.Bitbucket]: "Bitbucket",
[SecretSync.LaravelForge]: "Laravel Forge"
[SecretSync.LaravelForge]: "Laravel Forge",
[SecretSync.Chef]: "Chef"
};
export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
@@ -67,7 +68,8 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.DigitalOceanAppPlatform]: AppConnection.DigitalOcean,
[SecretSync.Netlify]: AppConnection.Netlify,
[SecretSync.Bitbucket]: AppConnection.Bitbucket,
[SecretSync.LaravelForge]: AppConnection.LaravelForge
[SecretSync.LaravelForge]: AppConnection.LaravelForge,
[SecretSync.Chef]: AppConnection.Chef
};
export const SECRET_SYNC_PLAN_MAP: Record<SecretSync, SecretSyncPlanType> = {
@@ -101,7 +103,8 @@ export const SECRET_SYNC_PLAN_MAP: Record<SecretSync, SecretSyncPlanType> = {
[SecretSync.DigitalOceanAppPlatform]: SecretSyncPlanType.Regular,
[SecretSync.Netlify]: SecretSyncPlanType.Regular,
[SecretSync.Bitbucket]: SecretSyncPlanType.Regular,
[SecretSync.LaravelForge]: SecretSyncPlanType.Regular
[SecretSync.LaravelForge]: SecretSyncPlanType.Regular,
[SecretSync.Chef]: SecretSyncPlanType.Regular
};
export const SECRET_SYNC_SKIP_FIELDS_MAP: Record<SecretSync, string[]> = {
@@ -144,7 +147,8 @@ export const SECRET_SYNC_SKIP_FIELDS_MAP: Record<SecretSync, string[]> = {
[SecretSync.DigitalOceanAppPlatform]: ["appName"],
[SecretSync.Netlify]: ["accountName", "siteName"],
[SecretSync.Bitbucket]: [],
[SecretSync.LaravelForge]: []
[SecretSync.LaravelForge]: [],
[SecretSync.Chef]: []
};
const defaultDuplicateCheck: DestinationDuplicateCheckFn = () => true;
@@ -204,5 +208,6 @@ export const DESTINATION_DUPLICATE_CHECK_MAP: Record<SecretSync, DestinationDupl
[SecretSync.DigitalOceanAppPlatform]: defaultDuplicateCheck,
[SecretSync.Netlify]: defaultDuplicateCheck,
[SecretSync.Bitbucket]: defaultDuplicateCheck,
[SecretSync.LaravelForge]: defaultDuplicateCheck
[SecretSync.LaravelForge]: defaultDuplicateCheck,
[SecretSync.Chef]: defaultDuplicateCheck
};
@@ -21,6 +21,7 @@ import {
TCamundaSyncListItem,
TCamundaSyncWithCredentials
} from "@app/services/secret-sync/camunda";
import { TChefSync, TChefSyncInput, TChefSyncListItem, TChefSyncWithCredentials } from "@app/services/secret-sync/chef";
import {
TDatabricksSync,
TDatabricksSyncInput,
@@ -163,6 +164,7 @@ export type TSecretSync =
| TGitHubSync
| TGcpSync
| TAzureKeyVaultSync
| TChefSync
| TAzureAppConfigurationSync
| TAzureDevOpsSync
| TDatabricksSync
@@ -195,6 +197,7 @@ export type TSecretSyncWithCredentials =
| TGitHubSyncWithCredentials
| TGcpSyncWithCredentials
| TAzureKeyVaultSyncWithCredentials
| TChefSyncWithCredentials
| TAzureAppConfigurationSyncWithCredentials
| TAzureDevOpsSyncWithCredentials
| TDatabricksSyncWithCredentials
@@ -228,6 +231,7 @@ export type TSecretSyncInput =
| TGitHubSyncInput
| TGcpSyncInput
| TAzureKeyVaultSyncInput
| TChefSyncInput
| TAzureAppConfigurationSyncInput
| TAzureDevOpsSyncInput
| TDatabricksSyncInput
@@ -261,6 +265,7 @@ export type TSecretSyncListItem =
| TGitHubSyncListItem
| TGcpSyncListItem
| TAzureKeyVaultSyncListItem
| TChefSyncListItem
| TAzureAppConfigurationSyncListItem
| TAzureDevOpsSyncListItem
| TDatabricksSyncListItem