mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-19 07:33:18 +00:00
Merge branch 'main' into feature/ldap-gateway-support
This commit is contained in:
@@ -62,6 +62,7 @@ export enum ApiDocsTags {
|
||||
PkiCertificateCollections = "PKI Certificate Collections",
|
||||
PkiAlerting = "PKI Alerting",
|
||||
PkiSubscribers = "PKI Subscribers",
|
||||
PkiAcme = "PKI ACME",
|
||||
SshCertificates = "SSH Certificates",
|
||||
SshCertificateAuthorities = "SSH Certificate Authorities",
|
||||
SshCertificateTemplates = "SSH Certificate Templates",
|
||||
@@ -2308,7 +2309,10 @@ export const AppConnections = {
|
||||
code: "The OAuth code to use to connect with Azure Client Secrets.",
|
||||
tenantId: "The Tenant ID to use to connect with Azure Client Secrets.",
|
||||
clientId: "The Client ID to use to connect with Azure Client Secrets.",
|
||||
clientSecret: "The Client Secret to use to connect with Azure Client Secrets."
|
||||
clientSecret: "The Client Secret to use to connect with Azure Client Secrets.",
|
||||
certificateBody: "The certificate body in PEM format to use to connect with Azure Client Secrets.",
|
||||
privateKey:
|
||||
"The private key to use to connect with Azure Client Secrets. This is never transmitted to Azure and is only used to sign the Azure client assertion with."
|
||||
},
|
||||
AZURE_DEVOPS: {
|
||||
code: "The OAuth code to use to connect with Azure DevOps.",
|
||||
|
||||
@@ -106,6 +106,21 @@ const envSchema = z
|
||||
HTTPS_ENABLED: zodStrBool,
|
||||
ROTATION_DEVELOPMENT_MODE: zodStrBool.default("false").optional(),
|
||||
DAILY_RESOURCE_CLEAN_UP_DEVELOPMENT_MODE: zodStrBool.default("false").optional(),
|
||||
// Note: The ACME feature is still in development and is not yet ready for production.
|
||||
// This is the feature flag to enable/disable the ACME feature.
|
||||
// It's not intended to be used by users outside of the development team yet.
|
||||
ACME_FEATURE_ENABLED: zodStrBool.default("false").optional(),
|
||||
ACME_DEVELOPMENT_MODE: zodStrBool.default("false").optional(),
|
||||
ACME_DEVELOPMENT_HTTP01_CHALLENGE_HOST_OVERRIDES: zpStr(
|
||||
z
|
||||
.string()
|
||||
.optional()
|
||||
.transform((val) => {
|
||||
if (!val) return {};
|
||||
return JSON.parse(val) as Record<string, string>;
|
||||
})
|
||||
.default("{}")
|
||||
),
|
||||
// smtp options
|
||||
SMTP_HOST: zpStr(z.string().optional()),
|
||||
SMTP_IGNORE_TLS: zodStrBool.default("false"),
|
||||
@@ -384,6 +399,8 @@ const envSchema = z
|
||||
(data.NODE_ENV === "development" && data.ROTATION_DEVELOPMENT_MODE) || data.NODE_ENV === "test",
|
||||
isDailyResourceCleanUpDevelopmentMode:
|
||||
data.NODE_ENV === "development" && data.DAILY_RESOURCE_CLEAN_UP_DEVELOPMENT_MODE,
|
||||
isAcmeFeatureEnabled: data.NODE_ENV === "development" && data.ACME_FEATURE_ENABLED === true,
|
||||
isAcmeDevelopmentMode: data.NODE_ENV === "development" && data.ACME_DEVELOPMENT_MODE,
|
||||
isProductionMode: data.NODE_ENV === "production" || IS_PACKAGED,
|
||||
isRedisSentinelMode: Boolean(data.REDIS_SENTINEL_HOSTS),
|
||||
REDIS_SENTINEL_HOSTS: data.REDIS_SENTINEL_HOSTS?.trim()
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { validateMicrosoftTeamsChannelsSchema } from "@app/services/microsoft-teams/microsoft-teams-fns";
|
||||
import { TMicrosoftTeamsServiceFactory } from "@app/services/microsoft-teams/microsoft-teams-service";
|
||||
import {
|
||||
TProjectMicrosoftTeamsConfigDALFactory,
|
||||
TProjectMicrosoftTeamsConfigWithIntegrations
|
||||
} from "@app/services/microsoft-teams/project-microsoft-teams-config-dal";
|
||||
|
||||
import { logger } from "../../logger";
|
||||
import { TNotification, TriggerFeature } from "../types";
|
||||
|
||||
const handleMicrosoftTeamsNotification = async ({
|
||||
microsoftTeamsConfig,
|
||||
notification,
|
||||
orgId,
|
||||
microsoftTeamsService
|
||||
}: {
|
||||
microsoftTeamsConfig: TProjectMicrosoftTeamsConfigWithIntegrations;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
microsoftTeamsService: Pick<TMicrosoftTeamsServiceFactory, "sendNotification">;
|
||||
}): Promise<void> => {
|
||||
let targetChannels: unknown;
|
||||
let isEnabled = false;
|
||||
|
||||
switch (notification.type) {
|
||||
case TriggerFeature.ACCESS_REQUEST:
|
||||
case TriggerFeature.ACCESS_REQUEST_UPDATED:
|
||||
targetChannels = microsoftTeamsConfig.accessRequestChannels;
|
||||
isEnabled = microsoftTeamsConfig.isAccessRequestNotificationEnabled;
|
||||
break;
|
||||
case TriggerFeature.SECRET_APPROVAL:
|
||||
targetChannels = microsoftTeamsConfig.secretRequestChannels;
|
||||
isEnabled = microsoftTeamsConfig.isSecretRequestNotificationEnabled;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEnabled && targetChannels) {
|
||||
const { success, data, error: validationError } = validateMicrosoftTeamsChannelsSchema.safeParse(targetChannels);
|
||||
|
||||
if (!success) {
|
||||
logger.error(validationError, "Invalid Microsoft Teams channel configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
await microsoftTeamsService
|
||||
.sendNotification({
|
||||
notification,
|
||||
target: data,
|
||||
tenantId: microsoftTeamsConfig.tenantId,
|
||||
microsoftTeamsIntegrationId: microsoftTeamsConfig.id,
|
||||
orgId
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(
|
||||
error,
|
||||
`Error sending Microsoft Teams notification. Notification type: ${notification.type}, Tenant ID: ${microsoftTeamsConfig.tenantId}, Project ID: ${microsoftTeamsConfig.projectId}`
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const triggerMicrosoftTeamsNotification = async ({
|
||||
projectId,
|
||||
notification,
|
||||
orgId,
|
||||
projectMicrosoftTeamsConfigDAL,
|
||||
microsoftTeamsService
|
||||
}: {
|
||||
projectId: string;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
projectMicrosoftTeamsConfigDAL: Pick<TProjectMicrosoftTeamsConfigDALFactory, "getIntegrationDetailsByProject">;
|
||||
microsoftTeamsService: Pick<TMicrosoftTeamsServiceFactory, "sendNotification">;
|
||||
}): Promise<void> => {
|
||||
try {
|
||||
const config = await projectMicrosoftTeamsConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
if (config) {
|
||||
await handleMicrosoftTeamsNotification({
|
||||
microsoftTeamsConfig: config,
|
||||
notification,
|
||||
orgId,
|
||||
microsoftTeamsService
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error, `Error handling Microsoft Teams notification. Project ID: ${projectId}`);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import {
|
||||
TProjectSlackConfigDALFactory,
|
||||
TProjectSlackConfigWithIntegrations
|
||||
} from "@app/services/slack/project-slack-config-dal";
|
||||
import { sendSlackNotification } from "@app/services/slack/slack-fns";
|
||||
|
||||
import { logger } from "../../logger";
|
||||
import { TNotification, TriggerFeature } from "../types";
|
||||
|
||||
const handleSlackNotification = async ({
|
||||
slackConfig,
|
||||
notification,
|
||||
orgId,
|
||||
kmsService
|
||||
}: {
|
||||
slackConfig: TProjectSlackConfigWithIntegrations;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
}): Promise<void> => {
|
||||
let targetChannelIds: string[] = [];
|
||||
let isEnabled = false;
|
||||
|
||||
switch (notification.type) {
|
||||
case TriggerFeature.ACCESS_REQUEST:
|
||||
case TriggerFeature.ACCESS_REQUEST_UPDATED:
|
||||
targetChannelIds = slackConfig.accessRequestChannels?.split(", ").filter(Boolean) || [];
|
||||
isEnabled = slackConfig.isAccessRequestNotificationEnabled;
|
||||
break;
|
||||
case TriggerFeature.SECRET_APPROVAL:
|
||||
targetChannelIds = slackConfig.secretRequestChannels?.split(", ").filter(Boolean) || [];
|
||||
isEnabled = slackConfig.isSecretRequestNotificationEnabled;
|
||||
break;
|
||||
case TriggerFeature.SECRET_SYNC_ERROR:
|
||||
targetChannelIds = slackConfig.secretSyncErrorChannels?.split(", ").filter(Boolean) || [];
|
||||
isEnabled = slackConfig.isSecretSyncErrorNotificationEnabled;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetChannelIds.length && isEnabled) {
|
||||
await sendSlackNotification({
|
||||
orgId,
|
||||
notification,
|
||||
kmsService,
|
||||
targetChannelIds,
|
||||
slackIntegration: slackConfig
|
||||
}).catch((error) => {
|
||||
logger.error(
|
||||
error,
|
||||
`Error sending Slack notification. Notification type: ${notification.type}, Target channel IDs: ${targetChannelIds.join(", ")}, Project ID: ${slackConfig.projectId}`
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const triggerSlackNotification = async ({
|
||||
projectId,
|
||||
notification,
|
||||
orgId,
|
||||
projectSlackConfigDAL,
|
||||
kmsService
|
||||
}: {
|
||||
projectId: string;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
}): Promise<void> => {
|
||||
try {
|
||||
const config = await projectSlackConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
if (config) {
|
||||
await handleSlackNotification({ slackConfig: config, notification, orgId, kmsService });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error, `Error handling Slack notification. Project ID: ${projectId}`);
|
||||
}
|
||||
};
|
||||
@@ -1,8 +1,7 @@
|
||||
import { validateMicrosoftTeamsChannelsSchema } from "@app/services/microsoft-teams/microsoft-teams-fns";
|
||||
import { sendSlackNotification } from "@app/services/slack/slack-fns";
|
||||
|
||||
import { logger } from "../logger";
|
||||
import { TriggerFeature, TTriggerWorkflowNotificationDTO } from "./types";
|
||||
import { triggerMicrosoftTeamsNotification } from "./notification-handlers/microsoft-teams";
|
||||
import { triggerSlackNotification } from "./notification-handlers/slack";
|
||||
import { TTriggerWorkflowNotificationDTO } from "./types";
|
||||
|
||||
export const triggerWorkflowIntegrationNotification = async (dto: TTriggerWorkflowNotificationDTO) => {
|
||||
try {
|
||||
@@ -16,88 +15,25 @@ export const triggerWorkflowIntegrationNotification = async (dto: TTriggerWorkfl
|
||||
return;
|
||||
}
|
||||
|
||||
const microsoftTeamsConfig = await projectMicrosoftTeamsConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
const slackConfig = await projectSlackConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
const handlerPromises = [
|
||||
triggerSlackNotification({
|
||||
projectId,
|
||||
notification,
|
||||
orgId: project.orgId,
|
||||
projectSlackConfigDAL,
|
||||
kmsService
|
||||
}),
|
||||
|
||||
if (slackConfig) {
|
||||
if (
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST ||
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST_UPDATED
|
||||
) {
|
||||
const targetChannelIds = slackConfig.accessRequestChannels?.split(", ") || [];
|
||||
if (targetChannelIds.length && slackConfig.isAccessRequestNotificationEnabled) {
|
||||
await sendSlackNotification({
|
||||
orgId: project.orgId,
|
||||
notification,
|
||||
kmsService,
|
||||
targetChannelIds,
|
||||
slackIntegration: slackConfig
|
||||
}).catch((error) => {
|
||||
logger.error(error, "Error sending Slack notification");
|
||||
});
|
||||
}
|
||||
} else if (notification.type === TriggerFeature.SECRET_APPROVAL) {
|
||||
const targetChannelIds = slackConfig.secretRequestChannels?.split(", ") || [];
|
||||
if (targetChannelIds.length && slackConfig.isSecretRequestNotificationEnabled) {
|
||||
await sendSlackNotification({
|
||||
orgId: project.orgId,
|
||||
notification,
|
||||
kmsService,
|
||||
targetChannelIds,
|
||||
slackIntegration: slackConfig
|
||||
}).catch((error) => {
|
||||
logger.error(error, "Error sending Slack notification");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
triggerMicrosoftTeamsNotification({
|
||||
projectId,
|
||||
notification,
|
||||
orgId: project.orgId,
|
||||
projectMicrosoftTeamsConfigDAL,
|
||||
microsoftTeamsService
|
||||
})
|
||||
];
|
||||
|
||||
if (microsoftTeamsConfig) {
|
||||
if (
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST ||
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST_UPDATED
|
||||
) {
|
||||
if (microsoftTeamsConfig.isAccessRequestNotificationEnabled && microsoftTeamsConfig.accessRequestChannels) {
|
||||
const { success, data } = validateMicrosoftTeamsChannelsSchema.safeParse(
|
||||
microsoftTeamsConfig.accessRequestChannels
|
||||
);
|
||||
|
||||
if (success && data) {
|
||||
await microsoftTeamsService
|
||||
.sendNotification({
|
||||
notification,
|
||||
target: data,
|
||||
tenantId: microsoftTeamsConfig.tenantId,
|
||||
microsoftTeamsIntegrationId: microsoftTeamsConfig.id,
|
||||
orgId: project.orgId
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(error, "Error sending Microsoft Teams notification");
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (notification.type === TriggerFeature.SECRET_APPROVAL) {
|
||||
if (microsoftTeamsConfig.isSecretRequestNotificationEnabled && microsoftTeamsConfig.secretRequestChannels) {
|
||||
const { success, data } = validateMicrosoftTeamsChannelsSchema.safeParse(
|
||||
microsoftTeamsConfig.secretRequestChannels
|
||||
);
|
||||
|
||||
if (success && data) {
|
||||
await microsoftTeamsService
|
||||
.sendNotification({
|
||||
notification,
|
||||
target: data,
|
||||
tenantId: microsoftTeamsConfig.tenantId,
|
||||
microsoftTeamsIntegrationId: microsoftTeamsConfig.id,
|
||||
orgId: project.orgId
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(error, "Error sending Microsoft Teams notification");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await Promise.allSettled(handlerPromises);
|
||||
} catch (error) {
|
||||
logger.error(error, "Error triggering workflow integration notification");
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { TProjectSlackConfigDALFactory } from "@app/services/slack/project-slack
|
||||
export enum TriggerFeature {
|
||||
SECRET_APPROVAL = "secret-approval",
|
||||
ACCESS_REQUEST = "access-request",
|
||||
ACCESS_REQUEST_UPDATED = "access-request-updated"
|
||||
ACCESS_REQUEST_UPDATED = "access-request-updated",
|
||||
SECRET_SYNC_ERROR = "secret-sync-error"
|
||||
}
|
||||
|
||||
export type TNotification =
|
||||
@@ -20,6 +21,7 @@ export type TNotification =
|
||||
requestId: string;
|
||||
projectId: string;
|
||||
secretKeys: string[];
|
||||
approvalUrl: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
@@ -31,6 +33,7 @@ export type TNotification =
|
||||
secretPath: string;
|
||||
environment: string;
|
||||
projectName: string;
|
||||
projectPath: string;
|
||||
permissions: string[];
|
||||
approvalUrl: string;
|
||||
note?: string;
|
||||
@@ -50,6 +53,21 @@ export type TNotification =
|
||||
editNote?: string;
|
||||
editorFullName?: string;
|
||||
editorEmail?: string;
|
||||
projectPath: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: TriggerFeature.SECRET_SYNC_ERROR;
|
||||
payload: {
|
||||
syncName: string;
|
||||
syncActionLabel: string;
|
||||
syncDestination: string;
|
||||
failureMessage: string;
|
||||
syncUrl: string;
|
||||
environment: string;
|
||||
secretPath: string;
|
||||
projectName: string;
|
||||
projectPath: string;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user