feat: govslack support

This commit is contained in:
Piyush Gupta
2025-12-14 12:58:29 +05:30
parent fd207db786
commit 6baeac678a
8 changed files with 85 additions and 11 deletions

View File

@@ -246,6 +246,8 @@ const envSchema = z
),
WORKFLOW_SLACK_CLIENT_ID: zpStr(z.string().optional()),
WORKFLOW_SLACK_CLIENT_SECRET: zpStr(z.string().optional()),
WORKFLOW_SLACK_GOV_ENABLED: zodStrBool.default("false"),
WORKFLOW_SLACK_GOV_BASE_URL: zpStr(z.string().optional().default("https://slack-gov.com")),
ENABLE_MSSQL_SECRET_ROTATION_ENCRYPT: zodStrBool.default("true"),
// Special Detection Feature

View File

@@ -374,7 +374,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
200: z.object({
slack: z.object({
clientId: z.string(),
clientSecret: z.string()
clientSecret: z.string(),
govEnabled: z.boolean()
}),
microsoftTeams: z.object({
appId: z.string(),

View File

@@ -1,4 +1,4 @@
import { WebClient } from "@slack/web-api";
import { WebClient, WebClientOptions } from "@slack/web-api";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
@@ -12,12 +12,20 @@ const COMPANY_BRAND_COLOR = "#e0ed34";
const ERROR_COLOR = "#e74c3c";
export const fetchSlackChannels = async (botKey: string) => {
const appCfg = getConfig();
const slackChannels: {
name: string;
id: string;
}[] = [];
const slackWebClient = new WebClient(botKey);
const webClientOptions: WebClientOptions = {};
if (appCfg.WORKFLOW_SLACK_GOV_ENABLED) {
const govBaseUrl = appCfg.WORKFLOW_SLACK_GOV_BASE_URL;
webClientOptions.slackApiUrl = `${govBaseUrl}/api`;
}
const slackWebClient = new WebClient(botKey, webClientOptions);
let cursor;
do {
@@ -269,6 +277,7 @@ export const sendSlackNotification = async ({
targetChannelIds,
slackIntegration
}: TSendSlackNotificationDTO) => {
const appCfg = getConfig();
const { decryptor: orgDataKeyDecryptor } = await kmsService.createCipherPairWithDataKey({
type: KmsDataKey.Organization,
orgId
@@ -276,7 +285,15 @@ export const sendSlackNotification = async ({
const botKey = orgDataKeyDecryptor({
cipherTextBlob: slackIntegration.encryptedBotAccessToken
}).toString("utf8");
const slackWebClient = new WebClient(botKey);
const webClientOptions: WebClientOptions = {};
if (appCfg.WORKFLOW_SLACK_GOV_ENABLED) {
const govBaseUrl = appCfg.WORKFLOW_SLACK_GOV_BASE_URL;
webClientOptions.slackApiUrl = `${govBaseUrl}/api`;
}
const slackWebClient = new WebClient(botKey, webClientOptions);
const { payloadMessage, payloadBlocks, color, headerBlocks } = buildSlackPayload(notification);

View File

@@ -1,5 +1,5 @@
import { ForbiddenError } from "@casl/ability";
import { InstallProvider } from "@slack/oauth";
import { InstallProvider, InstallProviderOptions } from "@slack/oauth";
import { OrganizationActionScope } from "@app/db/schemas";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
@@ -162,7 +162,7 @@ export const slackServiceFactory = ({
});
}
return new InstallProvider({
const installProviderOptions: InstallProviderOptions = {
clientId: slackClientId,
clientSecret: slackClientSecret,
stateSecret: appCfg.AUTH_SECRET,
@@ -218,7 +218,17 @@ export const slackServiceFactory = ({
return {} as never;
}
}
});
};
if (appCfg.WORKFLOW_SLACK_GOV_ENABLED) {
const govBaseUrl = appCfg.WORKFLOW_SLACK_GOV_BASE_URL;
installProviderOptions.authorizationUrl = `${govBaseUrl}/oauth/v2/authorize`;
installProviderOptions.clientOptions = {
slackApiUrl: `${govBaseUrl}/api`
};
}
return new InstallProvider(installProviderOptions);
};
const getInstallUrl = async ({

View File

@@ -235,10 +235,13 @@ export const superAdminServiceFactory = ({
? decrypt(serverCfg.encryptedGitHubAppConnectionPrivateKey).toString()
: "";
const appCfg = getConfig();
return {
slack: {
clientSecret: slackClientSecret,
clientId: slackClientId
clientId: slackClientId,
govEnabled: appCfg.WORKFLOW_SLACK_GOV_ENABLED
},
microsoftTeams: {
appId: microsoftAppId,

View File

@@ -62,6 +62,10 @@ This guide will provide step by step instructions on how to configure Slack inte
### Configure admin settings
Note that this step only has to be done once for the entire instance.
<Info>
If you're using GovSlack, you'll need to enable GovSlack mode by setting `WORKFLOW_SLACK_GOV_ENABLED=true` and `WORKFLOW_SLACK_GOV_BASE_URL` environment variables. See the [GovSlack Support](#govslack-support) section for more details.
</Info>
<Steps>
<Step title="Navigate to the Integrations tab in the Admin settings">
Before anything else, you need to setup the Slack app to be used by
@@ -145,6 +149,34 @@ This guide will provide step by step instructions on how to configure Slack inte
</Tab>
</Tabs>
## GovSlack Support
Infisical supports integration with GovSlack workspaces. When enabled, Infisical will use the GovSlack API endpoints instead of the standard Slack API.
<Info>
GovSlack support is only available for self-hosted instances. Contact your
instance administrator to enable this feature.
</Info>
### Enabling Slack Gov Mode
To enable Slack Gov support, set the following environment variables:
```bash
WORKFLOW_SLACK_GOV_ENABLED=true
WORKFLOW_SLACK_GOV_BASE_URL=https://slack-gov.com
```
<Note>
The `WORKFLOW_SLACK_GOV_BASE_URL` defaults to `https://slack-gov.com` if not
specified. If your organization uses a custom Slack Gov URL, update this value
accordingly.
</Note>
### Setting Up GovSlack Integration
When GovSlack mode is enabled, the integration process is the same as the standard Slack integration. You can follow the steps in the [Self-hosted setup](#self-hosted-setup) section to set up the Slack integration.
## Using the Slack integration in your private channels
<Steps>

View File

@@ -119,6 +119,7 @@ export type AdminIntegrationsConfig = {
slack: {
clientId: string;
clientSecret: string;
govEnabled: boolean;
};
microsoftTeams: {
appId: string;

View File

@@ -18,8 +18,9 @@ import { useToggle } from "@app/hooks";
import { useUpdateServerConfig } from "@app/hooks/api";
import { AdminIntegrationsConfig } from "@app/hooks/api/admin/types";
const getCustomSlackAppCreationUrl = () =>
`https://api.slack.com/apps?new_app=1&manifest_json=${encodeURIComponent(
const getCustomSlackAppCreationUrl = (govEnabled: boolean) => {
const baseUrl = govEnabled ? "https://api.slack-gov.com" : "https://api.slack.com";
return `${baseUrl}/apps?new_app=1&manifest_json=${encodeURIComponent(
JSON.stringify({
display_information: {
name: "Infisical",
@@ -56,6 +57,7 @@ const getCustomSlackAppCreationUrl = () =>
}
})
)}`;
};
const slackFormSchema = z.object({
clientId: z.string(),
@@ -119,7 +121,13 @@ export const SlackIntegrationForm = ({ adminIntegrationsConfig }: Props) => {
<div className="mb-6">
<Button
colorSchema="secondary"
onClick={() => window.open(getCustomSlackAppCreationUrl())}
onClick={() =>
window.open(
getCustomSlackAppCreationUrl(
adminIntegrationsConfig?.slack.govEnabled ?? false
)
)
}
>
Create Slack App
</Button>