mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 19:28:16 +00:00
feat(secret-approval): added new audit log and subscription on policy creation
This commit is contained in:
@@ -9,6 +9,8 @@ import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
|||||||
import { ISecretApprovalPolicy, SecretApprovalPolicy } from "../../models/secretApprovalPolicy";
|
import { ISecretApprovalPolicy, SecretApprovalPolicy } from "../../models/secretApprovalPolicy";
|
||||||
import { performSecretApprovalRequestMerge } from "../../services/SecretApprovalService";
|
import { performSecretApprovalRequestMerge } from "../../services/SecretApprovalService";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
import { EEAuditLogService } from "../../ee/services";
|
||||||
|
import { EventType } from "../../ee/models";
|
||||||
|
|
||||||
export const getSecretApprovalRequests = async (req: Request, res: Response) => {
|
export const getSecretApprovalRequests = async (req: Request, res: Response) => {
|
||||||
const {
|
const {
|
||||||
@@ -31,6 +33,7 @@ export const getSecretApprovalRequests = async (req: Request, res: Response) =>
|
|||||||
{
|
{
|
||||||
$match: query
|
$match: query
|
||||||
},
|
},
|
||||||
|
{ $sort: { createdAt: -1 } },
|
||||||
{
|
{
|
||||||
$lookup: {
|
$lookup: {
|
||||||
from: SecretApprovalPolicy.collection.name,
|
from: SecretApprovalPolicy.collection.name,
|
||||||
@@ -234,5 +237,37 @@ export const updateSecretApprovalRequestStatus = async (req: Request, res: Respo
|
|||||||
{ status, statusChangeBy: membership._id },
|
{ status, statusChangeBy: membership._id },
|
||||||
{ new: true }
|
{ new: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (status === "close") {
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.SECRET_APPROVAL_CLOSED,
|
||||||
|
metadata: {
|
||||||
|
closedBy: membership._id.toString(),
|
||||||
|
secretApprovalRequestId: id,
|
||||||
|
secretApprovalRequestSlug: secretApprovalRequest.slug
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
workspaceId: secretApprovalRequest.workspace
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
req.authData,
|
||||||
|
{
|
||||||
|
type: EventType.SECRET_APPROVAL_REOPENED,
|
||||||
|
metadata: {
|
||||||
|
reopenedBy: membership._id.toString(),
|
||||||
|
secretApprovalRequestId: id,
|
||||||
|
secretApprovalRequestSlug: secretApprovalRequest.slug
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
workspaceId: secretApprovalRequest.workspace
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
return res.send({ approval: updatedRequest });
|
return res.send({ approval: updatedRequest });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -595,33 +595,37 @@ export const createSecret = async (req: Request, res: Response) => {
|
|||||||
secretAction: ProjectPermissionActions.Create
|
secretAction: ProjectPermissionActions.Create
|
||||||
});
|
});
|
||||||
|
|
||||||
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
|
||||||
if (secretApprovalPolicy && membership && type !== "personal") {
|
if (membership && type !== "personal") {
|
||||||
const secretApprovalRequest = await generateSecretApprovalRequest({
|
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
||||||
workspaceId,
|
if (secretApprovalPolicy) {
|
||||||
environment,
|
const secretApprovalRequest = await generateSecretApprovalRequest({
|
||||||
secretPath,
|
workspaceId,
|
||||||
policy: secretApprovalPolicy,
|
environment,
|
||||||
commiterMembershipId: membership._id.toString(),
|
secretPath,
|
||||||
data: {
|
policy: secretApprovalPolicy,
|
||||||
[CommitType.CREATE]: [
|
commiterMembershipId: membership._id.toString(),
|
||||||
{
|
authData:req.authData,
|
||||||
secretName,
|
data: {
|
||||||
secretValueCiphertext,
|
[CommitType.CREATE]: [
|
||||||
secretValueIV,
|
{
|
||||||
secretValueTag,
|
secretName,
|
||||||
secretCommentIV,
|
secretValueCiphertext,
|
||||||
secretCommentTag,
|
secretValueIV,
|
||||||
secretCommentCiphertext,
|
secretValueTag,
|
||||||
skipMultilineEncoding,
|
secretCommentIV,
|
||||||
secretKeyTag,
|
secretCommentTag,
|
||||||
secretKeyCiphertext,
|
secretCommentCiphertext,
|
||||||
secretKeyIV
|
skipMultilineEncoding,
|
||||||
}
|
secretKeyTag,
|
||||||
]
|
secretKeyCiphertext,
|
||||||
}
|
secretKeyIV
|
||||||
});
|
}
|
||||||
return res.send({ approval: secretApprovalRequest });
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res.send({ approval: secretApprovalRequest });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = await SecretService.createSecret({
|
const secret = await SecretService.createSecret({
|
||||||
@@ -700,35 +704,38 @@ export const updateSecretByName = async (req: Request, res: Response) => {
|
|||||||
secretAction: ProjectPermissionActions.Edit
|
secretAction: ProjectPermissionActions.Edit
|
||||||
});
|
});
|
||||||
|
|
||||||
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
if (membership && type !== "personal") {
|
||||||
if (secretApprovalPolicy && membership && type !== "personal") {
|
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
||||||
const secretApprovalRequest = await generateSecretApprovalRequest({
|
if (secretApprovalPolicy) {
|
||||||
workspaceId,
|
const secretApprovalRequest = await generateSecretApprovalRequest({
|
||||||
environment,
|
workspaceId,
|
||||||
secretPath,
|
environment,
|
||||||
policy: secretApprovalPolicy,
|
secretPath,
|
||||||
commiterMembershipId: membership._id.toString(),
|
policy: secretApprovalPolicy,
|
||||||
data: {
|
commiterMembershipId: membership._id.toString(),
|
||||||
[CommitType.UPDATE]: [
|
authData: req.authData,
|
||||||
{
|
data: {
|
||||||
secretName,
|
[CommitType.UPDATE]: [
|
||||||
newSecretName,
|
{
|
||||||
secretValueCiphertext,
|
secretName,
|
||||||
secretValueIV,
|
newSecretName,
|
||||||
secretValueTag,
|
secretValueCiphertext,
|
||||||
tags,
|
secretValueIV,
|
||||||
secretCommentIV,
|
secretValueTag,
|
||||||
secretCommentTag,
|
tags,
|
||||||
secretCommentCiphertext,
|
secretCommentIV,
|
||||||
skipMultilineEncoding,
|
secretCommentTag,
|
||||||
secretKeyTag,
|
secretCommentCiphertext,
|
||||||
secretKeyCiphertext,
|
skipMultilineEncoding,
|
||||||
secretKeyIV
|
secretKeyTag,
|
||||||
}
|
secretKeyCiphertext,
|
||||||
]
|
secretKeyIV
|
||||||
}
|
}
|
||||||
});
|
]
|
||||||
return res.send({ approval: secretApprovalRequest });
|
}
|
||||||
|
});
|
||||||
|
return res.send({ approval: secretApprovalRequest });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = await SecretService.updateSecret({
|
const secret = await SecretService.updateSecret({
|
||||||
@@ -784,23 +791,26 @@ export const deleteSecretByName = async (req: Request, res: Response) => {
|
|||||||
secretAction: ProjectPermissionActions.Delete
|
secretAction: ProjectPermissionActions.Delete
|
||||||
});
|
});
|
||||||
|
|
||||||
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
if (membership && type !== "personal") {
|
||||||
if (secretApprovalPolicy && membership && type !== "personal") {
|
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
||||||
const secretApprovalRequest = await generateSecretApprovalRequest({
|
if (secretApprovalPolicy) {
|
||||||
workspaceId,
|
const secretApprovalRequest = await generateSecretApprovalRequest({
|
||||||
environment,
|
workspaceId,
|
||||||
secretPath,
|
environment,
|
||||||
policy: secretApprovalPolicy,
|
secretPath,
|
||||||
commiterMembershipId: membership._id.toString(),
|
authData: req.authData,
|
||||||
data: {
|
policy: secretApprovalPolicy,
|
||||||
[CommitType.DELETE]: [
|
commiterMembershipId: membership._id.toString(),
|
||||||
{
|
data: {
|
||||||
secretName
|
[CommitType.DELETE]: [
|
||||||
}
|
{
|
||||||
]
|
secretName
|
||||||
}
|
}
|
||||||
});
|
]
|
||||||
return res.send({ approval: secretApprovalRequest });
|
}
|
||||||
|
});
|
||||||
|
return res.send({ approval: secretApprovalRequest });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { secret } = await SecretService.deleteSecret({
|
const { secret } = await SecretService.deleteSecret({
|
||||||
@@ -838,19 +848,22 @@ export const createSecretByNameBatch = async (req: Request, res: Response) => {
|
|||||||
secretAction: ProjectPermissionActions.Create
|
secretAction: ProjectPermissionActions.Create
|
||||||
});
|
});
|
||||||
|
|
||||||
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
if (membership) {
|
||||||
if (secretApprovalPolicy && membership) {
|
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
||||||
const secretApprovalRequest = await generateSecretApprovalRequest({
|
if (secretApprovalPolicy) {
|
||||||
workspaceId,
|
const secretApprovalRequest = await generateSecretApprovalRequest({
|
||||||
environment,
|
workspaceId,
|
||||||
secretPath,
|
environment,
|
||||||
policy: secretApprovalPolicy,
|
secretPath,
|
||||||
commiterMembershipId: membership._id.toString(),
|
authData: req.authData,
|
||||||
data: {
|
policy: secretApprovalPolicy,
|
||||||
[CommitType.CREATE]: secrets.filter(({ type }) => type === "shared")
|
commiterMembershipId: membership._id.toString(),
|
||||||
}
|
data: {
|
||||||
});
|
[CommitType.CREATE]: secrets.filter(({ type }) => type === "shared")
|
||||||
return res.send({ approval: secretApprovalRequest });
|
}
|
||||||
|
});
|
||||||
|
return res.send({ approval: secretApprovalRequest });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdSecrets = await SecretService.createSecretBatch({
|
const createdSecrets = await SecretService.createSecretBatch({
|
||||||
@@ -879,19 +892,22 @@ export const updateSecretByNameBatch = async (req: Request, res: Response) => {
|
|||||||
secretAction: ProjectPermissionActions.Edit
|
secretAction: ProjectPermissionActions.Edit
|
||||||
});
|
});
|
||||||
|
|
||||||
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
if (membership) {
|
||||||
if (secretApprovalPolicy && membership) {
|
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
||||||
const secretApprovalRequest = await generateSecretApprovalRequest({
|
if (secretApprovalPolicy) {
|
||||||
workspaceId,
|
const secretApprovalRequest = await generateSecretApprovalRequest({
|
||||||
environment,
|
workspaceId,
|
||||||
secretPath,
|
environment,
|
||||||
policy: secretApprovalPolicy,
|
secretPath,
|
||||||
commiterMembershipId: membership._id.toString(),
|
policy: secretApprovalPolicy,
|
||||||
data: {
|
commiterMembershipId: membership._id.toString(),
|
||||||
[CommitType.UPDATE]: secrets.filter(({ type }) => type === "shared")
|
data: {
|
||||||
}
|
[CommitType.UPDATE]: secrets.filter(({ type }) => type === "shared")
|
||||||
});
|
},
|
||||||
return res.send({ approval: secretApprovalRequest });
|
authData: req.authData
|
||||||
|
});
|
||||||
|
return res.send({ approval: secretApprovalRequest });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedSecrets = await SecretService.updateSecretBatch({
|
const updatedSecrets = await SecretService.updateSecretBatch({
|
||||||
@@ -920,19 +936,23 @@ export const deleteSecretByNameBatch = async (req: Request, res: Response) => {
|
|||||||
secretAction: ProjectPermissionActions.Delete
|
secretAction: ProjectPermissionActions.Delete
|
||||||
});
|
});
|
||||||
|
|
||||||
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
|
||||||
if (secretApprovalPolicy && membership) {
|
if (membership) {
|
||||||
const secretApprovalRequest = await generateSecretApprovalRequest({
|
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
|
||||||
workspaceId,
|
if (secretApprovalPolicy) {
|
||||||
environment,
|
const secretApprovalRequest = await generateSecretApprovalRequest({
|
||||||
secretPath,
|
workspaceId,
|
||||||
policy: secretApprovalPolicy,
|
environment,
|
||||||
commiterMembershipId: membership._id.toString(),
|
secretPath,
|
||||||
data: {
|
policy: secretApprovalPolicy,
|
||||||
[CommitType.DELETE]: secrets.filter(({ type }) => type === "shared")
|
commiterMembershipId: membership._id.toString(),
|
||||||
}
|
data: {
|
||||||
});
|
[CommitType.DELETE]: secrets.filter(({ type }) => type === "shared")
|
||||||
return res.send({ approval: secretApprovalRequest });
|
},
|
||||||
|
authData: req.authData
|
||||||
|
});
|
||||||
|
return res.send({ approval: secretApprovalRequest });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deletedSecrets = await SecretService.deleteSecretBatch({
|
const deletedSecrets = await SecretService.deleteSecretBatch({
|
||||||
|
|||||||
@@ -12,43 +12,47 @@ 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",
|
||||||
REVEAL_SECRET = "reveal-secret",
|
REVEAL_SECRET = "reveal-secret",
|
||||||
CREATE_SECRET = "create-secret",
|
CREATE_SECRET = "create-secret",
|
||||||
CREATE_SECRETS = "create-secrets",
|
CREATE_SECRETS = "create-secrets",
|
||||||
UPDATE_SECRET = "update-secret",
|
UPDATE_SECRET = "update-secret",
|
||||||
UPDATE_SECRETS = "update-secrets",
|
UPDATE_SECRETS = "update-secrets",
|
||||||
DELETE_SECRET = "delete-secret",
|
DELETE_SECRET = "delete-secret",
|
||||||
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",
|
||||||
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
UNAUTHORIZE_INTEGRATION = "unauthorize-integration",
|
||||||
CREATE_INTEGRATION = "create-integration",
|
CREATE_INTEGRATION = "create-integration",
|
||||||
DELETE_INTEGRATION = "delete-integration",
|
DELETE_INTEGRATION = "delete-integration",
|
||||||
ADD_TRUSTED_IP = "add-trusted-ip",
|
ADD_TRUSTED_IP = "add-trusted-ip",
|
||||||
UPDATE_TRUSTED_IP = "update-trusted-ip",
|
UPDATE_TRUSTED_IP = "update-trusted-ip",
|
||||||
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
DELETE_TRUSTED_IP = "delete-trusted-ip",
|
||||||
CREATE_SERVICE_TOKEN = "create-service-token", // v2
|
CREATE_SERVICE_TOKEN = "create-service-token", // v2
|
||||||
DELETE_SERVICE_TOKEN = "delete-service-token", // v2
|
DELETE_SERVICE_TOKEN = "delete-service-token", // v2
|
||||||
CREATE_SERVICE_TOKEN_V3 = "create-service-token-v3", // v3
|
CREATE_SERVICE_TOKEN_V3 = "create-service-token-v3", // v3
|
||||||
UPDATE_SERVICE_TOKEN_V3 = "update-service-token-v3", // v3
|
UPDATE_SERVICE_TOKEN_V3 = "update-service-token-v3", // v3
|
||||||
DELETE_SERVICE_TOKEN_V3 = "delete-service-token-v3", // v3
|
DELETE_SERVICE_TOKEN_V3 = "delete-service-token-v3", // v3
|
||||||
CREATE_ENVIRONMENT = "create-environment",
|
CREATE_ENVIRONMENT = "create-environment",
|
||||||
UPDATE_ENVIRONMENT = "update-environment",
|
UPDATE_ENVIRONMENT = "update-environment",
|
||||||
DELETE_ENVIRONMENT = "delete-environment",
|
DELETE_ENVIRONMENT = "delete-environment",
|
||||||
ADD_WORKSPACE_MEMBER = "add-workspace-member",
|
ADD_WORKSPACE_MEMBER = "add-workspace-member",
|
||||||
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
|
REMOVE_WORKSPACE_MEMBER = "remove-workspace-member",
|
||||||
CREATE_FOLDER = "create-folder",
|
CREATE_FOLDER = "create-folder",
|
||||||
UPDATE_FOLDER = "update-folder",
|
UPDATE_FOLDER = "update-folder",
|
||||||
DELETE_FOLDER = "delete-folder",
|
DELETE_FOLDER = "delete-folder",
|
||||||
CREATE_WEBHOOK = "create-webhook",
|
CREATE_WEBHOOK = "create-webhook",
|
||||||
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
|
UPDATE_WEBHOOK_STATUS = "update-webhook-status",
|
||||||
DELETE_WEBHOOK = "delete-webhook",
|
DELETE_WEBHOOK = "delete-webhook",
|
||||||
GET_SECRET_IMPORTS = "get-secret-imports",
|
GET_SECRET_IMPORTS = "get-secret-imports",
|
||||||
CREATE_SECRET_IMPORT = "create-secret-import",
|
CREATE_SECRET_IMPORT = "create-secret-import",
|
||||||
UPDATE_SECRET_IMPORT = "update-secret-import",
|
UPDATE_SECRET_IMPORT = "update-secret-import",
|
||||||
DELETE_SECRET_IMPORT = "delete-secret-import",
|
DELETE_SECRET_IMPORT = "delete-secret-import",
|
||||||
UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role",
|
UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role",
|
||||||
UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions"
|
UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions",
|
||||||
}
|
SECRET_APPROVAL_MERGED = "secret-approval-merged",
|
||||||
|
SECRET_APPROVAL_REQUEST = "secret-approval-request",
|
||||||
|
SECRET_APPROVAL_CLOSED = "secret-approval-closed",
|
||||||
|
SECRET_APPROVAL_REOPENED = "secret-approval-reopened"
|
||||||
|
}
|
||||||
|
|||||||
@@ -437,43 +437,82 @@ interface UpdateUserDeniedPermissions {
|
|||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
interface SecretApprovalMerge {
|
||||||
|
type: EventType.SECRET_APPROVAL_MERGED;
|
||||||
|
metadata: {
|
||||||
|
mergedBy: string;
|
||||||
|
secretApprovalRequestSlug: string;
|
||||||
|
secretApprovalRequestId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type Event =
|
interface SecretApprovalClosed {
|
||||||
| GetSecretsEvent
|
type: EventType.SECRET_APPROVAL_CLOSED;
|
||||||
| GetSecretEvent
|
metadata: {
|
||||||
| CreateSecretEvent
|
closedBy: string;
|
||||||
| CreateSecretBatchEvent
|
secretApprovalRequestSlug: string;
|
||||||
| UpdateSecretEvent
|
secretApprovalRequestId: string;
|
||||||
| UpdateSecretBatchEvent
|
};
|
||||||
| DeleteSecretEvent
|
}
|
||||||
| DeleteSecretBatchEvent
|
|
||||||
| GetWorkspaceKeyEvent
|
interface SecretApprovalReopened {
|
||||||
| AuthorizeIntegrationEvent
|
type: EventType.SECRET_APPROVAL_REOPENED;
|
||||||
| UnauthorizeIntegrationEvent
|
metadata: {
|
||||||
| CreateIntegrationEvent
|
reopenedBy: string;
|
||||||
| DeleteIntegrationEvent
|
secretApprovalRequestSlug: string;
|
||||||
| AddTrustedIPEvent
|
secretApprovalRequestId: string;
|
||||||
| UpdateTrustedIPEvent
|
};
|
||||||
| DeleteTrustedIPEvent
|
}
|
||||||
| CreateServiceTokenEvent
|
|
||||||
| DeleteServiceTokenEvent
|
interface SecretApprovalRequest {
|
||||||
| CreateServiceTokenV3Event
|
type: EventType.SECRET_APPROVAL_REQUEST;
|
||||||
| UpdateServiceTokenV3Event
|
metadata: {
|
||||||
| DeleteServiceTokenV3Event
|
committedBy: string;
|
||||||
| CreateEnvironmentEvent
|
secretApprovalRequestSlug: string;
|
||||||
| UpdateEnvironmentEvent
|
secretApprovalRequestId: string;
|
||||||
| DeleteEnvironmentEvent
|
};
|
||||||
| AddWorkspaceMemberEvent
|
}
|
||||||
| RemoveWorkspaceMemberEvent
|
|
||||||
| CreateFolderEvent
|
export type Event =
|
||||||
| UpdateFolderEvent
|
| GetSecretsEvent
|
||||||
| DeleteFolderEvent
|
| GetSecretEvent
|
||||||
| CreateWebhookEvent
|
| CreateSecretEvent
|
||||||
| UpdateWebhookStatusEvent
|
| CreateSecretBatchEvent
|
||||||
| DeleteWebhookEvent
|
| UpdateSecretEvent
|
||||||
| GetSecretImportsEvent
|
| UpdateSecretBatchEvent
|
||||||
| CreateSecretImportEvent
|
| DeleteSecretEvent
|
||||||
| UpdateSecretImportEvent
|
| DeleteSecretBatchEvent
|
||||||
| DeleteSecretImportEvent
|
| GetWorkspaceKeyEvent
|
||||||
| UpdateUserRole
|
| AuthorizeIntegrationEvent
|
||||||
| UpdateUserDeniedPermissions;
|
| UnauthorizeIntegrationEvent
|
||||||
|
| CreateIntegrationEvent
|
||||||
|
| DeleteIntegrationEvent
|
||||||
|
| AddTrustedIPEvent
|
||||||
|
| UpdateTrustedIPEvent
|
||||||
|
| DeleteTrustedIPEvent
|
||||||
|
| CreateServiceTokenEvent
|
||||||
|
| DeleteServiceTokenEvent
|
||||||
|
| CreateServiceTokenV3Event
|
||||||
|
| UpdateServiceTokenV3Event
|
||||||
|
| DeleteServiceTokenV3Event
|
||||||
|
| CreateEnvironmentEvent
|
||||||
|
| UpdateEnvironmentEvent
|
||||||
|
| DeleteEnvironmentEvent
|
||||||
|
| AddWorkspaceMemberEvent
|
||||||
|
| RemoveWorkspaceMemberEvent
|
||||||
|
| CreateFolderEvent
|
||||||
|
| UpdateFolderEvent
|
||||||
|
| DeleteFolderEvent
|
||||||
|
| CreateWebhookEvent
|
||||||
|
| UpdateWebhookStatusEvent
|
||||||
|
| DeleteWebhookEvent
|
||||||
|
| GetSecretImportsEvent
|
||||||
|
| CreateSecretImportEvent
|
||||||
|
| UpdateSecretImportEvent
|
||||||
|
| DeleteSecretImportEvent
|
||||||
|
| UpdateUserRole
|
||||||
|
| UpdateUserDeniedPermissions
|
||||||
|
| SecretApprovalMerge
|
||||||
|
| SecretApprovalClosed
|
||||||
|
| SecretApprovalRequest
|
||||||
|
| SecretApprovalReopened;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Schema, Types, model } from "mongoose";
|
import { Schema, Types, model } from "mongoose";
|
||||||
|
import { customAlphabet } from "nanoid";
|
||||||
import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, ENCODING_SCHEME_UTF8 } from "../variables";
|
import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, ENCODING_SCHEME_UTF8 } from "../variables";
|
||||||
|
|
||||||
export enum ApprovalStatus {
|
export enum ApprovalStatus {
|
||||||
@@ -13,6 +14,9 @@ export enum CommitType {
|
|||||||
CREATE = "create"
|
CREATE = "create"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SLUG_ALPHABETS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
|
const nanoId = customAlphabet(SLUG_ALPHABETS, 10);
|
||||||
|
|
||||||
export interface ISecretApprovalSecChange {
|
export interface ISecretApprovalSecChange {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
version: number;
|
version: number;
|
||||||
@@ -54,6 +58,7 @@ export type ISecretCommits<T = Types.ObjectId, J = Types.ObjectId> = Array<
|
|||||||
export interface ISecretApprovalRequest {
|
export interface ISecretApprovalRequest {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
committer: Types.ObjectId;
|
committer: Types.ObjectId;
|
||||||
|
slug: string;
|
||||||
statusChangeBy: Types.ObjectId;
|
statusChangeBy: Types.ObjectId;
|
||||||
reviewers: {
|
reviewers: {
|
||||||
member: Types.ObjectId;
|
member: Types.ObjectId;
|
||||||
@@ -143,6 +148,10 @@ const secretApprovalRequestSchema = new Schema<ISecretApprovalRequest>(
|
|||||||
required: true,
|
required: true,
|
||||||
default: "root"
|
default: "root"
|
||||||
},
|
},
|
||||||
|
slug: {
|
||||||
|
type: String,
|
||||||
|
default: () => nanoId()
|
||||||
|
},
|
||||||
reviewers: {
|
reviewers: {
|
||||||
type: [
|
type: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ type TGenerateSecretApprovalRequestArg = {
|
|||||||
[CommitType.DELETE]?: { secretName: string }[];
|
[CommitType.DELETE]?: { secretName: string }[];
|
||||||
};
|
};
|
||||||
commiterMembershipId: string;
|
commiterMembershipId: string;
|
||||||
|
authData: AuthData;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateSecretApprovalRequest = async ({
|
export const generateSecretApprovalRequest = async ({
|
||||||
@@ -104,7 +105,8 @@ export const generateSecretApprovalRequest = async ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
policy,
|
policy,
|
||||||
data,
|
data,
|
||||||
commiterMembershipId
|
commiterMembershipId,
|
||||||
|
authData
|
||||||
}: TGenerateSecretApprovalRequestArg) => {
|
}: TGenerateSecretApprovalRequestArg) => {
|
||||||
// calculate folder id from secret path
|
// calculate folder id from secret path
|
||||||
let folderId = "root";
|
let folderId = "root";
|
||||||
@@ -313,6 +315,22 @@ export const generateSecretApprovalRequest = async ({
|
|||||||
committer: commiterMembershipId
|
committer: commiterMembershipId
|
||||||
});
|
});
|
||||||
await secretApprovalRequest.save();
|
await secretApprovalRequest.save();
|
||||||
|
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
authData,
|
||||||
|
{
|
||||||
|
type: EventType.SECRET_APPROVAL_REQUEST,
|
||||||
|
metadata: {
|
||||||
|
committedBy: commiterMembershipId,
|
||||||
|
secretApprovalRequestId: secretApprovalRequest._id.toString(),
|
||||||
|
secretApprovalRequestSlug: secretApprovalRequest.slug
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
workspaceId: secretApprovalRequest.workspace
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return secretApprovalRequest;
|
return secretApprovalRequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -436,26 +454,6 @@ export const performSecretApprovalRequestMerge = async (
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
// question to team where to keep secretKey
|
|
||||||
await EEAuditLogService.createAuditLog(
|
|
||||||
authData,
|
|
||||||
{
|
|
||||||
type: EventType.CREATE_SECRETS,
|
|
||||||
metadata: {
|
|
||||||
environment,
|
|
||||||
secretPath: "/",
|
|
||||||
secrets: newlyCreatedSecrets.map(({ version, _id }) => ({
|
|
||||||
secretId: _id.toString(),
|
|
||||||
secretKey: "",
|
|
||||||
secretVersion: version
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
workspaceId
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const secretUpdationCommits = secretApprovalRequest.commits.filter(
|
const secretUpdationCommits = secretApprovalRequest.commits.filter(
|
||||||
@@ -570,25 +568,6 @@ export const performSecretApprovalRequestMerge = async (
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
|
||||||
authData,
|
|
||||||
{
|
|
||||||
type: EventType.UPDATE_SECRETS,
|
|
||||||
metadata: {
|
|
||||||
environment,
|
|
||||||
secretPath: "/",
|
|
||||||
secrets: nonConflictSecrets.map(({ secret }) => ({
|
|
||||||
secretId: secret._id.toString(),
|
|
||||||
secretKey: "",
|
|
||||||
secretVersion: secret.version + 1
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
workspaceId
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const secretDeletionCommits = secretApprovalRequest.commits.filter(
|
const secretDeletionCommits = secretApprovalRequest.commits.filter(
|
||||||
@@ -614,25 +593,6 @@ export const performSecretApprovalRequestMerge = async (
|
|||||||
await EESecretService.markDeletedSecretVersions({
|
await EESecretService.markDeletedSecretVersions({
|
||||||
secretIds: secretDeletionCommits.map(({ secret }) => secret._id)
|
secretIds: secretDeletionCommits.map(({ secret }) => secret._id)
|
||||||
});
|
});
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
|
||||||
authData,
|
|
||||||
{
|
|
||||||
type: EventType.DELETE_SECRETS,
|
|
||||||
metadata: {
|
|
||||||
environment,
|
|
||||||
secretPath: "/",
|
|
||||||
secrets: secretDeletionCommits.map(({ secret: { _id, version } }) => ({
|
|
||||||
secretId: _id.toString(),
|
|
||||||
secretKey: "",
|
|
||||||
secretVersion: version
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
workspaceId
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedSecretApproval = await SecretApprovalRequest.findByIdAndUpdate(
|
const updatedSecretApproval = await SecretApprovalRequest.findByIdAndUpdate(
|
||||||
@@ -671,5 +631,21 @@ export const performSecretApprovalRequestMerge = async (
|
|||||||
folderId
|
folderId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// question to team where to keep secretKey
|
||||||
|
await EEAuditLogService.createAuditLog(
|
||||||
|
authData,
|
||||||
|
{
|
||||||
|
type: EventType.SECRET_APPROVAL_MERGED,
|
||||||
|
metadata: {
|
||||||
|
mergedBy: userMembershipId,
|
||||||
|
secretApprovalRequestId: id,
|
||||||
|
secretApprovalRequestSlug: secretApprovalRequest.slug
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
workspaceId
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return updatedSecretApproval;
|
return updatedSecretApproval;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export type TSecretApprovalRequest<
|
|||||||
J extends unknown = EncryptedSecret
|
J extends unknown = EncryptedSecret
|
||||||
> = {
|
> = {
|
||||||
_id: string;
|
_id: string;
|
||||||
|
slug: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
committer: string;
|
committer: string;
|
||||||
reviewers: {
|
reviewers: {
|
||||||
|
|||||||
@@ -11,12 +11,21 @@ export type SubscriptionPlan = {
|
|||||||
rbac: boolean;
|
rbac: boolean;
|
||||||
secretVersioning: boolean;
|
secretVersioning: boolean;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
secretApproval: string;
|
||||||
tier: number;
|
tier: number;
|
||||||
workspaceLimit: number;
|
workspaceLimit: number;
|
||||||
workspacesUsed: number;
|
workspacesUsed: number;
|
||||||
environmentLimit: number;
|
environmentLimit: number;
|
||||||
samlSSO: boolean;
|
samlSSO: boolean;
|
||||||
status: "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "canceled" | "unpaid" | null;
|
status:
|
||||||
|
| "incomplete"
|
||||||
|
| "incomplete_expired"
|
||||||
|
| "trialing"
|
||||||
|
| "active"
|
||||||
|
| "past_due"
|
||||||
|
| "canceled"
|
||||||
|
| "unpaid"
|
||||||
|
| null;
|
||||||
trial_end: number | null;
|
trial_end: number | null;
|
||||||
has_used_trial: boolean;
|
has_used_trial: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
+23
-4
@@ -14,9 +14,15 @@ import {
|
|||||||
Td,
|
Td,
|
||||||
Th,
|
Th,
|
||||||
THead,
|
THead,
|
||||||
Tr
|
Tr,
|
||||||
|
UpgradePlanModal
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission } from "@app/context";
|
import {
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionSub,
|
||||||
|
useProjectPermission,
|
||||||
|
useSubscription
|
||||||
|
} from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import {
|
import {
|
||||||
useDeleteSecretApprovalPolicy,
|
useDeleteSecretApprovalPolicy,
|
||||||
@@ -35,9 +41,11 @@ type Props = {
|
|||||||
export const SecretApprovalPolicyList = ({ workspaceId }: Props) => {
|
export const SecretApprovalPolicyList = ({ workspaceId }: Props) => {
|
||||||
const { handlePopUpToggle, handlePopUpOpen, handlePopUpClose, popUp } = usePopUp([
|
const { handlePopUpToggle, handlePopUpOpen, handlePopUpClose, popUp } = usePopUp([
|
||||||
"secretPolicyForm",
|
"secretPolicyForm",
|
||||||
"deletePolicy"
|
"deletePolicy",
|
||||||
|
"upgradePlan"
|
||||||
] as const);
|
] as const);
|
||||||
const permission = useProjectPermission();
|
const permission = useProjectPermission();
|
||||||
|
const { subscription } = useSubscription();
|
||||||
const { createNotification } = useNotificationContext();
|
const { createNotification } = useNotificationContext();
|
||||||
|
|
||||||
const { data: members } = useGetWorkspaceUsers(workspaceId);
|
const { data: members } = useGetWorkspaceUsers(workspaceId);
|
||||||
@@ -87,7 +95,13 @@ export const SecretApprovalPolicyList = ({ workspaceId }: Props) => {
|
|||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handlePopUpOpen("secretPolicyForm")}
|
onClick={() => {
|
||||||
|
if (subscription && !subscription?.secretApproval) {
|
||||||
|
handlePopUpOpen("upgradePlan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handlePopUpOpen("secretPolicyForm");
|
||||||
|
}}
|
||||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
isDisabled={!isAllowed}
|
isDisabled={!isAllowed}
|
||||||
>
|
>
|
||||||
@@ -147,6 +161,11 @@ export const SecretApprovalPolicyList = ({ workspaceId }: Props) => {
|
|||||||
onChange={(isOpen) => handlePopUpToggle("deletePolicy", isOpen)}
|
onChange={(isOpen) => handlePopUpToggle("deletePolicy", isOpen)}
|
||||||
onDeleteApproved={handleDeletePolicy}
|
onDeleteApproved={handleDeletePolicy}
|
||||||
/>
|
/>
|
||||||
|
<UpgradePlanModal
|
||||||
|
isOpen={popUp.upgradePlan.isOpen}
|
||||||
|
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||||
|
text="You can add secret approval policy if you switch to Infisical's Team plan."
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+1
@@ -213,6 +213,7 @@ export const SecretApprovalRequest = () => {
|
|||||||
<div className="mb-1">
|
<div className="mb-1">
|
||||||
<FontAwesomeIcon icon={faCodeBranch} className="mr-2" />
|
<FontAwesomeIcon icon={faCodeBranch} className="mr-2" />
|
||||||
{generateCommitText(commits)}
|
{generateCommitText(commits)}
|
||||||
|
<span className="text-xs text-bunker-300"> #{secretApproval.slug}</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs text-gray-500">
|
<span className="text-xs text-gray-500">
|
||||||
Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "}
|
Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "}
|
||||||
|
|||||||
+5
-3
@@ -139,9 +139,11 @@ export const SecretApprovalRequestChanges = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isSecretApprovalRequestLoading) {
|
if (isSecretApprovalRequestLoading) {
|
||||||
<div>
|
return (
|
||||||
<ContentLoader />
|
<div>
|
||||||
</div>;
|
<ContentLoader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSecretApprovalRequestSuccess)
|
if (!isSecretApprovalRequestSuccess)
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ export const SecretListView = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[environment, secretPath]
|
[environment, secretPath, isProtectedBranch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSecretDelete = useCallback(async () => {
|
const handleSecretDelete = useCallback(async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user