Merge branch 'main' into feat/remindersImprovement

This commit is contained in:
Carlos Monastyrski
2025-07-23 11:27:31 -03:00
619 changed files with 15481 additions and 6720 deletions
+28 -3
View File
@@ -3,6 +3,7 @@ import { Knex } from "knex";
import { TDbClient } from "@app/db";
import {
ProjectsSchema,
ProjectType,
ProjectUpgradeStatus,
ProjectVersion,
SortDirection,
@@ -21,12 +22,17 @@ export type TProjectDALFactory = ReturnType<typeof projectDALFactory>;
export const projectDALFactory = (db: TDbClient) => {
const projectOrm = ormify(db, TableName.Project);
const findIdentityProjects = async (identityId: string, orgId: string) => {
const findIdentityProjects = async (identityId: string, orgId: string, projectType?: ProjectType) => {
try {
const workspaces = await db(TableName.IdentityProjectMembership)
.where({ identityId })
.join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`)
.where(`${TableName.Project}.orgId`, orgId)
.andWhere((qb) => {
if (projectType) {
void qb.where(`${TableName.Project}.type`, projectType);
}
})
.leftJoin(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`)
.select(
selectAllTableCols(TableName.Project),
@@ -66,13 +72,18 @@ export const projectDALFactory = (db: TDbClient) => {
}
};
const findUserProjects = async (userId: string, orgId: string) => {
const findUserProjects = async (userId: string, orgId: string, projectType?: ProjectType) => {
try {
const workspaces = await db
.replicaNode()(TableName.ProjectMembership)
.where({ userId })
.join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`)
.where(`${TableName.Project}.orgId`, orgId)
.andWhere((qb) => {
if (projectType) {
void qb.where(`${TableName.Project}.type`, projectType);
}
})
.leftJoin(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`)
.select(
selectAllTableCols(TableName.Project),
@@ -92,6 +103,11 @@ export const projectDALFactory = (db: TDbClient) => {
.whereIn("groupId", groups)
.join(TableName.Project, `${TableName.GroupProjectMembership}.projectId`, `${TableName.Project}.id`)
.where(`${TableName.Project}.orgId`, orgId)
.andWhere((qb) => {
if (projectType) {
void qb.where(`${TableName.Project}.type`, projectType);
}
})
.whereNotIn(
`${TableName.Project}.id`,
workspaces.map(({ id }) => id)
@@ -161,12 +177,17 @@ export const projectDALFactory = (db: TDbClient) => {
}
};
const findAllProjectsByIdentity = async (identityId: string) => {
const findAllProjectsByIdentity = async (identityId: string, projectType?: ProjectType) => {
try {
const workspaces = await db
.replicaNode()(TableName.IdentityProjectMembership)
.where({ identityId })
.join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`)
.andWhere((qb) => {
if (projectType) {
void qb.where(`${TableName.Project}.type`, projectType);
}
})
.leftJoin(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`)
.select(
selectAllTableCols(TableName.Project),
@@ -372,6 +393,7 @@ export const projectDALFactory = (db: TDbClient) => {
orgId: string;
actor: ActorType;
actorId: string;
type?: ProjectType;
limit?: number;
offset?: number;
name?: string;
@@ -426,6 +448,9 @@ export const projectDALFactory = (db: TDbClient) => {
void query.orderBy([{ column: `${TableName.Project}.name`, order: sortDir }]);
}
if (dto.type) {
void query.where(`${TableName.Project}.type`, dto.type);
}
if (dto.name) {
void query.whereILike(`${TableName.Project}.name`, `%${dto.name}%`);
}
+106 -48
View File
@@ -1,7 +1,14 @@
import { ForbiddenError, subject } from "@casl/ability";
import slugify from "@sindresorhus/slugify";
import { ProjectMembershipRole, ProjectVersion, TableName, TProjectEnvironments } from "@app/db/schemas";
import {
ActionProjectType,
ProjectMembershipRole,
ProjectType,
ProjectVersion,
TableName,
TProjectEnvironments
} from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { throwIfMissingSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
@@ -242,7 +249,8 @@ export const projectServiceFactory = ({
kmsKeyId,
tx: trx,
createDefaultEnvs = true,
template = InfisicalProjectTemplate.Default
template = InfisicalProjectTemplate.Default,
type = ProjectType.SecretManager
}: TCreateProjectDTO) => {
const organization = await orgDAL.findOne({ id: actorOrgId });
const { permission, membership: orgMembership } = await permissionService.getOrgPermission(
@@ -258,7 +266,11 @@ export const projectServiceFactory = ({
await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.CreateProject(organization.id)]);
const plan = await licenseService.getPlan(organization.id);
if (plan.workspaceLimit !== null && plan.workspacesUsed >= plan.workspaceLimit) {
if (
plan.workspaceLimit !== null &&
plan.workspacesUsed >= plan.workspaceLimit &&
type === ProjectType.SecretManager
) {
// case: limit imposed on number of workspaces allowed
// case: number of workspaces used exceeds the number of workspaces allowed
throw new BadRequestError({
@@ -295,6 +307,7 @@ export const projectServiceFactory = ({
const project = await projectDAL.create(
{
name: workspaceName,
type,
description: workspaceDescription,
orgId: organization.id,
slug: projectSlug || slugify(`${workspaceName}-${alphaNumericNanoId(4)}`),
@@ -305,14 +318,16 @@ export const projectServiceFactory = ({
tx
);
await bootstrapSshProject({
projectId: project.id,
sshCertificateAuthorityDAL,
sshCertificateAuthoritySecretDAL,
kmsService,
projectSshConfigDAL,
tx
});
if (type === ProjectType.SSH) {
await bootstrapSshProject({
projectId: project.id,
sshCertificateAuthorityDAL,
sshCertificateAuthoritySecretDAL,
kmsService,
projectSshConfigDAL,
tx
});
}
// set ghost user as admin of project
const projectMembership = await projectMembershipDAL.create(
@@ -512,7 +527,8 @@ export const projectServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Project);
@@ -570,11 +586,11 @@ export const projectServiceFactory = ({
return deletedProject;
};
const getProjects = async ({ actorId, actor, includeRoles, actorAuthMethod, actorOrgId }: TListProjectsDTO) => {
const getProjects = async ({ actorId, actor, includeRoles, actorAuthMethod, actorOrgId, type }: TListProjectsDTO) => {
const workspaces =
actor === ActorType.IDENTITY
? await projectDAL.findIdentityProjects(actorId, actorOrgId)
: await projectDAL.findUserProjects(actorId, actorOrgId);
? await projectDAL.findIdentityProjects(actorId, actorOrgId, type)
: await projectDAL.findUserProjects(actorId, actorOrgId, type);
if (includeRoles) {
const { permission } = await permissionService.getUserOrgPermission(
@@ -598,7 +614,10 @@ export const projectServiceFactory = ({
workspaces.map(async (workspace) => {
return {
...workspace,
roles: [...(workspaceMappedToRoles[workspace.id] || []), ...getPredefinedRoles({ projectId: workspace.id })]
roles: [
...(workspaceMappedToRoles[workspace.id] || []),
...getPredefinedRoles({ projectId: workspace.id, projectType: workspace.type as ProjectType })
]
};
})
);
@@ -617,7 +636,8 @@ export const projectServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
return project;
};
@@ -630,7 +650,8 @@ export const projectServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
@@ -674,7 +695,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
@@ -699,7 +721,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
@@ -728,7 +751,8 @@ export const projectServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
if (!hasRole(ProjectMembershipRole.Admin))
@@ -759,7 +783,8 @@ export const projectServiceFactory = ({
actorId,
projectId: project.id,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
if (!hasRole(ProjectMembershipRole.Admin)) {
@@ -791,7 +816,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
@@ -812,7 +838,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Project);
@@ -882,7 +909,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret);
@@ -920,7 +948,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -966,7 +995,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -1010,7 +1040,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.PkiAlerts);
@@ -1037,7 +1068,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.PkiCollections);
@@ -1064,7 +1096,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
});
const allowedSubscribers = [];
@@ -1102,7 +1135,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.CertificateManager
});
const certificateTemplates = await certificateTemplateDAL.getCertTemplatesByProjectId(projectId);
@@ -1132,7 +1166,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.SSH
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -1165,7 +1200,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.SSH
});
const allowedHosts = [];
@@ -1204,7 +1240,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.SSH
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshHostGroups);
@@ -1231,7 +1268,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.SSH
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificates);
@@ -1269,7 +1307,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.SSH
});
ForbiddenError.from(permission).throwUnlessCan(
@@ -1303,7 +1342,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Kms);
@@ -1330,7 +1370,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Kms);
@@ -1359,7 +1400,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Kms);
@@ -1381,7 +1423,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
if (!membership) {
@@ -1413,7 +1456,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.SSH
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Settings);
@@ -1452,7 +1496,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.SSH
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
@@ -1535,7 +1580,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Settings);
@@ -1607,7 +1653,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
@@ -1684,7 +1731,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
@@ -1807,7 +1855,8 @@ export const projectServiceFactory = ({
actorId,
projectId,
actorAuthMethod,
actorOrgId
actorOrgId,
actionProjectType: ActionProjectType.Any
});
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Settings);
@@ -1835,7 +1884,15 @@ export const projectServiceFactory = ({
});
};
const searchProjects = async ({ name, offset, permission, limit, orderBy, orderDirection }: TSearchProjectsDTO) => {
const searchProjects = async ({
name,
offset,
permission,
limit,
type,
orderBy,
orderDirection
}: TSearchProjectsDTO) => {
// check user belong to org
await permissionService.getOrgPermission(
permission.type,
@@ -1849,6 +1906,7 @@ export const projectServiceFactory = ({
limit,
offset,
name,
type,
orgId: permission.orgId,
actor: permission.type,
actorId: permission.id,
@@ -1872,7 +1930,7 @@ export const projectServiceFactory = ({
actor: permission.type,
actorId: permission.id,
projectId,
actionProjectType: ActionProjectType.Any,
actorAuthMethod: permission.authMethod,
actorOrgId: permission.orgId
})
@@ -108,7 +108,7 @@ export type TDeleteProjectDTO = {
export type TListProjectsDTO = {
includeRoles: boolean;
type?: ProjectType | "all";
type?: ProjectType;
} & Omit<TProjectPermission, "projectId">;
export type TUpgradeProjectDTO = {