Add dashboard-specific secret and secret import audit logs, re-touch audit logs v2 UI

This commit is contained in:
Tuan Dang
2023-08-08 19:03:24 +07:00
parent 6cb8cf53f8
commit 0cad823267
19 changed files with 472 additions and 55 deletions

View File

@@ -86,9 +86,15 @@ export const createIntegration = async (req: Request, res: Response) => {
integration: integration.integration,
environment: integration.environment,
secretPath,
url: integration.url,
app: integration.app,
appId: integration.appId,
targetEnvironment: integration.targetEnvironment,
targetEnvironmentId: integration.targetEnvironmentId
targetEnvironmentId: integration.targetEnvironmentId,
targetService: integration.targetService,
targetServiceId: integration.targetServiceId,
path: integration.path,
region: integration.region
}
},
{
@@ -192,9 +198,15 @@ export const deleteIntegration = async (req: Request, res: Response) => {
integration: integration.integration,
environment: integration.environment,
secretPath: integration.secretPath,
url: integration.url,
app: integration.app,
appId: integration.appId,
targetEnvironment: integration.targetEnvironment,
targetEnvironmentId: integration.targetEnvironmentId
targetEnvironmentId: integration.targetEnvironmentId,
targetService: integration.targetService,
targetServiceId: integration.targetServiceId,
path: integration.path,
region: integration.region
}
},
{

View File

@@ -1,6 +1,9 @@
import { Types } from "mongoose";
import { Request, Response } from "express";
import { Key } from "../../models";
import { findMembership } from "../../helpers/membership";
import { EventType } from "../../ee/models";
import { EEAuditLogService } from "../../ee/services";
/**
* Add (encrypted) copy of workspace key for workspace with id [workspaceId] for user with
@@ -44,7 +47,7 @@ export const uploadKey = async (req: Request, res: Response) => {
*/
export const getLatestKey = async (req: Request, res: Response) => {
const { workspaceId } = req.params;
// get latest key
const latestKey = await Key.find({
workspace: workspaceId,
@@ -58,6 +61,18 @@ export const getLatestKey = async (req: Request, res: Response) => {
if (latestKey.length > 0) {
resObj["latestKey"] = latestKey[0];
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: latestKey[0]._id.toString()
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
}
return res.status(200).send(resObj);

View File

@@ -4,6 +4,8 @@ import SecretImport from "../../models/secretImports";
import { getAllImportedSecrets } from "../../services/SecretImportService";
import { BadRequestError } from "../../utils/errors";
import { ADMIN, MEMBER } from "../../variables";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
export const createSecretImport = async (req: Request, res: Response) => {
const { workspaceId, environment, folderId, secretImport } = req.body;
@@ -20,7 +22,24 @@ export const createSecretImport = async (req: Request, res: Response) => {
folderId,
imports: [{ environment: secretImport.environment, secretPath: secretImport.secretPath }]
});
await doc.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
environment,
secretImportId: doc._id.toString(),
folderId: doc.folderId.toString(),
importEnvironment: secretImport.environment,
importSecretPath: secretImport.secretPath
}
},
{
workspaceId: doc.workspace
}
);
return res.status(200).json({ message: "successfully created secret import" });
}
@@ -30,11 +49,29 @@ export const createSecretImport = async (req: Request, res: Response) => {
if (doesImportExist) {
throw BadRequestError({ message: "Secret import already exist" });
}
importSecDoc.imports.push({
environment: secretImport.environment,
secretPath: secretImport.secretPath
});
await importSecDoc.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
environment,
secretImportId: importSecDoc._id.toString(),
folderId: importSecDoc.folderId.toString(),
importEnvironment: secretImport.environment,
importSecretPath: secretImport.secretPath
}
},
{
workspaceId: importSecDoc.workspace
}
);
return res.status(200).json({ message: "successfully created secret import" });
};
@@ -56,6 +93,21 @@ export const updateSecretImport = async (req: Request, res: Response) => {
importSecDoc.imports = secretImports;
await importSecDoc.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_SECRET_IMPORT,
metadata: {
environment: importSecDoc.environment,
secretImportId: importSecDoc._id.toString(),
folderId: importSecDoc.folderId.toString(),
numberOfImports: secretImports.length
}
},
{
workspaceId: importSecDoc.workspace
}
);
return res.status(200).json({ message: "successfully updated secret import" });
};
@@ -77,6 +129,24 @@ export const deleteSecretImport = async (req: Request, res: Response) => {
!(environment === secretImportEnv && secretPath === secretImportPath)
);
await importSecDoc.save();
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_SECRET_IMPORT,
metadata: {
environment: importSecDoc.environment,
secretImportId: importSecDoc._id.toString(),
folderId: importSecDoc.folderId.toString(),
importEnvironment: secretImportEnv,
importSecretPath: secretImportPath
}
},
{
workspaceId: importSecDoc.workspace
}
);
return res.status(200).json({ message: "successfully delete secret import" });
};
@@ -111,6 +181,22 @@ export const getAllSecretsFromImport = async (req: Request, res: Response) => {
return res.status(200).json({ secrets: [] });
}
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.GET_SECRET_IMPORTS,
metadata: {
environment,
secretImportId: importSecDoc._id.toString(),
folderId,
numberOfImports: importSecDoc.imports.length
}
},
{
workspaceId: importSecDoc.workspace
}
);
const secrets = await getAllImportedSecrets(workspaceId, environment, folderId);
return res.status(200).json({ secrets });
};

View File

@@ -1,7 +1,7 @@
import { Types } from "mongoose";
import { Request, Response } from "express";
import { ISecret, Secret, ServiceTokenData } from "../../models";
import { IAction, SecretVersion } from "../../ee/models";
import { IAction, SecretVersion, EventType, AuditLog } from "../../ee/models";
import {
ACTION_ADD_SECRETS,
ACTION_DELETE_SECRETS,
@@ -14,7 +14,7 @@ import {
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import { EventService } from "../../services";
import { eventPushSecrets } from "../../events";
import { EELogService, EESecretService } from "../../ee/services";
import { EELogService, EESecretService, EEAuditLogService } from "../../ee/services";
import { SecretService, TelemetryService } from "../../services";
import { getUserAgentType } from "../../utils/posthog";
import { PERMISSION_WRITE_SECRETS } from "../../variables";
@@ -56,12 +56,13 @@ export const batchSecrets = async (req: Request, res: Response) => {
environment: string;
requests: BatchSecretRequest[];
} = req.body;
let secretPath = req.body.secretPath as string;
let folderId = req.body.folderId as string;
const createSecrets: BatchSecret[] = [];
const updateSecrets: BatchSecret[] = [];
const deleteSecrets: Types.ObjectId[] = [];
const deleteSecrets: { _id: Types.ObjectId, secretName: string; }[] = [];
const actions: IAction[] = [];
// get secret blind index salt
@@ -133,7 +134,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
});
break;
case "DELETE":
deleteSecrets.push(new Types.ObjectId(request.secret._id));
deleteSecrets.push({ _id: new Types.ObjectId(request.secret._id), secretName: request.secret.secretName });
break;
}
}
@@ -153,7 +154,31 @@ export const batchSecrets = async (req: Request, res: Response) => {
};
})
});
const auditLogs = await Promise.all(
createdSecrets.map((secret, index) => {
return EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.CREATE_SECRET,
metadata: {
environment: secret.environment,
secretPath: secretPath ?? "/",
secretId: secret._id.toString(),
secretKey: createSecrets[index].secretName,
secretVersion: secret.version
}
},
{
workspaceId: secret.workspace
},
false
);
})
);
await AuditLog.insertMany(auditLogs);
const addAction = (await EELogService.createAction({
name: ACTION_ADD_SECRETS,
userId: req.user?._id,
@@ -252,6 +277,30 @@ export const batchSecrets = async (req: Request, res: Response) => {
$in: updateSecrets.map((u) => new Types.ObjectId(u._id))
}
});
const auditLogs = await Promise.all(
updateSecrets.map((secret) => {
return EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.UPDATE_SECRET,
metadata: {
environment,
secretPath: secretPath ?? "/",
secretId: secret._id.toString(),
secretKey: secret.secretName,
secretVersion: listedSecretsObj[secret._id.toString()].version
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
},
false
);
})
);
await AuditLog.insertMany(auditLogs);
const updateAction = (await EELogService.createAction({
name: ACTION_UPDATE_SECRETS,
@@ -279,21 +328,60 @@ export const batchSecrets = async (req: Request, res: Response) => {
// handle delete secrets
if (deleteSecrets.length > 0) {
const deleteSecretIds: Types.ObjectId[] = deleteSecrets.map((s) => s._id);
const deletedSecretsObj = (await Secret.find({
_id: {
$in: deleteSecretIds
}
}))
.reduce(
(obj: any, secret: ISecret) => ({
...obj,
[secret._id.toString()]: secret
}),
{}
);
await Secret.deleteMany({
_id: {
$in: deleteSecrets
$in: deleteSecretIds
}
});
await EESecretService.markDeletedSecretVersions({
secretIds: deleteSecrets
secretIds: deleteSecretIds
});
const auditLogs = await Promise.all(
deleteSecrets.map((secret) => {
return EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.DELETE_SECRET,
metadata: {
environment,
secretPath: secretPath ?? "/",
secretId: secret._id.toString(),
secretKey: secret.secretName,
secretVersion: deletedSecretsObj[secret._id.toString()].version
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
},
false
);
})
);
await AuditLog.insertMany(auditLogs);
const deleteAction = (await EELogService.createAction({
name: ACTION_DELETE_SECRETS,
userId: req.user._id,
workspaceId: new Types.ObjectId(workspaceId),
secretIds: deleteSecrets
secretIds: deleteSecretIds
})) as IAction;
actions.push(deleteAction);
@@ -351,7 +439,7 @@ export const batchSecrets = async (req: Request, res: Response) => {
}
if (deleteSecrets.length > 0) {
resObj["deletedSecrets"] = deleteSecrets.map((d) => d.toString());
resObj["deletedSecrets"] = deleteSecrets.map((d) => d._id.toString());
}
return res.status(200).send(resObj);

View File

@@ -9,6 +9,8 @@ import {
import { pushKeys } from "../../helpers/key";
import { EventService, TelemetryService } from "../../services";
import { eventPushSecrets } from "../../events";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
interface V2PushSecret {
type: string; // personal or shared
@@ -180,16 +182,30 @@ export const getWorkspaceKey = async (req: Request, res: Response) => {
}
*/
const { workspaceId } = req.params;
const key = await Key.findOne({
workspace: workspaceId,
receiver: req.user._id
}).populate("sender", "+publicKey");
if (!key) throw new Error("Failed to find workspace key");
await EEAuditLogService.createAuditLog(
req.authData,
{
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: key._id.toString()
}
},
{
workspaceId: new Types.ObjectId(workspaceId)
}
);
return res.status(200).json(key);
};
export const getWorkspaceServiceTokenData = async (req: Request, res: Response) => {
const { workspaceId } = req.params;

View File

@@ -17,6 +17,7 @@ export enum EventType {
CREATE_SECRET = "create-secret",
UPDATE_SECRET = "update-secret",
DELETE_SECRET = "delete-secret",
GET_WORKSPACE_KEY = "get-workspace-key",
AUTHORIZE_INTEGRATION = "authorize-integration",
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
CREATE_INTEGRATION = "create-integration",
@@ -36,5 +37,9 @@ export enum EventType {
DELETE_FOLDER = "delete-folder",
CREATE_WEBHOOK = "create-webhook",
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
DELETE_WEBHOOK = "delete-webhook"
DELETE_WEBHOOK = "delete-webhook",
GET_SECRET_IMPORTS = "get-secret-imports",
CREATE_SECRET_IMPORT = "create-secret-import",
UPDATE_SECRET_IMPORT = "update-secret-import",
DELETE_SECRET_IMPORT = "delete-secret-import",
}

View File

@@ -80,17 +80,24 @@ interface DeleteSecretEvent {
}
}
interface GetWorkspaceKeyEvent {
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: string;
}
}
interface AuthorizeIntegrationEvent {
type: EventType.AUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
integration: string;
}
}
interface UnauthorizeIntegrationEvent {
type: EventType.UNAUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
integration: string;
}
}
@@ -101,9 +108,15 @@ interface CreateIntegrationEvent {
integration: string; // TODO: fix type
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string; // TODO: consider adding other vars
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
@@ -114,9 +127,15 @@ interface DeleteIntegrationEvent {
integration: string; // TODO: fix type
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
@@ -275,12 +294,55 @@ interface DeleteWebhookEvent {
}
}
interface GetSecretImportsEvent {
type: EventType.GET_SECRET_IMPORTS,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
numberOfImports: number;
}
}
interface CreateSecretImportEvent {
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
importEnvironment: string;
importSecretPath: string;
}
}
interface UpdateSecretImportEvent {
type: EventType.UPDATE_SECRET_IMPORT,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
numberOfImports: number;
}
}
interface DeleteSecretImportEvent {
type: EventType.DELETE_SECRET_IMPORT,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
importEnvironment: string;
importSecretPath: string;
}
}
export type Event =
| GetSecretsEvent
| GetSecretEvent
| CreateSecretEvent
| UpdateSecretEvent
| DeleteSecretEvent
| GetWorkspaceKeyEvent
| AuthorizeIntegrationEvent
| UnauthorizeIntegrationEvent
| CreateIntegrationEvent
@@ -300,4 +362,8 @@ export type Event =
| DeleteFolderEvent
| CreateWebhookEvent
| UpdateWebhookStatusEvent
| DeleteWebhookEvent;
| DeleteWebhookEvent
| GetSecretImportsEvent
| CreateSecretImportEvent
| UpdateSecretImportEvent
| DeleteSecretImportEvent;

View File

@@ -16,7 +16,7 @@ type ValidEventScope =
| Required<EventScope>
export default class EEAuditLogService {
static async createAuditLog(authData: AuthData, event: Event, eventScope: ValidEventScope) {
static async createAuditLog(authData: AuthData, event: Event, eventScope: ValidEventScope, shouldSave: boolean = true) {
const MS_IN_DAY = 24 * 60 * 60 * 1000;
@@ -39,7 +39,11 @@ export default class EEAuditLogService {
userAgent: authData.userAgent,
userAgentType: authData.userAgentType,
expiresAt: new Date(Date.now() + ttl)
}).save();
});
if (shouldSave) {
await auditLog.save();
}
return auditLog;
}

View File

@@ -30,6 +30,7 @@ export interface BatchSecretRequest {
export interface BatchSecret {
_id: string;
type: "shared" | "personal";
secretName: string;
secretBlindIndex: string;
secretKeyCiphertext: string;
secretKeyIV: string;

View File

@@ -1,11 +1,12 @@
import { EventType, UserAgentType } from "./enums";
export const eventToNameMap: { [K in EventType]: string } = {
[EventType.GET_SECRETS]: "Get secrets",
[EventType.GET_SECRET]: "Get secret",
[EventType.GET_SECRETS]: "List secrets",
[EventType.GET_SECRET]: "Read secret",
[EventType.CREATE_SECRET]: "Create secret",
[EventType.UPDATE_SECRET]: "Update secret",
[EventType.DELETE_SECRET]: "Delete secret",
[EventType.GET_WORKSPACE_KEY]: "Read project key",
[EventType.AUTHORIZE_INTEGRATION]: "Authorize integration",
[EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration",
[EventType.CREATE_INTEGRATION]: "Create integration",
@@ -26,6 +27,11 @@ export const eventToNameMap: { [K in EventType]: string } = {
[EventType.CREATE_WEBHOOK]: "Create webhook",
[EventType.UPDATE_WEBHOOK_STATUS]: "Update webhook status",
[EventType.DELETE_WEBHOOK]: "Delete webhook",
[EventType.GET_SECRET_IMPORTS]: "List secret imports",
[EventType.CREATE_SECRET_IMPORT]: "Create secret import",
[EventType.UPDATE_SECRET_IMPORT]: "Update secret import",
[EventType.DELETE_SECRET_IMPORT]: "Delete secret import",
};
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {

View File

@@ -16,6 +16,7 @@ export enum EventType {
CREATE_SECRET = "create-secret",
UPDATE_SECRET = "update-secret",
DELETE_SECRET = "delete-secret",
GET_WORKSPACE_KEY = "get-workspace-key",
AUTHORIZE_INTEGRATION = "authorize-integration",
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
CREATE_INTEGRATION = "create-integration",
@@ -35,5 +36,9 @@ export enum EventType {
DELETE_FOLDER = "delete-folder",
CREATE_WEBHOOK = "create-webhook",
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
DELETE_WEBHOOK = "delete-webhook"
DELETE_WEBHOOK = "delete-webhook",
GET_SECRET_IMPORTS = "get-secret-imports",
CREATE_SECRET_IMPORT = "create-secret-import",
UPDATE_SECRET_IMPORT = "update-secret-import",
DELETE_SECRET_IMPORT = "delete-secret-import"
}

View File

@@ -82,17 +82,24 @@ interface DeleteSecretEvent {
}
}
interface GetWorkspaceKeyEvent {
type: EventType.GET_WORKSPACE_KEY,
metadata: {
keyId: string;
}
}
interface AuthorizeIntegrationEvent {
type: EventType.AUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
integration: string;
}
}
interface UnauthorizeIntegrationEvent {
type: EventType.UNAUTHORIZE_INTEGRATION;
metadata: {
integration: string; // TODO: fix type
integration: string;
}
}
@@ -100,12 +107,18 @@ interface CreateIntegrationEvent {
type: EventType.CREATE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
integration: string;
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string; // TODO: consider adding other vars
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
@@ -113,12 +126,18 @@ interface DeleteIntegrationEvent {
type: EventType.DELETE_INTEGRATION;
metadata: {
integrationId: string;
integration: string; // TODO: fix type
integration: string;
environment: string;
secretPath: string;
url?: string;
app?: string;
appId?: string;
targetEnvironment?: string;
targetEnvironmentId?: string;
targetService?: string;
targetServiceId?: string;
path?: string;
region?: string;
}
}
@@ -277,12 +296,55 @@ interface DeleteWebhookEvent {
}
}
interface GetSecretImportsEvent {
type: EventType.GET_SECRET_IMPORTS,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
numberOfImports: number;
}
}
interface CreateSecretImportEvent {
type: EventType.CREATE_SECRET_IMPORT,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
importEnvironment: string;
importSecretPath: string;
}
}
interface UpdateSecretImportEvent {
type: EventType.UPDATE_SECRET_IMPORT,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
numberOfImports: number;
}
}
interface DeleteSecretImportEvent {
type: EventType.DELETE_SECRET_IMPORT,
metadata: {
environment: string;
secretImportId: string;
folderId: string;
importEnvironment: string;
importSecretPath: string;
}
}
export type Event =
| GetSecretsEvent
| GetSecretEvent
| CreateSecretEvent
| UpdateSecretEvent
| DeleteSecretEvent
| GetWorkspaceKeyEvent
| AuthorizeIntegrationEvent
| UnauthorizeIntegrationEvent
| CreateIntegrationEvent
@@ -302,7 +364,11 @@ export type Event =
| DeleteFolderEvent
| CreateWebhookEvent
| UpdateWebhookStatusEvent
| DeleteWebhookEvent;
| DeleteWebhookEvent
| GetSecretImportsEvent
| CreateSecretImportEvent
| UpdateSecretImportEvent
| DeleteSecretImportEvent;
export type AuditLog = {
_id: string;

View File

@@ -79,7 +79,7 @@ export type UpdateSecretArg = {
export type CreateSecretArg = Omit<UpdateSecretArg, "_id">;
export type DeleteSecretArg = { _id: string };
export type DeleteSecretArg = { _id: string, secretName: string; };
export type BatchSecretDTO = {
workspaceId: string;

View File

@@ -149,7 +149,7 @@ export const DashboardPage = () => {
const [snapshotId, setSnaphotId] = useState<string | null>(null);
const [selectedEnv, setSelectedEnv] = useState<WorkspaceEnv | null>(null);
const [sortDir, setSortDir] = useState<"asc" | "desc">("asc");
const deletedSecretIds = useRef<string[]>([]);
const deletedSecretIds = useRef<{ id: string; secretName: string; }[]>([]);
const { hasUnsavedChanges, setHasUnsavedChanges } = useLeaveConfirm({ initialValue: false });
const folderId = router.query.folderId as string;
@@ -498,9 +498,15 @@ export const DashboardPage = () => {
// record all deleted ids
// This will make final deletion easier
const onSecretDelete = useCallback((index: number, id?: string, overrideId?: string) => {
if (id) deletedSecretIds.current.push(id);
if (overrideId) deletedSecretIds.current.push(overrideId);
const onSecretDelete = useCallback((index: number, secretName: string, id?: string, overrideId?: string) => {
if (id) deletedSecretIds.current.push({
id,
secretName
});
if (overrideId) deletedSecretIds.current.push({
id: overrideId,
secretName
});
remove(index);
// just the case if this is called from drawer
handlePopUpClose("secretDetails");

View File

@@ -182,15 +182,18 @@ const deepCompareSecrets = (lhs: DecryptedSecret, rhs: any) =>
JSON.stringify(lhs.tags) === JSON.stringify(rhs.tags);
export const transformSecretsToBatchSecretReq = (
deletedSecretIds: string[],
deletedSecretIds: { id: string; secretName: string; }[],
latestFileKey: any,
secrets: FormData["secrets"],
intialValues: DecryptedSecret[] = []
) => {
// deleted secrets
const secretsToBeDeleted: BatchSecretDTO["requests"] = deletedSecretIds.map((id) => ({
const secretsToBeDeleted: BatchSecretDTO["requests"] = deletedSecretIds.map(({ id, secretName }) => ({
method: "DELETE",
secret: { _id: id }
secret: {
_id: id,
secretName
}
}));
const secretsToBeUpdated: BatchSecretDTO["requests"] = [];
@@ -261,7 +264,7 @@ export const transformSecretsToBatchSecretReq = (
if (idOverride) {
// if action is deleted meaning override has been removed but id is kept to collect at this point
if (overrideAction === SecretActionType.Deleted) {
secretsToBeDeleted.push({ method: "DELETE", secret: { _id: idOverride } });
secretsToBeDeleted.push({ method: "DELETE", secret: { _id: idOverride, secretName: key } });
} else {
// if not deleted action then as id is there its an updated
const initialSecretValue = intialValues?.find(({ _id: secId }) => secId === _id)!;

View File

@@ -67,7 +67,7 @@ type Props = {
isSecretValueHidden: boolean;
searchTerm: string;
// to record the ids of deleted ones
onSecretDelete: (index: number, id?: string, overrideId?: string) => void;
onSecretDelete: (index: number, secretName: string, id?: string, overrideId?: string) => void;
// sidebar control props
onRowExpand: (secId: string | undefined, index: number) => void;
// tag props
@@ -495,7 +495,9 @@ export const SecretInputRow = memo(
colorSchema="danger"
ariaLabel="delete"
isDisabled={isReadOnly || isRollbackMode}
onClick={() => onSecretDelete(index, secId, idOverride)}
onClick={() => {
onSecretDelete(index, secKey, secId, idOverride);
}}
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>

View File

@@ -73,7 +73,7 @@ export const LogsFilter = ({
className="w-40 mr-4"
>
<Select
defaultValue={field.value}
{...(field.value ? { value: field.value } : { placeholder: "Select" })}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
@@ -99,7 +99,7 @@ export const LogsFilter = ({
className="w-40 mr-4"
>
<Select
defaultValue={field.value}
{...(field.value ? { value: field.value } : { placeholder: "Select" })}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
@@ -121,7 +121,7 @@ export const LogsFilter = ({
className="w-40 mr-4"
>
<Select
defaultValue={field.value}
{...(field.value ? { value: field.value } : { placeholder: "Select" })}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
@@ -189,7 +189,7 @@ export const LogsFilter = ({
}}
/>
</div>
<div>
{/* <div>
<Button
isLoading={false}
colorSchema="primary"
@@ -198,15 +198,15 @@ export const LogsFilter = ({
leftIcon={<FontAwesomeIcon icon={faFilterCircleXmark} className="mr-2" />}
onClick={() => reset({
eventType: undefined,
actor: "",
userAgentType: "",
actor: undefined,
userAgentType: undefined,
startDate: undefined,
endDate: undefined
})}
>
Clear filters
</Button>
</div>
</div> */}
</div>
);
}

View File

@@ -32,12 +32,14 @@ export const LogsSection = () => {
const perPage = watch("perPage") as number;
return (
<div className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600">
<div className="flex items-center mb-8">
<div
// className="p-4 bg-mineshaft-900 mb-6 rounded-lg border border-mineshaft-600"
>
{/* <div className="flex items-center mb-8">
<h2 className="text-xl font-semibold flex-1 text-white">
Audit Logs
</h2>
</div>
</div> */}
<LogsFilter
control={control}
reset={reset}

View File

@@ -100,6 +100,9 @@ export const LogsTableRow = ({
{event.metadata.app && (
<p>{`Target app: ${event.metadata.app}`}</p>
)}
{event.metadata.appId && (
<p>{`Target app: ${event.metadata.appId}`}</p>
)}
{event.metadata.targetEnvironment && (
<p>{`Target environment: ${event.metadata.targetEnvironment}`}</p>
)}
@@ -117,6 +120,9 @@ export const LogsTableRow = ({
{event.metadata.app && (
<p>{`Target App: ${event.metadata.app}`}</p>
)}
{event.metadata.appId && (
<p>{`Target app: ${event.metadata.appId}`}</p>
)}
{event.metadata.targetEnvironment && (
<p>{`Target environment: ${event.metadata.targetEnvironment}`}</p>
)}
@@ -219,7 +225,7 @@ export const LogsTableRow = ({
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Secret Path: ${event.metadata.secretPath}`}</p>
<p>{`Secret path: ${event.metadata.secretPath}`}</p>
<p>{`Webhook URL: ${event.metadata.webhookUrl}`}</p>
<p>{`Disabled: ${event.metadata.isDisabled}`}</p>
</Td>
@@ -228,7 +234,7 @@ export const LogsTableRow = ({
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Secret Path: ${event.metadata.secretPath}`}</p>
<p>{`Secret path: ${event.metadata.secretPath}`}</p>
<p>{`Webhook URL: ${event.metadata.webhookUrl}`}</p>
<p>{`Disabled: ${event.metadata.isDisabled}`}</p>
</Td>
@@ -237,14 +243,42 @@ export const LogsTableRow = ({
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Secret Path: ${event.metadata.secretPath}`}</p>
<p>{`Secret path: ${event.metadata.secretPath}`}</p>
<p>{`Webhook URL: ${event.metadata.webhookUrl}`}</p>
<p>{`Disabled: ${event.metadata.isDisabled}`}</p>
</Td>
);
case EventType.GET_SECRET_IMPORTS:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`# Imported paths: ${event.metadata.numberOfImports}`}</p>
</Td>
);
case EventType.CREATE_SECRET_IMPORT:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Imported path: ${event.metadata.importSecretPath}`}</p>
</Td>
);
case EventType.UPDATE_SECRET_IMPORT:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`# Imported path: ${event.metadata.numberOfImports}`}</p>
</Td>
);
case EventType.DELETE_SECRET_IMPORT:
return (
<Td>
<p>{`Environment: ${event.metadata.environment}`}</p>
<p>{`Imported path: ${event.metadata.importSecretPath}`}</p>
</Td>
);
default:
return (
<Td>Test</Td>
<Td></Td>
);
}
}