feat(secret-approval): moved approval code to ee

This commit is contained in:
Akhil Mohan
2023-10-05 21:10:18 +05:30
parent cb893f71ee
commit 7f463cabce
17 changed files with 109 additions and 112 deletions

View File

@@ -16,8 +16,6 @@ import * as workspaceController from "./workspaceController";
import * as secretScanningController from "./secretScanningController";
import * as webhookController from "./webhookController";
import * as secretImpsController from "./secretImpsController";
import * as secretApprovalPolicyController from "./secretApprovalPolicyController";
import * as secretApprovalRequestController from "./secretApprovalRequestsController";
export {
authController,
botController,
@@ -36,7 +34,5 @@ export {
workspaceController,
secretScanningController,
webhookController,
secretImpsController,
secretApprovalPolicyController,
secretApprovalRequestController
secretImpsController
};

View File

@@ -3,22 +3,11 @@ import { Types } from "mongoose";
import { EventService, SecretService } from "../../services";
import { eventPushSecrets } from "../../events";
import { BotService } from "../../services";
import {
containsGlobPatterns,
isValidScopeV3,
repackageSecretToRaw
} from "../../helpers/secrets";
import { containsGlobPatterns, isValidScopeV3, repackageSecretToRaw } from "../../helpers/secrets";
import { encryptSymmetric128BitHexKeyUTF8 } from "../../utils/crypto";
import { getAllImportedSecrets } from "../../services/SecretImportService";
import {
Folder,
IMembership,
IServiceTokenData,
IServiceTokenDataV3
} from "../../models";
import {
Permission
} from "../../models/serviceTokenDataV3";
import { Folder, IMembership, IServiceTokenData, IServiceTokenDataV3 } from "../../models";
import { Permission } from "../../models/serviceTokenDataV3";
import { getFolderByPath, getFolderWithPathFromId } from "../../services/FolderService";
import { BadRequestError } from "../../utils/errors";
import { validateRequest } from "../../helpers/validation";
@@ -29,7 +18,7 @@ import {
getUserProjectPermissions
} from "../../ee/services/ProjectRoleService";
import { ForbiddenError, subject } from "@casl/ability";
import {
import {
validateServiceTokenDataClientForWorkspace,
validateServiceTokenDataV3ClientForWorkspace
} from "../../validation";
@@ -37,6 +26,12 @@ import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variabl
import { ActorType } from "../../ee/models";
import { UnauthorizedRequestError } from "../../utils/errors";
import { AuthData } from "../../interfaces/middleware";
import {
generateSecretApprovalRequest,
getSecretPolicyOfBoard
} from "../../ee/services/SecretApprovalService";
import { CommitType } from "../../ee/models/secretApprovalRequest";
import { IRole } from "../../ee/models/role";
const checkSecretsPermission = async ({
authData,
@@ -50,8 +45,10 @@ const checkSecretsPermission = async ({
environment: string;
secretPath: string;
secretAction: ProjectPermissionActions; // CRUD
}): Promise<{authVerifier:(env: string, secPath: string) => boolean,membership?:Omit<IMembership,"customRole"> & {customRole: IRole}}> => {
}): Promise<{
authVerifier: (env: string, secPath: string) => boolean;
membership?: Omit<IMembership, "customRole"> & { customRole: IRole };
}> => {
let STV2RequiredPermissions = [];
let STV3RequiredPermissions: Permission[] = [];
@@ -73,22 +70,28 @@ const checkSecretsPermission = async ({
STV3RequiredPermissions = [Permission.WRITE];
break;
}
switch (authData.actor.type) {
case ActorType.USER: {
const { permission,membership } = await getUserProjectPermissions(authData.actor.metadata.userId, workspaceId);
const { permission, membership } = await getUserProjectPermissions(
authData.actor.metadata.userId,
workspaceId
);
ForbiddenError.from(permission).throwUnlessCan(
secretAction,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
return {authVerifier: (env: string, secPath: string) =>
permission.can(
secretAction,
subject(ProjectPermissionSub.Secrets, {
environment: env,
secretPath: secPath
})
),membership};
return {
authVerifier: (env: string, secPath: string) =>
permission.can(
secretAction,
subject(ProjectPermissionSub.Secrets, {
environment: env,
secretPath: secPath
})
),
membership
};
}
case ActorType.SERVICE: {
await validateServiceTokenDataClientForWorkspace({
@@ -98,7 +101,7 @@ const checkSecretsPermission = async ({
secretPath,
requiredPermissions: STV2RequiredPermissions
});
return {authVerifier:() => true};
return { authVerifier: () => true };
}
case ActorType.SERVICE_V3: {
await validateServiceTokenDataV3ClientForWorkspace({
@@ -109,25 +112,21 @@ const checkSecretsPermission = async ({
secretPath,
requiredPermissions: STV3RequiredPermissions
});
return {authVerifier: (env: string, secPath: string) =>
isValidScopeV3({
authPayload: authData.authPayload as IServiceTokenDataV3,
environment: env,
secretPath: secPath,
requiredPermissions: STV3RequiredPermissions
})};
return {
authVerifier: (env: string, secPath: string) =>
isValidScopeV3({
authPayload: authData.authPayload as IServiceTokenDataV3,
environment: env,
secretPath: secPath,
requiredPermissions: STV3RequiredPermissions
})
};
}
default: {
throw UnauthorizedRequestError();
}
}
}
import {
generateSecretApprovalRequest,
getSecretPolicyOfBoard
} from "../../services/SecretApprovalService";
import { CommitType } from "../../models/secretApprovalRequest";
import { IRole } from "../../ee/models/role";
};
/**
* Return secrets for workspace with id [workspaceId] and environment
@@ -167,7 +166,7 @@ export const getSecretsRaw = async (req: Request, res: Response) => {
if (!environment || !workspaceId)
throw BadRequestError({ message: "Missing environment or workspace id" });
const {authVerifier:permissionCheckFn} = await checkSecretsPermission({
const { authVerifier: permissionCheckFn } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
@@ -239,7 +238,7 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
query: { secretPath, environment, workspaceId, type, include_imports },
params: { secretName }
} = await validateRequest(reqValidator.GetSecretByNameRawV3, req);
await checkSecretsPermission({
authData: req.authData,
workspaceId,
@@ -482,7 +481,7 @@ export const getSecrets = async (req: Request, res: Response) => {
secretPath = getFolderWithPathFromId(folder.nodes, folderId).folderPath;
}
const {authVerifier:permissionCheckFn} = await checkSecretsPermission({
const { authVerifier: permissionCheckFn } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
@@ -536,7 +535,7 @@ export const getSecretByName = async (req: Request, res: Response) => {
query: { secretPath, environment, workspaceId, type, include_imports },
params: { secretName }
} = await validateRequest(reqValidator.GetSecretByNameV3, req);
await checkSecretsPermission({
authData: req.authData,
workspaceId,
@@ -586,8 +585,8 @@ export const createSecret = async (req: Request, res: Response) => {
},
params: { secretName }
} = await validateRequest(reqValidator.CreateSecretV3, req);
const {membership} = await checkSecretsPermission({
const { membership } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
@@ -595,8 +594,7 @@ export const createSecret = async (req: Request, res: Response) => {
secretAction: ProjectPermissionActions.Create
});
if (membership && type !== "personal") {
if (membership && type !== "personal") {
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
if (secretApprovalPolicy) {
const secretApprovalRequest = await generateSecretApprovalRequest({
@@ -605,7 +603,7 @@ export const createSecret = async (req: Request, res: Response) => {
secretPath,
policy: secretApprovalPolicy,
commiterMembershipId: membership._id.toString(),
authData:req.authData,
authData: req.authData,
data: {
[CommitType.CREATE]: [
{
@@ -691,12 +689,12 @@ export const updateSecretByName = async (req: Request, res: Response) => {
},
params: { secretName }
} = await validateRequest(reqValidator.UpdateSecretByNameV3, req);
if (newSecretName && (!secretKeyIV || !secretKeyTag || !secretKeyCiphertext)) {
throw BadRequestError({ message: "Missing encrypted key" });
}
const {membership} = await checkSecretsPermission({
const { membership } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
@@ -704,7 +702,7 @@ export const updateSecretByName = async (req: Request, res: Response) => {
secretAction: ProjectPermissionActions.Edit
});
if (membership && type !== "personal") {
if (membership && type !== "personal") {
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
if (secretApprovalPolicy) {
const secretApprovalRequest = await generateSecretApprovalRequest({
@@ -783,7 +781,7 @@ export const deleteSecretByName = async (req: Request, res: Response) => {
params: { secretName }
} = await validateRequest(reqValidator.DeleteSecretByNameV3, req);
const {membership} = await checkSecretsPermission({
const { membership } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
@@ -791,7 +789,7 @@ export const deleteSecretByName = async (req: Request, res: Response) => {
secretAction: ProjectPermissionActions.Delete
});
if (membership && type !== "personal") {
if (membership && type !== "personal") {
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
if (secretApprovalPolicy) {
const secretApprovalRequest = await generateSecretApprovalRequest({
@@ -839,8 +837,8 @@ export const createSecretByNameBatch = async (req: Request, res: Response) => {
const {
body: { secrets, secretPath, environment, workspaceId }
} = await validateRequest(reqValidator.CreateSecretByNameBatchV3, req);
const {membership} = await checkSecretsPermission({
const { membership } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
@@ -884,7 +882,7 @@ export const updateSecretByNameBatch = async (req: Request, res: Response) => {
body: { secrets, secretPath, environment, workspaceId }
} = await validateRequest(reqValidator.UpdateSecretByNameBatchV3, req);
const {membership} = await checkSecretsPermission({
const { membership } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
@@ -928,14 +926,13 @@ export const deleteSecretByNameBatch = async (req: Request, res: Response) => {
body: { secrets, secretPath, environment, workspaceId }
} = await validateRequest(reqValidator.DeleteSecretByNameBatchV3, req);
const {membership} = await checkSecretsPermission({
const { membership } = await checkSecretsPermission({
authData: req.authData,
workspaceId,
environment,
secretPath,
secretAction: ProjectPermissionActions.Delete
});
if (membership) {
const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath);
@@ -966,4 +963,4 @@ export const deleteSecretByNameBatch = async (req: Request, res: Response) => {
return res.status(200).send({
secrets: deletedSecrets
});
};
};

View File

@@ -8,6 +8,8 @@ import * as actionController from "./actionController";
import * as membershipController from "./membershipController";
import * as cloudProductsController from "./cloudProductsController";
import * as roleController from "./roleController";
import * as secretApprovalPolicyController from "./secretApprovalPolicyController";
import * as secretApprovalRequestController from "./secretApprovalRequestsController";
export {
secretController,
@@ -19,5 +21,7 @@ export {
actionController,
membershipController,
cloudProductsController,
roleController
roleController,
secretApprovalPolicyController,
secretApprovalRequestController
};

View File

@@ -5,11 +5,11 @@ import {
ProjectPermissionActions,
ProjectPermissionSub,
getUserProjectPermissions
} from "../../ee/services/ProjectRoleService";
import { validateRequest } from "../../helpers/validation";
} from "../../services/ProjectRoleService";
import { validateRequest } from "../../../helpers/validation";
import { SecretApprovalPolicy } from "../../models/secretApprovalPolicy";
import { getSecretPolicyOfBoard } from "../../services/SecretApprovalService";
import { BadRequestError } from "../../utils/errors";
import { BadRequestError } from "../../../utils/errors";
import * as reqValidator from "../../validation/secretApproval";
const ERR_SECRET_APPROVAL_NOT_FOUND = BadRequestError({ message: "secret approval not found" });

View File

@@ -1,16 +1,16 @@
import { Request, Response } from "express";
import { getUserProjectPermissions } from "../../ee/services/ProjectRoleService";
import { validateRequest } from "../../helpers/validation";
import { Folder } from "../../models";
import { getUserProjectPermissions } from "../../services/ProjectRoleService";
import { validateRequest } from "../../../helpers/validation";
import { Folder } from "../../../models";
import { ApprovalStatus, SecretApprovalRequest } from "../../models/secretApprovalRequest";
import * as reqValidator from "../../validation/secretApprovalRequest";
import { getFolderWithPathFromId } from "../../services/FolderService";
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import { getFolderWithPathFromId } from "../../../services/FolderService";
import { BadRequestError, UnauthorizedRequestError } from "../../../utils/errors";
import { ISecretApprovalPolicy, SecretApprovalPolicy } from "../../models/secretApprovalPolicy";
import { performSecretApprovalRequestMerge } from "../../services/SecretApprovalService";
import { Types } from "mongoose";
import { EEAuditLogService } from "../../ee/services";
import { EventType } from "../../ee/models";
import { EEAuditLogService } from "../../services";
import { EventType } from "../../models";
export const getSecretApprovalRequestCount = async (req: Request, res: Response) => {
const {

View File

@@ -1,6 +1,10 @@
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 {
PENDING = "pending",

View File

@@ -8,6 +8,8 @@ import action from "./action";
import cloudProducts from "./cloudProducts";
import secretScanning from "./secretScanning";
import roles from "./role";
import secretApprovalPolicy from "./secretApprovalPolicy";
import secretApprovalRequest from "./secretApprovalRequest";
export {
secret,
@@ -19,5 +21,7 @@ export {
action,
cloudProducts,
secretScanning,
roles
roles,
secretApprovalPolicy,
secretApprovalRequest
};

View File

@@ -1,8 +1,8 @@
import express from "express";
const router = express.Router();
import { requireAuth } from "../../middleware";
import { requireAuth } from "../../../middleware";
import { secretApprovalPolicyController } from "../../controllers/v1";
import { AuthMode } from "../../variables";
import { AuthMode } from "../../../variables";
router.get(
"/",

View File

@@ -1,8 +1,8 @@
import express from "express";
const router = express.Router();
import { requireAuth } from "../../middleware";
import { requireAuth } from "../../../middleware";
import { secretApprovalRequestController } from "../../controllers/v1";
import { AuthMode } from "../../variables";
import { AuthMode } from "../../../variables";
router.get(
"/",

View File

@@ -4,8 +4,8 @@ import {
containsGlobPatterns,
generateSecretBlindIndexWithSaltHelper,
getSecretBlindIndexSaltHelper
} from "../helpers/secrets";
import { Folder, ISecret, Secret } from "../models";
} from "../../helpers/secrets";
import { Folder, ISecret, Secret } from "../../models";
import { ISecretApprovalPolicy, SecretApprovalPolicy } from "../models/secretApprovalPolicy";
import {
CommitType,
@@ -14,13 +14,13 @@ import {
ISecretCommits,
SecretApprovalRequest
} from "../models/secretApprovalRequest";
import { BadRequestError } from "../utils/errors";
import { getFolderByPath } from "./FolderService";
import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_UTF8, SECRET_SHARED } from "../variables";
import TelemetryService from "./TelemetryService";
import { EEAuditLogService, EESecretService } from "../ee/services";
import { EventType, SecretVersion } from "../ee/models";
import { AuthData } from "../interfaces/middleware";
import { BadRequestError } from "../../utils/errors";
import { getFolderByPath } from "../../services/FolderService";
import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_UTF8, SECRET_SHARED } from "../../variables";
import TelemetryService from "../../services/TelemetryService";
import { EEAuditLogService, EESecretService } from "../services";
import { EventType, SecretVersion } from "../models";
import { AuthData } from "../../interfaces/middleware";
// if glob pattern score is 1, if not exist score is 0 and if its not both then its exact path meaning score 2
const getPolicyScore = (policy: ISecretApprovalPolicy) =>

View File

@@ -25,11 +25,11 @@ import {
users as eeUsersRouter,
workspace as eeWorkspaceRouter,
roles as v1RoleRouter,
secretApprovalPolicy as v1SecretApprovalPolicy,
secretApprovalRequest as v1SecretApprovalRequest,
secretScanning as v1SecretScanningRouter
} from "./ee/routes/v1";
import {
serviceTokenData as v3ServiceTokenDataRouter
} from "./ee/routes/v3";
import { serviceTokenData as v3ServiceTokenDataRouter } from "./ee/routes/v3";
import {
auth as v1AuthRouter,
bot as v1BotRouter,
@@ -42,8 +42,6 @@ import {
organization as v1OrganizationRouter,
password as v1PasswordRouter,
sso as v1SSORouter,
secretApprovalPolicy as v1SecretApprovalPolicy,
secretApprovalRequest as v1SecretApprovalRequest,
secretImps as v1SecretImpsRouter,
secret as v1SecretRouter,
secretsFolder as v1SecretsFolder,
@@ -230,24 +228,23 @@ const main = async () => {
// await createTestUserForDevelopment();
setUpHealthEndpoint(server);
const serverCleanup = async () => {
await DatabaseService.closeDatabase();
syncSecretsToThirdPartyServices.close();
githubPushEventSecretScan.close();
process.exit(0);
}
};
process.on("SIGINT", function () {
server.close(async () => {
await serverCleanup()
await serverCleanup();
});
});
process.on("SIGTERM", function () {
server.close(async () => {
await serverCleanup()
await serverCleanup();
});
});

View File

@@ -18,8 +18,6 @@ import integrationAuth from "./integrationAuth";
import secretsFolder from "./secretsFolder";
import webhooks from "./webhook";
import secretImps from "./secretImps";
import secretApprovalPolicy from "./secretApprovalPolicy";
import secretApprovalRequest from "./secretApprovalRequest";
export {
signup,
@@ -41,7 +39,5 @@ export {
secretsFolder,
webhooks,
secretImps,
sso,
secretApprovalPolicy,
secretApprovalRequest
sso
};

View File

@@ -1,4 +1,3 @@
export * from "./secretApproval";
export * from "./user";
export * from "./workspace";
export * from "./bot";

View File

@@ -508,7 +508,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
IP Allowlist
</MenuItem>
</a>
</Link> */}
</Link>
<Link href={`/project/${currentWorkspace?._id}/audit-logs`} passHref>
<a>
<MenuItem
@@ -704,12 +704,12 @@ export const AppLayout = ({ children }: LayoutProps) => {
</div>
</button>
)}
{infisicalPlatformVersion && (
{infisicalPlatformVersion && (
<div className="mb-2 w-full pl-5 duration-200 hover:text-mineshaft-200">
<FontAwesomeIcon icon={faInfo} className="mr-4 px-[0.1rem]" />
Platform Version: {infisicalPlatformVersion}
Platform Version: {infisicalPlatformVersion}
</div>
)}
)}
</div>
</nav>
</aside>