Merge pull request #3988 from Infisical/ENG-2932

feat(secret-sync): Cloudflare Workers
This commit is contained in:
x032205
2025-07-11 14:04:54 -04:00
committed by GitHub
56 changed files with 738 additions and 13 deletions
+3
View File
@@ -2472,6 +2472,9 @@ export const SecretSyncs = {
projectName: "The name of the Cloudflare Pages project to sync secrets to.", projectName: "The name of the Cloudflare Pages project to sync secrets to.",
environment: "The environment of the Cloudflare Pages project to sync secrets to." environment: "The environment of the Cloudflare Pages project to sync secrets to."
}, },
CLOUDFLARE_WORKERS: {
scriptId: "The ID of the Cloudflare Workers script to sync secrets to."
},
ZABBIX: { ZABBIX: {
scope: "The Zabbix scope that secrets should be synced to.", scope: "The Zabbix scope that secrets should be synced to.",
hostId: "The ID of the Zabbix host to sync secrets to.", hostId: "The ID of the Zabbix host to sync secrets to.",
@@ -50,4 +50,32 @@ export const registerCloudflareConnectionRouter = async (server: FastifyZodProvi
return projects; return projects;
} }
}); });
server.route({
method: "GET",
url: `/:connectionId/cloudflare-workers-scripts`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const projects = await server.services.appConnection.cloudflare.listWorkersScripts(connectionId, req.permission);
return projects;
}
});
}; };
@@ -0,0 +1,17 @@
import {
CloudflareWorkersSyncSchema,
CreateCloudflareWorkersSyncSchema,
UpdateCloudflareWorkersSyncSchema
} from "@app/services/secret-sync/cloudflare-workers/cloudflare-workers-schemas";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerCloudflareWorkersSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.CloudflareWorkers,
server,
responseSchema: CloudflareWorkersSyncSchema,
createSchema: CreateCloudflareWorkersSyncSchema,
updateSchema: UpdateCloudflareWorkersSyncSchema
});
@@ -9,6 +9,7 @@ import { registerAzureDevOpsSyncRouter } from "./azure-devops-sync-router";
import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router"; import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router";
import { registerCamundaSyncRouter } from "./camunda-sync-router"; import { registerCamundaSyncRouter } from "./camunda-sync-router";
import { registerCloudflarePagesSyncRouter } from "./cloudflare-pages-sync-router"; import { registerCloudflarePagesSyncRouter } from "./cloudflare-pages-sync-router";
import { registerCloudflareWorkersSyncRouter } from "./cloudflare-workers-sync-router";
import { registerDatabricksSyncRouter } from "./databricks-sync-router"; import { registerDatabricksSyncRouter } from "./databricks-sync-router";
import { registerFlyioSyncRouter } from "./flyio-sync-router"; import { registerFlyioSyncRouter } from "./flyio-sync-router";
import { registerGcpSyncRouter } from "./gcp-sync-router"; import { registerGcpSyncRouter } from "./gcp-sync-router";
@@ -50,6 +51,8 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
[SecretSync.Flyio]: registerFlyioSyncRouter, [SecretSync.Flyio]: registerFlyioSyncRouter,
[SecretSync.GitLab]: registerGitLabSyncRouter, [SecretSync.GitLab]: registerGitLabSyncRouter,
[SecretSync.CloudflarePages]: registerCloudflarePagesSyncRouter, [SecretSync.CloudflarePages]: registerCloudflarePagesSyncRouter,
[SecretSync.CloudflareWorkers]: registerCloudflareWorkersSyncRouter,
[SecretSync.Zabbix]: registerZabbixSyncRouter, [SecretSync.Zabbix]: registerZabbixSyncRouter,
[SecretSync.Railway]: registerRailwaySyncRouter [SecretSync.Railway]: registerRailwaySyncRouter
}; };
@@ -26,6 +26,10 @@ import {
CloudflarePagesSyncListItemSchema, CloudflarePagesSyncListItemSchema,
CloudflarePagesSyncSchema CloudflarePagesSyncSchema
} from "@app/services/secret-sync/cloudflare-pages/cloudflare-pages-schema"; } from "@app/services/secret-sync/cloudflare-pages/cloudflare-pages-schema";
import {
CloudflareWorkersSyncListItemSchema,
CloudflareWorkersSyncSchema
} from "@app/services/secret-sync/cloudflare-workers/cloudflare-workers-schemas";
import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks"; import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks";
import { FlyioSyncListItemSchema, FlyioSyncSchema } from "@app/services/secret-sync/flyio"; import { FlyioSyncListItemSchema, FlyioSyncSchema } from "@app/services/secret-sync/flyio";
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp"; import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
@@ -65,6 +69,8 @@ const SecretSyncSchema = z.discriminatedUnion("destination", [
FlyioSyncSchema, FlyioSyncSchema,
GitLabSyncSchema, GitLabSyncSchema,
CloudflarePagesSyncSchema, CloudflarePagesSyncSchema,
CloudflareWorkersSyncSchema,
ZabbixSyncSchema, ZabbixSyncSchema,
RailwaySyncSchema RailwaySyncSchema
]); ]);
@@ -92,6 +98,8 @@ const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
FlyioSyncListItemSchema, FlyioSyncListItemSchema,
GitLabSyncListItemSchema, GitLabSyncListItemSchema,
CloudflarePagesSyncListItemSchema, CloudflarePagesSyncListItemSchema,
CloudflareWorkersSyncListItemSchema,
ZabbixSyncListItemSchema, ZabbixSyncListItemSchema,
RailwaySyncListItemSchema RailwaySyncListItemSchema
]); ]);
@@ -9,7 +9,8 @@ import { CloudflareConnectionMethod } from "./cloudflare-connection-enum";
import { import {
TCloudflareConnection, TCloudflareConnection,
TCloudflareConnectionConfig, TCloudflareConnectionConfig,
TCloudflarePagesProject TCloudflarePagesProject,
TCloudflareWorkersScript
} from "./cloudflare-connection-types"; } from "./cloudflare-connection-types";
export const getCloudflareConnectionListItem = () => { export const getCloudflareConnectionListItem = () => {
@@ -43,6 +44,28 @@ export const listCloudflarePagesProjects = async (
})); }));
}; };
export const listCloudflareWorkersScripts = async (
appConnection: TCloudflareConnection
): Promise<TCloudflareWorkersScript[]> => {
const {
credentials: { apiToken, accountId }
} = appConnection;
const { data } = await request.get<{ result: { id: string }[] }>(
`${IntegrationUrls.CLOUDFLARE_API_URL}/client/v4/accounts/${accountId}/workers/scripts`,
{
headers: {
Authorization: `Bearer ${apiToken}`,
Accept: "application/json"
}
}
);
return data.result.map((a) => ({
id: a.id
}));
};
export const validateCloudflareConnectionCredentials = async (config: TCloudflareConnectionConfig) => { export const validateCloudflareConnectionCredentials = async (config: TCloudflareConnectionConfig) => {
const { apiToken, accountId } = config.credentials; const { apiToken, accountId } = config.credentials;
@@ -2,7 +2,7 @@ import { logger } from "@app/lib/logger";
import { OrgServiceActor } from "@app/lib/types"; import { OrgServiceActor } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums"; import { AppConnection } from "../app-connection-enums";
import { listCloudflarePagesProjects } from "./cloudflare-connection-fns"; import { listCloudflarePagesProjects, listCloudflareWorkersScripts } from "./cloudflare-connection-fns";
import { TCloudflareConnection } from "./cloudflare-connection-types"; import { TCloudflareConnection } from "./cloudflare-connection-types";
type TGetAppConnectionFunc = ( type TGetAppConnectionFunc = (
@@ -19,12 +19,31 @@ export const cloudflareConnectionService = (getAppConnection: TGetAppConnectionF
return projects; return projects;
} catch (error) { } catch (error) {
logger.error(error, "Failed to list Cloudflare Pages projects for Cloudflare connection"); logger.error(
error,
`Failed to list Cloudflare Pages projects for Cloudflare connection [connectionId=${connectionId}]`
);
return [];
}
};
const listWorkersScripts = async (connectionId: string, actor: OrgServiceActor) => {
const appConnection = await getAppConnection(AppConnection.Cloudflare, connectionId, actor);
try {
const projects = await listCloudflareWorkersScripts(appConnection);
return projects;
} catch (error) {
logger.error(
error,
`Failed to list Cloudflare Workers scripts for Cloudflare connection [connectionId=${connectionId}]`
);
return []; return [];
} }
}; };
return { return {
listPagesProjects listPagesProjects,
listWorkersScripts
}; };
}; };
@@ -28,3 +28,7 @@ export type TCloudflarePagesProject = {
id: string; id: string;
name: string; name: string;
}; };
export type TCloudflareWorkersScript = {
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 CLOUDFLARE_WORKERS_SYNC_LIST_OPTION: TSecretSyncListItem = {
name: "Cloudflare Workers",
destination: SecretSync.CloudflareWorkers,
connection: AppConnection.Cloudflare,
canImportSecrets: false
};
@@ -0,0 +1,121 @@
import { request } from "@app/lib/config/request";
import { applyJitter } from "@app/lib/dates";
import { delay as delayMs } from "@app/lib/delay";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
import { TCloudflareWorkersSyncWithCredentials } from "./cloudflare-workers-types";
const getSecretKeys = async (secretSync: TCloudflareWorkersSyncWithCredentials): Promise<string[]> => {
const {
destinationConfig,
connection: {
credentials: { apiToken, accountId }
}
} = secretSync;
const { data } = await request.get<{
result: Array<{ name: string }>;
}>(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accountId}/workers/scripts/${destinationConfig.scriptId}/secrets`,
{
headers: {
Authorization: `Bearer ${apiToken}`,
Accept: "application/json"
}
}
);
return data.result.map((s) => s.name);
};
export const CloudflareWorkersSyncFns = {
syncSecrets: async (secretSync: TCloudflareWorkersSyncWithCredentials, secretMap: TSecretMap) => {
const {
connection: {
credentials: { apiToken, accountId }
},
destinationConfig: { scriptId }
} = secretSync;
const existingSecretNames = await getSecretKeys(secretSync);
const secretMapKeys = new Set(Object.keys(secretMap));
for await (const [key, val] of Object.entries(secretMap)) {
await delayMs(Math.max(0, applyJitter(100, 200)));
await request.put(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accountId}/workers/scripts/${scriptId}/secrets`,
{ name: key, text: val.value, type: "secret_text" },
{
headers: {
Authorization: `Bearer ${apiToken}`,
"Content-Type": "application/json"
}
}
);
}
if (!secretSync.syncOptions.disableSecretDeletion) {
const secretsToDelete = existingSecretNames.filter((existingKey) => {
const isManagedBySchema = matchesSchema(
existingKey,
secretSync.environment?.slug || "",
secretSync.syncOptions.keySchema
);
const isInNewSecretMap = secretMapKeys.has(existingKey);
return !isInNewSecretMap && isManagedBySchema;
});
for await (const key of secretsToDelete) {
await delayMs(Math.max(0, applyJitter(100, 200)));
await request.delete(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accountId}/workers/scripts/${scriptId}/secrets/${key}`,
{
headers: {
Authorization: `Bearer ${apiToken}`
}
}
);
}
}
},
getSecrets: async (secretSync: TCloudflareWorkersSyncWithCredentials): Promise<TSecretMap> => {
throw new Error(`${SECRET_SYNC_NAME_MAP[secretSync.destination]} does not support importing secrets.`);
},
removeSecrets: async (secretSync: TCloudflareWorkersSyncWithCredentials, secretMap: TSecretMap) => {
const {
connection: {
credentials: { apiToken, accountId }
},
destinationConfig: { scriptId }
} = secretSync;
const existingSecretNames = await getSecretKeys(secretSync);
const secretMapToRemoveKeys = new Set(Object.keys(secretMap));
for await (const existingKey of existingSecretNames) {
const isManagedBySchema = matchesSchema(
existingKey,
secretSync.environment?.slug || "",
secretSync.syncOptions.keySchema
);
const isInSecretMapToRemove = secretMapToRemoveKeys.has(existingKey);
if (isInSecretMapToRemove && isManagedBySchema) {
await delayMs(Math.max(0, applyJitter(100, 200)));
await request.delete(
`${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accountId}/workers/scripts/${scriptId}/secrets/${existingKey}`,
{
headers: {
Authorization: `Bearer ${apiToken}`
}
}
);
}
}
}
};
@@ -0,0 +1,55 @@
import RE2 from "re2";
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 CloudflareWorkersSyncDestinationConfigSchema = z.object({
scriptId: z
.string()
.min(1, "Script ID is required")
.max(64)
.refine((val) => {
const re2 = new RE2(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/);
return re2.test(val);
}, "Invalid script ID format")
.describe(SecretSyncs.DESTINATION_CONFIG.CLOUDFLARE_WORKERS.scriptId)
});
const CloudflareWorkersSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: false };
export const CloudflareWorkersSyncSchema = BaseSecretSyncSchema(
SecretSync.CloudflareWorkers,
CloudflareWorkersSyncOptionsConfig
).extend({
destination: z.literal(SecretSync.CloudflareWorkers),
destinationConfig: CloudflareWorkersSyncDestinationConfigSchema
});
export const CreateCloudflareWorkersSyncSchema = GenericCreateSecretSyncFieldsSchema(
SecretSync.CloudflareWorkers,
CloudflareWorkersSyncOptionsConfig
).extend({
destinationConfig: CloudflareWorkersSyncDestinationConfigSchema
});
export const UpdateCloudflareWorkersSyncSchema = GenericUpdateSecretSyncFieldsSchema(
SecretSync.CloudflareWorkers,
CloudflareWorkersSyncOptionsConfig
).extend({
destinationConfig: CloudflareWorkersSyncDestinationConfigSchema.optional()
});
export const CloudflareWorkersSyncListItemSchema = z.object({
name: z.literal("Cloudflare Workers"),
connection: z.literal(AppConnection.Cloudflare),
destination: z.literal(SecretSync.CloudflareWorkers),
canImportSecrets: z.literal(false)
});
@@ -0,0 +1,19 @@
import z from "zod";
import { TCloudflareConnection } from "@app/services/app-connection/cloudflare/cloudflare-connection-types";
import {
CloudflareWorkersSyncListItemSchema,
CloudflareWorkersSyncSchema,
CreateCloudflareWorkersSyncSchema
} from "./cloudflare-workers-schemas";
export type TCloudflareWorkersSyncListItem = z.infer<typeof CloudflareWorkersSyncListItemSchema>;
export type TCloudflareWorkersSync = z.infer<typeof CloudflareWorkersSyncSchema>;
export type TCloudflareWorkersSyncInput = z.infer<typeof CreateCloudflareWorkersSyncSchema>;
export type TCloudflareWorkersSyncWithCredentials = TCloudflareWorkersSync & {
connection: TCloudflareConnection;
};
@@ -0,0 +1,4 @@
export * from "./cloudflare-workers-constants";
export * from "./cloudflare-workers-fns";
export * from "./cloudflare-workers-schemas";
export * from "./cloudflare-workers-types";
@@ -21,6 +21,8 @@ export enum SecretSync {
Flyio = "flyio", Flyio = "flyio",
GitLab = "gitlab", GitLab = "gitlab",
CloudflarePages = "cloudflare-pages", CloudflarePages = "cloudflare-pages",
CloudflareWorkers = "cloudflare-workers",
Zabbix = "zabbix", Zabbix = "zabbix",
Railway = "railway" Railway = "railway"
} }
@@ -31,6 +31,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 { CLOUDFLARE_PAGES_SYNC_LIST_OPTION } from "./cloudflare-pages/cloudflare-pages-constants"; import { CLOUDFLARE_PAGES_SYNC_LIST_OPTION } from "./cloudflare-pages/cloudflare-pages-constants";
import { CloudflarePagesSyncFns } from "./cloudflare-pages/cloudflare-pages-fns"; import { CloudflarePagesSyncFns } from "./cloudflare-pages/cloudflare-pages-fns";
import { CLOUDFLARE_WORKERS_SYNC_LIST_OPTION, CloudflareWorkersSyncFns } from "./cloudflare-workers";
import { FLYIO_SYNC_LIST_OPTION, FlyioSyncFns } from "./flyio"; import { FLYIO_SYNC_LIST_OPTION, FlyioSyncFns } from "./flyio";
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";
@@ -72,6 +73,8 @@ const SECRET_SYNC_LIST_OPTIONS: Record<SecretSync, TSecretSyncListItem> = {
[SecretSync.Flyio]: FLYIO_SYNC_LIST_OPTION, [SecretSync.Flyio]: FLYIO_SYNC_LIST_OPTION,
[SecretSync.GitLab]: GITLAB_SYNC_LIST_OPTION, [SecretSync.GitLab]: GITLAB_SYNC_LIST_OPTION,
[SecretSync.CloudflarePages]: CLOUDFLARE_PAGES_SYNC_LIST_OPTION, [SecretSync.CloudflarePages]: CLOUDFLARE_PAGES_SYNC_LIST_OPTION,
[SecretSync.CloudflareWorkers]: CLOUDFLARE_WORKERS_SYNC_LIST_OPTION,
[SecretSync.Zabbix]: ZABBIX_SYNC_LIST_OPTION, [SecretSync.Zabbix]: ZABBIX_SYNC_LIST_OPTION,
[SecretSync.Railway]: RAILWAY_SYNC_LIST_OPTION [SecretSync.Railway]: RAILWAY_SYNC_LIST_OPTION
}; };
@@ -241,6 +244,8 @@ export const SecretSyncFns = {
return GitLabSyncFns.syncSecrets(secretSync, schemaSecretMap, { appConnectionDAL, kmsService }); return GitLabSyncFns.syncSecrets(secretSync, schemaSecretMap, { appConnectionDAL, kmsService });
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
return CloudflarePagesSyncFns.syncSecrets(secretSync, schemaSecretMap); return CloudflarePagesSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.CloudflareWorkers:
return CloudflareWorkersSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Zabbix: case SecretSync.Zabbix:
return ZabbixSyncFns.syncSecrets(secretSync, schemaSecretMap); return ZabbixSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Railway: case SecretSync.Railway:
@@ -337,6 +342,9 @@ export const SecretSyncFns = {
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
secretMap = await CloudflarePagesSyncFns.getSecrets(secretSync); secretMap = await CloudflarePagesSyncFns.getSecrets(secretSync);
break; break;
case SecretSync.CloudflareWorkers:
secretMap = await CloudflareWorkersSyncFns.getSecrets(secretSync);
break;
case SecretSync.Zabbix: case SecretSync.Zabbix:
secretMap = await ZabbixSyncFns.getSecrets(secretSync); secretMap = await ZabbixSyncFns.getSecrets(secretSync);
break; break;
@@ -420,6 +428,8 @@ export const SecretSyncFns = {
return GitLabSyncFns.removeSecrets(secretSync, schemaSecretMap, { appConnectionDAL, kmsService }); return GitLabSyncFns.removeSecrets(secretSync, schemaSecretMap, { appConnectionDAL, kmsService });
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
return CloudflarePagesSyncFns.removeSecrets(secretSync, schemaSecretMap); return CloudflarePagesSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.CloudflareWorkers:
return CloudflareWorkersSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Zabbix: case SecretSync.Zabbix:
return ZabbixSyncFns.removeSecrets(secretSync, schemaSecretMap); return ZabbixSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Railway: case SecretSync.Railway:
@@ -24,6 +24,8 @@ export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
[SecretSync.Flyio]: "Fly.io", [SecretSync.Flyio]: "Fly.io",
[SecretSync.GitLab]: "GitLab", [SecretSync.GitLab]: "GitLab",
[SecretSync.CloudflarePages]: "Cloudflare Pages", [SecretSync.CloudflarePages]: "Cloudflare Pages",
[SecretSync.CloudflareWorkers]: "Cloudflare Workers",
[SecretSync.Zabbix]: "Zabbix", [SecretSync.Zabbix]: "Zabbix",
[SecretSync.Railway]: "Railway" [SecretSync.Railway]: "Railway"
}; };
@@ -51,6 +53,8 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.Flyio]: AppConnection.Flyio, [SecretSync.Flyio]: AppConnection.Flyio,
[SecretSync.GitLab]: AppConnection.GitLab, [SecretSync.GitLab]: AppConnection.GitLab,
[SecretSync.CloudflarePages]: AppConnection.Cloudflare, [SecretSync.CloudflarePages]: AppConnection.Cloudflare,
[SecretSync.CloudflareWorkers]: AppConnection.Cloudflare,
[SecretSync.Zabbix]: AppConnection.Zabbix, [SecretSync.Zabbix]: AppConnection.Zabbix,
[SecretSync.Railway]: AppConnection.Railway [SecretSync.Railway]: AppConnection.Railway
}; };
@@ -78,6 +82,8 @@ export const SECRET_SYNC_PLAN_MAP: Record<SecretSync, SecretSyncPlanType> = {
[SecretSync.Flyio]: SecretSyncPlanType.Regular, [SecretSync.Flyio]: SecretSyncPlanType.Regular,
[SecretSync.GitLab]: SecretSyncPlanType.Regular, [SecretSync.GitLab]: SecretSyncPlanType.Regular,
[SecretSync.CloudflarePages]: SecretSyncPlanType.Regular, [SecretSync.CloudflarePages]: SecretSyncPlanType.Regular,
[SecretSync.CloudflareWorkers]: SecretSyncPlanType.Regular,
[SecretSync.Zabbix]: SecretSyncPlanType.Regular, [SecretSync.Zabbix]: SecretSyncPlanType.Regular,
[SecretSync.Railway]: SecretSyncPlanType.Regular [SecretSync.Railway]: SecretSyncPlanType.Regular
}; };
@@ -78,6 +78,12 @@ import {
TCloudflarePagesSyncListItem, TCloudflarePagesSyncListItem,
TCloudflarePagesSyncWithCredentials TCloudflarePagesSyncWithCredentials
} from "./cloudflare-pages/cloudflare-pages-types"; } from "./cloudflare-pages/cloudflare-pages-types";
import {
TCloudflareWorkersSync,
TCloudflareWorkersSyncInput,
TCloudflareWorkersSyncListItem,
TCloudflareWorkersSyncWithCredentials
} from "./cloudflare-workers";
import { TFlyioSync, TFlyioSyncInput, TFlyioSyncListItem, TFlyioSyncWithCredentials } from "./flyio/flyio-sync-types"; import { TFlyioSync, TFlyioSyncInput, TFlyioSyncListItem, TFlyioSyncWithCredentials } from "./flyio/flyio-sync-types";
import { TGcpSync, TGcpSyncInput, TGcpSyncListItem, TGcpSyncWithCredentials } from "./gcp"; import { TGcpSync, TGcpSyncInput, TGcpSyncListItem, TGcpSyncWithCredentials } from "./gcp";
import { TGitLabSync, TGitLabSyncInput, TGitLabSyncListItem, TGitLabSyncWithCredentials } from "./gitlab"; import { TGitLabSync, TGitLabSyncInput, TGitLabSyncListItem, TGitLabSyncWithCredentials } from "./gitlab";
@@ -144,6 +150,7 @@ export type TSecretSync =
| TFlyioSync | TFlyioSync
| TGitLabSync | TGitLabSync
| TCloudflarePagesSync | TCloudflarePagesSync
| TCloudflareWorkersSync
| TZabbixSync | TZabbixSync
| TRailwaySync; | TRailwaySync;
@@ -170,6 +177,7 @@ export type TSecretSyncWithCredentials =
| TFlyioSyncWithCredentials | TFlyioSyncWithCredentials
| TGitLabSyncWithCredentials | TGitLabSyncWithCredentials
| TCloudflarePagesSyncWithCredentials | TCloudflarePagesSyncWithCredentials
| TCloudflareWorkersSyncWithCredentials
| TZabbixSyncWithCredentials | TZabbixSyncWithCredentials
| TRailwaySyncWithCredentials; | TRailwaySyncWithCredentials;
@@ -196,6 +204,7 @@ export type TSecretSyncInput =
| TFlyioSyncInput | TFlyioSyncInput
| TGitLabSyncInput | TGitLabSyncInput
| TCloudflarePagesSyncInput | TCloudflarePagesSyncInput
| TCloudflareWorkersSyncInput
| TZabbixSyncInput | TZabbixSyncInput
| TRailwaySyncInput; | TRailwaySyncInput;
@@ -222,6 +231,7 @@ export type TSecretSyncListItem =
| TFlyioSyncListItem | TFlyioSyncListItem
| TGitLabSyncListItem | TGitLabSyncListItem
| TCloudflarePagesSyncListItem | TCloudflarePagesSyncListItem
| TCloudflareWorkersSyncListItem
| TZabbixSyncListItem | TZabbixSyncListItem
| TRailwaySyncListItem; | TRailwaySyncListItem;
@@ -0,0 +1,4 @@
---
title: "Create"
openapi: "POST /api/v1/secret-syncs/cloudflare-workers"
---
@@ -0,0 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/secret-syncs/cloudflare-workers/{syncId}"
---
@@ -0,0 +1,4 @@
---
title: "Get by ID"
openapi: "GET /api/v1/secret-syncs/cloudflare-workers/{syncId}"
---
@@ -0,0 +1,4 @@
---
title: "Get by Name"
openapi: "GET /api/v1/secret-syncs/cloudflare-workers/sync-name/{syncName}"
---
@@ -0,0 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/secret-syncs/cloudflare-workers"
---
@@ -0,0 +1,4 @@
---
title: "Remove Secrets"
openapi: "POST /api/v1/secret-syncs/cloudflare-workers/{syncId}/remove-secrets"
---
@@ -0,0 +1,4 @@
---
title: "Sync Secrets"
openapi: "POST /api/v1/secret-syncs/cloudflare-workers/{syncId}/sync-secrets"
---
@@ -0,0 +1,4 @@
---
title: "Update"
openapi: "PATCH /api/v1/secret-syncs/cloudflare-workers/{syncId}"
---
+14
View File
@@ -514,6 +514,7 @@
"integrations/secret-syncs/azure-key-vault", "integrations/secret-syncs/azure-key-vault",
"integrations/secret-syncs/camunda", "integrations/secret-syncs/camunda",
"integrations/secret-syncs/cloudflare-pages", "integrations/secret-syncs/cloudflare-pages",
"integrations/secret-syncs/cloudflare-workers",
"integrations/secret-syncs/databricks", "integrations/secret-syncs/databricks",
"integrations/secret-syncs/flyio", "integrations/secret-syncs/flyio",
"integrations/secret-syncs/gcp-secret-manager", "integrations/secret-syncs/gcp-secret-manager",
@@ -1720,6 +1721,19 @@
"api-reference/endpoints/secret-syncs/cloudflare-pages/remove-secrets" "api-reference/endpoints/secret-syncs/cloudflare-pages/remove-secrets"
] ]
}, },
{
"group": "Cloudflare Workers",
"pages": [
"api-reference/endpoints/secret-syncs/cloudflare-workers/list",
"api-reference/endpoints/secret-syncs/cloudflare-workers/get-by-id",
"api-reference/endpoints/secret-syncs/cloudflare-workers/get-by-name",
"api-reference/endpoints/secret-syncs/cloudflare-workers/create",
"api-reference/endpoints/secret-syncs/cloudflare-workers/update",
"api-reference/endpoints/secret-syncs/cloudflare-workers/delete",
"api-reference/endpoints/secret-syncs/cloudflare-workers/sync-secrets",
"api-reference/endpoints/secret-syncs/cloudflare-workers/remove-secrets"
]
},
{ {
"group": "Databricks", "group": "Databricks",
"pages": [ "pages": [
Binary file not shown.

After

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 KiB

@@ -35,6 +35,17 @@ Infisical supports connecting to Cloudflare using API tokens and Account ID for
- **Account** - **Cloudflare Pages** - **Edit** - **Account** - **Cloudflare Pages** - **Edit**
- **Account** - **Account Settings** - **Read** - **Account** - **Account Settings** - **Read**
Add these permissions to your API token and click **Continue to summary**, then **Create Token** to generate your API token.
</Accordion>
<Accordion title="Cloudflare Workers">
Use the following permissions to grant Infisical access to sync secrets to Cloudflare Workers:
![Configure Token](/images/app-connections/cloudflare/cloudflare-workers-configure-permissions.png)
**Required Permissions:**
- **Account** - **Workers Scripts** - **Edit**
- **Account** - **Account Settings** - **Read**
Add these permissions to your API token and click **Continue to summary**, then **Create Token** to generate your API token. Add these permissions to your API token and click **Continue to summary**, then **Create Token** to generate your API token.
</Accordion> </Accordion>
</AccordionGroup> </AccordionGroup>
@@ -44,7 +55,7 @@ Infisical supports connecting to Cloudflare using API tokens and Account ID for
</Step> </Step>
<Step title="Save Your API Token"> <Step title="Save Your API Token">
After creation, copy and securely store your API token as it will not be shown again. After creation, copy and securely store your API token as it will not be shown again.
![Generated API Token](/images/app-connections/cloudflare/cloudflare-generated-token.png) ![Generated API Token](/images/app-connections/cloudflare/cloudflare-generated-token.png)
<Warning> <Warning>
@@ -0,0 +1,128 @@
---
title: "Cloudflare Workers Sync"
description: "Learn how to configure a Cloudflare Workers Sync for Infisical."
---
**Prerequisites:**
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
- Create a [Cloudflare Connection](/integrations/app-connections/cloudflare)
<Tabs>
<Tab title="Infisical UI">
1. Navigate to **Project** > **Integrations** and select the **Secret Syncs** tab. Click on the **Add Sync** button.
![Secret Syncs Tab](/images/secret-syncs/general/secret-sync-tab.png)
2. Select the **Cloudflare Workers** option.
![Select Cloudflare Workers](/images/secret-syncs/cloudflare-workers/select-cloudflare-workers-option.png)
3. Configure the **Source** from where secrets should be retrieved, then click **Next**.
![Configure Source](/images/secret-syncs/cloudflare-workers/cloudflare-workers-sync-source.png)
- **Environment**: The project environment to retrieve secrets from.
- **Secret Path**: The folder path to retrieve secrets from.
<Tip>
If you need to sync secrets from multiple folder locations, check out [secret imports](/documentation/platform/secret-reference#secret-imports).
</Tip>
4. Configure the **Destination** to where secrets should be deployed, then click **Next**.
![Configure Destination](/images/secret-syncs/cloudflare-workers/cloudflare-workers-sync-destination.png)
- **Cloudflare Connection**: The Cloudflare Connection to authenticate with.
- **Cloudflare Workers Script**: Choose the Cloudflare Workers script you want to sync secrets to.
5. Configure the **Sync Options** to specify how secrets should be synced, then click **Next**.
![Configure Options](/images/secret-syncs/cloudflare-workers/cloudflare-workers-sync-options.png)
- **Initial Sync Behavior**: Determines how Infisical should resolve the initial sync.
- **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical.
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name and `{{environment}}` for the environment.
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
6. Configure the **Details** of your Cloudflare Workers Sync, then click **Next**.
![Configure Details](/images/secret-syncs/cloudflare-workers/cloudflare-workers-sync-details.png)
- **Name**: The name of your sync. Must be slug-friendly.
- **Description**: An optional description for your sync.
7. Review your Cloudflare Workers Sync configuration, then click **Create Sync**.
![Confirm Configuration](/images/secret-syncs/cloudflare-workers/cloudflare-workers-sync-review.png)
8. If enabled, your Cloudflare Workers Sync will begin syncing your secrets to the destination endpoint.
![Sync Secrets](/images/secret-syncs/cloudflare-workers/cloudflare-workers-sync-created.png)
</Tab>
<Tab title="API">
To create a **Cloudflare Workers Sync**, make an API request to the [Create Cloudflare Workers Sync](/api-reference/endpoints/secret-syncs/cloudflare-workers/create) API endpoint.
### Sample request
```bash Request
curl --request POST \
--url https://app.infisical.com/api/v1/secret-syncs/cloudflare-workers \
--header 'Content-Type: application/json' \
--data '{
"name": "my-cloudflare-workers-sync",
"projectId": "your-project-id",
"description": "an example sync",
"connectionId": "your-cloudflare-connection-id",
"environment": "production",
"secretPath": "/my-secrets",
"isEnabled": true,
"syncOptions": {
"initialSyncBehavior": "overwrite-destination"
},
"destinationConfig": {
"scriptId": "my-workers-script"
}
}'
```
### Sample response
```bash Response
{
"secretSync": {
"id": "your-sync-id",
"name": "my-cloudflare-workers-sync",
"description": "an example sync",
"isEnabled": true,
"version": 1,
"folderId": "your-folder-id",
"connectionId": "your-cloudflare-connection-id",
"createdAt": "2024-05-01T12:00:00Z",
"updatedAt": "2024-05-01T12:00:00Z",
"syncStatus": "succeeded",
"lastSyncJobId": "123",
"lastSyncMessage": null,
"lastSyncedAt": "2024-05-01T12:00:00Z",
"syncOptions": {
"initialSyncBehavior": "overwrite-destination"
},
"projectId": "your-project-id",
"connection": {
"app": "cloudflare",
"name": "my-cloudflare-connection",
"id": "your-cloudflare-connection-id"
},
"environment": {
"slug": "production",
"name": "Production",
"id": "your-env-id"
},
"folder": {
"id": "your-folder-id",
"path": "/my-secrets"
},
"destination": "cloudflare-workers",
"destinationConfig": {
"scriptId": "my-workers-script"
}
}
}
```
</Tab>
</Tabs>
@@ -4,7 +4,7 @@ import { SingleValue } from "react-select";
import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField"; import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField";
import { FilterableSelect, FormControl, Select, SelectItem } from "@app/components/v2"; import { FilterableSelect, FormControl, Select, SelectItem } from "@app/components/v2";
import { import {
TCloudflareProject, TCloudflarePagesProject,
useCloudflareConnectionListPagesProjects useCloudflareConnectionListPagesProjects
} from "@app/hooks/api/appConnections/cloudflare"; } from "@app/hooks/api/appConnections/cloudflare";
import { SecretSync } from "@app/hooks/api/secretSyncs"; import { SecretSync } from "@app/hooks/api/secretSyncs";
@@ -52,7 +52,7 @@ export const CloudflarePagesSyncFields = () => {
isDisabled={!connectionId} isDisabled={!connectionId}
value={projects ? (projects.find((project) => project.name === value) ?? []) : []} value={projects ? (projects.find((project) => project.name === value) ?? []) : []}
onChange={(option) => { onChange={(option) => {
onChange((option as SingleValue<TCloudflareProject>)?.name ?? null); onChange((option as SingleValue<TCloudflarePagesProject>)?.name ?? null);
}} }}
options={projects} options={projects}
placeholder="Select a project..." placeholder="Select a project..."
@@ -0,0 +1,59 @@
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 {
TCloudflareWorkersScript,
useCloudflareConnectionListWorkersScripts
} from "@app/hooks/api/appConnections/cloudflare";
import { SecretSync } from "@app/hooks/api/secretSyncs";
import { TSecretSyncForm } from "../schemas";
export const CloudflareWorkersSyncFields = () => {
const { control, setValue } = useFormContext<
TSecretSyncForm & { destination: SecretSync.CloudflareWorkers }
>();
const connectionId = useWatch({ name: "connection.id", control });
const { data: scripts = [], isPending: isScriptsPending } =
useCloudflareConnectionListWorkersScripts(connectionId, {
enabled: Boolean(connectionId)
});
return (
<>
<SecretSyncConnectionField
onChange={() => {
setValue("destinationConfig.scriptId", "");
}}
/>
<Controller
name="destinationConfig.scriptId"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Worker Script"
>
<FilterableSelect
isLoading={isScriptsPending && Boolean(connectionId)}
isDisabled={!connectionId}
value={scripts?.find((script) => script.id === value) || []}
onChange={(option) => {
onChange((option as SingleValue<TCloudflareWorkersScript>)?.id ?? null);
}}
options={scripts}
placeholder="Select a worker script..."
getOptionLabel={(option) => option.id}
getOptionValue={(option) => option.id}
/>
</FormControl>
)}
/>
</>
);
};
@@ -11,6 +11,7 @@ import { AzureDevOpsSyncFields } from "./AzureDevOpsSyncFields";
import { AzureKeyVaultSyncFields } from "./AzureKeyVaultSyncFields"; import { AzureKeyVaultSyncFields } from "./AzureKeyVaultSyncFields";
import { CamundaSyncFields } from "./CamundaSyncFields"; import { CamundaSyncFields } from "./CamundaSyncFields";
import { CloudflarePagesSyncFields } from "./CloudflarePagesSyncFields"; import { CloudflarePagesSyncFields } from "./CloudflarePagesSyncFields";
import { CloudflareWorkersSyncFields } from "./CloudflareWorkersSyncFields";
import { DatabricksSyncFields } from "./DatabricksSyncFields"; import { DatabricksSyncFields } from "./DatabricksSyncFields";
import { FlyioSyncFields } from "./FlyioSyncFields"; import { FlyioSyncFields } from "./FlyioSyncFields";
import { GcpSyncFields } from "./GcpSyncFields"; import { GcpSyncFields } from "./GcpSyncFields";
@@ -78,6 +79,8 @@ export const SecretSyncDestinationFields = () => {
return <GitLabSyncFields />; return <GitLabSyncFields />;
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
return <CloudflarePagesSyncFields />; return <CloudflarePagesSyncFields />;
case SecretSync.CloudflareWorkers:
return <CloudflareWorkersSyncFields />;
case SecretSync.Zabbix: case SecretSync.Zabbix:
return <ZabbixSyncFields />; return <ZabbixSyncFields />;
case SecretSync.Railway: case SecretSync.Railway:
@@ -58,6 +58,7 @@ export const SecretSyncOptionsFields = ({ hideInitialSync }: Props) => {
case SecretSync.Flyio: case SecretSync.Flyio:
case SecretSync.GitLab: case SecretSync.GitLab:
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
case SecretSync.CloudflareWorkers:
case SecretSync.Zabbix: case SecretSync.Zabbix:
case SecretSync.Railway: case SecretSync.Railway:
AdditionalSyncOptionsFieldsComponent = null; AdditionalSyncOptionsFieldsComponent = null;
@@ -0,0 +1,14 @@
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 CloudflareWorkersSyncReviewFields = () => {
const { watch } = useFormContext<
TSecretSyncForm & { destination: SecretSync.CloudflareWorkers }
>();
const scriptId = watch("destinationConfig.scriptId");
return <GenericFieldLabel label="Script">{scriptId}</GenericFieldLabel>;
};
@@ -20,6 +20,7 @@ import { AzureDevOpsSyncReviewFields } from "./AzureDevOpsSyncReviewFields";
import { AzureKeyVaultSyncReviewFields } from "./AzureKeyVaultSyncReviewFields"; import { AzureKeyVaultSyncReviewFields } from "./AzureKeyVaultSyncReviewFields";
import { CamundaSyncReviewFields } from "./CamundaSyncReviewFields"; import { CamundaSyncReviewFields } from "./CamundaSyncReviewFields";
import { CloudflarePagesSyncReviewFields } from "./CloudflarePagesReviewFields"; import { CloudflarePagesSyncReviewFields } from "./CloudflarePagesReviewFields";
import { CloudflareWorkersSyncReviewFields } from "./CloudflareWorkersReviewFields";
import { DatabricksSyncReviewFields } from "./DatabricksSyncReviewFields"; import { DatabricksSyncReviewFields } from "./DatabricksSyncReviewFields";
import { FlyioSyncReviewFields } from "./FlyioSyncReviewFields"; import { FlyioSyncReviewFields } from "./FlyioSyncReviewFields";
import { GcpSyncReviewFields } from "./GcpSyncReviewFields"; import { GcpSyncReviewFields } from "./GcpSyncReviewFields";
@@ -126,6 +127,9 @@ export const SecretSyncReviewFields = () => {
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
DestinationFieldsComponent = <CloudflarePagesSyncReviewFields />; DestinationFieldsComponent = <CloudflarePagesSyncReviewFields />;
break; break;
case SecretSync.CloudflareWorkers:
DestinationFieldsComponent = <CloudflareWorkersSyncReviewFields />;
break;
case SecretSync.Zabbix: case SecretSync.Zabbix:
DestinationFieldsComponent = <ZabbixSyncReviewFields />; DestinationFieldsComponent = <ZabbixSyncReviewFields />;
break; break;
@@ -0,0 +1,18 @@
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 CloudflareWorkersSyncDestinationSchema = BaseSecretSyncSchema().merge(
z.object({
destination: z.literal(SecretSync.CloudflareWorkers),
destinationConfig: z.object({
scriptId: z
.string()
.trim()
.min(1, "Script ID is required")
.max(64)
.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "Invalid script ID format")
})
})
);
@@ -8,6 +8,7 @@ import { AzureDevOpsSyncDestinationSchema } from "./azure-devops-sync-destinatio
import { AzureKeyVaultSyncDestinationSchema } from "./azure-key-vault-sync-destination-schema"; import { AzureKeyVaultSyncDestinationSchema } from "./azure-key-vault-sync-destination-schema";
import { CamundaSyncDestinationSchema } from "./camunda-sync-destination-schema"; import { CamundaSyncDestinationSchema } from "./camunda-sync-destination-schema";
import { CloudflarePagesSyncDestinationSchema } from "./cloudflare-pages-sync-destination-schema"; import { CloudflarePagesSyncDestinationSchema } from "./cloudflare-pages-sync-destination-schema";
import { CloudflareWorkersSyncDestinationSchema } from "./cloudflare-workers-sync-destination-schema";
import { DatabricksSyncDestinationSchema } from "./databricks-sync-destination-schema"; import { DatabricksSyncDestinationSchema } from "./databricks-sync-destination-schema";
import { FlyioSyncDestinationSchema } from "./flyio-sync-destination-schema"; import { FlyioSyncDestinationSchema } from "./flyio-sync-destination-schema";
import { GcpSyncDestinationSchema } from "./gcp-sync-destination-schema"; import { GcpSyncDestinationSchema } from "./gcp-sync-destination-schema";
@@ -48,6 +49,8 @@ const SecretSyncUnionSchema = z.discriminatedUnion("destination", [
FlyioSyncDestinationSchema, FlyioSyncDestinationSchema,
GitlabSyncDestinationSchema, GitlabSyncDestinationSchema,
CloudflarePagesSyncDestinationSchema, CloudflarePagesSyncDestinationSchema,
CloudflareWorkersSyncDestinationSchema,
ZabbixSyncDestinationSchema, ZabbixSyncDestinationSchema,
RailwaySyncDestinationSchema RailwaySyncDestinationSchema
]); ]);
+6
View File
@@ -82,6 +82,10 @@ export const SECRET_SYNC_MAP: Record<SecretSync, { name: string; image: string }
name: "Cloudflare Pages", name: "Cloudflare Pages",
image: "Cloudflare.png" image: "Cloudflare.png"
}, },
[SecretSync.CloudflareWorkers]: {
name: "Cloudflare Workers",
image: "Cloudflare.png"
},
[SecretSync.Zabbix]: { [SecretSync.Zabbix]: {
name: "Zabbix", name: "Zabbix",
image: "Zabbix.png" image: "Zabbix.png"
@@ -115,6 +119,8 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.Flyio]: AppConnection.Flyio, [SecretSync.Flyio]: AppConnection.Flyio,
[SecretSync.GitLab]: AppConnection.Gitlab, [SecretSync.GitLab]: AppConnection.Gitlab,
[SecretSync.CloudflarePages]: AppConnection.Cloudflare, [SecretSync.CloudflarePages]: AppConnection.Cloudflare,
[SecretSync.CloudflareWorkers]: AppConnection.Cloudflare,
[SecretSync.Zabbix]: AppConnection.Zabbix, [SecretSync.Zabbix]: AppConnection.Zabbix,
[SecretSync.Railway]: AppConnection.Railway [SecretSync.Railway]: AppConnection.Railway
}; };
@@ -3,21 +3,23 @@ import { useQuery, UseQueryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request"; import { apiRequest } from "@app/config/request";
import { appConnectionKeys } from "../queries"; import { appConnectionKeys } from "../queries";
import { TCloudflareProject } from "./types"; import { TCloudflarePagesProject, TCloudflareWorkersScript } from "./types";
const cloudflareConnectionKeys = { const cloudflareConnectionKeys = {
all: [...appConnectionKeys.all, "cloudflare"] as const, all: [...appConnectionKeys.all, "cloudflare"] as const,
listPagesProjects: (connectionId: string) => listPagesProjects: (connectionId: string) =>
[...cloudflareConnectionKeys.all, "pages-projects", connectionId] as const [...cloudflareConnectionKeys.all, "pages-projects", connectionId] as const,
listWorkersScripts: (connectionId: string) =>
[...cloudflareConnectionKeys.all, "workers-scripts", connectionId] as const
}; };
export const useCloudflareConnectionListPagesProjects = ( export const useCloudflareConnectionListPagesProjects = (
connectionId: string, connectionId: string,
options?: Omit< options?: Omit<
UseQueryOptions< UseQueryOptions<
TCloudflareProject[], TCloudflarePagesProject[],
unknown, unknown,
TCloudflareProject[], TCloudflarePagesProject[],
ReturnType<typeof cloudflareConnectionKeys.listPagesProjects> ReturnType<typeof cloudflareConnectionKeys.listPagesProjects>
>, >,
"queryKey" | "queryFn" "queryKey" | "queryFn"
@@ -26,7 +28,7 @@ export const useCloudflareConnectionListPagesProjects = (
return useQuery({ return useQuery({
queryKey: cloudflareConnectionKeys.listPagesProjects(connectionId), queryKey: cloudflareConnectionKeys.listPagesProjects(connectionId),
queryFn: async () => { queryFn: async () => {
const { data } = await apiRequest.get<TCloudflareProject[]>( const { data } = await apiRequest.get<TCloudflarePagesProject[]>(
`/api/v1/app-connections/cloudflare/${connectionId}/cloudflare-pages-projects` `/api/v1/app-connections/cloudflare/${connectionId}/cloudflare-pages-projects`
); );
@@ -35,3 +37,28 @@ export const useCloudflareConnectionListPagesProjects = (
...options ...options
}); });
}; };
export const useCloudflareConnectionListWorkersScripts = (
connectionId: string,
options?: Omit<
UseQueryOptions<
TCloudflareWorkersScript[],
unknown,
TCloudflareWorkersScript[],
ReturnType<typeof cloudflareConnectionKeys.listWorkersScripts>
>,
"queryKey" | "queryFn"
>
) => {
return useQuery({
queryKey: cloudflareConnectionKeys.listWorkersScripts(connectionId),
queryFn: async () => {
const { data } = await apiRequest.get<TCloudflareWorkersScript[]>(
`/api/v1/app-connections/cloudflare/${connectionId}/cloudflare-workers-scripts`
);
return data;
},
...options
});
};
@@ -1,4 +1,8 @@
export type TCloudflareProject = { export type TCloudflarePagesProject = {
id: string; id: string;
name: string; name: string;
}; };
export type TCloudflareWorkersScript = {
id: string;
};
@@ -21,6 +21,8 @@ export enum SecretSync {
Flyio = "flyio", Flyio = "flyio",
GitLab = "gitlab", GitLab = "gitlab",
CloudflarePages = "cloudflare-pages", CloudflarePages = "cloudflare-pages",
CloudflareWorkers = "cloudflare-workers",
Zabbix = "zabbix", Zabbix = "zabbix",
Railway = "railway" Railway = "railway"
} }
@@ -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 TCloudflareWorkersSync = TRootSecretSync & {
destination: SecretSync.CloudflareWorkers;
destinationConfig: {
scriptId: string;
};
connection: {
app: AppConnection.Cloudflare;
name: string;
id: string;
};
};
@@ -10,6 +10,7 @@ import { TAzureDevOpsSync } from "./azure-devops-sync";
import { TAzureKeyVaultSync } from "./azure-key-vault-sync"; import { TAzureKeyVaultSync } from "./azure-key-vault-sync";
import { TCamundaSync } from "./camunda-sync"; import { TCamundaSync } from "./camunda-sync";
import { TCloudflarePagesSync } from "./cloudflare-pages-sync"; import { TCloudflarePagesSync } from "./cloudflare-pages-sync";
import { TCloudflareWorkersSync } from "./cloudflare-workers-sync";
import { TDatabricksSync } from "./databricks-sync"; import { TDatabricksSync } from "./databricks-sync";
import { TFlyioSync } from "./flyio-sync"; import { TFlyioSync } from "./flyio-sync";
import { TGcpSync } from "./gcp-sync"; import { TGcpSync } from "./gcp-sync";
@@ -56,6 +57,7 @@ export type TSecretSync =
| TFlyioSync | TFlyioSync
| TGitLabSync | TGitLabSync
| TCloudflarePagesSync | TCloudflarePagesSync
| TCloudflareWorkersSync
| TZabbixSync | TZabbixSync
| TRailwaySync; | TRailwaySync;
@@ -0,0 +1,14 @@
import { TCloudflareWorkersSync } from "@app/hooks/api/secretSyncs/types/cloudflare-workers-sync";
import { getSecretSyncDestinationColValues } from "../helpers";
import { SecretSyncTableCell } from "../SecretSyncTableCell";
type Props = {
secretSync: TCloudflareWorkersSync;
};
export const CloudflareWorkersSyncDestinationCol = ({ secretSync }: Props) => {
const { primaryText, secondaryText } = getSecretSyncDestinationColValues(secretSync);
return <SecretSyncTableCell primaryText={primaryText} secondaryText={secondaryText} />;
};
@@ -8,6 +8,7 @@ import { AzureDevOpsSyncDestinationCol } from "./AzureDevOpsSyncDestinationCol";
import { AzureKeyVaultDestinationSyncCol } from "./AzureKeyVaultDestinationSyncCol"; import { AzureKeyVaultDestinationSyncCol } from "./AzureKeyVaultDestinationSyncCol";
import { CamundaSyncDestinationCol } from "./CamundaSyncDestinationCol"; import { CamundaSyncDestinationCol } from "./CamundaSyncDestinationCol";
import { CloudflarePagesSyncDestinationCol } from "./CloudflarePagesSyncDestinationCol"; import { CloudflarePagesSyncDestinationCol } from "./CloudflarePagesSyncDestinationCol";
import { CloudflareWorkersSyncDestinationCol } from "./CloudflareWorkersSyncDestinationCol";
import { DatabricksSyncDestinationCol } from "./DatabricksSyncDestinationCol"; import { DatabricksSyncDestinationCol } from "./DatabricksSyncDestinationCol";
import { FlyioSyncDestinationCol } from "./FlyioSyncDestinationCol"; import { FlyioSyncDestinationCol } from "./FlyioSyncDestinationCol";
import { GcpSyncDestinationCol } from "./GcpSyncDestinationCol"; import { GcpSyncDestinationCol } from "./GcpSyncDestinationCol";
@@ -75,6 +76,8 @@ export const SecretSyncDestinationCol = ({ secretSync }: Props) => {
return <GitLabSyncDestinationCol secretSync={secretSync} />; return <GitLabSyncDestinationCol secretSync={secretSync} />;
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
return <CloudflarePagesSyncDestinationCol secretSync={secretSync} />; return <CloudflarePagesSyncDestinationCol secretSync={secretSync} />;
case SecretSync.CloudflareWorkers:
return <CloudflareWorkersSyncDestinationCol secretSync={secretSync} />;
case SecretSync.Zabbix: case SecretSync.Zabbix:
return <ZabbixSyncDestinationCol secretSync={secretSync} />; return <ZabbixSyncDestinationCol secretSync={secretSync} />;
case SecretSync.Railway: case SecretSync.Railway:
@@ -145,6 +145,10 @@ export const getSecretSyncDestinationColValues = (secretSync: TSecretSync) => {
primaryText = destinationConfig.projectName; primaryText = destinationConfig.projectName;
secondaryText = destinationConfig.environment; secondaryText = destinationConfig.environment;
break; break;
case SecretSync.CloudflareWorkers:
primaryText = destinationConfig.scriptId;
secondaryText = "Script ID";
break;
case SecretSync.Zabbix: case SecretSync.Zabbix:
if (destinationConfig.scope === ZabbixSyncScope.Host) { if (destinationConfig.scope === ZabbixSyncScope.Host) {
primaryText = destinationConfig.hostName; primaryText = destinationConfig.hostName;
@@ -0,0 +1,14 @@
import { GenericFieldLabel } from "@app/components/secret-syncs";
import { TCloudflareWorkersSync } from "@app/hooks/api/secretSyncs/types/cloudflare-workers-sync";
type Props = {
secretSync: TCloudflareWorkersSync;
};
export const CloudflareWorkersSyncDestinationSection = ({ secretSync }: Props) => {
const {
destinationConfig: { scriptId }
} = secretSync;
return <GenericFieldLabel label="Script ID">{scriptId}</GenericFieldLabel>;
};
@@ -19,6 +19,7 @@ import { AzureDevOpsSyncDestinationSection } from "./AzureDevOpsSyncDestinationS
import { AzureKeyVaultSyncDestinationSection } from "./AzureKeyVaultSyncDestinationSection"; import { AzureKeyVaultSyncDestinationSection } from "./AzureKeyVaultSyncDestinationSection";
import { CamundaSyncDestinationSection } from "./CamundaSyncDestinationSection"; import { CamundaSyncDestinationSection } from "./CamundaSyncDestinationSection";
import { CloudflarePagesSyncDestinationSection } from "./CloudflarePagesSyncDestinationSection"; import { CloudflarePagesSyncDestinationSection } from "./CloudflarePagesSyncDestinationSection";
import { CloudflareWorkersSyncDestinationSection } from "./CloudflareWorkersSyncDestinationSection";
import { DatabricksSyncDestinationSection } from "./DatabricksSyncDestinationSection"; import { DatabricksSyncDestinationSection } from "./DatabricksSyncDestinationSection";
import { FlyioSyncDestinationSection } from "./FlyioSyncDestinationSection"; import { FlyioSyncDestinationSection } from "./FlyioSyncDestinationSection";
import { GcpSyncDestinationSection } from "./GcpSyncDestinationSection"; import { GcpSyncDestinationSection } from "./GcpSyncDestinationSection";
@@ -116,6 +117,9 @@ export const SecretSyncDestinationSection = ({ secretSync, onEditDestination }:
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
DestinationComponents = <CloudflarePagesSyncDestinationSection secretSync={secretSync} />; DestinationComponents = <CloudflarePagesSyncDestinationSection secretSync={secretSync} />;
break; break;
case SecretSync.CloudflareWorkers:
DestinationComponents = <CloudflareWorkersSyncDestinationSection secretSync={secretSync} />;
break;
case SecretSync.Zabbix: case SecretSync.Zabbix:
DestinationComponents = <ZabbixSyncDestinationSection secretSync={secretSync} />; DestinationComponents = <ZabbixSyncDestinationSection secretSync={secretSync} />;
break; break;
@@ -60,6 +60,7 @@ export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) =
case SecretSync.Flyio: case SecretSync.Flyio:
case SecretSync.GitLab: case SecretSync.GitLab:
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
case SecretSync.CloudflareWorkers:
case SecretSync.Zabbix: case SecretSync.Zabbix:
case SecretSync.Railway: case SecretSync.Railway:
AdditionalSyncOptionsComponent = null; AdditionalSyncOptionsComponent = null;