mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-12 11:29:15 +00:00
Add dashboard-specific secret and secret import audit logs, re-touch audit logs v2 UI
This commit is contained in:
@@ -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 } = {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)!;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user