feat: Checkly app connection and secrets sync (#4078)

* feat: checkly app connection
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
Sid
2025-07-16 00:07:42 +05:30
committed by GitHub
co-authored by greptile-apps[bot]
parent 023079be16
commit 7ef077228e
91 changed files with 1448 additions and 36 deletions
@@ -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 CHECKLY_SYNC_LIST_OPTION: TSecretSyncListItem = {
name: "Checkly",
destination: SecretSync.Checkly,
connection: AppConnection.Checkly,
canImportSecrets: false
};
@@ -0,0 +1,102 @@
/* eslint-disable no-continue */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ChecklyPublicAPI } from "@app/services/app-connection/checkly/checkly-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 { TChecklySyncWithCredentials } from "./checkly-sync-types";
export const ChecklySyncFns = {
async getSecrets(secretSync: TChecklySyncWithCredentials) {
throw new Error(`${SECRET_SYNC_NAME_MAP[secretSync.destination]} does not support importing secrets.`);
},
async syncSecrets(secretSync: TChecklySyncWithCredentials, secretMap: TSecretMap) {
const {
environment,
syncOptions: { disableSecretDeletion, keySchema }
} = secretSync;
const config = secretSync.destinationConfig;
const variables = await ChecklyPublicAPI.getVariables(secretSync.connection, config.accountId);
const checklySecrets = Object.fromEntries(variables!.map((variable) => [variable.key, variable]));
for await (const key of Object.keys(secretMap)) {
try {
const entry = secretMap[key];
// If value is empty, we skip the upsert - checkly does not allow empty values
if (entry.value.trim() === "") {
// Delete the secret from Checkly if its empty
if (!disableSecretDeletion) {
await ChecklyPublicAPI.deleteVariable(secretSync.connection, config.accountId, {
key
});
}
continue; // Skip empty values
}
await ChecklyPublicAPI.upsertVariable(secretSync.connection, config.accountId, {
key,
value: entry.value,
secret: true,
locked: true
});
} catch (error) {
throw new SecretSyncError({
error,
secretKey: key
});
}
}
if (disableSecretDeletion) return;
for await (const key of Object.keys(checklySecrets)) {
try {
// eslint-disable-next-line no-continue
if (!matchesSchema(key, environment?.slug || "", keySchema)) continue;
if (!secretMap[key]) {
await ChecklyPublicAPI.deleteVariable(secretSync.connection, config.accountId, {
key
});
}
} catch (error) {
throw new SecretSyncError({
error,
secretKey: key
});
}
}
},
async removeSecrets(secretSync: TChecklySyncWithCredentials, secretMap: TSecretMap) {
const config = secretSync.destinationConfig;
const variables = await ChecklyPublicAPI.getVariables(secretSync.connection, config.accountId);
const checklySecrets = Object.fromEntries(variables!.map((variable) => [variable.key, variable]));
for await (const secret of Object.keys(checklySecrets)) {
try {
if (secret in secretMap) {
await ChecklyPublicAPI.deleteVariable(secretSync.connection, config.accountId, {
key: secret
});
}
} catch (error) {
throw new SecretSyncError({
error,
secretKey: secret
});
}
}
}
};
@@ -0,0 +1,43 @@
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 ChecklySyncDestinationConfigSchema = z.object({
accountId: z.string().min(1, "Account ID is required").max(255, "Account ID must be less than 255 characters"),
accountName: z.string().min(1, "Account Name is required").max(255, "Account ID must be less than 255 characters")
});
const ChecklySyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: false };
export const ChecklySyncSchema = BaseSecretSyncSchema(SecretSync.Checkly, ChecklySyncOptionsConfig).extend({
destination: z.literal(SecretSync.Checkly),
destinationConfig: ChecklySyncDestinationConfigSchema
});
export const CreateChecklySyncSchema = GenericCreateSecretSyncFieldsSchema(
SecretSync.Checkly,
ChecklySyncOptionsConfig
).extend({
destinationConfig: ChecklySyncDestinationConfigSchema
});
export const UpdateChecklySyncSchema = GenericUpdateSecretSyncFieldsSchema(
SecretSync.Checkly,
ChecklySyncOptionsConfig
).extend({
destinationConfig: ChecklySyncDestinationConfigSchema.optional()
});
export const ChecklySyncListItemSchema = z.object({
name: z.literal("Checkly"),
connection: z.literal(AppConnection.Checkly),
destination: z.literal(SecretSync.Checkly),
canImportSecrets: z.literal(false)
});
@@ -0,0 +1,23 @@
import z from "zod";
import { TChecklyConnection, TChecklyVariable } from "@app/services/app-connection/checkly";
import { ChecklySyncListItemSchema, ChecklySyncSchema, CreateChecklySyncSchema } from "./checkly-sync-schemas";
export type TChecklySyncListItem = z.infer<typeof ChecklySyncListItemSchema>;
export type TChecklySync = z.infer<typeof ChecklySyncSchema>;
export type TChecklySyncInput = z.infer<typeof CreateChecklySyncSchema>;
export type TChecklySyncWithCredentials = TChecklySync & {
connection: TChecklyConnection;
};
export type TChecklySecret = TChecklyVariable;
export type TChecklyVariablesGraphResponse = {
data: {
variables: Record<string, string>;
};
};