feat: server logic for secret approval group

This commit is contained in:
=
2024-07-03 20:17:16 +05:30
parent b6a9dc7f53
commit 612cf4f968
10 changed files with 242 additions and 144 deletions
@@ -25,10 +25,10 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
.optional() .optional()
.nullable() .nullable()
.transform((val) => (val ? removeTrailingSlash(val) : val)), .transform((val) => (val ? removeTrailingSlash(val) : val)),
approvers: z.string().array().min(1), approverUserIds: z.string().array().min(1),
approvals: z.number().min(1).default(1) approvals: z.number().min(1).default(1)
}) })
.refine((data) => data.approvals <= data.approvers.length, { .refine((data) => data.approvals <= data.approverUserIds.length, {
path: ["approvals"], path: ["approvals"],
message: "The number of approvals should be lower than the number of approvers." message: "The number of approvals should be lower than the number of approvers."
}), }),
@@ -66,7 +66,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
body: z body: z
.object({ .object({
name: z.string().optional(), name: z.string().optional(),
approvers: z.string().array().min(1), approverUserIds: z.string().array().min(1),
approvals: z.number().min(1).default(1), approvals: z.number().min(1).default(1),
secretPath: z secretPath: z
.string() .string()
@@ -74,7 +74,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
.nullable() .nullable()
.transform((val) => (val ? removeTrailingSlash(val) : val)) .transform((val) => (val ? removeTrailingSlash(val) : val))
}) })
.refine((data) => data.approvals <= data.approvers.length, { .refine((data) => data.approvals <= data.approverUserIds.length, {
path: ["approvals"], path: ["approvals"],
message: "The number of approvals should be lower than the number of approvers." message: "The number of approvals should be lower than the number of approvers."
}), }),
@@ -139,7 +139,15 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
}), }),
response: { response: {
200: z.object({ 200: z.object({
approvals: sapPubSchema.merge(z.object({ approvers: z.string().array() })).array() approvals: sapPubSchema
.extend({
userApprovers: z
.object({
userId: z.string()
})
.array()
})
.array()
}) })
} }
}, },
@@ -170,7 +178,11 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
}), }),
response: { response: {
200: z.object({ 200: z.object({
policy: sapPubSchema.merge(z.object({ approvers: z.string().array() })).optional() policy: sapPubSchema
.extend({
userApprovers: z.object({ userId: z.string() }).array()
})
.optional()
}) })
} }
}, },
@@ -6,7 +6,8 @@ import {
SecretApprovalRequestsSecretsSchema, SecretApprovalRequestsSecretsSchema,
SecretsSchema, SecretsSchema,
SecretTagsSchema, SecretTagsSchema,
SecretVersionsSchema SecretVersionsSchema,
UsersSchema
} from "@app/db/schemas"; } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApprovalStatus, RequestState } from "@app/ee/services/secret-approval-request/secret-approval-request-types"; import { ApprovalStatus, RequestState } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
@@ -14,6 +15,15 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
const approvalRequestUser = z.object({ userId: z.string() }).merge(
UsersSchema.pick({
email: true,
firstName: true,
lastName: true,
username: true
})
);
export const registerSecretApprovalRequestRouter = async (server: FastifyZodProvider) => { export const registerSecretApprovalRequestRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
method: "GET", method: "GET",
@@ -41,9 +51,10 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
approvers: z.string().array(), approvers: z.string().array(),
secretPath: z.string().optional().nullable() secretPath: z.string().optional().nullable()
}), }),
committerUser: approvalRequestUser,
commits: z.object({ op: z.string(), secretId: z.string().nullable().optional() }).array(), commits: z.object({ op: z.string(), secretId: z.string().nullable().optional() }).array(),
environment: z.string(), environment: z.string(),
reviewers: z.object({ member: z.string(), status: z.string() }).array(), reviewers: z.object({ userId: z.string(), status: z.string() }).array(),
approvers: z.string().array() approvers: z.string().array()
}).array() }).array()
}) })
@@ -195,7 +206,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED, type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED,
// eslint-disable-next-line // eslint-disable-next-line
metadata: { metadata: {
[isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: approval.statusChangeBy as string, [isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: approval.statusChangedByUserId as string,
secretApprovalRequestId: approval.id, secretApprovalRequestId: approval.id,
secretApprovalRequestSlug: approval.slug secretApprovalRequestSlug: approval.slug
// eslint-disable-next-line // eslint-disable-next-line
@@ -216,6 +227,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
}) })
.array() .array()
.optional(); .optional();
server.route({ server.route({
method: "GET", method: "GET",
url: "/:id", url: "/:id",
@@ -235,12 +247,13 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
id: z.string(), id: z.string(),
name: z.string(), name: z.string(),
approvals: z.number(), approvals: z.number(),
approvers: z.string().array(), approvers: approvalRequestUser.array(),
secretPath: z.string().optional().nullable() secretPath: z.string().optional().nullable()
}), }),
environment: z.string(), environment: z.string(),
reviewers: z.object({ member: z.string(), status: z.string() }).array(), statusChangedByUser: approvalRequestUser.optional(),
approvers: z.string().array(), committerUser: approvalRequestUser,
reviewers: approvalRequestUser.extend({ status: z.string() }).array(),
secretPath: z.string(), secretPath: z.string(),
commits: SecretApprovalRequestsSecretsSchema.omit({ secretBlindIndex: true }) commits: SecretApprovalRequestsSecretsSchema.omit({ secretBlindIndex: true })
.merge( .merge(
@@ -1,49 +1,59 @@
import { Knex } from "knex"; import { Knex } from "knex";
import { TDbClient } from "@app/db"; import { TDbClient } from "@app/db";
import { TableName, TSecretApprovalPolicies } from "@app/db/schemas"; import { SecretApprovalPoliciesSchema, TableName, TSecretApprovalPolicies } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors"; import { DatabaseError } from "@app/lib/errors";
import { buildFindFilter, mergeOneToManyRelation, ormify, selectAllTableCols, TFindFilter } from "@app/lib/knex"; import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindFilter } from "@app/lib/knex";
export type TSecretApprovalPolicyDALFactory = ReturnType<typeof secretApprovalPolicyDALFactory>; export type TSecretApprovalPolicyDALFactory = ReturnType<typeof secretApprovalPolicyDALFactory>;
export const secretApprovalPolicyDALFactory = (db: TDbClient) => { export const secretApprovalPolicyDALFactory = (db: TDbClient) => {
const secretApprovalPolicyOrm = ormify(db, TableName.SecretApprovalPolicy); const secretApprovalPolicyOrm = ormify(db, TableName.SecretApprovalPolicy);
const sapFindQuery = (tx: Knex, filter: TFindFilter<TSecretApprovalPolicies>) => const secretApprovalPolicyFindQuery = (tx: Knex, filter: TFindFilter<TSecretApprovalPolicies>) =>
tx(TableName.SecretApprovalPolicy) tx(TableName.SecretApprovalPolicy)
// eslint-disable-next-line // eslint-disable-next-line
.where(buildFindFilter(filter)) .where(buildFindFilter(filter))
.join(TableName.Environment, `${TableName.SecretApprovalPolicy}.envId`, `${TableName.Environment}.id`) .join(TableName.Environment, `${TableName.SecretApprovalPolicy}.envId`, `${TableName.Environment}.id`)
.join( .leftJoin(
TableName.SecretApprovalPolicyApprover, TableName.SecretApprovalPolicyApprover,
`${TableName.SecretApprovalPolicy}.id`, `${TableName.SecretApprovalPolicy}.id`,
`${TableName.SecretApprovalPolicyApprover}.policyId` `${TableName.SecretApprovalPolicyApprover}.policyId`
) )
.select(tx.ref("approverId").withSchema(TableName.SecretApprovalPolicyApprover)) .select(tx.ref("approverUserId").withSchema(TableName.SecretApprovalPolicyApprover))
.select(tx.ref("name").withSchema(TableName.Environment).as("envName")) .select(
.select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug")) tx.ref("name").withSchema(TableName.Environment).as("envName"),
.select(tx.ref("id").withSchema(TableName.Environment).as("envId")) tx.ref("slug").withSchema(TableName.Environment).as("envSlug"),
.select(tx.ref("projectId").withSchema(TableName.Environment)) tx.ref("id").withSchema(TableName.Environment).as("envId"),
tx.ref("projectId").withSchema(TableName.Environment)
)
.select(selectAllTableCols(TableName.SecretApprovalPolicy)) .select(selectAllTableCols(TableName.SecretApprovalPolicy))
.orderBy("createdAt", "asc"); .orderBy("createdAt", "asc");
const findById = async (id: string, tx?: Knex) => { const findById = async (id: string, tx?: Knex) => {
try { try {
const doc = await sapFindQuery(tx || db.replicaNode(), { const doc = await secretApprovalPolicyFindQuery(tx || db.replicaNode(), {
[`${TableName.SecretApprovalPolicy}.id` as "id"]: id [`${TableName.SecretApprovalPolicy}.id` as "id"]: id
}); });
const formatedDoc = mergeOneToManyRelation( const formatedDoc = sqlNestRelationships({
doc, data: doc,
"id", key: "id",
({ approverId, envId, envName: name, envSlug: slug, ...el }) => ({ parentMapper: (data) => ({
...el, environment: { id: data.envId, name: data.envName, slug: data.envSlug },
envId, projectId: data.projectId,
environment: { id: envId, name, slug } ...SecretApprovalPoliciesSchema.parse(data)
}), }),
({ approverId }) => approverId, childrenMapper: [
"approvers" {
); key: "approverUserId",
label: "userApprovers" as const,
mapper: ({ approverUserId }) => ({
userId: approverUserId
})
}
]
});
return formatedDoc?.[0]; return formatedDoc?.[0];
} catch (error) { } catch (error) {
throw new DatabaseError({ error, name: "FindById" }); throw new DatabaseError({ error, name: "FindById" });
@@ -52,18 +62,25 @@ export const secretApprovalPolicyDALFactory = (db: TDbClient) => {
const find = async (filter: TFindFilter<TSecretApprovalPolicies & { projectId: string }>, tx?: Knex) => { const find = async (filter: TFindFilter<TSecretApprovalPolicies & { projectId: string }>, tx?: Knex) => {
try { try {
const docs = await sapFindQuery(tx || db.replicaNode(), filter); const docs = await secretApprovalPolicyFindQuery(tx || db.replicaNode(), filter);
const formatedDoc = mergeOneToManyRelation( const formatedDoc = sqlNestRelationships({
docs, data: docs,
"id", key: "id",
({ approverId, envId, envName: name, envSlug: slug, ...el }) => ({ parentMapper: (data) => ({
...el, environment: { id: data.envId, name: data.envName, slug: data.envSlug },
envId, projectId: data.projectId,
environment: { id: envId, name, slug } ...SecretApprovalPoliciesSchema.parse(data)
}), }),
({ approverId }) => approverId, childrenMapper: [
"approvers" {
); key: "approverUserId",
label: "userApprovers" as const,
mapper: ({ approverUserId }) => ({
userId: approverUserId
})
}
]
});
return formatedDoc; return formatedDoc;
} catch (error) { } catch (error) {
throw new DatabaseError({ error, name: "Find" }); throw new DatabaseError({ error, name: "Find" });
@@ -7,7 +7,6 @@ import { BadRequestError } from "@app/lib/errors";
import { removeTrailingSlash } from "@app/lib/fn"; import { removeTrailingSlash } from "@app/lib/fn";
import { containsGlobPatterns } from "@app/lib/picomatch"; import { containsGlobPatterns } from "@app/lib/picomatch";
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal"; import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
import { TSecretApprovalPolicyApproverDALFactory } from "./secret-approval-policy-approver-dal"; import { TSecretApprovalPolicyApproverDALFactory } from "./secret-approval-policy-approver-dal";
import { TSecretApprovalPolicyDALFactory } from "./secret-approval-policy-dal"; import { TSecretApprovalPolicyDALFactory } from "./secret-approval-policy-dal";
@@ -29,7 +28,6 @@ type TSecretApprovalPolicyServiceFactoryDep = {
secretApprovalPolicyDAL: TSecretApprovalPolicyDALFactory; secretApprovalPolicyDAL: TSecretApprovalPolicyDALFactory;
projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne">; projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne">;
secretApprovalPolicyApproverDAL: TSecretApprovalPolicyApproverDALFactory; secretApprovalPolicyApproverDAL: TSecretApprovalPolicyApproverDALFactory;
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
}; };
export type TSecretApprovalPolicyServiceFactory = ReturnType<typeof secretApprovalPolicyServiceFactory>; export type TSecretApprovalPolicyServiceFactory = ReturnType<typeof secretApprovalPolicyServiceFactory>;
@@ -38,8 +36,7 @@ export const secretApprovalPolicyServiceFactory = ({
secretApprovalPolicyDAL, secretApprovalPolicyDAL,
permissionService, permissionService,
secretApprovalPolicyApproverDAL, secretApprovalPolicyApproverDAL,
projectEnvDAL, projectEnvDAL
projectMembershipDAL
}: TSecretApprovalPolicyServiceFactoryDep) => { }: TSecretApprovalPolicyServiceFactoryDep) => {
const createSecretApprovalPolicy = async ({ const createSecretApprovalPolicy = async ({
name, name,
@@ -48,12 +45,12 @@ export const secretApprovalPolicyServiceFactory = ({
actorOrgId, actorOrgId,
actorAuthMethod, actorAuthMethod,
approvals, approvals,
approvers, approverUserIds,
projectId, projectId,
secretPath, secretPath,
environment environment
}: TCreateSapDTO) => { }: TCreateSapDTO) => {
if (approvals > approvers.length) if (approvals > approverUserIds.length)
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" }); throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
@@ -70,13 +67,6 @@ export const secretApprovalPolicyServiceFactory = ({
const env = await projectEnvDAL.findOne({ slug: environment, projectId }); const env = await projectEnvDAL.findOne({ slug: environment, projectId });
if (!env) throw new BadRequestError({ message: "Environment not found" }); if (!env) throw new BadRequestError({ message: "Environment not found" });
const secretApprovers = await projectMembershipDAL.find({
projectId,
$in: { id: approvers }
});
if (secretApprovers.length !== approvers.length)
throw new BadRequestError({ message: "Approver not found in project" });
const secretApproval = await secretApprovalPolicyDAL.transaction(async (tx) => { const secretApproval = await secretApprovalPolicyDAL.transaction(async (tx) => {
const doc = await secretApprovalPolicyDAL.create( const doc = await secretApprovalPolicyDAL.create(
{ {
@@ -88,8 +78,8 @@ export const secretApprovalPolicyServiceFactory = ({
tx tx
); );
await secretApprovalPolicyApproverDAL.insertMany( await secretApprovalPolicyApproverDAL.insertMany(
secretApprovers.map(({ id }) => ({ approverUserIds.map((approverUserId) => ({
approverId: id, approverUserId,
policyId: doc.id policyId: doc.id
})), })),
tx tx
@@ -100,7 +90,7 @@ export const secretApprovalPolicyServiceFactory = ({
}; };
const updateSecretApprovalPolicy = async ({ const updateSecretApprovalPolicy = async ({
approvers, approverUserIds,
secretPath, secretPath,
name, name,
actorId, actorId,
@@ -132,22 +122,11 @@ export const secretApprovalPolicyServiceFactory = ({
}, },
tx tx
); );
if (approvers) { if (approverUserIds) {
const secretApprovers = await projectMembershipDAL.find(
{
projectId: secretApprovalPolicy.projectId,
$in: { id: approvers }
},
{ tx }
);
if (secretApprovers.length !== approvers.length)
throw new BadRequestError({ message: "Approver not found in project" });
if (doc.approvals > secretApprovers.length)
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
await secretApprovalPolicyApproverDAL.delete({ policyId: doc.id }, tx); await secretApprovalPolicyApproverDAL.delete({ policyId: doc.id }, tx);
await secretApprovalPolicyApproverDAL.insertMany( await secretApprovalPolicyApproverDAL.insertMany(
secretApprovers.map(({ id }) => ({ approverUserIds.map((approverUserId) => ({
approverId: id, approverUserId,
policyId: doc.id policyId: doc.id
})), })),
tx tx
@@ -4,7 +4,7 @@ export type TCreateSapDTO = {
approvals: number; approvals: number;
secretPath?: string | null; secretPath?: string | null;
environment: string; environment: string;
approvers: string[]; approverUserIds: string[];
projectId: string; projectId: string;
name: string; name: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
@@ -13,7 +13,7 @@ export type TUpdateSapDTO = {
secretPolicyId: string; secretPolicyId: string;
approvals?: number; approvals?: number;
secretPath?: string | null; secretPath?: string | null;
approvers: string[]; approverUserIds: string[];
name?: string; name?: string;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
@@ -5,7 +5,8 @@ import {
SecretApprovalRequestsSchema, SecretApprovalRequestsSchema,
TableName, TableName,
TSecretApprovalRequests, TSecretApprovalRequests,
TSecretApprovalRequestsSecrets TSecretApprovalRequestsSecrets,
TUsers
} from "@app/db/schemas"; } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors"; import { DatabaseError } from "@app/lib/errors";
import { ormify, selectAllTableCols, sqlNestRelationships, stripUndefinedInWhere, TFindFilter } from "@app/lib/knex"; import { ormify, selectAllTableCols, sqlNestRelationships, stripUndefinedInWhere, TFindFilter } from "@app/lib/knex";
@@ -16,7 +17,7 @@ export type TSecretApprovalRequestDALFactory = ReturnType<typeof secretApprovalR
type TFindQueryFilter = { type TFindQueryFilter = {
projectId: string; projectId: string;
membershipId: string; userId: string;
status?: RequestState; status?: RequestState;
environment?: string; environment?: string;
committer?: string; committer?: string;
@@ -37,27 +38,63 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
`${TableName.SecretApprovalRequest}.policyId`, `${TableName.SecretApprovalRequest}.policyId`,
`${TableName.SecretApprovalPolicy}.id` `${TableName.SecretApprovalPolicy}.id`
) )
.leftJoin<TUsers>(
db(TableName.Users).as("statusChangedByUser"),
`${TableName.SecretApprovalRequest}.statusChangedByUserId`,
`statusChangedByUser.id`
)
.join<TUsers>(
db(TableName.Users).as("committerUser"),
`${TableName.SecretApprovalRequest}.committerUserId`,
`committerUser.id`
)
.join( .join(
TableName.SecretApprovalPolicyApprover, TableName.SecretApprovalPolicyApprover,
`${TableName.SecretApprovalPolicy}.id`, `${TableName.SecretApprovalPolicy}.id`,
`${TableName.SecretApprovalPolicyApprover}.policyId` `${TableName.SecretApprovalPolicyApprover}.policyId`
) )
.join<TUsers>(
db(TableName.Users).as("secretApprovalPolicyApproverUser"),
`${TableName.SecretApprovalPolicyApprover}.approverUserId`,
"secretApprovalPolicyApproverUser.id"
)
.leftJoin( .leftJoin(
TableName.SecretApprovalRequestReviewer, TableName.SecretApprovalRequestReviewer,
`${TableName.SecretApprovalRequest}.id`, `${TableName.SecretApprovalRequest}.id`,
`${TableName.SecretApprovalRequestReviewer}.requestId` `${TableName.SecretApprovalRequestReviewer}.requestId`
) )
.leftJoin<TUsers>(
db(TableName.Users).as("secretApprovalReviewerUser"),
`${TableName.SecretApprovalRequestReviewer}.reviewerUserId`,
`secretApprovalReviewerUser.id`
)
.select(selectAllTableCols(TableName.SecretApprovalRequest)) .select(selectAllTableCols(TableName.SecretApprovalRequest))
.select( .select(
tx.ref("member").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerMemberId"), tx.ref("approverUserId").withSchema(TableName.SecretApprovalPolicyApprover),
tx.ref("email").withSchema("secretApprovalPolicyApproverUser").as("approverEmail"),
tx.ref("username").withSchema("secretApprovalPolicyApproverUser").as("approverUsername"),
tx.ref("firstName").withSchema("secretApprovalPolicyApproverUser").as("approverFirstName"),
tx.ref("lastName").withSchema("secretApprovalPolicyApproverUser").as("approverLastName"),
tx.ref("email").withSchema("statusChangedByUser").as("statusChangedByUserEmail"),
tx.ref("username").withSchema("statusChangedByUser").as("statusChangedByUserUsername"),
tx.ref("firstName").withSchema("statusChangedByUser").as("statusChangedByUserFirstName"),
tx.ref("lastName").withSchema("statusChangedByUser").as("statusChangedByUserLastName"),
tx.ref("email").withSchema("committerUser").as("committerUserEmail"),
tx.ref("username").withSchema("committerUser").as("committerUserUsername"),
tx.ref("firstName").withSchema("committerUser").as("committerUserFirstName"),
tx.ref("lastName").withSchema("committerUser").as("committerUserLastName"),
tx.ref("reviewerUserId").withSchema(TableName.SecretApprovalRequestReviewer),
tx.ref("status").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerStatus"), tx.ref("status").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerStatus"),
tx.ref("email").withSchema("secretApprovalReviewerUser").as("reviewerEmail"),
tx.ref("username").withSchema("secretApprovalReviewerUser").as("reviewerUsername"),
tx.ref("firstName").withSchema("secretApprovalReviewerUser").as("reviewerFirstName"),
tx.ref("lastName").withSchema("secretApprovalReviewerUser").as("reviewerLastName"),
tx.ref("id").withSchema(TableName.SecretApprovalPolicy).as("policyId"), tx.ref("id").withSchema(TableName.SecretApprovalPolicy).as("policyId"),
tx.ref("name").withSchema(TableName.SecretApprovalPolicy).as("policyName"), tx.ref("name").withSchema(TableName.SecretApprovalPolicy).as("policyName"),
tx.ref("projectId").withSchema(TableName.Environment), tx.ref("projectId").withSchema(TableName.Environment),
tx.ref("slug").withSchema(TableName.Environment).as("environment"), tx.ref("slug").withSchema(TableName.Environment).as("environment"),
tx.ref("secretPath").withSchema(TableName.SecretApprovalPolicy).as("policySecretPath"), tx.ref("secretPath").withSchema(TableName.SecretApprovalPolicy).as("policySecretPath"),
tx.ref("approvals").withSchema(TableName.SecretApprovalPolicy).as("policyApprovals"), tx.ref("approvals").withSchema(TableName.SecretApprovalPolicy).as("policyApprovals")
tx.ref("approverId").withSchema(TableName.SecretApprovalPolicyApprover)
); );
const findById = async (id: string, tx?: Knex) => { const findById = async (id: string, tx?: Knex) => {
@@ -71,6 +108,22 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
...SecretApprovalRequestsSchema.parse(el), ...SecretApprovalRequestsSchema.parse(el),
projectId: el.projectId, projectId: el.projectId,
environment: el.environment, environment: el.environment,
statusChangedByUser: el.statusChangedByUserId
? {
userId: el.statusChangedByUserId,
email: el.statusChangedByUserEmail,
firstName: el.statusChangedByUserFirstName,
lastName: el.statusChangedByUserLastName,
username: el.statusChangedByUserUsername
}
: undefined,
committerUser: {
userId: el.committerUserId,
email: el.committerUserEmail,
firstName: el.committerUserFirstName,
lastName: el.committerUserLastName,
username: el.committerUserUsername
},
policy: { policy: {
id: el.policyId, id: el.policyId,
name: el.policyName, name: el.policyName,
@@ -80,11 +133,34 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
}), }),
childrenMapper: [ childrenMapper: [
{ {
key: "reviewerMemberId", key: "reviewerUserId",
label: "reviewers" as const, label: "reviewers" as const,
mapper: ({ reviewerMemberId: member, reviewerStatus: status }) => (member ? { member, status } : undefined) mapper: ({
reviewerUserId: userId,
reviewerStatus: status,
reviewerEmail: email,
reviewerLastName: lastName,
reviewerUsername: username,
reviewerFirstName: firstName
}) => (userId ? { userId, status, email, firstName, lastName, username } : undefined)
}, },
{ key: "approverId", label: "approvers" as const, mapper: ({ approverId }) => approverId } {
key: "approverUserId",
label: "approvers" as const,
mapper: ({
approverUserId,
approverEmail: email,
approverUsername: username,
approverLastName: lastName,
approverFirstName: firstName
}) => ({
userId: approverUserId,
email,
firstName,
lastName,
username
})
}
] ]
}); });
if (!formatedDoc?.[0]) return; if (!formatedDoc?.[0]) return;
@@ -97,7 +173,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
} }
}; };
const findProjectRequestCount = async (projectId: string, membershipId: string, tx?: Knex) => { const findProjectRequestCount = async (projectId: string, userId: string, tx?: Knex) => {
try { try {
const docs = await (tx || db) const docs = await (tx || db)
.with( .with(
@@ -114,8 +190,8 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
.andWhere( .andWhere(
(bd) => (bd) =>
void bd void bd
.where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) .where(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, userId)
.orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) .orWhere(`${TableName.SecretApprovalRequest}.committerUserId`, userId)
) )
.select("status", `${TableName.SecretApprovalRequest}.id`) .select("status", `${TableName.SecretApprovalRequest}.id`)
.groupBy(`${TableName.SecretApprovalRequest}.id`, "status") .groupBy(`${TableName.SecretApprovalRequest}.id`, "status")
@@ -142,7 +218,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
}; };
const findByProjectId = async ( const findByProjectId = async (
{ status, limit = 20, offset = 0, projectId, committer, environment, membershipId }: TFindQueryFilter, { status, limit = 20, offset = 0, projectId, committer, environment, userId }: TFindQueryFilter,
tx?: Knex tx?: Knex
) => { ) => {
try { try {
@@ -161,6 +237,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
`${TableName.SecretApprovalPolicy}.id`, `${TableName.SecretApprovalPolicy}.id`,
`${TableName.SecretApprovalPolicyApprover}.policyId` `${TableName.SecretApprovalPolicyApprover}.policyId`
) )
.join<TUsers>(
db(TableName.Users).as("committerUser"),
`${TableName.SecretApprovalRequest}.committerUserId`,
`committerUser.id`
)
.leftJoin( .leftJoin(
TableName.SecretApprovalRequestReviewer, TableName.SecretApprovalRequestReviewer,
`${TableName.SecretApprovalRequest}.id`, `${TableName.SecretApprovalRequest}.id`,
@@ -176,20 +257,21 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
projectId, projectId,
[`${TableName.Environment}.slug` as "slug"]: environment, [`${TableName.Environment}.slug` as "slug"]: environment,
[`${TableName.SecretApprovalRequest}.status`]: status, [`${TableName.SecretApprovalRequest}.status`]: status,
committerId: committer committerUserId: committer
}) })
) )
.andWhere( .andWhere(
(bd) => (bd) =>
void bd void bd
.where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) .where(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, userId)
.orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) .orWhere(`${TableName.SecretApprovalRequest}.committerUserId`, userId)
) )
.select(selectAllTableCols(TableName.SecretApprovalRequest)) .select(selectAllTableCols(TableName.SecretApprovalRequest))
.select( .select(
db.ref("projectId").withSchema(TableName.Environment), db.ref("projectId").withSchema(TableName.Environment),
db.ref("slug").withSchema(TableName.Environment).as("environment"), db.ref("slug").withSchema(TableName.Environment).as("environment"),
db.ref("id").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerMemberId"), db.ref("id").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerId"),
db.ref("reviewerUserId").withSchema(TableName.SecretApprovalRequestReviewer),
db.ref("status").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerStatus"), db.ref("status").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerStatus"),
db.ref("id").withSchema(TableName.SecretApprovalPolicy).as("policyId"), db.ref("id").withSchema(TableName.SecretApprovalPolicy).as("policyId"),
db.ref("name").withSchema(TableName.SecretApprovalPolicy).as("policyName"), db.ref("name").withSchema(TableName.SecretApprovalPolicy).as("policyName"),
@@ -201,7 +283,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
), ),
db.ref("secretPath").withSchema(TableName.SecretApprovalPolicy).as("policySecretPath"), db.ref("secretPath").withSchema(TableName.SecretApprovalPolicy).as("policySecretPath"),
db.ref("approvals").withSchema(TableName.SecretApprovalPolicy).as("policyApprovals"), db.ref("approvals").withSchema(TableName.SecretApprovalPolicy).as("policyApprovals"),
db.ref("approverId").withSchema(TableName.SecretApprovalPolicyApprover) db.ref("approverUserId").withSchema(TableName.SecretApprovalPolicyApprover),
db.ref("email").withSchema("committerUser").as("committerUserEmail"),
db.ref("username").withSchema("committerUser").as("committerUserUsername"),
db.ref("firstName").withSchema("committerUser").as("committerUserFirstName"),
db.ref("lastName").withSchema("committerUser").as("committerUserLastName")
) )
.orderBy("createdAt", "desc"); .orderBy("createdAt", "desc");
@@ -223,18 +309,26 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
name: el.policyName, name: el.policyName,
approvals: el.policyApprovals, approvals: el.policyApprovals,
secretPath: el.policySecretPath secretPath: el.policySecretPath
},
committerUser: {
userId: el.committerUserId,
email: el.committerUserEmail,
firstName: el.committerUserFirstName,
lastName: el.committerUserLastName,
username: el.committerUserUsername
} }
}), }),
childrenMapper: [ childrenMapper: [
{ {
key: "reviewerMemberId", key: "reviewerId",
label: "reviewers" as const, label: "reviewers" as const,
mapper: ({ reviewerMemberId: member, reviewerStatus: s }) => (member ? { member, status: s } : undefined) mapper: ({ reviewerUserId, reviewerStatus: s }) =>
reviewerUserId ? { userId: reviewerUserId, status: s } : undefined
}, },
{ {
key: "approverId", key: "approverUserId",
label: "approvers" as const, label: "approvers" as const,
mapper: ({ approverId }) => approverId mapper: ({ approverUserId }) => approverUserId
}, },
{ {
key: "commitId", key: "commitId",
@@ -87,7 +87,7 @@ export const secretApprovalRequestServiceFactory = ({
const requestCount = async ({ projectId, actor, actorId, actorOrgId, actorAuthMethod }: TApprovalRequestCountDTO) => { const requestCount = async ({ projectId, actor, actorId, actorOrgId, actorAuthMethod }: TApprovalRequestCountDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { membership } = await permissionService.getProjectPermission( await permissionService.getProjectPermission(
actor as ActorType.USER, actor as ActorType.USER,
actorId, actorId,
projectId, projectId,
@@ -95,7 +95,7 @@ export const secretApprovalRequestServiceFactory = ({
actorOrgId actorOrgId
); );
const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id); const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, actorId);
return count; return count;
}; };
@@ -113,19 +113,13 @@ export const secretApprovalRequestServiceFactory = ({
}: TListApprovalsDTO) => { }: TListApprovalsDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { membership } = await permissionService.getProjectPermission( await permissionService.getProjectPermission(actor, actorId, projectId, actorAuthMethod, actorOrgId);
actor,
actorId,
projectId,
actorAuthMethod,
actorOrgId
);
const approvals = await secretApprovalRequestDAL.findByProjectId({ const approvals = await secretApprovalRequestDAL.findByProjectId({
projectId, projectId,
committer, committer,
environment, environment,
status, status,
membershipId: membership.id, userId: actorId,
limit, limit,
offset offset
}); });
@@ -145,7 +139,7 @@ export const secretApprovalRequestServiceFactory = ({
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
const { policy } = secretApprovalRequest; const { policy } = secretApprovalRequest;
const { membership, hasRole } = await permissionService.getProjectPermission( const { hasRole } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
secretApprovalRequest.projectId, secretApprovalRequest.projectId,
@@ -154,8 +148,8 @@ export const secretApprovalRequestServiceFactory = ({
); );
if ( if (
!hasRole(ProjectMembershipRole.Admin) && !hasRole(ProjectMembershipRole.Admin) &&
secretApprovalRequest.committerId !== membership.id && secretApprovalRequest.committerUserId !== actorId &&
!policy.approvers.find((approverId) => approverId === membership.id) !policy.approvers.find(({ userId }) => userId === actorId)
) { ) {
throw new UnauthorizedError({ message: "User has no access" }); throw new UnauthorizedError({ message: "User has no access" });
} }
@@ -180,7 +174,7 @@ export const secretApprovalRequestServiceFactory = ({
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
const { policy } = secretApprovalRequest; const { policy } = secretApprovalRequest;
const { membership, hasRole } = await permissionService.getProjectPermission( const { hasRole } = await permissionService.getProjectPermission(
ActorType.USER, ActorType.USER,
actorId, actorId,
secretApprovalRequest.projectId, secretApprovalRequest.projectId,
@@ -189,8 +183,8 @@ export const secretApprovalRequestServiceFactory = ({
); );
if ( if (
!hasRole(ProjectMembershipRole.Admin) && !hasRole(ProjectMembershipRole.Admin) &&
secretApprovalRequest.committerId !== membership.id && secretApprovalRequest.committerUserId !== actorId &&
!policy.approvers.find((approverId) => approverId === membership.id) !policy.approvers.find(({ userId }) => userId === actorId)
) { ) {
throw new UnauthorizedError({ message: "User has no access" }); throw new UnauthorizedError({ message: "User has no access" });
} }
@@ -198,7 +192,7 @@ export const secretApprovalRequestServiceFactory = ({
const review = await secretApprovalRequestReviewerDAL.findOne( const review = await secretApprovalRequestReviewerDAL.findOne(
{ {
requestId: secretApprovalRequest.id, requestId: secretApprovalRequest.id,
member: membership.id reviewerUserId: actorId
}, },
tx tx
); );
@@ -207,7 +201,7 @@ export const secretApprovalRequestServiceFactory = ({
{ {
status, status,
requestId: secretApprovalRequest.id, requestId: secretApprovalRequest.id,
member: membership.id reviewerUserId: actorId
}, },
tx tx
); );
@@ -230,7 +224,7 @@ export const secretApprovalRequestServiceFactory = ({
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
const { policy } = secretApprovalRequest; const { policy } = secretApprovalRequest;
const { membership, hasRole } = await permissionService.getProjectPermission( const { hasRole } = await permissionService.getProjectPermission(
ActorType.USER, ActorType.USER,
actorId, actorId,
secretApprovalRequest.projectId, secretApprovalRequest.projectId,
@@ -239,8 +233,8 @@ export const secretApprovalRequestServiceFactory = ({
); );
if ( if (
!hasRole(ProjectMembershipRole.Admin) && !hasRole(ProjectMembershipRole.Admin) &&
secretApprovalRequest.committerId !== membership.id && secretApprovalRequest.committerUserId !== actorId &&
!policy.approvers.find((approverId) => approverId === membership.id) !policy.approvers.find(({ userId }) => userId === actorId)
) { ) {
throw new UnauthorizedError({ message: "User has no access" }); throw new UnauthorizedError({ message: "User has no access" });
} }
@@ -253,7 +247,7 @@ export const secretApprovalRequestServiceFactory = ({
const updatedRequest = await secretApprovalRequestDAL.updateById(secretApprovalRequest.id, { const updatedRequest = await secretApprovalRequestDAL.updateById(secretApprovalRequest.id, {
status, status,
statusChangeBy: membership.id statusChangedByUserId: actorId
}); });
return { ...secretApprovalRequest, ...updatedRequest }; return { ...secretApprovalRequest, ...updatedRequest };
}; };
@@ -270,7 +264,7 @@ export const secretApprovalRequestServiceFactory = ({
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
const { policy, folderId, projectId } = secretApprovalRequest; const { policy, folderId, projectId } = secretApprovalRequest;
const { membership, hasRole } = await permissionService.getProjectPermission( const { hasRole } = await permissionService.getProjectPermission(
ActorType.USER, ActorType.USER,
actorId, actorId,
projectId, projectId,
@@ -280,19 +274,19 @@ export const secretApprovalRequestServiceFactory = ({
if ( if (
!hasRole(ProjectMembershipRole.Admin) && !hasRole(ProjectMembershipRole.Admin) &&
secretApprovalRequest.committerId !== membership.id && secretApprovalRequest.committerUserId !== actorId &&
!policy.approvers.find((approverId) => approverId === membership.id) !policy.approvers.find(({ userId }) => userId === actorId)
) { ) {
throw new UnauthorizedError({ message: "User has no access" }); throw new UnauthorizedError({ message: "User has no access" });
} }
const reviewers = secretApprovalRequest.reviewers.reduce<Record<string, ApprovalStatus>>( const reviewers = secretApprovalRequest.reviewers.reduce<Record<string, ApprovalStatus>>(
(prev, curr) => ({ ...prev, [curr.member.toString()]: curr.status as ApprovalStatus }), (prev, curr) => ({ ...prev, [curr.userId.toString()]: curr.status as ApprovalStatus }),
{} {}
); );
const hasMinApproval = const hasMinApproval =
secretApprovalRequest.policy.approvals <= secretApprovalRequest.policy.approvals <=
secretApprovalRequest.policy.approvers.filter( secretApprovalRequest.policy.approvers.filter(
(approverId) => reviewers[approverId.toString()] === ApprovalStatus.APPROVED ({ userId: approverId }) => reviewers[approverId.toString()] === ApprovalStatus.APPROVED
).length; ).length;
if (!hasMinApproval) throw new BadRequestError({ message: "Doesn't have minimum approvals needed" }); if (!hasMinApproval) throw new BadRequestError({ message: "Doesn't have minimum approvals needed" });
@@ -472,7 +466,7 @@ export const secretApprovalRequestServiceFactory = ({
conflicts: JSON.stringify(conflicts), conflicts: JSON.stringify(conflicts),
hasMerged: true, hasMerged: true,
status: RequestState.Closed, status: RequestState.Closed,
statusChangeBy: membership.id statusChangedByUserId: actorId
}, },
tx tx
); );
@@ -509,7 +503,7 @@ export const secretApprovalRequestServiceFactory = ({
}: TGenerateSecretApprovalRequestDTO) => { }: TGenerateSecretApprovalRequestDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { permission, membership } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
actorId, actorId,
projectId, projectId,
@@ -663,7 +657,7 @@ export const secretApprovalRequestServiceFactory = ({
policyId: policy.id, policyId: policy.id,
status: "open", status: "open",
hasMerged: false, hasMerged: false,
committerId: membership.id committerUserId: actorId
}, },
tx tx
); );
@@ -11,7 +11,6 @@ import { alphaNumericNanoId } from "@app/lib/nanoid";
import { QueueName, TQueueServiceFactory } from "@app/queue"; import { QueueName, TQueueServiceFactory } from "@app/queue";
import { ActorType } from "@app/services/auth/auth-type"; import { ActorType } from "@app/services/auth/auth-type";
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service"; import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
import { TSecretDALFactory } from "@app/services/secret/secret-dal"; import { TSecretDALFactory } from "@app/services/secret/secret-dal";
import { fnSecretBulkInsert, fnSecretBulkUpdate } from "@app/services/secret/secret-fns"; import { fnSecretBulkInsert, fnSecretBulkUpdate } from "@app/services/secret/secret-fns";
import { TSecretQueueFactory, uniqueSecretQueueKey } from "@app/services/secret/secret-queue"; import { TSecretQueueFactory, uniqueSecretQueueKey } from "@app/services/secret/secret-queue";
@@ -46,7 +45,6 @@ type TSecretReplicationServiceFactoryDep = {
secretBlindIndexDAL: Pick<TSecretBlindIndexDALFactory, "findOne">; secretBlindIndexDAL: Pick<TSecretBlindIndexDALFactory, "findOne">;
secretTagDAL: Pick<TSecretTagDALFactory, "findManyTagsById" | "saveTagsToSecret" | "deleteTagsManySecret" | "find">; secretTagDAL: Pick<TSecretTagDALFactory, "findManyTagsById" | "saveTagsToSecret" | "deleteTagsManySecret" | "find">;
secretApprovalRequestDAL: Pick<TSecretApprovalRequestDALFactory, "create" | "transaction">; secretApprovalRequestDAL: Pick<TSecretApprovalRequestDALFactory, "create" | "transaction">;
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "findOne">;
secretApprovalRequestSecretDAL: Pick< secretApprovalRequestSecretDAL: Pick<
TSecretApprovalRequestSecretDALFactory, TSecretApprovalRequestSecretDALFactory,
"insertMany" | "insertApprovalSecretTags" "insertMany" | "insertApprovalSecretTags"
@@ -92,7 +90,6 @@ export const secretReplicationServiceFactory = ({
secretApprovalRequestSecretDAL, secretApprovalRequestSecretDAL,
secretApprovalRequestDAL, secretApprovalRequestDAL,
secretQueueService, secretQueueService,
projectMembershipDAL,
projectBotService projectBotService
}: TSecretReplicationServiceFactoryDep) => { }: TSecretReplicationServiceFactoryDep) => {
const getReplicatedSecrets = ( const getReplicatedSecrets = (
@@ -297,12 +294,6 @@ export const secretReplicationServiceFactory = ({
); );
// this means it should be a approval request rather than direct replication // this means it should be a approval request rather than direct replication
if (policy && actor === ActorType.USER) { if (policy && actor === ActorType.USER) {
const membership = await projectMembershipDAL.findOne({ projectId, userId: actorId });
if (!membership) {
logger.error("Project membership not found in %s for user %s", projectId, actorId);
return;
}
const localSecretsLatestVersions = destinationLocalSecrets.map(({ id }) => id); const localSecretsLatestVersions = destinationLocalSecrets.map(({ id }) => id);
const latestSecretVersions = await secretVersionDAL.findLatestVersionMany( const latestSecretVersions = await secretVersionDAL.findLatestVersionMany(
destinationReplicationFolderId, destinationReplicationFolderId,
@@ -316,7 +307,7 @@ export const secretReplicationServiceFactory = ({
policyId: policy.id, policyId: policy.id,
status: "open", status: "open",
hasMerged: false, hasMerged: false,
committerId: membership.id, committerUserId: actorId,
isReplicated: true isReplicated: true
}, },
tx tx
-2
View File
@@ -319,7 +319,6 @@ export const registerRoutes = async (
auditLogStreamDAL auditLogStreamDAL
}); });
const secretApprovalPolicyService = secretApprovalPolicyServiceFactory({ const secretApprovalPolicyService = secretApprovalPolicyServiceFactory({
projectMembershipDAL,
projectEnvDAL, projectEnvDAL,
secretApprovalPolicyApproverDAL: sapApproverDAL, secretApprovalPolicyApproverDAL: sapApproverDAL,
permissionService, permissionService,
@@ -768,7 +767,6 @@ export const registerRoutes = async (
secretApprovalRequestDAL, secretApprovalRequestDAL,
secretApprovalRequestSecretDAL, secretApprovalRequestSecretDAL,
secretQueueService, secretQueueService,
projectMembershipDAL,
projectBotService projectBotService
}); });
const secretRotationQueue = secretRotationQueueFactory({ const secretRotationQueue = secretRotationQueueFactory({
@@ -949,7 +949,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
event: { event: {
type: EventType.SECRET_APPROVAL_REQUEST, type: EventType.SECRET_APPROVAL_REQUEST,
metadata: { metadata: {
committedBy: approval.committerId, committedBy: approval.committerUserId,
secretApprovalRequestId: approval.id, secretApprovalRequestId: approval.id,
secretApprovalRequestSlug: approval.slug secretApprovalRequestSlug: approval.slug
} }
@@ -1133,7 +1133,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
event: { event: {
type: EventType.SECRET_APPROVAL_REQUEST, type: EventType.SECRET_APPROVAL_REQUEST,
metadata: { metadata: {
committedBy: approval.committerId, committedBy: approval.committerUserId,
secretApprovalRequestId: approval.id, secretApprovalRequestId: approval.id,
secretApprovalRequestSlug: approval.slug secretApprovalRequestSlug: approval.slug
} }
@@ -1271,7 +1271,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
event: { event: {
type: EventType.SECRET_APPROVAL_REQUEST, type: EventType.SECRET_APPROVAL_REQUEST,
metadata: { metadata: {
committedBy: approval.committerId, committedBy: approval.committerUserId,
secretApprovalRequestId: approval.id, secretApprovalRequestId: approval.id,
secretApprovalRequestSlug: approval.slug secretApprovalRequestSlug: approval.slug
} }
@@ -1397,7 +1397,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
event: { event: {
type: EventType.SECRET_APPROVAL_REQUEST, type: EventType.SECRET_APPROVAL_REQUEST,
metadata: { metadata: {
committedBy: approval.committerId, committedBy: approval.committerUserId,
secretApprovalRequestId: approval.id, secretApprovalRequestId: approval.id,
secretApprovalRequestSlug: approval.slug secretApprovalRequestSlug: approval.slug
} }
@@ -1524,7 +1524,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
event: { event: {
type: EventType.SECRET_APPROVAL_REQUEST, type: EventType.SECRET_APPROVAL_REQUEST,
metadata: { metadata: {
committedBy: approval.committerId, committedBy: approval.committerUserId,
secretApprovalRequestId: approval.id, secretApprovalRequestId: approval.id,
secretApprovalRequestSlug: approval.slug secretApprovalRequestSlug: approval.slug
} }
@@ -1638,7 +1638,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
event: { event: {
type: EventType.SECRET_APPROVAL_REQUEST, type: EventType.SECRET_APPROVAL_REQUEST,
metadata: { metadata: {
committedBy: approval.committerId, committedBy: approval.committerUserId,
secretApprovalRequestId: approval.id, secretApprovalRequestId: approval.id,
secretApprovalRequestSlug: approval.slug secretApprovalRequestSlug: approval.slug
} }