mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 19:26:19 +00:00
Merge pull request #2855 from akhilmhdh/feat/integration-auth-update-endpoint
feat: added endpoint to update integration auth
This commit is contained in:
@@ -60,6 +60,7 @@ export enum EventType {
|
|||||||
DELETE_SECRETS = "delete-secrets",
|
DELETE_SECRETS = "delete-secrets",
|
||||||
GET_WORKSPACE_KEY = "get-workspace-key",
|
GET_WORKSPACE_KEY = "get-workspace-key",
|
||||||
AUTHORIZE_INTEGRATION = "authorize-integration",
|
AUTHORIZE_INTEGRATION = "authorize-integration",
|
||||||
|
UPDATE_INTEGRATION_AUTH = "update-integration-auth",
|
||||||
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
||||||
CREATE_INTEGRATION = "create-integration",
|
CREATE_INTEGRATION = "create-integration",
|
||||||
DELETE_INTEGRATION = "delete-integration",
|
DELETE_INTEGRATION = "delete-integration",
|
||||||
@@ -357,6 +358,13 @@ interface AuthorizeIntegrationEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface UpdateIntegrationAuthEvent {
|
||||||
|
type: EventType.UPDATE_INTEGRATION_AUTH;
|
||||||
|
metadata: {
|
||||||
|
integration: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface UnauthorizeIntegrationEvent {
|
interface UnauthorizeIntegrationEvent {
|
||||||
type: EventType.UNAUTHORIZE_INTEGRATION;
|
type: EventType.UNAUTHORIZE_INTEGRATION;
|
||||||
metadata: {
|
metadata: {
|
||||||
@@ -1680,6 +1688,7 @@ export type Event =
|
|||||||
| DeleteSecretBatchEvent
|
| DeleteSecretBatchEvent
|
||||||
| GetWorkspaceKeyEvent
|
| GetWorkspaceKeyEvent
|
||||||
| AuthorizeIntegrationEvent
|
| AuthorizeIntegrationEvent
|
||||||
|
| UpdateIntegrationAuthEvent
|
||||||
| UnauthorizeIntegrationEvent
|
| UnauthorizeIntegrationEvent
|
||||||
| CreateIntegrationEvent
|
| CreateIntegrationEvent
|
||||||
| DeleteIntegrationEvent
|
| DeleteIntegrationEvent
|
||||||
|
|||||||
@@ -1032,6 +1032,9 @@ export const INTEGRATION_AUTH = {
|
|||||||
DELETE_BY_ID: {
|
DELETE_BY_ID: {
|
||||||
integrationAuthId: "The ID of integration authentication object to delete."
|
integrationAuthId: "The ID of integration authentication object to delete."
|
||||||
},
|
},
|
||||||
|
UPDATE_BY_ID: {
|
||||||
|
integrationAuthId: "The ID of integration authentication object to update."
|
||||||
|
},
|
||||||
CREATE_ACCESS_TOKEN: {
|
CREATE_ACCESS_TOKEN: {
|
||||||
workspaceId: "The ID of the project to create the integration auth for.",
|
workspaceId: "The ID of the project to create the integration auth for.",
|
||||||
integration: "The slug of integration for the auth object.",
|
integration: "The slug of integration for the auth object.",
|
||||||
@@ -1088,11 +1091,13 @@ export const INTEGRATION = {
|
|||||||
},
|
},
|
||||||
UPDATE: {
|
UPDATE: {
|
||||||
integrationId: "The ID of the integration object.",
|
integrationId: "The ID of the integration object.",
|
||||||
|
region: "AWS region to sync secrets to.",
|
||||||
app: "The name of the external integration providers app entity that you want to sync secrets with. Used in Netlify, GitHub, Vercel integrations.",
|
app: "The name of the external integration providers app entity that you want to sync secrets with. Used in Netlify, GitHub, Vercel integrations.",
|
||||||
appId:
|
appId:
|
||||||
"The ID of the external integration providers app entity that you want to sync secrets with. Used in Netlify, GitHub, Vercel integrations.",
|
"The ID of the external integration providers app entity that you want to sync secrets with. Used in Netlify, GitHub, Vercel integrations.",
|
||||||
isActive: "Whether the integration should be active or disabled.",
|
isActive: "Whether the integration should be active or disabled.",
|
||||||
secretPath: "The path of the secrets to sync secrets from.",
|
secretPath: "The path of the secrets to sync secrets from.",
|
||||||
|
path: "Path to save the synced secrets. Used by Gitlab, AWS Parameter Store, Vault.",
|
||||||
owner: "External integration providers service entity owner. Used in Github.",
|
owner: "External integration providers service entity owner. Used in Github.",
|
||||||
targetEnvironment:
|
targetEnvironment:
|
||||||
"The target environment of the integration provider. Used in cloudflare pages, TeamCity, Gitlab integrations.",
|
"The target environment of the integration provider. Used in cloudflare pages, TeamCity, Gitlab integrations.",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
|||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { OctopusDeployScope } from "@app/services/integration-auth/integration-auth-types";
|
import { OctopusDeployScope } from "@app/services/integration-auth/integration-auth-types";
|
||||||
|
import { Integrations } from "@app/services/integration-auth/integration-list";
|
||||||
|
|
||||||
import { integrationAuthPubSchema } from "../sanitizedSchemas";
|
import { integrationAuthPubSchema } from "../sanitizedSchemas";
|
||||||
|
|
||||||
@@ -82,6 +83,67 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:integrationAuthId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
|
schema: {
|
||||||
|
description: "Update the integration authentication object required for syncing secrets.",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
querystring: z.object({
|
||||||
|
integrationAuthId: z.string().trim().describe(INTEGRATION_AUTH.UPDATE_BY_ID.integrationAuthId)
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
integration: z.nativeEnum(Integrations).optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.integration),
|
||||||
|
accessId: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.accessId),
|
||||||
|
accessToken: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.accessToken),
|
||||||
|
awsAssumeIamRoleArn: z
|
||||||
|
.string()
|
||||||
|
.url()
|
||||||
|
.trim()
|
||||||
|
.optional()
|
||||||
|
.describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.awsAssumeIamRoleArn),
|
||||||
|
url: z.string().url().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.url),
|
||||||
|
namespace: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.namespace),
|
||||||
|
refreshToken: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.refreshToken)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
integrationAuth: integrationAuthPubSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const integrationAuth = await server.services.integrationAuth.updateIntegrationAuth({
|
||||||
|
actorId: req.permission.id,
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
integrationAuthId: req.query.integrationAuthId,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
projectId: integrationAuth.projectId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_INTEGRATION_AUTH,
|
||||||
|
metadata: {
|
||||||
|
integration: integrationAuth.integration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { integrationAuth };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
url: "/",
|
url: "/",
|
||||||
|
|||||||
@@ -141,7 +141,9 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
|||||||
targetEnvironment: z.string().trim().optional().describe(INTEGRATION.UPDATE.targetEnvironment),
|
targetEnvironment: z.string().trim().optional().describe(INTEGRATION.UPDATE.targetEnvironment),
|
||||||
owner: z.string().trim().optional().describe(INTEGRATION.UPDATE.owner),
|
owner: z.string().trim().optional().describe(INTEGRATION.UPDATE.owner),
|
||||||
environment: z.string().trim().optional().describe(INTEGRATION.UPDATE.environment),
|
environment: z.string().trim().optional().describe(INTEGRATION.UPDATE.environment),
|
||||||
metadata: IntegrationMetadataSchema.optional()
|
path: z.string().trim().optional().describe(INTEGRATION.UPDATE.path),
|
||||||
|
metadata: IntegrationMetadataSchema.optional(),
|
||||||
|
region: z.string().trim().optional().describe(INTEGRATION.UPDATE.region)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import {
|
|||||||
TOctopusDeployVariableSet,
|
TOctopusDeployVariableSet,
|
||||||
TSaveIntegrationAccessTokenDTO,
|
TSaveIntegrationAccessTokenDTO,
|
||||||
TTeamCityBuildConfig,
|
TTeamCityBuildConfig,
|
||||||
|
TUpdateIntegrationAuthDTO,
|
||||||
TVercelBranches
|
TVercelBranches
|
||||||
} from "./integration-auth-types";
|
} from "./integration-auth-types";
|
||||||
import { getIntegrationOptions, Integrations, IntegrationUrls } from "./integration-list";
|
import { getIntegrationOptions, Integrations, IntegrationUrls } from "./integration-list";
|
||||||
@@ -368,6 +369,148 @@ export const integrationAuthServiceFactory = ({
|
|||||||
return integrationAuthDAL.create(updateDoc);
|
return integrationAuthDAL.create(updateDoc);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updateIntegrationAuth = async ({
|
||||||
|
integrationAuthId,
|
||||||
|
refreshToken,
|
||||||
|
actorId,
|
||||||
|
integration: newIntegration,
|
||||||
|
url,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
accessId,
|
||||||
|
namespace,
|
||||||
|
accessToken,
|
||||||
|
awsAssumeIamRoleArn
|
||||||
|
}: TUpdateIntegrationAuthDTO) => {
|
||||||
|
const integrationAuth = await integrationAuthDAL.findById(integrationAuthId);
|
||||||
|
if (!integrationAuth) {
|
||||||
|
throw new NotFoundError({ message: `Integration auth with id ${integrationAuthId} not found.` });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
integrationAuth.projectId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);
|
||||||
|
|
||||||
|
const { projectId } = integrationAuth;
|
||||||
|
const integration = newIntegration || integrationAuth.integration;
|
||||||
|
|
||||||
|
const updateDoc: TIntegrationAuthsInsert = {
|
||||||
|
projectId,
|
||||||
|
integration,
|
||||||
|
namespace,
|
||||||
|
url,
|
||||||
|
algorithm: SecretEncryptionAlgo.AES_256_GCM,
|
||||||
|
keyEncoding: SecretKeyEncoding.UTF8,
|
||||||
|
...(integration === Integrations.GCP_SECRET_MANAGER
|
||||||
|
? {
|
||||||
|
metadata: {
|
||||||
|
authMethod: "serviceAccount"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: {})
|
||||||
|
};
|
||||||
|
|
||||||
|
const { shouldUseSecretV2Bridge, botKey } = await projectBotService.getBotKey(projectId);
|
||||||
|
if (shouldUseSecretV2Bridge) {
|
||||||
|
const { encryptor: secretManagerEncryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
type: KmsDataKey.SecretManager,
|
||||||
|
projectId
|
||||||
|
});
|
||||||
|
if (refreshToken) {
|
||||||
|
const tokenDetails = await exchangeRefresh(
|
||||||
|
integration,
|
||||||
|
refreshToken,
|
||||||
|
url,
|
||||||
|
updateDoc.metadata as Record<string, string>
|
||||||
|
);
|
||||||
|
const refreshEncToken = secretManagerEncryptor({
|
||||||
|
plainText: Buffer.from(tokenDetails.refreshToken)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
updateDoc.encryptedRefresh = refreshEncToken;
|
||||||
|
|
||||||
|
const accessEncToken = secretManagerEncryptor({
|
||||||
|
plainText: Buffer.from(tokenDetails.accessToken)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
updateDoc.encryptedAccess = accessEncToken;
|
||||||
|
updateDoc.accessExpiresAt = tokenDetails.accessExpiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!refreshToken && (accessId || accessToken || awsAssumeIamRoleArn)) {
|
||||||
|
if (accessToken) {
|
||||||
|
const accessEncToken = secretManagerEncryptor({
|
||||||
|
plainText: Buffer.from(accessToken)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
updateDoc.encryptedAccess = accessEncToken;
|
||||||
|
updateDoc.encryptedAwsAssumeIamRoleArn = null;
|
||||||
|
}
|
||||||
|
if (accessId) {
|
||||||
|
const accessEncToken = secretManagerEncryptor({
|
||||||
|
plainText: Buffer.from(accessId)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
updateDoc.encryptedAccessId = accessEncToken;
|
||||||
|
updateDoc.encryptedAwsAssumeIamRoleArn = null;
|
||||||
|
}
|
||||||
|
if (awsAssumeIamRoleArn) {
|
||||||
|
const awsAssumeIamRoleArnEncrypted = secretManagerEncryptor({
|
||||||
|
plainText: Buffer.from(awsAssumeIamRoleArn)
|
||||||
|
}).cipherTextBlob;
|
||||||
|
updateDoc.encryptedAwsAssumeIamRoleArn = awsAssumeIamRoleArnEncrypted;
|
||||||
|
updateDoc.encryptedAccess = null;
|
||||||
|
updateDoc.encryptedAccessId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!botKey) throw new NotFoundError({ message: `Project bot key for project with ID '${projectId}' not found` });
|
||||||
|
if (refreshToken) {
|
||||||
|
const tokenDetails = await exchangeRefresh(
|
||||||
|
integration,
|
||||||
|
refreshToken,
|
||||||
|
url,
|
||||||
|
updateDoc.metadata as Record<string, string>
|
||||||
|
);
|
||||||
|
const refreshEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.refreshToken, botKey);
|
||||||
|
updateDoc.refreshIV = refreshEncToken.iv;
|
||||||
|
updateDoc.refreshTag = refreshEncToken.tag;
|
||||||
|
updateDoc.refreshCiphertext = refreshEncToken.ciphertext;
|
||||||
|
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(tokenDetails.accessToken, botKey);
|
||||||
|
updateDoc.accessIV = accessEncToken.iv;
|
||||||
|
updateDoc.accessTag = accessEncToken.tag;
|
||||||
|
updateDoc.accessCiphertext = accessEncToken.ciphertext;
|
||||||
|
|
||||||
|
updateDoc.accessExpiresAt = tokenDetails.accessExpiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!refreshToken && (accessId || accessToken || awsAssumeIamRoleArn)) {
|
||||||
|
if (accessToken) {
|
||||||
|
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessToken, botKey);
|
||||||
|
updateDoc.accessIV = accessEncToken.iv;
|
||||||
|
updateDoc.accessTag = accessEncToken.tag;
|
||||||
|
updateDoc.accessCiphertext = accessEncToken.ciphertext;
|
||||||
|
}
|
||||||
|
if (accessId) {
|
||||||
|
const accessEncToken = encryptSymmetric128BitHexKeyUTF8(accessId, botKey);
|
||||||
|
updateDoc.accessIdIV = accessEncToken.iv;
|
||||||
|
updateDoc.accessIdTag = accessEncToken.tag;
|
||||||
|
updateDoc.accessIdCiphertext = accessEncToken.ciphertext;
|
||||||
|
}
|
||||||
|
if (awsAssumeIamRoleArn) {
|
||||||
|
const awsAssumeIamRoleArnEnc = encryptSymmetric128BitHexKeyUTF8(awsAssumeIamRoleArn, botKey);
|
||||||
|
updateDoc.awsAssumeIamRoleArnCipherText = awsAssumeIamRoleArnEnc.ciphertext;
|
||||||
|
updateDoc.awsAssumeIamRoleArnIV = awsAssumeIamRoleArnEnc.iv;
|
||||||
|
updateDoc.awsAssumeIamRoleArnTag = awsAssumeIamRoleArnEnc.tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return integrationAuthDAL.updateById(integrationAuthId, updateDoc);
|
||||||
|
};
|
||||||
|
|
||||||
// helper function
|
// helper function
|
||||||
const getIntegrationAccessToken = async (
|
const getIntegrationAccessToken = async (
|
||||||
integrationAuth: TIntegrationAuths,
|
integrationAuth: TIntegrationAuths,
|
||||||
@@ -1615,6 +1758,7 @@ export const integrationAuthServiceFactory = ({
|
|||||||
getIntegrationAuth,
|
getIntegrationAuth,
|
||||||
oauthExchange,
|
oauthExchange,
|
||||||
saveIntegrationToken,
|
saveIntegrationToken,
|
||||||
|
updateIntegrationAuth,
|
||||||
deleteIntegrationAuthById,
|
deleteIntegrationAuthById,
|
||||||
deleteIntegrationAuths,
|
deleteIntegrationAuths,
|
||||||
getIntegrationAuthTeams,
|
getIntegrationAuthTeams,
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ export type TSaveIntegrationAccessTokenDTO = {
|
|||||||
awsAssumeIamRoleArn?: string;
|
awsAssumeIamRoleArn?: string;
|
||||||
} & TProjectPermission;
|
} & TProjectPermission;
|
||||||
|
|
||||||
|
export type TUpdateIntegrationAuthDTO = Omit<TSaveIntegrationAccessTokenDTO, "projectId" | "integration"> & {
|
||||||
|
integrationAuthId: string;
|
||||||
|
integration?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type TDeleteIntegrationAuthsDTO = TProjectPermission & {
|
export type TDeleteIntegrationAuthsDTO = TProjectPermission & {
|
||||||
integration: string;
|
integration: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
|||||||
@@ -151,7 +151,9 @@ export const integrationServiceFactory = ({
|
|||||||
isActive,
|
isActive,
|
||||||
environment,
|
environment,
|
||||||
secretPath,
|
secretPath,
|
||||||
metadata
|
region,
|
||||||
|
metadata,
|
||||||
|
path
|
||||||
}: TUpdateIntegrationDTO) => {
|
}: TUpdateIntegrationDTO) => {
|
||||||
const integration = await integrationDAL.findById(id);
|
const integration = await integrationDAL.findById(id);
|
||||||
if (!integration) throw new NotFoundError({ message: `Integration with ID '${id}' not found` });
|
if (!integration) throw new NotFoundError({ message: `Integration with ID '${id}' not found` });
|
||||||
@@ -192,7 +194,9 @@ export const integrationServiceFactory = ({
|
|||||||
appId,
|
appId,
|
||||||
targetEnvironment,
|
targetEnvironment,
|
||||||
owner,
|
owner,
|
||||||
|
region,
|
||||||
secretPath,
|
secretPath,
|
||||||
|
path,
|
||||||
metadata: {
|
metadata: {
|
||||||
...(integration.metadata as object),
|
...(integration.metadata as object),
|
||||||
...metadata
|
...metadata
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ export type TUpdateIntegrationDTO = {
|
|||||||
appId?: string;
|
appId?: string;
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
secretPath?: string;
|
secretPath?: string;
|
||||||
|
region?: string;
|
||||||
|
path?: string;
|
||||||
targetEnvironment?: string;
|
targetEnvironment?: string;
|
||||||
owner?: string;
|
owner?: string;
|
||||||
environment?: string;
|
environment?: string;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
|||||||
[EventType.DELETE_SECRET]: "Delete secret",
|
[EventType.DELETE_SECRET]: "Delete secret",
|
||||||
[EventType.GET_WORKSPACE_KEY]: "Read project key",
|
[EventType.GET_WORKSPACE_KEY]: "Read project key",
|
||||||
[EventType.AUTHORIZE_INTEGRATION]: "Authorize integration",
|
[EventType.AUTHORIZE_INTEGRATION]: "Authorize integration",
|
||||||
|
[EventType.UPDATE_INTEGRATION_AUTH]: "Update integration auth",
|
||||||
[EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration",
|
[EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration",
|
||||||
[EventType.CREATE_INTEGRATION]: "Create integration",
|
[EventType.CREATE_INTEGRATION]: "Create integration",
|
||||||
[EventType.DELETE_INTEGRATION]: "Delete integration",
|
[EventType.DELETE_INTEGRATION]: "Delete integration",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export enum EventType {
|
|||||||
DELETE_SECRET = "delete-secret",
|
DELETE_SECRET = "delete-secret",
|
||||||
GET_WORKSPACE_KEY = "get-workspace-key",
|
GET_WORKSPACE_KEY = "get-workspace-key",
|
||||||
AUTHORIZE_INTEGRATION = "authorize-integration",
|
AUTHORIZE_INTEGRATION = "authorize-integration",
|
||||||
|
UPDATE_INTEGRATION_AUTH = "update-integration-auth",
|
||||||
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
||||||
CREATE_INTEGRATION = "create-integration",
|
CREATE_INTEGRATION = "create-integration",
|
||||||
DELETE_INTEGRATION = "delete-integration",
|
DELETE_INTEGRATION = "delete-integration",
|
||||||
|
|||||||
Reference in New Issue
Block a user