Add more audit log events

This commit is contained in:
Tuan Dang
2023-08-08 09:50:49 +07:00
parent 648968c453
commit 2591161272
19 changed files with 1117 additions and 53 deletions
@@ -3,7 +3,9 @@ import { Types } from "mongoose";
import { standardRequest } from "../../config/request"; import { standardRequest } from "../../config/request";
import { getApps, getTeams, revokeAccess } from "../../integrations"; import { getApps, getTeams, revokeAccess } from "../../integrations";
import { Bot, IntegrationAuth } from "../../models"; import { Bot, IntegrationAuth } from "../../models";
import { EventType } from "../../ee/models";
import { IntegrationService } from "../../services"; import { IntegrationService } from "../../services";
import { EEAuditLogService } from "../../ee/services";
import { import {
ALGORITHM_AES_256_GCM, ALGORITHM_AES_256_GCM,
ENCODING_SCHEME_UTF8, ENCODING_SCHEME_UTF8,
@@ -62,6 +64,19 @@ export const oAuthExchange = async (req: Request, res: Response) => {
environment: environments[0].slug environment: environments[0].slug
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.AUTHORIZE_INTEGRATION,
metadata: {
integration: integrationAuth.integration
}
},
{
workspaceId: integrationAuth.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
}); });
@@ -130,6 +145,19 @@ export const saveIntegrationAccessToken = async (req: Request, res: Response) =>
if (!integrationAuth) throw new Error("Failed to save integration access token"); if (!integrationAuth) throw new Error("Failed to save integration access token");
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.AUTHORIZE_INTEGRATION,
metadata: {
integration: integrationAuth.integration
}
},
{
workspaceId: integrationAuth.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
}); });
@@ -531,6 +559,23 @@ export const deleteIntegrationAuth = async (req: Request, res: Response) => {
accessToken: req.accessToken accessToken: req.accessToken
}); });
if (!integrationAuth) return res.status(400).send({
message: "Failed to find integration authorization"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UNAUTHORIZE_INTEGRATION,
metadata: {
integration: integrationAuth.integration
}
},
{
workspaceId: integrationAuth.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integrationAuth integrationAuth
}); });
@@ -6,6 +6,8 @@ import { eventStartIntegration } from "../../events";
import Folder from "../../models/folder"; import Folder from "../../models/folder";
import { getFolderByPath } from "../../services/FolderService"; import { getFolderByPath } from "../../services/FolderService";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError } from "../../utils/errors";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
/** /**
* Create/initialize an (empty) integration for integration authorization * Create/initialize an (empty) integration for integration authorization
@@ -75,6 +77,25 @@ export const createIntegration = async (req: Request, res: Response) => {
}); });
} }
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_INTEGRATION,
metadata: {
integrationId: integration._id.toString(),
integration: integration.integration,
environment: integration.environment,
secretPath,
app: integration.app,
targetEnvironment: integration.targetEnvironment,
targetEnvironmentId: integration.targetEnvironmentId
}
},
{
workspaceId: integration.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integration integration
}); });
@@ -148,8 +169,7 @@ export const updateIntegration = async (req: Request, res: Response) => {
}; };
/** /**
* Delete integration with id [integrationId] and deactivate bot if there are * Delete integration with id [integrationId]
* no integrations left
* @param req * @param req
* @param res * @param res
* @returns * @returns
@@ -163,6 +183,25 @@ export const deleteIntegration = async (req: Request, res: Response) => {
if (!integration) throw new Error("Failed to find integration"); if (!integration) throw new Error("Failed to find integration");
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_INTEGRATION,
metadata: {
integrationId: integration._id.toString(),
integration: integration.integration,
environment: integration.environment,
secretPath: integration.secretPath,
app: integration.app,
targetEnvironment: integration.targetEnvironment,
targetEnvironmentId: integration.targetEnvironmentId
}
},
{
workspaceId: integration.workspace
}
);
return res.status(200).send({ return res.status(200).send({
integration integration
}); });
@@ -1,9 +1,12 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Key, Membership, MembershipOrg, User } from "../../models"; import { Types } from "mongoose";
import { Key, Membership, MembershipOrg, User, IUser } from "../../models";
import { EventType } from "../../ee/models";
import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership"; import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership";
import { sendMail } from "../../helpers/nodemailer"; import { sendMail } from "../../helpers/nodemailer";
import { ACCEPTED, ADMIN, MEMBER } from "../../variables"; import { ACCEPTED, ADMIN, MEMBER } from "../../variables";
import { getSiteURL } from "../../config"; import { getSiteURL } from "../../config";
import { EEAuditLogService } from "../../ee/services";
/** /**
* Check that user is a member of workspace with id [workspaceId] * Check that user is a member of workspace with id [workspaceId]
@@ -40,7 +43,7 @@ export const deleteMembership = async (req: Request, res: Response) => {
// check if membership to delete exists // check if membership to delete exists
const membershipToDelete = await Membership.findOne({ const membershipToDelete = await Membership.findOne({
_id: membershipId _id: membershipId
}).populate("user"); }).populate<{ user: IUser }>("user");
if (!membershipToDelete) { if (!membershipToDelete) {
throw new Error("Failed to delete workspace membership that doesn't exist"); throw new Error("Failed to delete workspace membership that doesn't exist");
@@ -67,6 +70,20 @@ export const deleteMembership = async (req: Request, res: Response) => {
membershipId: membershipToDelete._id.toString() membershipId: membershipToDelete._id.toString()
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.REMOVE_WORKSPACE_MEMBER,
metadata: {
userId: membershipToDelete.user._id.toString(),
email: membershipToDelete.user.email
}
},
{
workspaceId: membership.workspace
}
);
return res.status(200).send({ return res.status(200).send({
deletedMembership deletedMembership
}); });
@@ -140,7 +157,7 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
const inviteeMembership = await Membership.findOne({ const inviteeMembership = await Membership.findOne({
user: invitee._id, user: invitee._id,
workspace: workspaceId workspace: workspaceId
}); }).populate<{ user: IUser }>("user");
if (inviteeMembership) throw new Error("Failed to add existing member of workspace"); if (inviteeMembership) throw new Error("Failed to add existing member of workspace");
@@ -181,6 +198,20 @@ export const inviteUserToWorkspace = async (req: Request, res: Response) => {
} }
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.ADD_WORKSPACE_MEMBER,
metadata: {
userId: invitee._id.toString(),
email: invitee.email
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.status(200).send({ return res.status(200).send({
invitee, invitee,
latestKey latestKey
@@ -1,5 +1,6 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Secret } from "../../models"; import { Secret } from "../../models";
import { Types } from "mongoose";
import Folder from "../../models/folder"; import Folder from "../../models/folder";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError } from "../../utils/errors";
import { import {
@@ -8,6 +9,7 @@ import {
generateFolderId, generateFolderId,
getAllFolderIds, getAllFolderIds,
getFolderByPath, getFolderByPath,
getFolderPath,
getParentFromFolderId, getParentFromFolderId,
searchByFolderId, searchByFolderId,
searchByFolderIdWithDir, searchByFolderIdWithDir,
@@ -15,10 +17,9 @@ import {
} from "../../services/FolderService"; } from "../../services/FolderService";
import { ADMIN, MEMBER } from "../../variables"; import { ADMIN, MEMBER } from "../../variables";
import { validateMembership } from "../../helpers/membership"; import { validateMembership } from "../../helpers/membership";
import { FolderVersion } from "../../ee/models"; import { FolderVersion, EventType } from "../../ee/models";
import { EESecretService } from "../../ee/services"; import { EESecretService, EEAuditLogService } from "../../ee/services";
// TODO
// verify workspace id/environment // verify workspace id/environment
export const createFolder = async (req: Request, res: Response) => { export const createFolder = async (req: Request, res: Response) => {
const { workspaceId, environment, folderName, parentFolderId } = req.body; const { workspaceId, environment, folderName, parentFolderId } = req.body;
@@ -33,6 +34,7 @@ export const createFolder = async (req: Request, res: Response) => {
environment, environment,
}).lean(); }).lean();
// space has no folders initialized // space has no folders initialized
if (!folders) { if (!folders) {
const id = generateFolderId(); const id = generateFolderId();
const folder = new Folder({ const folder = new Folder({
@@ -56,13 +58,32 @@ export const createFolder = async (req: Request, res: Response) => {
workspaceId, workspaceId,
environment, environment,
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_FOLDER,
metadata: {
environment,
folderId: id,
folderName,
folderPath: `root/${folderName}`
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.json({ folder: { id, name: folderName } }); return res.json({ folder: { id, name: folderName } });
} }
const folder = appendFolder(folders.nodes, { folderName, parentFolderId }); const folder = appendFolder(folders.nodes, { folderName, parentFolderId });
await Folder.findByIdAndUpdate(folders._id, folders); await Folder.findByIdAndUpdate(folders._id, folders);
const parentFolder = searchByFolderId(folders.nodes, parentFolderId); const parentFolder = searchByFolderId(folders.nodes, parentFolderId);
const folderVersion = new FolderVersion({ const folderVersion = new FolderVersion({
workspace: workspaceId, workspace: workspaceId,
environment, environment,
@@ -76,6 +97,24 @@ export const createFolder = async (req: Request, res: Response) => {
folderId: parentFolderId, folderId: parentFolderId,
}); });
const folderPath = await getFolderPath(folders, folder.id);
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_FOLDER,
metadata: {
environment,
folderId: folder.id,
folderName,
folderPath
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.json({ folder }); return res.json({ folder });
}; };
@@ -100,10 +139,12 @@ export const updateFolderById = async (req: Request, res: Response) => {
throw BadRequestError({ message: "The folder doesn't exist" }); throw BadRequestError({ message: "The folder doesn't exist" });
} }
const folder = parentFolder.children.find(({ id }) => id === folderId); const folder = parentFolder.children.find(({ id }) => id === folderId);
if (!folder) { if (!folder) {
throw BadRequestError({ message: "The folder doesn't exist" }); throw BadRequestError({ message: "The folder doesn't exist" });
} }
const oldFolderName = folder.name;
parentFolder.version += 1; parentFolder.version += 1;
folder.name = name; folder.name = name;
@@ -121,6 +162,25 @@ export const updateFolderById = async (req: Request, res: Response) => {
folderId: parentFolder.id, folderId: parentFolder.id,
}); });
const folderPath = await getFolderPath(folders, folder.id);
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_FOLDER,
metadata: {
environment,
folderId: folder.id,
oldFolderName,
newFolderName: name,
folderPath
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.json({ return res.json({
message: "Successfully updated folder", message: "Successfully updated folder",
folder: { name: folder.name, id: folder.id }, folder: { name: folder.name, id: folder.id },
@@ -143,6 +203,8 @@ export const deleteFolder = async (req: Request, res: Response) => {
acceptedRoles: [ADMIN, MEMBER], acceptedRoles: [ADMIN, MEMBER],
}); });
const folderPath = await getFolderPath(folders, folderId);
const delOp = deleteFolderById(folders.nodes, folderId); const delOp = deleteFolderById(folders.nodes, folderId);
if (!delOp) { if (!delOp) {
throw BadRequestError({ message: "The folder doesn't exist" }); throw BadRequestError({ message: "The folder doesn't exist" });
@@ -173,6 +235,22 @@ export const deleteFolder = async (req: Request, res: Response) => {
folderId: parentFolder.id, folderId: parentFolder.id,
}); });
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_FOLDER ,
metadata: {
environment,
folderId,
folderName: delFolder.name,
folderPath
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
res.send({ message: "successfully deleted folders", folders: delFolderIds }); res.send({ message: "successfully deleted folders", folders: delFolderIds });
}; };
@@ -4,7 +4,9 @@ import { client, getRootEncryptionKey } from "../../config";
import { validateMembership } from "../../helpers"; import { validateMembership } from "../../helpers";
import Webhook from "../../models/webhooks"; import Webhook from "../../models/webhooks";
import { getWebhookPayload, triggerWebhookRequest } from "../../services/WebhookService"; import { getWebhookPayload, triggerWebhookRequest } from "../../services/WebhookService";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
import { ADMIN, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, MEMBER } from "../../variables"; import { ADMIN, ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, MEMBER } from "../../variables";
export const createWebhook = async (req: Request, res: Response) => { export const createWebhook = async (req: Request, res: Response) => {
@@ -28,6 +30,23 @@ export const createWebhook = async (req: Request, res: Response) => {
await webhook.save(); await webhook.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_WEBHOOK,
metadata: {
webhookId: webhook._id.toString(),
environment,
secretPath,
webhookUrl,
isDisabled: false
}
},
{
workspaceId
}
);
return res.status(200).send({ return res.status(200).send({
webhook, webhook,
message: "successfully created webhook" message: "successfully created webhook"
@@ -54,6 +73,23 @@ export const updateWebhook = async (req: Request, res: Response) => {
} }
await webhook.save(); await webhook.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_WEBHOOK_STATUS,
metadata: {
webhookId: webhook._id.toString(),
environment: webhook.environment,
secretPath: webhook.secretPath,
webhookUrl: webhook.url,
isDisabled
}
},
{
workspaceId: webhook.workspace
}
);
return res.status(200).send({ return res.status(200).send({
webhook, webhook,
message: "successfully updated webhook" message: "successfully updated webhook"
@@ -62,9 +98,10 @@ export const updateWebhook = async (req: Request, res: Response) => {
export const deleteWebhook = async (req: Request, res: Response) => { export const deleteWebhook = async (req: Request, res: Response) => {
const { webhookId } = req.params; const { webhookId } = req.params;
const webhook = await Webhook.findById(webhookId); let webhook = await Webhook.findById(webhookId);
if (!webhook) { if (!webhook) {
throw BadRequestError({ message: "Webhook not found!!" }); throw ResourceNotFoundError({ message: "Webhook not found!!" });
} }
await validateMembership({ await validateMembership({
@@ -73,7 +110,28 @@ export const deleteWebhook = async (req: Request, res: Response) => {
acceptedRoles: [ADMIN, MEMBER] acceptedRoles: [ADMIN, MEMBER]
}); });
await webhook.deleteOne(); webhook = await Webhook.findByIdAndDelete(webhookId);
if (!webhook) {
throw ResourceNotFoundError({ message: "Webhook not found!!" });
}
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_WEBHOOK,
metadata: {
webhookId: webhook._id.toString(),
environment: webhook.environment,
secretPath: webhook.secretPath,
webhookUrl: webhook.url,
isDisabled: webhook.isDisabled
}
},
{
workspaceId: webhook.workspace
}
);
return res.status(200).send({ return res.status(200).send({
message: "successfully removed webhook" message: "successfully removed webhook"
@@ -8,8 +8,8 @@ import {
ServiceTokenData, ServiceTokenData,
Workspace, Workspace,
} from "../../models"; } from "../../models";
import { SecretVersion } from "../../ee/models"; import { SecretVersion, EventType } from "../../ee/models";
import { EELicenseService } from "../../ee/services"; import { EELicenseService, EEAuditLogService } from "../../ee/services";
import { BadRequestError, WorkspaceNotFoundError } from "../../utils/errors"; import { BadRequestError, WorkspaceNotFoundError } from "../../utils/errors";
import _ from "lodash"; import _ from "lodash";
import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables"; import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables";
@@ -61,6 +61,20 @@ export const createWorkspaceEnvironment = async (
await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId)); await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId));
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_ENVIRONMENT,
metadata: {
name: environmentName,
slug: environmentSlug
}
},
{
workspaceId: workspace._id
}
);
return res.status(200).send({ return res.status(200).send({
message: "Successfully created new environment", message: "Successfully created new environment",
workspace: workspaceId, workspace: workspaceId,
@@ -111,6 +125,8 @@ export const renameWorkspaceEnvironment = async (
throw new Error("Invalid environment given"); throw new Error("Invalid environment given");
} }
const oldEnvironment = workspace.environments[envIndex];
workspace.environments[envIndex].name = environmentName; workspace.environments[envIndex].name = environmentName;
workspace.environments[envIndex].slug = environmentSlug.toLowerCase(); workspace.environments[envIndex].slug = environmentSlug.toLowerCase();
@@ -142,8 +158,23 @@ export const renameWorkspaceEnvironment = async (
}, },
{ $set: { "deniedPermissions.$[element].environmentSlug": environmentSlug } }, { $set: { "deniedPermissions.$[element].environmentSlug": environmentSlug } },
{ arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] } { arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] }
) );
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_ENVIRONMENT,
metadata: {
oldName: oldEnvironment.name,
newName: environmentName,
oldSlug: oldEnvironment.slug,
newSlug: environmentSlug.toLowerCase()
}
},
{
workspaceId: workspace._id
}
);
return res.status(200).send({ return res.status(200).send({
message: "Successfully update environment", message: "Successfully update environment",
@@ -180,6 +211,8 @@ export const deleteWorkspaceEnvironment = async (
throw new Error("Invalid environment given"); throw new Error("Invalid environment given");
} }
const oldEnvironment = workspace.environments[envIndex];
workspace.environments.splice(envIndex, 1); workspace.environments.splice(envIndex, 1);
await workspace.save(); await workspace.save();
@@ -218,6 +251,20 @@ export const deleteWorkspaceEnvironment = async (
await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId)); await EELicenseService.refreshPlan(workspace.organization, new Types.ObjectId(workspaceId));
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_ENVIRONMENT,
metadata: {
name: oldEnvironment.name,
slug: oldEnvironment.slug
}
},
{
workspaceId: workspace._id
}
);
return res.status(200).send({ return res.status(200).send({
message: "Successfully deleted environment", message: "Successfully deleted environment",
workspace: workspaceId, workspace: workspaceId,
@@ -4,7 +4,8 @@ import bcrypt from "bcrypt";
import { ServiceTokenData } from "../../models"; import { ServiceTokenData } from "../../models";
import { getSaltRounds } from "../../config"; import { getSaltRounds } from "../../config";
import { BadRequestError } from "../../utils/errors"; import { BadRequestError } from "../../utils/errors";
import { ActorType } from "../../ee/models"; import { ActorType, EventType } from "../../ee/models";
import { EEAuditLogService } from "../../ee/services";
/** /**
* Return service token data associated with service token on request * Return service token data associated with service token on request
@@ -100,6 +101,20 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
const serviceToken = `st.${serviceTokenData._id.toString()}.${secret}`; const serviceToken = `st.${serviceTokenData._id.toString()}.${secret}`;
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SERVICE_TOKEN,
metadata: {
name,
scopes
}
},
{
workspaceId
}
);
return res.status(200).send({ return res.status(200).send({
serviceToken, serviceToken,
serviceTokenData serviceTokenData
@@ -117,6 +132,24 @@ export const deleteServiceTokenData = async (req: Request, res: Response) => {
const serviceTokenData = await ServiceTokenData.findByIdAndDelete(serviceTokenDataId); const serviceTokenData = await ServiceTokenData.findByIdAndDelete(serviceTokenDataId);
if (!serviceTokenData) return res.status(200).send({
message: "Failed to delete service token"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_SERVICE_TOKEN,
metadata: {
name: serviceTokenData.name,
scopes: serviceTokenData?.scopes
}
},
{
workspaceId: serviceTokenData.workspace
}
);
return res.status(200).send({ return res.status(200).send({
serviceTokenData serviceTokenData
}); });
@@ -13,13 +13,14 @@ import {
ServiceActor, ServiceActor,
TFolderRootVersionSchema, TFolderRootVersionSchema,
TrustedIP, TrustedIP,
UserActor UserActor,
EventType
} from "../../models"; } from "../../models";
import { EESecretService } from "../../services"; import { EESecretService } from "../../services";
import { getLatestSecretVersionIds } from "../../helpers/secretVersion"; import { getLatestSecretVersionIds } from "../../helpers/secretVersion";
import Folder, { TFolderSchema } from "../../../models/folder"; import Folder, { TFolderSchema } from "../../../models/folder";
import { searchByFolderId } from "../../../services/FolderService"; import { searchByFolderId } from "../../../services/FolderService";
import { EELicenseService } from "../../services"; import { EELicenseService, EEAuditLogService } from "../../services";
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip"; import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
/** /**
@@ -731,6 +732,21 @@ export const addWorkspaceTrustedIp = async (req: Request, res: Response) => {
comment, comment,
}).save(); }).save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.ADD_TRUSTED_IP,
metadata: {
trustedIpId: trustedIp._id.toString(),
ipAddress: trustedIp.ipAddress,
prefix: trustedIp.prefix
}
},
{
workspaceId: trustedIp.workspace
}
);
return res.status(200).send({ return res.status(200).send({
trustedIp trustedIp
}); });
@@ -793,6 +809,25 @@ export const updateWorkspaceTrustedIp = async (req: Request, res: Response) => {
} }
); );
if (!trustedIp) return res.status(400).send({
message: "Failed to update trusted IP"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_TRUSTED_IP,
metadata: {
trustedIpId: trustedIp._id.toString(),
ipAddress: trustedIp.ipAddress,
prefix: trustedIp.prefix
}
},
{
workspaceId: trustedIp.workspace
}
);
return res.status(200).send({ return res.status(200).send({
trustedIp trustedIp
}); });
@@ -817,6 +852,25 @@ export const deleteWorkspaceTrustedIp = async (req: Request, res: Response) => {
workspace: new Types.ObjectId(workspaceId) workspace: new Types.ObjectId(workspaceId)
}); });
if (!trustedIp) return res.status(400).send({
message: "Failed to delete trusted IP"
});
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_TRUSTED_IP,
metadata: {
trustedIpId: trustedIp._id.toString(),
ipAddress: trustedIp.ipAddress,
prefix: trustedIp.prefix
}
},
{
workspaceId: trustedIp.workspace
}
);
return res.status(200).send({ return res.status(200).send({
trustedIp trustedIp
}); });
+21 -1
View File
@@ -16,5 +16,25 @@ export enum EventType {
REVEAL_SECRET = "reveal-secret", REVEAL_SECRET = "reveal-secret",
CREATE_SECRET = "create-secret", CREATE_SECRET = "create-secret",
UPDATE_SECRET = "update-secret", UPDATE_SECRET = "update-secret",
DELETE_SECRET = "delete-secret" DELETE_SECRET = "delete-secret",
AUTHORIZE_INTEGRATION = "authorize-integration",
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
CREATE_INTEGRATION = "create-integration",
DELETE_INTEGRATION = "delete-integration",
ADD_TRUSTED_IP = "add-trusted-ip",
UPDATE_TRUSTED_IP = "update-trusted-ip",
DELETE_TRUSTED_IP = "delete-trusted-ip",
CREATE_SERVICE_TOKEN = "create-service-token",
DELETE_SERVICE_TOKEN = "delete-service-token",
CREATE_ENVIRONMENT = "create-environment",
UPDATE_ENVIRONMENT = "update-environment",
DELETE_ENVIRONMENT = "delete-environment",
ADD_WORKSPACE_MEMBER = "add-workspace-member",
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
CREATE_FOLDER = "create-folder",
UPDATE_FOLDER = "update-folder",
DELETE_FOLDER = "delete-folder",
CREATE_WEBHOOK = "create-webhook",
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
DELETE_WEBHOOK = "delete-webhook"
} }
+216 -1
View File
@@ -80,9 +80,224 @@ interface DeleteSecretEvent {
} }
} }
interface AuthorizeIntegrationEvent {
type: EventType.AUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
}
}
interface UnauthorizeIntegrationEvent {
type: EventType.UNAUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
}
}
interface CreateIntegrationEvent {
type: EventType.CREATE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
environment: string;
secretPath: string;
app?: string;
targetEnvironment?: string;
targetEnvironmentId?: string; // TODO: consider adding other vars
}
}
interface DeleteIntegrationEvent {
type: EventType.DELETE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
environment: string;
secretPath: string;
app?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
}
}
interface AddTrustedIPEvent {
type: EventType.ADD_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface UpdateTrustedIPEvent {
type: EventType.UPDATE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface DeleteTrustedIPEvent {
type: EventType.DELETE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface CreateServiceTokenEvent {
type: EventType.CREATE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface DeleteServiceTokenEvent {
type: EventType.DELETE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface CreateEnvironmentEvent {
type: EventType.CREATE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface UpdateEnvironmentEvent {
type: EventType.UPDATE_ENVIRONMENT;
metadata: {
oldName: string;
newName: string;
oldSlug: string;
newSlug: string;
}
}
interface DeleteEnvironmentEvent {
type: EventType.DELETE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface AddWorkspaceMemberEvent {
type: EventType.ADD_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface RemoveWorkspaceMemberEvent {
type: EventType.REMOVE_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface CreateFolderEvent {
type: EventType.CREATE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface UpdateFolderEvent {
type: EventType.UPDATE_FOLDER;
metadata: {
environment: string;
folderId: string;
oldFolderName: string;
newFolderName: string;
folderPath: string;
}
}
interface DeleteFolderEvent {
type: EventType.DELETE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface CreateWebhookEvent {
type: EventType.CREATE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface UpdateWebhookStatusEvent {
type: EventType.UPDATE_WEBHOOK_STATUS,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface DeleteWebhookEvent {
type: EventType.DELETE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
export type Event = export type Event =
| GetSecretsEvent | GetSecretsEvent
| GetSecretEvent | GetSecretEvent
| CreateSecretEvent | CreateSecretEvent
| UpdateSecretEvent | UpdateSecretEvent
| DeleteSecretEvent; | DeleteSecretEvent
| AuthorizeIntegrationEvent
| UnauthorizeIntegrationEvent
| CreateIntegrationEvent
| DeleteIntegrationEvent
| AddTrustedIPEvent
| UpdateTrustedIPEvent
| DeleteTrustedIPEvent
| CreateServiceTokenEvent
| DeleteServiceTokenEvent
| CreateEnvironmentEvent
| UpdateEnvironmentEvent
| DeleteEnvironmentEvent
| AddWorkspaceMemberEvent
| RemoveWorkspaceMemberEvent
| CreateFolderEvent
| UpdateFolderEvent
| DeleteFolderEvent
| CreateWebhookEvent
| UpdateWebhookStatusEvent
| DeleteWebhookEvent;
+2 -2
View File
@@ -97,8 +97,8 @@ router.get(
query("eventType").isString().isIn(Object.values(EventType)).optional({ nullable: true }), query("eventType").isString().isIn(Object.values(EventType)).optional({ nullable: true }),
query("userAgentType").isString().isIn(Object.values(UserAgentType)).optional({ nullable: true }), query("userAgentType").isString().isIn(Object.values(UserAgentType)).optional({ nullable: true }),
query("actor").isString().optional({ nullable: true }), query("actor").isString().optional({ nullable: true }),
query("offset").isString().default("0"), query("offset").default("0"),
query("limit").isString().default("20"), query("limit").default("20"),
validateRequest, validateRequest,
workspaceController.getWorkspaceAuditLogs workspaceController.getWorkspaceAuditLogs
); );
+3 -3
View File
@@ -63,12 +63,12 @@ class EELicenseService {
environmentsUsed: 0, environmentsUsed: 0,
secretVersioning: true, secretVersioning: true,
pitRecovery: false, pitRecovery: false,
ipAllowlisting: false, ipAllowlisting: true,
rbac: true, rbac: true,
customRateLimits: true, customRateLimits: true,
customAlerts: true, customAlerts: true,
auditLogs: false, auditLogs: true,
auditLogsRetentionDays: 0, auditLogsRetentionDays: 30,
samlSSO: false, samlSSO: false,
status: null, status: null,
trial_end: null, trial_end: null,
+16 -1
View File
@@ -1,6 +1,7 @@
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { Types } from "mongoose"; import { Types } from "mongoose";
import Folder, { TFolderSchema } from "../models/folder"; import Folder, { TFolderSchema, TFolderRootSchema } from "../models/folder";
import { ResourceNotFoundError } from "../utils/errors";
type TAppendFolderDTO = { type TAppendFolderDTO = {
folderName: string; folderName: string;
@@ -172,6 +173,20 @@ export const searchByFolderIdWithDir = (
return; return;
}; };
export const getFolderPath = (
folders: TFolderRootSchema,
folderId: string
) => {
const folderBySearch = searchByFolderIdWithDir(folders.nodes, folderId);
if (!folderBySearch) throw ResourceNotFoundError({
message: "Failed to find folder"
});
const folderPath = folderBySearch.dir.map((folder) => folder.name).join("/");
return folderPath;
}
// to get folder of a path given // to get folder of a path given
// Like /frontend/folder#1 // Like /frontend/folder#1
export const getFolderByPath = (folders: TFolderSchema, searchPath: string) => { export const getFolderByPath = (folders: TFolderSchema, searchPath: string) => {
+25 -5
View File
@@ -1,11 +1,31 @@
import { EventType, UserAgentType } from "./enums"; import { EventType, UserAgentType } from "./enums";
export const eventToNameMap: { [K in EventType]: string } = { export const eventToNameMap: { [K in EventType]: string } = {
[EventType.GET_SECRETS]: "Get Secrets", [EventType.GET_SECRETS]: "Get secrets",
[EventType.GET_SECRET]: "Get Secret", [EventType.GET_SECRET]: "Get secret",
[EventType.CREATE_SECRET]: "Create Secret", [EventType.CREATE_SECRET]: "Create secret",
[EventType.UPDATE_SECRET]: "Update Secret", [EventType.UPDATE_SECRET]: "Update secret",
[EventType.DELETE_SECRET]: "Delete Secret", [EventType.DELETE_SECRET]: "Delete secret",
[EventType.AUTHORIZE_INTEGRATION]: "Authorize integration",
[EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration",
[EventType.CREATE_INTEGRATION]: "Create integration",
[EventType.DELETE_INTEGRATION]: "Delete integration",
[EventType.ADD_TRUSTED_IP]: "Add trusted IP",
[EventType.UPDATE_TRUSTED_IP]: "Update trusted IP",
[EventType.DELETE_TRUSTED_IP]: "Delete trusted IP",
[EventType.CREATE_SERVICE_TOKEN]: "Create service token",
[EventType.DELETE_SERVICE_TOKEN]: "Delete service token",
[EventType.CREATE_ENVIRONMENT]: "Create environment",
[EventType.UPDATE_ENVIRONMENT]: "Update environment",
[EventType.DELETE_ENVIRONMENT]: "Delete environment",
[EventType.ADD_WORKSPACE_MEMBER]: "Add member",
[EventType.REMOVE_WORKSPACE_MEMBER]: "Remove member",
[EventType.CREATE_FOLDER]: "Create folder",
[EventType.UPDATE_FOLDER]: "Update folder",
[EventType.DELETE_FOLDER]: "Delete folder",
[EventType.CREATE_WEBHOOK]: "Create webhook",
[EventType.UPDATE_WEBHOOK_STATUS]: "Update webhook status",
[EventType.DELETE_WEBHOOK]: "Delete webhook",
}; };
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = { export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
+25 -5
View File
@@ -11,9 +11,29 @@ export enum UserAgentType {
} }
export enum EventType { export enum EventType {
GET_SECRETS = "get-secrets", GET_SECRETS = "get-secrets",
GET_SECRET = "get-secret", GET_SECRET = "get-secret",
CREATE_SECRET = "create-secret", CREATE_SECRET = "create-secret",
UPDATE_SECRET = "update-secret", UPDATE_SECRET = "update-secret",
DELETE_SECRET = "delete-secret" DELETE_SECRET = "delete-secret",
AUTHORIZE_INTEGRATION = "authorize-integration",
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
CREATE_INTEGRATION = "create-integration",
DELETE_INTEGRATION = "delete-integration",
ADD_TRUSTED_IP = "add-trusted-ip",
UPDATE_TRUSTED_IP = "update-trusted-ip",
DELETE_TRUSTED_IP = "delete-trusted-ip",
CREATE_SERVICE_TOKEN = "create-service-token",
DELETE_SERVICE_TOKEN = "delete-service-token",
CREATE_ENVIRONMENT = "create-environment",
UPDATE_ENVIRONMENT = "update-environment",
DELETE_ENVIRONMENT = "delete-environment",
ADD_WORKSPACE_MEMBER = "add-workspace-member",
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
CREATE_FOLDER = "create-folder",
UPDATE_FOLDER = "update-folder",
DELETE_FOLDER = "delete-folder",
CREATE_WEBHOOK = "create-webhook",
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
DELETE_WEBHOOK = "delete-webhook"
} }
+13 -12
View File
@@ -2,28 +2,22 @@ import { useQuery } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request"; import { apiRequest } from "@app/config/request";
import { EventType, UserAgentType } from "./enums";
import { import {
Actor, Actor,
AuditLog} from "./types"; AuditLog,
AuditLogFilters
} from "./types";
export const workspaceKeys = { export const workspaceKeys = {
getAuditLogs: (workspaceId: string, filters: { getAuditLogs: (workspaceId: string, filters: AuditLogFilters) => [{ workspaceId, filters }, "audit-logs"] as const,
eventType?: EventType;
userAgentType?: UserAgentType;
actor?: string;
}) => [{ workspaceId, filters }, "audit-logs"] as const,
getAuditLogActorFilterOpts: (workspaceId: string) => [{ workspaceId }, "audit-log-actor-filters"] as const getAuditLogActorFilterOpts: (workspaceId: string) => [{ workspaceId }, "audit-log-actor-filters"] as const
} }
export const useGetAuditLogs = (workspaceId: string, filters: { export const useGetAuditLogs = (workspaceId: string, filters: AuditLogFilters) => {
eventType?: EventType;
userAgentType?: UserAgentType;
actor?: string;
}) => {
return useQuery({ return useQuery({
queryKey: workspaceKeys.getAuditLogs(workspaceId, filters), queryKey: workspaceKeys.getAuditLogs(workspaceId, filters),
queryFn: async () => { queryFn: async () => {
const params = new URLSearchParams(); const params = new URLSearchParams();
if (filters.eventType) { if (filters.eventType) {
params.append("eventType", filters.eventType); params.append("eventType", filters.eventType);
@@ -37,6 +31,13 @@ export const useGetAuditLogs = (workspaceId: string, filters: {
params.append("actor", filters.actor); params.append("actor", filters.actor);
} }
if (filters.actor) {
params.append("actor", filters.actor);
}
params.append("offset ", String(filters.offset));
params.append("limit ", String(filters.limit));
const { data } = await apiRequest.get<{ auditLogs: AuditLog[] }>(`/api/v1/workspace/${workspaceId}/audit-logs`, { params }); const { data } = await apiRequest.get<{ auditLogs: AuditLog[] }>(`/api/v1/workspace/${workspaceId}/audit-logs`, { params });
return data.auditLogs; return data.auditLogs;
} }
+224 -1
View File
@@ -82,12 +82,227 @@ interface DeleteSecretEvent {
} }
} }
interface AuthorizeIntegrationEvent {
type: EventType.AUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
}
}
interface UnauthorizeIntegrationEvent {
type: EventType.UNAUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
}
}
interface CreateIntegrationEvent {
type: EventType.CREATE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
environment: string;
secretPath: string;
app?: string;
targetEnvironment?: string;
targetEnvironmentId?: string; // TODO: consider adding other vars
}
}
interface DeleteIntegrationEvent {
type: EventType.DELETE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
environment: string;
secretPath: string;
app?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
}
}
interface AddTrustedIPEvent {
type: EventType.ADD_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface UpdateTrustedIPEvent {
type: EventType.UPDATE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface DeleteTrustedIPEvent {
type: EventType.DELETE_TRUSTED_IP;
metadata: {
trustedIpId: string;
ipAddress: string;
prefix?: number;
}
}
interface CreateServiceTokenEvent {
type: EventType.CREATE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface DeleteServiceTokenEvent {
type: EventType.DELETE_SERVICE_TOKEN;
metadata: {
name: string;
scopes: Array<{
environment: string;
secretPath: string;
}>;
}
}
interface CreateEnvironmentEvent {
type: EventType.CREATE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface UpdateEnvironmentEvent {
type: EventType.UPDATE_ENVIRONMENT;
metadata: {
oldName: string;
newName: string;
oldSlug: string;
newSlug: string;
}
}
interface DeleteEnvironmentEvent {
type: EventType.DELETE_ENVIRONMENT;
metadata: {
name: string;
slug: string;
}
}
interface AddWorkspaceMemberEvent {
type: EventType.ADD_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface RemoveWorkspaceMemberEvent {
type: EventType.REMOVE_WORKSPACE_MEMBER;
metadata: {
userId: string;
email: string;
}
}
interface CreateFolderEvent {
type: EventType.CREATE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface UpdateFolderEvent {
type: EventType.UPDATE_FOLDER;
metadata: {
environment: string;
folderId: string;
oldFolderName: string;
newFolderName: string;
folderPath: string;
}
}
interface DeleteFolderEvent {
type: EventType.DELETE_FOLDER;
metadata: {
environment: string;
folderId: string;
folderName: string;
folderPath: string;
}
}
interface CreateWebhookEvent {
type: EventType.CREATE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface UpdateWebhookStatusEvent {
type: EventType.UPDATE_WEBHOOK_STATUS,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
interface DeleteWebhookEvent {
type: EventType.DELETE_WEBHOOK,
metadata: {
webhookId: string;
environment: string;
secretPath: string;
webhookUrl: string;
isDisabled: boolean;
}
}
export type Event = export type Event =
| GetSecretsEvent | GetSecretsEvent
| GetSecretEvent | GetSecretEvent
| CreateSecretEvent | CreateSecretEvent
| UpdateSecretEvent | UpdateSecretEvent
| DeleteSecretEvent; | DeleteSecretEvent
| AuthorizeIntegrationEvent
| UnauthorizeIntegrationEvent
| CreateIntegrationEvent
| DeleteIntegrationEvent
| AddTrustedIPEvent
| UpdateTrustedIPEvent
| DeleteTrustedIPEvent
| CreateServiceTokenEvent
| DeleteServiceTokenEvent
| CreateEnvironmentEvent
| UpdateEnvironmentEvent
| DeleteEnvironmentEvent
| AddWorkspaceMemberEvent
| RemoveWorkspaceMemberEvent
| CreateFolderEvent
| UpdateFolderEvent
| DeleteFolderEvent
| CreateWebhookEvent
| UpdateWebhookStatusEvent
| DeleteWebhookEvent;
export type AuditLog = { export type AuditLog = {
_id: string; _id: string;
@@ -101,3 +316,11 @@ export type AuditLog = {
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
export type AuditLogFilters = {
eventType?: EventType;
userAgentType?: UserAgentType;
actor?: string;
offset: number;
limit: number;
}
@@ -33,7 +33,9 @@ export const LogsTable = ({
const { data, isLoading } = useGetAuditLogs(currentWorkspace?._id ?? "", { const { data, isLoading } = useGetAuditLogs(currentWorkspace?._id ?? "", {
eventType, eventType,
userAgentType, userAgentType,
actor actor,
offset: 0, // TODO: update with pagination
limit: 20 // TODO: update with pagination
}); });
return ( return (
@@ -79,6 +79,169 @@ export const LogsTableRow = ({
<p>{`Secret: ${event.metadata.secretKey}`}</p> <p>{`Secret: ${event.metadata.secretKey}`}</p>
</Td> </Td>
); );
case EventType.AUTHORIZE_INTEGRATION:
return (
<Td>
<p>{`Integration: ${event.metadata.integration}`}</p>
</Td>
);
case EventType.UNAUTHORIZE_INTEGRATION:
return (
<Td>
<p>{`Integration: ${event.metadata.integration}`}</p>
</Td>
);
case EventType.CREATE_INTEGRATION:
return (
<Td>
<p>{`Integration: ${event.metadata.integration}`}</p>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Path: ${event.metadata.secretPath}`}</p>
{event.metadata.app && (
<p>{`Target app: ${event.metadata.app}`}</p>
)}
{event.metadata.targetEnvironment && (
<p>{`Target environment: ${event.metadata.targetEnvironment}`}</p>
)}
{event.metadata.targetEnvironmentId && (
<p>{`Target environment ID: ${event.metadata.targetEnvironmentId}`}</p>
)}
</Td>
);
case EventType.DELETE_INTEGRATION:
return (
<Td>
<p>{`Integration: ${event.metadata.integration}`}</p>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Path: ${event.metadata.secretPath}`}</p>
{event.metadata.app && (
<p>{`Target App: ${event.metadata.app}`}</p>
)}
{event.metadata.targetEnvironment && (
<p>{`Target environment: ${event.metadata.targetEnvironment}`}</p>
)}
{event.metadata.targetEnvironmentId && (
<p>{`Target environment ID: ${event.metadata.targetEnvironmentId}`}</p>
)}
</Td>
);
case EventType.ADD_TRUSTED_IP:
return (
<Td>
<p>{`IP: ${event.metadata.ipAddress}${event.metadata.prefix !== undefined ? `/${event.metadata.prefix}` : ""}`}</p>
</Td>
);
case EventType.UPDATE_TRUSTED_IP:
return (
<Td>
<p>{`IP: ${event.metadata.ipAddress}${event.metadata.prefix !== undefined ? `/${event.metadata.prefix}` : ""}`}</p>
</Td>
);
case EventType.DELETE_TRUSTED_IP:
return (
<Td>
<p>{`IP: ${event.metadata.ipAddress}${event.metadata.prefix !== undefined ? `/${event.metadata.prefix}` : ""}`}</p>
</Td>
);
case EventType.CREATE_SERVICE_TOKEN:
return (
<Td>
<p>{`Name: ${event.metadata.name}`}</p>
</Td>
);
case EventType.DELETE_SERVICE_TOKEN:
return (
<Td>
<p>{`Name: ${event.metadata.name}`}</p>
</Td>
);
case EventType.CREATE_ENVIRONMENT:
return (
<Td>
<p>{`Name: ${event.metadata.name}`}</p>
<p>{`Slug: ${event.metadata.slug}`}</p>
</Td>
);
case EventType.UPDATE_ENVIRONMENT:
return (
<Td>
<p>{`Old name: ${event.metadata.oldName}`}</p>
<p>{`New name: ${event.metadata.newName}`}</p>
<p>{`Old slug: ${event.metadata.oldSlug}`}</p>
<p>{`New slug: ${event.metadata.newSlug}`}</p>
</Td>
);
case EventType.DELETE_ENVIRONMENT:
return (
<Td>
<p>{`Name: ${event.metadata.name}`}</p>
<p>{`Slug: ${event.metadata.slug}`}</p>
</Td>
);
case EventType.ADD_WORKSPACE_MEMBER:
return (
<Td>
<p>{`Email: ${event.metadata.email}`}</p>
</Td>
);
case EventType.REMOVE_WORKSPACE_MEMBER:
return (
<Td>
<p>{`Email: ${event.metadata.email}`}</p>
</Td>
);
case EventType.CREATE_FOLDER:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Path: ${event.metadata.folderPath}`}</p>
<p>{`Folder: ${event.metadata.folderName}`}</p>
</Td>
);
case EventType.UPDATE_FOLDER:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Path: ${event.metadata.folderPath}`}</p>
<p>{`Old folder: ${event.metadata.oldFolderName}`}</p>
<p>{`New folder: ${event.metadata.newFolderName}`}</p>
</Td>
);
case EventType.DELETE_FOLDER:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Path: ${event.metadata.folderPath}`}</p>
<p>{`Folder: ${event.metadata.folderName}`}</p>
</Td>
);
case EventType.CREATE_WEBHOOK:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Secret Path: ${event.metadata.secretPath}`}</p>
<p>{`Webhook URL: ${event.metadata.webhookUrl}`}</p>
<p>{`Disabled: ${event.metadata.isDisabled}`}</p>
</Td>
);
case EventType.UPDATE_WEBHOOK_STATUS:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Secret Path: ${event.metadata.secretPath}`}</p>
<p>{`Webhook URL: ${event.metadata.webhookUrl}`}</p>
<p>{`Disabled: ${event.metadata.isDisabled}`}</p>
</Td>
);
case EventType.DELETE_WEBHOOK:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Secret Path: ${event.metadata.secretPath}`}</p>
<p>{`Webhook URL: ${event.metadata.webhookUrl}`}</p>
<p>{`Disabled: ${event.metadata.isDisabled}`}</p>
</Td>
);
default: default:
return ( return (
<Td>Test</Td> <Td>Test</Td>