mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 19:16:22 +00:00
Merge remote-tracking branch 'origin/main' into feat/add-cloudflare-app-connection-and-sync
This commit is contained in:
@@ -23,6 +23,7 @@ export enum AppConnection {
|
||||
OCI = "oci",
|
||||
OracleDB = "oracledb",
|
||||
OnePass = "1password",
|
||||
Heroku = "heroku",
|
||||
Render = "render",
|
||||
Flyio = "flyio",
|
||||
Cloudflare = "cloudflare"
|
||||
|
||||
@@ -69,6 +69,7 @@ import {
|
||||
HCVaultConnectionMethod,
|
||||
validateHCVaultConnectionCredentials
|
||||
} from "./hc-vault";
|
||||
import { getHerokuConnectionListItem, HerokuConnectionMethod, validateHerokuConnectionCredentials } from "./heroku";
|
||||
import {
|
||||
getHumanitecConnectionListItem,
|
||||
HumanitecConnectionMethod,
|
||||
@@ -130,6 +131,7 @@ export const listAppConnectionOptions = () => {
|
||||
getOCIConnectionListItem(),
|
||||
getOracleDBConnectionListItem(),
|
||||
getOnePassConnectionListItem(),
|
||||
getHerokuConnectionListItem(),
|
||||
getRenderConnectionListItem(),
|
||||
getFlyioConnectionListItem(),
|
||||
getCloudflareConnectionListItem()
|
||||
@@ -208,6 +210,7 @@ export const validateAppConnectionCredentials = async (
|
||||
[AppConnection.OCI]: validateOCIConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.OracleDB]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.OnePass]: validateOnePassConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Heroku]: validateHerokuConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Render]: validateRenderConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Flyio]: validateFlyioConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||
[AppConnection.Cloudflare]: validateCloudflareConnectionCredentials as TAppConnectionCredentialsValidator
|
||||
@@ -226,7 +229,10 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
||||
case AzureClientSecretsConnectionMethod.OAuth:
|
||||
case GitHubConnectionMethod.OAuth:
|
||||
case AzureDevOpsConnectionMethod.OAuth:
|
||||
case HerokuConnectionMethod.OAuth:
|
||||
return "OAuth";
|
||||
case HerokuConnectionMethod.AuthToken:
|
||||
return "Auth Token";
|
||||
case AwsConnectionMethod.AccessKey:
|
||||
case OCIConnectionMethod.AccessKey:
|
||||
return "Access Key";
|
||||
@@ -318,6 +324,7 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
|
||||
[AppConnection.OCI]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.OracleDB]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
||||
[AppConnection.OnePass]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.Heroku]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.Render]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.Flyio]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.Cloudflare]: platformManagedCredentialsNotSupported
|
||||
|
||||
@@ -25,6 +25,7 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
||||
[AppConnection.OCI]: "OCI",
|
||||
[AppConnection.OracleDB]: "OracleDB",
|
||||
[AppConnection.OnePass]: "1Password",
|
||||
[AppConnection.Heroku]: "Heroku",
|
||||
[AppConnection.Render]: "Render",
|
||||
[AppConnection.Flyio]: "Fly.io",
|
||||
[AppConnection.Cloudflare]: "Cloudflare"
|
||||
@@ -55,6 +56,7 @@ export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanTyp
|
||||
[AppConnection.OracleDB]: AppConnectionPlanType.Enterprise,
|
||||
[AppConnection.OnePass]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.MySql]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Heroku]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Render]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Flyio]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Cloudflare]: AppConnectionPlanType.Regular
|
||||
|
||||
@@ -60,6 +60,8 @@ import { githubConnectionService } from "./github/github-connection-service";
|
||||
import { ValidateGitHubRadarConnectionCredentialsSchema } from "./github-radar";
|
||||
import { ValidateHCVaultConnectionCredentialsSchema } from "./hc-vault";
|
||||
import { hcVaultConnectionService } from "./hc-vault/hc-vault-connection-service";
|
||||
import { ValidateHerokuConnectionCredentialsSchema } from "./heroku";
|
||||
import { herokuConnectionService } from "./heroku/heroku-connection-service";
|
||||
import { ValidateHumanitecConnectionCredentialsSchema } from "./humanitec";
|
||||
import { humanitecConnectionService } from "./humanitec/humanitec-connection-service";
|
||||
import { ValidateLdapConnectionCredentialsSchema } from "./ldap";
|
||||
@@ -111,6 +113,7 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
|
||||
[AppConnection.OCI]: ValidateOCIConnectionCredentialsSchema,
|
||||
[AppConnection.OracleDB]: ValidateOracleDBConnectionCredentialsSchema,
|
||||
[AppConnection.OnePass]: ValidateOnePassConnectionCredentialsSchema,
|
||||
[AppConnection.Heroku]: ValidateHerokuConnectionCredentialsSchema,
|
||||
[AppConnection.Render]: ValidateRenderConnectionCredentialsSchema,
|
||||
[AppConnection.Flyio]: ValidateFlyioConnectionCredentialsSchema,
|
||||
[AppConnection.Cloudflare]: ValidateCloudflareConnectionCredentialsSchema
|
||||
@@ -519,6 +522,7 @@ export const appConnectionServiceFactory = ({
|
||||
teamcity: teamcityConnectionService(connectAppConnectionById),
|
||||
oci: ociConnectionService(connectAppConnectionById, licenseService),
|
||||
onepass: onePassConnectionService(connectAppConnectionById),
|
||||
heroku: herokuConnectionService(connectAppConnectionById, appConnectionDAL, kmsService),
|
||||
render: renderConnectionService(connectAppConnectionById),
|
||||
cloudflare: cloudflareConnectionService(connectAppConnectionById),
|
||||
flyio: flyioConnectionService(connectAppConnectionById)
|
||||
|
||||
@@ -98,6 +98,12 @@ import {
|
||||
THCVaultConnectionInput,
|
||||
TValidateHCVaultConnectionCredentialsSchema
|
||||
} from "./hc-vault";
|
||||
import {
|
||||
THerokuConnection,
|
||||
THerokuConnectionConfig,
|
||||
THerokuConnectionInput,
|
||||
TValidateHerokuConnectionCredentialsSchema
|
||||
} from "./heroku";
|
||||
import {
|
||||
THumanitecConnection,
|
||||
THumanitecConnectionConfig,
|
||||
@@ -179,6 +185,7 @@ export type TAppConnection = { id: string } & (
|
||||
| TOCIConnection
|
||||
| TOracleDBConnection
|
||||
| TOnePassConnection
|
||||
| THerokuConnection
|
||||
| TRenderConnection
|
||||
| TFlyioConnection
|
||||
| TCloudflareConnection
|
||||
@@ -213,6 +220,7 @@ export type TAppConnectionInput = { id: string } & (
|
||||
| TOCIConnectionInput
|
||||
| TOracleDBConnectionInput
|
||||
| TOnePassConnectionInput
|
||||
| THerokuConnectionInput
|
||||
| TRenderConnectionInput
|
||||
| TFlyioConnectionInput
|
||||
| TCloudflareConnectionInput
|
||||
@@ -255,6 +263,7 @@ export type TAppConnectionConfig =
|
||||
| TTeamCityConnectionConfig
|
||||
| TOCIConnectionConfig
|
||||
| TOnePassConnectionConfig
|
||||
| THerokuConnectionConfig
|
||||
| TRenderConnectionConfig
|
||||
| TFlyioConnectionConfig
|
||||
| TCloudflareConnectionConfig;
|
||||
@@ -284,6 +293,7 @@ export type TValidateAppConnectionCredentialsSchema =
|
||||
| TValidateOCIConnectionCredentialsSchema
|
||||
| TValidateOracleDBConnectionCredentialsSchema
|
||||
| TValidateOnePassConnectionCredentialsSchema
|
||||
| TValidateHerokuConnectionCredentialsSchema
|
||||
| TValidateRenderConnectionCredentialsSchema
|
||||
| TValidateFlyioConnectionCredentialsSchema
|
||||
| TValidateCloudflareConnectionCredentialsSchema;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum HerokuConnectionMethod {
|
||||
AuthToken = "auth-token",
|
||||
OAuth = "oauth"
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
import { AxiosError, AxiosResponse } from "axios";
|
||||
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { request } from "@app/lib/config/request";
|
||||
import { BadRequestError, InternalServerError } from "@app/lib/errors";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { encryptAppConnectionCredentials } from "@app/services/app-connection/app-connection-fns";
|
||||
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { TAppConnectionDALFactory } from "../app-connection-dal";
|
||||
import { HerokuConnectionMethod } from "./heroku-connection-enums";
|
||||
import { THerokuApp, THerokuConnection, THerokuConnectionConfig } from "./heroku-connection-types";
|
||||
|
||||
interface HerokuOAuthTokenResponse {
|
||||
access_token: string;
|
||||
expires_in: number;
|
||||
refresh_token: string;
|
||||
token_type: string;
|
||||
user_id: string;
|
||||
session_nonce: string;
|
||||
}
|
||||
|
||||
export const getHerokuConnectionListItem = () => {
|
||||
const { CLIENT_ID_HEROKU } = getConfig();
|
||||
|
||||
return {
|
||||
name: "Heroku" as const,
|
||||
app: AppConnection.Heroku as const,
|
||||
methods: Object.values(HerokuConnectionMethod) as [HerokuConnectionMethod.AuthToken, HerokuConnectionMethod.OAuth],
|
||||
oauthClientId: CLIENT_ID_HEROKU
|
||||
};
|
||||
};
|
||||
|
||||
export const refreshHerokuToken = async (
|
||||
refreshToken: string,
|
||||
appId: string,
|
||||
orgId: string,
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||
): Promise<string> => {
|
||||
const { CLIENT_SECRET_HEROKU } = getConfig();
|
||||
|
||||
const payload = {
|
||||
grant_type: "refresh_token",
|
||||
refresh_token: refreshToken,
|
||||
client_secret: CLIENT_SECRET_HEROKU
|
||||
};
|
||||
|
||||
const { data } = await request.post<{ access_token: string; expires_in: number }>(
|
||||
IntegrationUrls.HEROKU_TOKEN_URL,
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const encryptedCredentials = await encryptAppConnectionCredentials({
|
||||
credentials: {
|
||||
refreshToken,
|
||||
authToken: data.access_token,
|
||||
expiresAt: new Date(Date.now() + data.expires_in * 1000 - 60000)
|
||||
},
|
||||
orgId,
|
||||
kmsService
|
||||
});
|
||||
|
||||
await appConnectionDAL.updateById(appId, { encryptedCredentials });
|
||||
|
||||
return data.access_token;
|
||||
};
|
||||
|
||||
export const exchangeHerokuOAuthCode = async (code: string): Promise<HerokuOAuthTokenResponse> => {
|
||||
const { CLIENT_SECRET_HEROKU } = getConfig();
|
||||
|
||||
try {
|
||||
const response = await request.post<HerokuOAuthTokenResponse>(
|
||||
IntegrationUrls.HEROKU_TOKEN_URL,
|
||||
{
|
||||
grant_type: "authorization_code",
|
||||
code,
|
||||
client_secret: CLIENT_SECRET_HEROKU
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.data) {
|
||||
throw new InternalServerError({
|
||||
message: "Failed to exchange OAuth code: Empty response"
|
||||
});
|
||||
}
|
||||
|
||||
return response.data;
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof AxiosError) {
|
||||
throw new BadRequestError({
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
message: `Failed to exchange OAuth code: ${error.response?.data?.message || error.message || "Unknown error"}`
|
||||
});
|
||||
}
|
||||
throw new BadRequestError({
|
||||
message: "Unable to exchange OAuth code"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const validateHerokuConnectionCredentials = async (config: THerokuConnectionConfig) => {
|
||||
const { credentials: inputCredentials, method } = config;
|
||||
|
||||
let authToken: string;
|
||||
let oauthData: HerokuOAuthTokenResponse | null = null;
|
||||
|
||||
if (method === HerokuConnectionMethod.OAuth && "code" in inputCredentials) {
|
||||
oauthData = await exchangeHerokuOAuthCode(inputCredentials.code);
|
||||
authToken = oauthData.access_token;
|
||||
} else if (method === HerokuConnectionMethod.AuthToken && "authToken" in inputCredentials) {
|
||||
authToken = inputCredentials.authToken;
|
||||
} else {
|
||||
throw new BadRequestError({
|
||||
message: "Invalid credentials for the selected connection method"
|
||||
});
|
||||
}
|
||||
|
||||
let response: AxiosResponse<THerokuApp[]> | null = null;
|
||||
|
||||
try {
|
||||
response = await request.get<THerokuApp[]>(`${IntegrationUrls.HEROKU_API_URL}/apps`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
Accept: "application/vnd.heroku+json; version=3"
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof AxiosError) {
|
||||
throw new BadRequestError({
|
||||
message: `Failed to validate credentials: ${error.message || "Unknown error"}`
|
||||
});
|
||||
}
|
||||
throw new BadRequestError({
|
||||
message: "Unable to validate connection: verify credentials"
|
||||
});
|
||||
}
|
||||
|
||||
if (!response?.data) {
|
||||
throw new InternalServerError({
|
||||
message: "Failed to get apps: Response was empty"
|
||||
});
|
||||
}
|
||||
|
||||
if (method === HerokuConnectionMethod.OAuth && oauthData) {
|
||||
return {
|
||||
authToken,
|
||||
refreshToken: oauthData.refresh_token,
|
||||
expiresIn: oauthData.expires_in,
|
||||
tokenType: oauthData.token_type,
|
||||
userId: oauthData.user_id,
|
||||
sessionNonce: oauthData.session_nonce
|
||||
};
|
||||
}
|
||||
|
||||
return inputCredentials;
|
||||
};
|
||||
|
||||
export const listHerokuApps = async ({
|
||||
appConnection,
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
}: {
|
||||
appConnection: THerokuConnection;
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
}): Promise<THerokuApp[]> => {
|
||||
let authCredential = appConnection.credentials.authToken;
|
||||
if (
|
||||
appConnection.method === HerokuConnectionMethod.OAuth &&
|
||||
appConnection.credentials.refreshToken &&
|
||||
appConnection.credentials.expiresAt < new Date()
|
||||
) {
|
||||
authCredential = await refreshHerokuToken(
|
||||
appConnection.credentials.refreshToken,
|
||||
appConnection.id,
|
||||
appConnection.orgId,
|
||||
appConnectionDAL,
|
||||
kmsService
|
||||
);
|
||||
}
|
||||
|
||||
const { data } = await request.get<THerokuApp[]>(`${IntegrationUrls.HEROKU_API_URL}/apps`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${authCredential}`,
|
||||
Accept: "application/vnd.heroku+json; version=3"
|
||||
}
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
throw new InternalServerError({
|
||||
message: "Failed to get apps: Response was empty"
|
||||
});
|
||||
}
|
||||
|
||||
return data.map((res) => ({ name: res.name, id: res.id }));
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
import z from "zod";
|
||||
|
||||
import { AppConnections } from "@app/lib/api-docs";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import {
|
||||
BaseAppConnectionSchema,
|
||||
GenericCreateAppConnectionFieldsSchema,
|
||||
GenericUpdateAppConnectionFieldsSchema
|
||||
} from "@app/services/app-connection/app-connection-schemas";
|
||||
|
||||
import { HerokuConnectionMethod } from "./heroku-connection-enums";
|
||||
|
||||
export const HerokuConnectionAuthTokenCredentialsSchema = z.object({
|
||||
authToken: z.string().trim().min(1, "Auth Token required").startsWith("HRKU-", "Token must start with 'HRKU-")
|
||||
});
|
||||
|
||||
export const HerokuConnectionOAuthCredentialsSchema = z.object({
|
||||
code: z.string().trim().min(1, "OAuth code required")
|
||||
});
|
||||
|
||||
export const HerokuConnectionOAuthOutputCredentialsSchema = z.object({
|
||||
authToken: z.string().trim(),
|
||||
refreshToken: z.string().trim(),
|
||||
expiresAt: z.date()
|
||||
});
|
||||
|
||||
// Schema for refresh token input during initial setup
|
||||
export const HerokuConnectionRefreshTokenCredentialsSchema = z.object({
|
||||
refreshToken: z.string().trim().min(1, "Refresh token required")
|
||||
});
|
||||
|
||||
const BaseHerokuConnectionSchema = BaseAppConnectionSchema.extend({
|
||||
app: z.literal(AppConnection.Heroku)
|
||||
});
|
||||
|
||||
export const HerokuConnectionSchema = z.intersection(
|
||||
BaseHerokuConnectionSchema,
|
||||
z.discriminatedUnion("method", [
|
||||
z.object({
|
||||
method: z.literal(HerokuConnectionMethod.AuthToken),
|
||||
credentials: HerokuConnectionAuthTokenCredentialsSchema
|
||||
}),
|
||||
z.object({
|
||||
method: z.literal(HerokuConnectionMethod.OAuth),
|
||||
credentials: HerokuConnectionOAuthOutputCredentialsSchema
|
||||
})
|
||||
])
|
||||
);
|
||||
|
||||
export const SanitizedHerokuConnectionSchema = z.discriminatedUnion("method", [
|
||||
BaseHerokuConnectionSchema.extend({
|
||||
method: z.literal(HerokuConnectionMethod.AuthToken),
|
||||
credentials: HerokuConnectionAuthTokenCredentialsSchema.pick({})
|
||||
}),
|
||||
BaseHerokuConnectionSchema.extend({
|
||||
method: z.literal(HerokuConnectionMethod.OAuth),
|
||||
credentials: HerokuConnectionOAuthOutputCredentialsSchema.pick({})
|
||||
})
|
||||
]);
|
||||
|
||||
export const ValidateHerokuConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||
z.object({
|
||||
method: z.literal(HerokuConnectionMethod.AuthToken).describe(AppConnections.CREATE(AppConnection.Heroku).method),
|
||||
credentials: HerokuConnectionAuthTokenCredentialsSchema.describe(
|
||||
AppConnections.CREATE(AppConnection.Heroku).credentials
|
||||
)
|
||||
}),
|
||||
z.object({
|
||||
method: z.literal(HerokuConnectionMethod.OAuth).describe(AppConnections.CREATE(AppConnection.Heroku).method),
|
||||
credentials: z
|
||||
.union([
|
||||
HerokuConnectionOAuthCredentialsSchema,
|
||||
HerokuConnectionRefreshTokenCredentialsSchema,
|
||||
HerokuConnectionOAuthOutputCredentialsSchema
|
||||
])
|
||||
.describe(AppConnections.CREATE(AppConnection.Heroku).credentials)
|
||||
})
|
||||
]);
|
||||
|
||||
export const CreateHerokuConnectionSchema = ValidateHerokuConnectionCredentialsSchema.and(
|
||||
GenericCreateAppConnectionFieldsSchema(AppConnection.Heroku)
|
||||
);
|
||||
|
||||
export const UpdateHerokuConnectionSchema = z
|
||||
.object({
|
||||
credentials: z
|
||||
.union([
|
||||
HerokuConnectionAuthTokenCredentialsSchema,
|
||||
HerokuConnectionOAuthOutputCredentialsSchema,
|
||||
HerokuConnectionRefreshTokenCredentialsSchema,
|
||||
HerokuConnectionOAuthCredentialsSchema
|
||||
])
|
||||
.optional()
|
||||
.describe(AppConnections.UPDATE(AppConnection.Heroku).credentials)
|
||||
})
|
||||
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.Heroku));
|
||||
|
||||
export const HerokuConnectionListItemSchema = z.object({
|
||||
name: z.literal("Heroku"),
|
||||
app: z.literal(AppConnection.Heroku),
|
||||
methods: z.nativeEnum(HerokuConnectionMethod).array(),
|
||||
oauthClientId: z.string().optional()
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { OrgServiceActor } from "@app/lib/types";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { TAppConnectionDALFactory } from "../app-connection-dal";
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import { listHerokuApps as getHerokuApps } from "./heroku-connection-fns";
|
||||
import { THerokuConnection } from "./heroku-connection-types";
|
||||
|
||||
type TGetAppConnectionFunc = (
|
||||
app: AppConnection,
|
||||
connectionId: string,
|
||||
actor: OrgServiceActor
|
||||
) => Promise<THerokuConnection>;
|
||||
|
||||
export const herokuConnectionService = (
|
||||
getAppConnection: TGetAppConnectionFunc,
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
|
||||
) => {
|
||||
const listApps = async (connectionId: string, actor: OrgServiceActor) => {
|
||||
const appConnection = await getAppConnection(AppConnection.Heroku, connectionId, actor);
|
||||
try {
|
||||
const apps = await getHerokuApps({ appConnection, appConnectionDAL, kmsService });
|
||||
return apps;
|
||||
} catch (error) {
|
||||
logger.error(error, `Failed to establish connection with Heroku for app ${connectionId}`);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
listApps
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import z from "zod";
|
||||
|
||||
import { DiscriminativePick } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import {
|
||||
CreateHerokuConnectionSchema,
|
||||
HerokuConnectionSchema,
|
||||
ValidateHerokuConnectionCredentialsSchema
|
||||
} from "./heroku-connection-schemas";
|
||||
|
||||
export type THerokuConnection = z.infer<typeof HerokuConnectionSchema>;
|
||||
|
||||
export type THerokuConnectionInput = z.infer<typeof CreateHerokuConnectionSchema> & {
|
||||
app: AppConnection.Heroku;
|
||||
};
|
||||
|
||||
export type TValidateHerokuConnectionCredentialsSchema = typeof ValidateHerokuConnectionCredentialsSchema;
|
||||
|
||||
export type THerokuConnectionConfig = DiscriminativePick<THerokuConnectionInput, "method" | "app" | "credentials"> & {
|
||||
orgId: string;
|
||||
};
|
||||
|
||||
export type THerokuApp = {
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./heroku-connection-enums";
|
||||
export * from "./heroku-connection-fns";
|
||||
export * from "./heroku-connection-schemas";
|
||||
export * from "./heroku-connection-types";
|
||||
Reference in New Issue
Block a user