mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-19 22:20:36 +00:00
Add Humanitec secret sync integration
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
export enum HumanitecConnectionMethod {
|
||||
AccessKey = "access-key"
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { AxiosError, AxiosResponse } from "axios";
|
||||
|
||||
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 { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||
|
||||
import { HumanitecConnectionMethod } from "./humanitec-connection-enums";
|
||||
import {
|
||||
HumanitecApp,
|
||||
HumanitecOrg,
|
||||
HumanitecOrgWithApps,
|
||||
THumanitecConnection,
|
||||
THumanitecConnectionConfig
|
||||
} from "./humanitec-connection-types";
|
||||
|
||||
export const getHumanitecConnectionListItem = () => {
|
||||
return {
|
||||
name: "Humanitec" as const,
|
||||
app: AppConnection.Humanitec as const,
|
||||
methods: Object.values(HumanitecConnectionMethod) as [HumanitecConnectionMethod.AccessKey]
|
||||
};
|
||||
};
|
||||
|
||||
export const validateHumanitecConnectionCredentials = async (config: THumanitecConnectionConfig) => {
|
||||
const { credentials: inputCredentials } = config;
|
||||
|
||||
let response: AxiosResponse<HumanitecOrg[]> | null = null;
|
||||
|
||||
try {
|
||||
response = await request.get<HumanitecOrg[]>(`${IntegrationUrls.HUMANITEC_API_URL}/orgs`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${inputCredentials.accessKeyId}`
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof AxiosError) {
|
||||
throw new BadRequestError({
|
||||
message: `Failed to validate credentials: ${error.response?.data || "Unknown error"}`
|
||||
});
|
||||
}
|
||||
throw new BadRequestError({
|
||||
message: "Unable to validate connection - verify credentials"
|
||||
});
|
||||
}
|
||||
|
||||
if (!response?.data) {
|
||||
throw new InternalServerError({
|
||||
message: "Failed to get organizations: Response was empty"
|
||||
});
|
||||
}
|
||||
|
||||
return inputCredentials;
|
||||
};
|
||||
|
||||
export const listOrganizations = async (appConnection: THumanitecConnection): Promise<HumanitecOrgWithApps[]> => {
|
||||
const {
|
||||
credentials: { accessKeyId }
|
||||
} = appConnection;
|
||||
const response = await request.get<HumanitecOrg[]>(`${IntegrationUrls.HUMANITEC_API_URL}/orgs`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessKeyId}`
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.data) {
|
||||
throw new InternalServerError({
|
||||
message: "Failed to get organizations: Response was empty"
|
||||
});
|
||||
}
|
||||
|
||||
const orgs = response.data;
|
||||
const appPromises = orgs.map(async (org) => {
|
||||
return request.get<HumanitecApp[]>(`${IntegrationUrls.HUMANITEC_API_URL}/orgs/${org.id}/apps`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessKeyId}`
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const appsResponses = await Promise.all(appPromises);
|
||||
|
||||
const orgsWithApps: HumanitecOrgWithApps[] = orgs.map((org, index) => {
|
||||
if (!appsResponses[index].data) {
|
||||
throw new InternalServerError({
|
||||
message: "Failed to get apps for organization: Response was empty"
|
||||
});
|
||||
}
|
||||
|
||||
const apps = appsResponses[index].data;
|
||||
return {
|
||||
...org,
|
||||
apps: apps.map((app) => ({
|
||||
name: app.name,
|
||||
id: app.id,
|
||||
envs: app.envs
|
||||
}))
|
||||
};
|
||||
});
|
||||
return orgsWithApps;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
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 { HumanitecConnectionMethod } from "./humanitec-connection-enums";
|
||||
|
||||
export const HumanitecConnectionAccessTokenCredentialsSchema = z.object({
|
||||
accessKeyId: z.string().trim().min(1, "Access Key ID required")
|
||||
});
|
||||
|
||||
const BaseHumanitecConnectionSchema = BaseAppConnectionSchema.extend({ app: z.literal(AppConnection.Humanitec) });
|
||||
|
||||
export const HumanitecConnectionSchema = BaseHumanitecConnectionSchema.extend({
|
||||
method: z.literal(HumanitecConnectionMethod.AccessKey),
|
||||
credentials: HumanitecConnectionAccessTokenCredentialsSchema
|
||||
});
|
||||
|
||||
export const SanitizedHumanitecConnectionSchema = z.discriminatedUnion("method", [
|
||||
BaseHumanitecConnectionSchema.extend({
|
||||
method: z.literal(HumanitecConnectionMethod.AccessKey),
|
||||
credentials: HumanitecConnectionAccessTokenCredentialsSchema.pick({})
|
||||
})
|
||||
]);
|
||||
|
||||
export const ValidateHumanitecConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||
z.object({
|
||||
method: z
|
||||
.literal(HumanitecConnectionMethod.AccessKey)
|
||||
.describe(AppConnections?.CREATE(AppConnection.Humanitec).method),
|
||||
credentials: HumanitecConnectionAccessTokenCredentialsSchema.describe(
|
||||
AppConnections.CREATE(AppConnection.Humanitec).credentials
|
||||
)
|
||||
})
|
||||
]);
|
||||
|
||||
export const CreateHumanitecConnectionSchema = ValidateHumanitecConnectionCredentialsSchema.and(
|
||||
GenericCreateAppConnectionFieldsSchema(AppConnection.Humanitec)
|
||||
);
|
||||
|
||||
export const UpdateHumanitecConnectionSchema = z
|
||||
.object({
|
||||
credentials: HumanitecConnectionAccessTokenCredentialsSchema.optional().describe(
|
||||
AppConnections.UPDATE(AppConnection.Humanitec).credentials
|
||||
)
|
||||
})
|
||||
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.Humanitec));
|
||||
|
||||
export const HumanitecConnectionListItemSchema = z.object({
|
||||
name: z.literal("Humanitec"),
|
||||
app: z.literal(AppConnection.Humanitec),
|
||||
methods: z.nativeEnum(HumanitecConnectionMethod).array()
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { OrgServiceActor } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import { listOrganizations as getHumanitecOrganizations } from "./humanitec-connection-fns";
|
||||
import { THumanitecConnection } from "./humanitec-connection-types";
|
||||
|
||||
type TGetAppConnectionFunc = (
|
||||
app: AppConnection,
|
||||
connectionId: string,
|
||||
actor: OrgServiceActor
|
||||
) => Promise<THumanitecConnection>;
|
||||
|
||||
export const humanitecConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
|
||||
const listOrganizations = async (connectionId: string, actor: OrgServiceActor) => {
|
||||
const appConnection = await getAppConnection(AppConnection.Humanitec, connectionId, actor);
|
||||
try {
|
||||
const organizations = await getHumanitecOrganizations(appConnection);
|
||||
return organizations;
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
listOrganizations
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import z from "zod";
|
||||
|
||||
import { DiscriminativePick } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import {
|
||||
CreateHumanitecConnectionSchema,
|
||||
HumanitecConnectionSchema,
|
||||
ValidateHumanitecConnectionCredentialsSchema
|
||||
} from "./humanitec-connection-schemas";
|
||||
|
||||
export type THumanitecConnection = z.infer<typeof HumanitecConnectionSchema>;
|
||||
|
||||
export type THumanitecConnectionInput = z.infer<typeof CreateHumanitecConnectionSchema> & {
|
||||
app: AppConnection.Humanitec;
|
||||
};
|
||||
|
||||
export type TValidateHumanitecConnectionCredentials = typeof ValidateHumanitecConnectionCredentialsSchema;
|
||||
|
||||
export type THumanitecConnectionConfig = DiscriminativePick<
|
||||
THumanitecConnectionInput,
|
||||
"method" | "app" | "credentials"
|
||||
> & {
|
||||
orgId: string;
|
||||
};
|
||||
|
||||
export type HumanitecOrg = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type HumanitecApp = {
|
||||
name: string;
|
||||
id: string;
|
||||
envs: { name: string; id: string }[];
|
||||
};
|
||||
|
||||
export type HumanitecOrgWithApps = HumanitecOrg & {
|
||||
apps: HumanitecApp[];
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./humanitec-connection-enums";
|
||||
export * from "./humanitec-connection-fns";
|
||||
export * from "./humanitec-connection-schemas";
|
||||
export * from "./humanitec-connection-types";
|
||||
Reference in New Issue
Block a user