mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 20:25:43 +00:00
feat: Digital Ocean App connection and App Platform secret sync (#4203)
* fix: save wip * feat: final impl * feat: docs * Update backend/src/services/app-connection/digital-ocean/digital-ocean-connection-service.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * chore: remove empty conflict files * Update backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update frontend/src/components/secret-syncs/forms/schemas/digital-ocean-app-platform-sync-destination-schema.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update frontend/src/components/secret-syncs/forms/schemas/digital-ocean-app-platform-sync-destination-schema.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update frontend/src/components/secret-syncs/forms/SecretSyncDestinationFields/DigitalOceanAppPlatformSyncFields.tsx Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update backend/src/services/secret-sync/digital-ocean-app-platform/digital-ocean-app-platform-sync-schemas.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * fix: lint * fix: api client * fix: lint and types * fix: typecheck lint * fix: docs * fix: docs * fix: linting --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
greptile-apps[bot]
parent
95b997c100
commit
ab56a69d59
+10
@@ -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 DIGITAL_OCEAN_APP_PLATFORM_SYNC_LIST_OPTION: TSecretSyncListItem = {
|
||||
name: "Digital Ocean App Platform" as const,
|
||||
destination: SecretSync.DigitalOceanAppPlatform,
|
||||
connection: AppConnection.DigitalOcean,
|
||||
canImportSecrets: false
|
||||
};
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/* eslint-disable no-continue */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
|
||||
import { TDigitalOceanVariable } from "@app/services/app-connection/digital-ocean";
|
||||
import { DigitalOceanAppPlatformPublicAPI } from "@app/services/app-connection/digital-ocean/digital-ocean-connection-public-client";
|
||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||
|
||||
import { SecretSyncError } from "../secret-sync-errors";
|
||||
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
|
||||
import { TSecretMap } from "../secret-sync-types";
|
||||
import { TDigitalOceanAppPlatformSyncWithCredentials } from "./digital-ocean-app-platform-sync-types";
|
||||
|
||||
export const DigitalOceanAppPlatformSyncFns = {
|
||||
async getSecrets(secretSync: TDigitalOceanAppPlatformSyncWithCredentials) {
|
||||
throw new Error(`${SECRET_SYNC_NAME_MAP[secretSync.destination]} does not support importing secrets.`);
|
||||
},
|
||||
|
||||
async syncSecrets(secretSync: TDigitalOceanAppPlatformSyncWithCredentials, secretMap: TSecretMap) {
|
||||
const {
|
||||
environment,
|
||||
syncOptions: { disableSecretDeletion, keySchema }
|
||||
} = secretSync;
|
||||
|
||||
const config = secretSync.destinationConfig;
|
||||
|
||||
const existing = await DigitalOceanAppPlatformPublicAPI.getVariables(secretSync.connection, config.appId);
|
||||
|
||||
const variables: Record<string, TDigitalOceanVariable> = Object.fromEntries(existing.map((v) => [v.key, v]));
|
||||
|
||||
for (const [key, value] of Object.entries(secretMap)) {
|
||||
variables[key] = {
|
||||
key,
|
||||
value: value.value,
|
||||
type: "SECRET"
|
||||
} as TDigitalOceanVariable;
|
||||
}
|
||||
|
||||
if (!disableSecretDeletion) {
|
||||
for (const v of existing) {
|
||||
if (!matchesSchema(v.key, environment?.slug || "", keySchema)) continue;
|
||||
if (!(v.key in secretMap)) {
|
||||
delete variables[v.key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const vars = Object.values(variables);
|
||||
await DigitalOceanAppPlatformPublicAPI.putVariables(secretSync.connection, config.appId, ...vars);
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async removeSecrets(secretSync: TDigitalOceanAppPlatformSyncWithCredentials, secretMap: TSecretMap) {
|
||||
const config = secretSync.destinationConfig;
|
||||
|
||||
try {
|
||||
const existingSecrets = await DigitalOceanAppPlatformPublicAPI.getVariables(secretSync.connection, config.appId);
|
||||
|
||||
const vars = Object.entries(existingSecrets)
|
||||
.map(([key, v]) => {
|
||||
if (!(key in secretMap)) return;
|
||||
|
||||
return {
|
||||
key,
|
||||
value: v.value,
|
||||
type: "SECRET"
|
||||
} as TDigitalOceanVariable;
|
||||
})
|
||||
.filter(Boolean) as TDigitalOceanVariable[];
|
||||
|
||||
await DigitalOceanAppPlatformPublicAPI.deleteVariables(secretSync.connection, config.appId, ...vars);
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
import { z } from "zod";
|
||||
|
||||
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 DigitalOceanAppPlatformSyncDestinationConfigSchema = z.object({
|
||||
appId: z.string().min(1, "Account ID is required").max(255, "Account ID must be less than 255 characters"),
|
||||
appName: z.string().min(1, "Account Name is required").max(255, "Account Name must be less than 255 characters")
|
||||
});
|
||||
|
||||
const DigitalOceanAppPlatformSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: false };
|
||||
|
||||
export const DigitalOceanAppPlatformSyncSchema = BaseSecretSyncSchema(
|
||||
SecretSync.DigitalOceanAppPlatform,
|
||||
DigitalOceanAppPlatformSyncOptionsConfig
|
||||
).extend({
|
||||
destination: z.literal(SecretSync.DigitalOceanAppPlatform),
|
||||
destinationConfig: DigitalOceanAppPlatformSyncDestinationConfigSchema
|
||||
});
|
||||
|
||||
export const CreateDigitalOceanAppPlatformSyncSchema = GenericCreateSecretSyncFieldsSchema(
|
||||
SecretSync.DigitalOceanAppPlatform,
|
||||
DigitalOceanAppPlatformSyncOptionsConfig
|
||||
).extend({
|
||||
destinationConfig: DigitalOceanAppPlatformSyncDestinationConfigSchema
|
||||
});
|
||||
|
||||
export const UpdateDigitalOceanAppPlatformSyncSchema = GenericUpdateSecretSyncFieldsSchema(
|
||||
SecretSync.DigitalOceanAppPlatform,
|
||||
DigitalOceanAppPlatformSyncOptionsConfig
|
||||
).extend({
|
||||
destinationConfig: DigitalOceanAppPlatformSyncDestinationConfigSchema.optional()
|
||||
});
|
||||
|
||||
export const DigitalOceanAppPlatformSyncListItemSchema = z.object({
|
||||
name: z.literal("Digital Ocean App Platform"),
|
||||
connection: z.literal(AppConnection.DigitalOcean),
|
||||
destination: z.literal(SecretSync.DigitalOceanAppPlatform),
|
||||
canImportSecrets: z.literal(false)
|
||||
});
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import z from "zod";
|
||||
|
||||
import { TDigitalOceanConnection, TDigitalOceanVariable } from "@app/services/app-connection/digital-ocean";
|
||||
|
||||
import {
|
||||
CreateDigitalOceanAppPlatformSyncSchema,
|
||||
DigitalOceanAppPlatformSyncListItemSchema,
|
||||
DigitalOceanAppPlatformSyncSchema
|
||||
} from "./digital-ocean-app-platform-sync-schemas";
|
||||
|
||||
export type TDigitalOceanAppPlatformSyncListItem = z.infer<typeof DigitalOceanAppPlatformSyncListItemSchema>;
|
||||
|
||||
export type TDigitalOceanAppPlatformSync = z.infer<typeof DigitalOceanAppPlatformSyncSchema>;
|
||||
|
||||
export type TDigitalOceanAppPlatformSyncInput = z.infer<typeof CreateDigitalOceanAppPlatformSyncSchema>;
|
||||
|
||||
export type TDigitalOceanAppPlatformSyncWithCredentials = TDigitalOceanAppPlatformSync & {
|
||||
connection: TDigitalOceanConnection;
|
||||
};
|
||||
|
||||
export type TDigitalOceanAppPlatformSecret = TDigitalOceanVariable & {
|
||||
type: "SECRET";
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./digital-ocean-app-platform-sync-constants";
|
||||
export * from "./digital-ocean-app-platform-sync-fns";
|
||||
export * from "./digital-ocean-app-platform-sync-schemas";
|
||||
export * from "./digital-ocean-app-platform-sync-types";
|
||||
Reference in New Issue
Block a user