mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 19:26:38 +00:00
Merge remote-tracking branch 'origin/main' into feat/add-render-app-connection-and-secret-sync
This commit is contained in:
Vendored
+13
-15
@@ -3,13 +3,12 @@ import "fastify";
|
|||||||
import { Redis } from "ioredis";
|
import { Redis } from "ioredis";
|
||||||
|
|
||||||
import { TUsers } from "@app/db/schemas";
|
import { TUsers } from "@app/db/schemas";
|
||||||
import { TAccessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-service";
|
import { TAccessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-types";
|
||||||
import { TAccessApprovalRequestServiceFactory } from "@app/ee/services/access-approval-request/access-approval-request-service";
|
import { TAccessApprovalRequestServiceFactory } from "@app/ee/services/access-approval-request/access-approval-request-types";
|
||||||
import { TAssumePrivilegeServiceFactory } from "@app/ee/services/assume-privilege/assume-privilege-service";
|
import { TAssumePrivilegeServiceFactory } from "@app/ee/services/assume-privilege/assume-privilege-types";
|
||||||
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
import { TAuditLogServiceFactory, TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { TCreateAuditLogDTO } from "@app/ee/services/audit-log/audit-log-types";
|
import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-types";
|
||||||
import { TAuditLogStreamServiceFactory } from "@app/ee/services/audit-log-stream/audit-log-stream-service";
|
import { TCertificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-types";
|
||||||
import { TCertificateAuthorityCrlServiceFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-service";
|
|
||||||
import { TCertificateEstServiceFactory } from "@app/ee/services/certificate-est/certificate-est-service";
|
import { TCertificateEstServiceFactory } from "@app/ee/services/certificate-est/certificate-est-service";
|
||||||
import { TDynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
|
import { TDynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
|
||||||
import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
|
import { TDynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
|
||||||
@@ -25,14 +24,13 @@ import { TKmipServiceFactory } from "@app/ee/services/kmip/kmip-service";
|
|||||||
import { TLdapConfigServiceFactory } from "@app/ee/services/ldap-config/ldap-config-service";
|
import { TLdapConfigServiceFactory } from "@app/ee/services/ldap-config/ldap-config-service";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TOidcConfigServiceFactory } from "@app/ee/services/oidc/oidc-config-service";
|
import { TOidcConfigServiceFactory } from "@app/ee/services/oidc/oidc-config-service";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { TPitServiceFactory } from "@app/ee/services/pit/pit-service";
|
import { TPitServiceFactory } from "@app/ee/services/pit/pit-service";
|
||||||
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service";
|
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-types";
|
||||||
import { TProjectUserAdditionalPrivilegeServiceFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-service";
|
import { TProjectUserAdditionalPrivilegeServiceFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-types";
|
||||||
import { TRateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-service";
|
import { RateLimitConfiguration, TRateLimitServiceFactory } from "@app/ee/services/rate-limit/rate-limit-types";
|
||||||
import { RateLimitConfiguration } from "@app/ee/services/rate-limit/rate-limit-types";
|
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-types";
|
||||||
import { TSamlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-service";
|
import { TScimServiceFactory } from "@app/ee/services/scim/scim-types";
|
||||||
import { TScimServiceFactory } from "@app/ee/services/scim/scim-service";
|
|
||||||
import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
||||||
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
import { TSecretApprovalRequestServiceFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-service";
|
||||||
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
import { TSecretRotationServiceFactory } from "@app/ee/services/secret-rotation/secret-rotation-service";
|
||||||
@@ -44,7 +42,7 @@ import { TSshCertificateAuthorityServiceFactory } from "@app/ee/services/ssh/ssh
|
|||||||
import { TSshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
import { TSshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
||||||
import { TSshHostServiceFactory } from "@app/ee/services/ssh-host/ssh-host-service";
|
import { TSshHostServiceFactory } from "@app/ee/services/ssh-host/ssh-host-service";
|
||||||
import { TSshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
import { TSshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
||||||
import { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
import { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-types";
|
||||||
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
||||||
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
import { TApiKeyServiceFactory } from "@app/services/api-key/api-key-service";
|
||||||
import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service";
|
import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import knex, { Knex } from "knex";
|
import knex, { Knex } from "knex";
|
||||||
|
|
||||||
export type TDbClient = ReturnType<typeof initDbConnection>;
|
export type TDbClient = Knex;
|
||||||
export const initDbConnection = ({
|
export const initDbConnection = ({
|
||||||
dbConnectionUri,
|
dbConnectionUri,
|
||||||
dbRootCert,
|
dbRootCert,
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.Identity, "hasDeleteProtection");
|
||||||
|
if (!hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.boolean("hasDeleteProtection").notNullable().defaultTo(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.Identity, "hasDeleteProtection");
|
||||||
|
if (hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.dropColumn("hasDeleteProtection");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasColumn = await knex.schema.hasColumn(TableName.IdentityAwsAuth, "allowedPrincipalArns");
|
||||||
|
if (hasColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.IdentityAwsAuth, (t) => {
|
||||||
|
t.string("allowedPrincipalArns", 2048).notNullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasColumn = await knex.schema.hasColumn(TableName.IdentityAwsAuth, "allowedPrincipalArns");
|
||||||
|
if (hasColumn) {
|
||||||
|
await knex.schema.alterTable(TableName.IdentityAwsAuth, (t) => {
|
||||||
|
t.string("allowedPrincipalArns", 255).notNullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@ export const IdentitiesSchema = z.object({
|
|||||||
name: z.string(),
|
name: z.string(),
|
||||||
authMethod: z.string().nullable().optional(),
|
authMethod: z.string().nullable().optional(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date(),
|
||||||
|
hasDeleteProtection: z.boolean().default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TIdentities = z.infer<typeof IdentitiesSchema>;
|
export type TIdentities = z.infer<typeof IdentitiesSchema>;
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
|
|||||||
id: z.string().trim().describe(GROUPS.GET_BY_ID.id)
|
id: z.string().trim().describe(GROUPS.GET_BY_ID.id)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: GroupsSchema
|
200: GroupsSchema.extend({
|
||||||
|
customRoleSlug: z.string().nullable()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
|||||||
@@ -285,6 +285,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
commits: secretRawSchema
|
commits: secretRawSchema
|
||||||
.omit({ _id: true, environment: true, workspace: true, type: true, version: true, secretValue: true })
|
.omit({ _id: true, environment: true, workspace: true, type: true, version: true, secretValue: true })
|
||||||
.extend({
|
.extend({
|
||||||
|
secretValueHidden: z.boolean(),
|
||||||
secretValue: z.string().optional(),
|
secretValue: z.string().optional(),
|
||||||
isRotatedSecret: z.boolean().optional(),
|
isRotatedSecret: z.boolean().optional(),
|
||||||
op: z.string(),
|
op: z.string(),
|
||||||
@@ -296,6 +297,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
version: z.number(),
|
version: z.number(),
|
||||||
secretKey: z.string(),
|
secretKey: z.string(),
|
||||||
secretValue: z.string().optional(),
|
secretValue: z.string().optional(),
|
||||||
|
secretValueHidden: z.boolean(),
|
||||||
secretComment: z.string().optional()
|
secretComment: z.string().optional()
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
@@ -306,6 +308,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
version: z.number(),
|
version: z.number(),
|
||||||
secretKey: z.string(),
|
secretKey: z.string(),
|
||||||
secretValue: z.string().optional(),
|
secretValue: z.string().optional(),
|
||||||
|
secretValueHidden: z.boolean(),
|
||||||
secretComment: z.string().optional(),
|
secretComment: z.string().optional(),
|
||||||
tags: SanitizedTagSchema.array().optional(),
|
tags: SanitizedTagSchema.array().optional(),
|
||||||
secretMetadata: ResourceMetadataSchema.nullish()
|
secretMetadata: ResourceMetadataSchema.nullish()
|
||||||
|
|||||||
+3
-3
@@ -1,15 +1,15 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TAccessApprovalPolicyApproverDALFactory = ReturnType<typeof accessApprovalPolicyApproverDALFactory>;
|
export type TAccessApprovalPolicyApproverDALFactory = TOrmify<TableName.AccessApprovalPolicyApprover>;
|
||||||
|
|
||||||
export const accessApprovalPolicyApproverDALFactory = (db: TDbClient) => {
|
export const accessApprovalPolicyApproverDALFactory = (db: TDbClient) => {
|
||||||
const accessApprovalPolicyApproverOrm = ormify(db, TableName.AccessApprovalPolicyApprover);
|
const accessApprovalPolicyApproverOrm = ormify(db, TableName.AccessApprovalPolicyApprover);
|
||||||
return { ...accessApprovalPolicyApproverOrm };
|
return { ...accessApprovalPolicyApproverOrm };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAccessApprovalPolicyBypasserDALFactory = ReturnType<typeof accessApprovalPolicyBypasserDALFactory>;
|
export type TAccessApprovalPolicyBypasserDALFactory = TOrmify<TableName.AccessApprovalPolicyBypasser>;
|
||||||
|
|
||||||
export const accessApprovalPolicyBypasserDALFactory = (db: TDbClient) => {
|
export const accessApprovalPolicyBypasserDALFactory = (db: TDbClient) => {
|
||||||
const accessApprovalPolicyBypasserOrm = ormify(db, TableName.AccessApprovalPolicyBypasser);
|
const accessApprovalPolicyBypasserOrm = ormify(db, TableName.AccessApprovalPolicyBypasser);
|
||||||
|
|||||||
@@ -3,13 +3,363 @@ import { Knex } from "knex";
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { AccessApprovalPoliciesSchema, TableName, TAccessApprovalPolicies, TUsers } from "@app/db/schemas";
|
import { AccessApprovalPoliciesSchema, TableName, TAccessApprovalPolicies, TUsers } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindFilter } from "@app/lib/knex";
|
import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindFilter, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
import { ApproverType, BypasserType } from "./access-approval-policy-types";
|
import {
|
||||||
|
ApproverType,
|
||||||
|
BypasserType,
|
||||||
|
TCreateAccessApprovalPolicy,
|
||||||
|
TDeleteAccessApprovalPolicy,
|
||||||
|
TGetAccessApprovalPolicyByIdDTO,
|
||||||
|
TGetAccessPolicyCountByEnvironmentDTO,
|
||||||
|
TListAccessApprovalPoliciesDTO,
|
||||||
|
TUpdateAccessApprovalPolicy
|
||||||
|
} from "./access-approval-policy-types";
|
||||||
|
|
||||||
export type TAccessApprovalPolicyDALFactory = ReturnType<typeof accessApprovalPolicyDALFactory>;
|
export interface TAccessApprovalPolicyDALFactory
|
||||||
|
extends Omit<TOrmify<TableName.AccessApprovalPolicy>, "findById" | "find"> {
|
||||||
|
find: (
|
||||||
|
filter: TFindFilter<
|
||||||
|
TAccessApprovalPolicies & {
|
||||||
|
projectId: string;
|
||||||
|
}
|
||||||
|
>,
|
||||||
|
customFilter?: {
|
||||||
|
policyId?: string;
|
||||||
|
},
|
||||||
|
tx?: Knex
|
||||||
|
) => Promise<
|
||||||
|
{
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType.User;
|
||||||
|
name: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType.Group;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
bypassers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType.User;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType.Group;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
findById: (
|
||||||
|
policyId: string,
|
||||||
|
tx?: Knex
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
approvers: {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
>;
|
||||||
|
softDeleteById: (
|
||||||
|
policyId: string,
|
||||||
|
tx?: Knex
|
||||||
|
) => Promise<{
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
}>;
|
||||||
|
findLastValidPolicy: (
|
||||||
|
{
|
||||||
|
envId,
|
||||||
|
secretPath
|
||||||
|
}: {
|
||||||
|
envId: string;
|
||||||
|
secretPath: string;
|
||||||
|
},
|
||||||
|
tx?: Knex
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
export interface TAccessApprovalPolicyServiceFactory {
|
||||||
|
getAccessPolicyCountByEnvSlug: ({
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
projectSlug,
|
||||||
|
actorId,
|
||||||
|
envSlug
|
||||||
|
}: TGetAccessPolicyCountByEnvironmentDTO) => Promise<{
|
||||||
|
count: number;
|
||||||
|
}>;
|
||||||
|
createAccessApprovalPolicy: ({
|
||||||
|
name,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
secretPath,
|
||||||
|
actorAuthMethod,
|
||||||
|
approvals,
|
||||||
|
approvers,
|
||||||
|
bypassers,
|
||||||
|
projectSlug,
|
||||||
|
environment,
|
||||||
|
enforcementLevel,
|
||||||
|
allowedSelfApprovals,
|
||||||
|
approvalsRequired
|
||||||
|
}: TCreateAccessApprovalPolicy) => Promise<{
|
||||||
|
environment: {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
projectId: string;
|
||||||
|
slug: string;
|
||||||
|
position: number;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
}>;
|
||||||
|
deleteAccessApprovalPolicy: ({
|
||||||
|
policyId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}: TDeleteAccessApprovalPolicy) => Promise<{
|
||||||
|
approvers: {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
}>;
|
||||||
|
updateAccessApprovalPolicy: ({
|
||||||
|
policyId,
|
||||||
|
approvers,
|
||||||
|
bypassers,
|
||||||
|
secretPath,
|
||||||
|
name,
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
approvals,
|
||||||
|
enforcementLevel,
|
||||||
|
allowedSelfApprovals,
|
||||||
|
approvalsRequired
|
||||||
|
}: TUpdateAccessApprovalPolicy) => Promise<{
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
}>;
|
||||||
|
getAccessApprovalPolicyByProjectSlug: ({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
projectSlug
|
||||||
|
}: TListAccessApprovalPoliciesDTO) => Promise<
|
||||||
|
{
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType;
|
||||||
|
name: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
bypassers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
getAccessApprovalPolicyById: ({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
policyId
|
||||||
|
}: TGetAccessApprovalPolicyByIdDTO) => Promise<{
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType.User;
|
||||||
|
name: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType.Group;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
bypassers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType.User;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType.Group;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const accessApprovalPolicyDALFactory = (db: TDbClient): TAccessApprovalPolicyDALFactory => {
|
||||||
const accessApprovalPolicyOrm = ormify(db, TableName.AccessApprovalPolicy);
|
const accessApprovalPolicyOrm = ormify(db, TableName.AccessApprovalPolicy);
|
||||||
|
|
||||||
const accessApprovalPolicyFindQuery = async (
|
const accessApprovalPolicyFindQuery = async (
|
||||||
@@ -61,7 +411,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const findById = async (policyId: string, tx?: Knex) => {
|
const findById: TAccessApprovalPolicyDALFactory["findById"] = async (policyId, tx) => {
|
||||||
try {
|
try {
|
||||||
const doc = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), {
|
const doc = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), {
|
||||||
[`${TableName.AccessApprovalPolicy}.id` as "id"]: policyId
|
[`${TableName.AccessApprovalPolicy}.id` as "id"]: policyId
|
||||||
@@ -112,13 +462,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const find = async (
|
const find: TAccessApprovalPolicyDALFactory["find"] = async (filter, customFilter, tx) => {
|
||||||
filter: TFindFilter<TAccessApprovalPolicies & { projectId: string }>,
|
|
||||||
customFilter?: {
|
|
||||||
policyId?: string;
|
|
||||||
},
|
|
||||||
tx?: Knex
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const docs = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), filter, customFilter);
|
const docs = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), filter, customFilter);
|
||||||
|
|
||||||
@@ -141,7 +485,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
label: "approvers" as const,
|
label: "approvers" as const,
|
||||||
mapper: ({ approverUserId: id, approverUsername, approverSequence, approvalsRequired }) => ({
|
mapper: ({ approverUserId: id, approverUsername, approverSequence, approvalsRequired }) => ({
|
||||||
id,
|
id,
|
||||||
type: ApproverType.User,
|
type: ApproverType.User as const,
|
||||||
name: approverUsername,
|
name: approverUsername,
|
||||||
sequence: approverSequence,
|
sequence: approverSequence,
|
||||||
approvalsRequired
|
approvalsRequired
|
||||||
@@ -152,7 +496,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
label: "approvers" as const,
|
label: "approvers" as const,
|
||||||
mapper: ({ approverGroupId: id, approverSequence, approvalsRequired }) => ({
|
mapper: ({ approverGroupId: id, approverSequence, approvalsRequired }) => ({
|
||||||
id,
|
id,
|
||||||
type: ApproverType.Group,
|
type: ApproverType.Group as const,
|
||||||
sequence: approverSequence,
|
sequence: approverSequence,
|
||||||
approvalsRequired
|
approvalsRequired
|
||||||
})
|
})
|
||||||
@@ -162,7 +506,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
label: "bypassers" as const,
|
label: "bypassers" as const,
|
||||||
mapper: ({ bypasserUserId: id, bypasserUsername }) => ({
|
mapper: ({ bypasserUserId: id, bypasserUsername }) => ({
|
||||||
id,
|
id,
|
||||||
type: BypasserType.User,
|
type: BypasserType.User as const,
|
||||||
name: bypasserUsername
|
name: bypasserUsername
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -171,7 +515,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
label: "bypassers" as const,
|
label: "bypassers" as const,
|
||||||
mapper: ({ bypasserGroupId: id }) => ({
|
mapper: ({ bypasserGroupId: id }) => ({
|
||||||
id,
|
id,
|
||||||
type: BypasserType.Group
|
type: BypasserType.Group as const
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -186,12 +530,15 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const softDeleteById = async (policyId: string, tx?: Knex) => {
|
const softDeleteById: TAccessApprovalPolicyDALFactory["softDeleteById"] = async (policyId, tx) => {
|
||||||
const softDeletedPolicy = await accessApprovalPolicyOrm.updateById(policyId, { deletedAt: new Date() }, tx);
|
const softDeletedPolicy = await accessApprovalPolicyOrm.updateById(policyId, { deletedAt: new Date() }, tx);
|
||||||
return softDeletedPolicy;
|
return softDeletedPolicy;
|
||||||
};
|
};
|
||||||
|
|
||||||
const findLastValidPolicy = async ({ envId, secretPath }: { envId: string; secretPath: string }, tx?: Knex) => {
|
const findLastValidPolicy: TAccessApprovalPolicyDALFactory["findLastValidPolicy"] = async (
|
||||||
|
{ envId, secretPath },
|
||||||
|
tx
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const result = await (tx || db.replicaNode())(TableName.AccessApprovalPolicy)
|
const result = await (tx || db.replicaNode())(TableName.AccessApprovalPolicy)
|
||||||
.where(
|
.where(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { groupBy } from "@app/lib/fn";
|
import { groupBy } from "@app/lib/fn";
|
||||||
@@ -24,9 +24,8 @@ import { TAccessApprovalPolicyDALFactory } from "./access-approval-policy-dal";
|
|||||||
import {
|
import {
|
||||||
ApproverType,
|
ApproverType,
|
||||||
BypasserType,
|
BypasserType,
|
||||||
TCreateAccessApprovalPolicy,
|
TAccessApprovalPolicyServiceFactory,
|
||||||
TDeleteAccessApprovalPolicy,
|
TDeleteAccessApprovalPolicy,
|
||||||
TGetAccessApprovalPolicyByIdDTO,
|
|
||||||
TGetAccessPolicyCountByEnvironmentDTO,
|
TGetAccessPolicyCountByEnvironmentDTO,
|
||||||
TListAccessApprovalPoliciesDTO,
|
TListAccessApprovalPoliciesDTO,
|
||||||
TUpdateAccessApprovalPolicy
|
TUpdateAccessApprovalPolicy
|
||||||
@@ -48,8 +47,6 @@ type TAccessApprovalPolicyServiceFactoryDep = {
|
|||||||
orgMembershipDAL: Pick<TOrgMembershipDALFactory, "find">;
|
orgMembershipDAL: Pick<TOrgMembershipDALFactory, "find">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAccessApprovalPolicyServiceFactory = ReturnType<typeof accessApprovalPolicyServiceFactory>;
|
|
||||||
|
|
||||||
export const accessApprovalPolicyServiceFactory = ({
|
export const accessApprovalPolicyServiceFactory = ({
|
||||||
accessApprovalPolicyDAL,
|
accessApprovalPolicyDAL,
|
||||||
accessApprovalPolicyApproverDAL,
|
accessApprovalPolicyApproverDAL,
|
||||||
@@ -63,8 +60,8 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
additionalPrivilegeDAL,
|
additionalPrivilegeDAL,
|
||||||
accessApprovalRequestReviewerDAL,
|
accessApprovalRequestReviewerDAL,
|
||||||
orgMembershipDAL
|
orgMembershipDAL
|
||||||
}: TAccessApprovalPolicyServiceFactoryDep) => {
|
}: TAccessApprovalPolicyServiceFactoryDep): TAccessApprovalPolicyServiceFactory => {
|
||||||
const createAccessApprovalPolicy = async ({
|
const createAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["createAccessApprovalPolicy"] = async ({
|
||||||
name,
|
name,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -79,7 +76,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
enforcementLevel,
|
enforcementLevel,
|
||||||
allowedSelfApprovals,
|
allowedSelfApprovals,
|
||||||
approvalsRequired
|
approvalsRequired
|
||||||
}: TCreateAccessApprovalPolicy) => {
|
}) => {
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
|
|
||||||
@@ -240,31 +237,26 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
return { ...accessApproval, environment: env, projectId: project.id };
|
return { ...accessApproval, environment: env, projectId: project.id };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAccessApprovalPolicyByProjectSlug = async ({
|
const getAccessApprovalPolicyByProjectSlug: TAccessApprovalPolicyServiceFactory["getAccessApprovalPolicyByProjectSlug"] =
|
||||||
actorId,
|
async ({ actorId, actor, actorOrgId, actorAuthMethod, projectSlug }: TListAccessApprovalPoliciesDTO) => {
|
||||||
actor,
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
actorOrgId,
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
actorAuthMethod,
|
|
||||||
projectSlug
|
|
||||||
}: TListAccessApprovalPoliciesDTO) => {
|
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
|
||||||
|
|
||||||
// Anyone in the project should be able to get the policies.
|
// Anyone in the project should be able to get the policies.
|
||||||
await permissionService.getProjectPermission({
|
await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.SecretManager
|
actionProjectType: ActionProjectType.SecretManager
|
||||||
});
|
});
|
||||||
|
|
||||||
const accessApprovalPolicies = await accessApprovalPolicyDAL.find({ projectId: project.id, deletedAt: null });
|
const accessApprovalPolicies = await accessApprovalPolicyDAL.find({ projectId: project.id, deletedAt: null });
|
||||||
return accessApprovalPolicies;
|
return accessApprovalPolicies;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateAccessApprovalPolicy = async ({
|
const updateAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["updateAccessApprovalPolicy"] = async ({
|
||||||
policyId,
|
policyId,
|
||||||
approvers,
|
approvers,
|
||||||
bypassers,
|
bypassers,
|
||||||
@@ -483,6 +475,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...updatedPolicy,
|
...updatedPolicy,
|
||||||
environment: accessApprovalPolicy.environment,
|
environment: accessApprovalPolicy.environment,
|
||||||
@@ -490,7 +483,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteAccessApprovalPolicy = async ({
|
const deleteAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["deleteAccessApprovalPolicy"] = async ({
|
||||||
policyId,
|
policyId,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -539,7 +532,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
return policy;
|
return policy;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAccessPolicyCountByEnvSlug = async ({
|
const getAccessPolicyCountByEnvSlug: TAccessApprovalPolicyServiceFactory["getAccessPolicyCountByEnvSlug"] = async ({
|
||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
@@ -576,13 +569,13 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
return { count: policies.length };
|
return { count: policies.length };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAccessApprovalPolicyById = async ({
|
const getAccessApprovalPolicyById: TAccessApprovalPolicyServiceFactory["getAccessApprovalPolicyById"] = async ({
|
||||||
actorId,
|
actorId,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
policyId
|
policyId
|
||||||
}: TGetAccessApprovalPolicyByIdDTO) => {
|
}) => {
|
||||||
const [policy] = await accessApprovalPolicyDAL.find({}, { policyId });
|
const [policy] = await accessApprovalPolicyDAL.find({}, { policyId });
|
||||||
|
|
||||||
if (!policy) {
|
if (!policy) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EnforcementLevel, TProjectPermission } from "@app/lib/types";
|
import { EnforcementLevel, TProjectPermission } from "@app/lib/types";
|
||||||
import { ActorAuthMethod } from "@app/services/auth/auth-type";
|
import { ActorAuthMethod } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
|
|
||||||
export type TIsApproversValid = {
|
export type TIsApproversValid = {
|
||||||
userIds: string[];
|
userIds: string[];
|
||||||
@@ -76,3 +76,217 @@ export type TGetAccessApprovalPolicyByIdDTO = {
|
|||||||
export type TListAccessApprovalPoliciesDTO = {
|
export type TListAccessApprovalPoliciesDTO = {
|
||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export interface TAccessApprovalPolicyServiceFactory {
|
||||||
|
getAccessPolicyCountByEnvSlug: ({
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
projectSlug,
|
||||||
|
actorId,
|
||||||
|
envSlug
|
||||||
|
}: TGetAccessPolicyCountByEnvironmentDTO) => Promise<{
|
||||||
|
count: number;
|
||||||
|
}>;
|
||||||
|
createAccessApprovalPolicy: ({
|
||||||
|
name,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
secretPath,
|
||||||
|
actorAuthMethod,
|
||||||
|
approvals,
|
||||||
|
approvers,
|
||||||
|
bypassers,
|
||||||
|
projectSlug,
|
||||||
|
environment,
|
||||||
|
enforcementLevel,
|
||||||
|
allowedSelfApprovals,
|
||||||
|
approvalsRequired
|
||||||
|
}: TCreateAccessApprovalPolicy) => Promise<{
|
||||||
|
environment: {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
projectId: string;
|
||||||
|
slug: string;
|
||||||
|
position: number;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
}>;
|
||||||
|
deleteAccessApprovalPolicy: ({
|
||||||
|
policyId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}: TDeleteAccessApprovalPolicy) => Promise<{
|
||||||
|
approvers: {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
}>;
|
||||||
|
updateAccessApprovalPolicy: ({
|
||||||
|
policyId,
|
||||||
|
approvers,
|
||||||
|
bypassers,
|
||||||
|
secretPath,
|
||||||
|
name,
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
approvals,
|
||||||
|
enforcementLevel,
|
||||||
|
allowedSelfApprovals,
|
||||||
|
approvalsRequired
|
||||||
|
}: TUpdateAccessApprovalPolicy) => Promise<{
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
}>;
|
||||||
|
getAccessApprovalPolicyByProjectSlug: ({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
projectSlug
|
||||||
|
}: TListAccessApprovalPoliciesDTO) => Promise<
|
||||||
|
{
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType;
|
||||||
|
name: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
bypassers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
getAccessApprovalPolicyById: ({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
policyId
|
||||||
|
}: TGetAccessApprovalPolicyByIdDTO) => Promise<{
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType.User;
|
||||||
|
name: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: ApproverType.Group;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
approvals: number;
|
||||||
|
envId: string;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
secretPath?: string | null | undefined;
|
||||||
|
deletedAt?: Date | null | undefined;
|
||||||
|
environment: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
bypassers: (
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType.User;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: string | null | undefined;
|
||||||
|
type: BypasserType.Group;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,229 +9,442 @@ import {
|
|||||||
TUsers
|
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, TFindFilter } from "@app/lib/knex";
|
import { ormify, selectAllTableCols, sqlNestRelationships, TFindFilter, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
import { ApprovalStatus } from "./access-approval-request-types";
|
import { ApprovalStatus } from "./access-approval-request-types";
|
||||||
|
|
||||||
export type TAccessApprovalRequestDALFactory = ReturnType<typeof accessApprovalRequestDALFactory>;
|
export interface TAccessApprovalRequestDALFactory extends Omit<TOrmify<TableName.AccessApprovalRequest>, "findById"> {
|
||||||
|
findById: (
|
||||||
|
id: string,
|
||||||
|
tx?: Knex
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
policy: {
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
bypassers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
approvals: number;
|
||||||
|
secretPath: string | null | undefined;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
deletedAt: Date | null | undefined;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
environment: string;
|
||||||
|
requestedByUser: {
|
||||||
|
userId: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
|
status: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
policyId: string;
|
||||||
|
isTemporary: boolean;
|
||||||
|
requestedByUserId: string;
|
||||||
|
privilegeId?: string | null | undefined;
|
||||||
|
requestedBy?: string | null | undefined;
|
||||||
|
temporaryRange?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
note?: string | null | undefined;
|
||||||
|
privilegeDeletedAt?: Date | null | undefined;
|
||||||
|
reviewers: {
|
||||||
|
userId: string;
|
||||||
|
status: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}[];
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
bypassers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
>;
|
||||||
|
findRequestsWithPrivilegeByPolicyIds: (policyIds: string[]) => Promise<
|
||||||
|
{
|
||||||
|
policy: {
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
bypassers: string[];
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
approvals: number;
|
||||||
|
secretPath: string | null | undefined;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
envId: string;
|
||||||
|
deletedAt: Date | null | undefined;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
environment: string;
|
||||||
|
environmentName: string;
|
||||||
|
requestedByUser: {
|
||||||
|
userId: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
|
privilege: {
|
||||||
|
membershipId: string;
|
||||||
|
userId: string;
|
||||||
|
projectId: string;
|
||||||
|
isTemporary: boolean;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
permissions: unknown;
|
||||||
|
} | null;
|
||||||
|
isApproved: boolean;
|
||||||
|
status: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
policyId: string;
|
||||||
|
isTemporary: boolean;
|
||||||
|
requestedByUserId: string;
|
||||||
|
privilegeId?: string | null | undefined;
|
||||||
|
requestedBy?: string | null | undefined;
|
||||||
|
temporaryRange?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
note?: string | null | undefined;
|
||||||
|
privilegeDeletedAt?: Date | null | undefined;
|
||||||
|
reviewers: {
|
||||||
|
userId: string;
|
||||||
|
status: string;
|
||||||
|
}[];
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
bypassers: string[];
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
getCount: ({ projectId }: { projectId: string }) => Promise<{
|
||||||
|
pendingCount: number;
|
||||||
|
finalizedCount: number;
|
||||||
|
}>;
|
||||||
|
resetReviewByPolicyId: (policyId: string, tx?: Knex) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
export const accessApprovalRequestDALFactory = (db: TDbClient): TAccessApprovalRequestDALFactory => {
|
||||||
const accessApprovalRequestOrm = ormify(db, TableName.AccessApprovalRequest);
|
const accessApprovalRequestOrm = ormify(db, TableName.AccessApprovalRequest);
|
||||||
|
|
||||||
const findRequestsWithPrivilegeByPolicyIds = async (policyIds: string[]) => {
|
const findRequestsWithPrivilegeByPolicyIds: TAccessApprovalRequestDALFactory["findRequestsWithPrivilegeByPolicyIds"] =
|
||||||
try {
|
async (policyIds) => {
|
||||||
const docs = await db
|
try {
|
||||||
.replicaNode()(TableName.AccessApprovalRequest)
|
const docs = await db
|
||||||
.whereIn(`${TableName.AccessApprovalRequest}.policyId`, policyIds)
|
.replicaNode()(TableName.AccessApprovalRequest)
|
||||||
|
.whereIn(`${TableName.AccessApprovalRequest}.policyId`, policyIds)
|
||||||
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.ProjectUserAdditionalPrivilege,
|
TableName.ProjectUserAdditionalPrivilege,
|
||||||
`${TableName.AccessApprovalRequest}.privilegeId`,
|
`${TableName.AccessApprovalRequest}.privilegeId`,
|
||||||
`${TableName.ProjectUserAdditionalPrivilege}.id`
|
`${TableName.ProjectUserAdditionalPrivilege}.id`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.AccessApprovalPolicy,
|
TableName.AccessApprovalPolicy,
|
||||||
`${TableName.AccessApprovalRequest}.policyId`,
|
`${TableName.AccessApprovalRequest}.policyId`,
|
||||||
`${TableName.AccessApprovalPolicy}.id`
|
`${TableName.AccessApprovalPolicy}.id`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.AccessApprovalRequestReviewer,
|
TableName.AccessApprovalRequestReviewer,
|
||||||
`${TableName.AccessApprovalRequest}.id`,
|
`${TableName.AccessApprovalRequest}.id`,
|
||||||
`${TableName.AccessApprovalRequestReviewer}.requestId`
|
`${TableName.AccessApprovalRequestReviewer}.requestId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.AccessApprovalPolicyApprover,
|
TableName.AccessApprovalPolicyApprover,
|
||||||
`${TableName.AccessApprovalPolicy}.id`,
|
`${TableName.AccessApprovalPolicy}.id`,
|
||||||
`${TableName.AccessApprovalPolicyApprover}.policyId`
|
`${TableName.AccessApprovalPolicyApprover}.policyId`
|
||||||
)
|
)
|
||||||
.leftJoin<TUsers>(
|
.leftJoin<TUsers>(
|
||||||
db(TableName.Users).as("accessApprovalPolicyApproverUser"),
|
db(TableName.Users).as("accessApprovalPolicyApproverUser"),
|
||||||
`${TableName.AccessApprovalPolicyApprover}.approverUserId`,
|
`${TableName.AccessApprovalPolicyApprover}.approverUserId`,
|
||||||
"accessApprovalPolicyApproverUser.id"
|
"accessApprovalPolicyApproverUser.id"
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.UserGroupMembership,
|
TableName.UserGroupMembership,
|
||||||
`${TableName.AccessApprovalPolicyApprover}.approverGroupId`,
|
`${TableName.AccessApprovalPolicyApprover}.approverGroupId`,
|
||||||
`${TableName.UserGroupMembership}.groupId`
|
`${TableName.UserGroupMembership}.groupId`
|
||||||
)
|
)
|
||||||
.leftJoin(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
.leftJoin(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||||
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.AccessApprovalPolicyBypasser,
|
TableName.AccessApprovalPolicyBypasser,
|
||||||
`${TableName.AccessApprovalPolicy}.id`,
|
`${TableName.AccessApprovalPolicy}.id`,
|
||||||
`${TableName.AccessApprovalPolicyBypasser}.policyId`
|
`${TableName.AccessApprovalPolicyBypasser}.policyId`
|
||||||
)
|
)
|
||||||
.leftJoin<TUserGroupMembership>(
|
.leftJoin<TUserGroupMembership>(
|
||||||
db(TableName.UserGroupMembership).as("bypasserUserGroupMembership"),
|
db(TableName.UserGroupMembership).as("bypasserUserGroupMembership"),
|
||||||
`${TableName.AccessApprovalPolicyBypasser}.bypasserGroupId`,
|
`${TableName.AccessApprovalPolicyBypasser}.bypasserGroupId`,
|
||||||
`bypasserUserGroupMembership.groupId`
|
`bypasserUserGroupMembership.groupId`
|
||||||
)
|
)
|
||||||
|
|
||||||
.join<TUsers>(
|
.join<TUsers>(
|
||||||
db(TableName.Users).as("requestedByUser"),
|
db(TableName.Users).as("requestedByUser"),
|
||||||
`${TableName.AccessApprovalRequest}.requestedByUserId`,
|
`${TableName.AccessApprovalRequest}.requestedByUserId`,
|
||||||
`requestedByUser.id`
|
`requestedByUser.id`
|
||||||
)
|
)
|
||||||
|
|
||||||
.leftJoin(TableName.Environment, `${TableName.AccessApprovalPolicy}.envId`, `${TableName.Environment}.id`)
|
.leftJoin(TableName.Environment, `${TableName.AccessApprovalPolicy}.envId`, `${TableName.Environment}.id`)
|
||||||
|
|
||||||
.select(selectAllTableCols(TableName.AccessApprovalRequest))
|
.select(selectAllTableCols(TableName.AccessApprovalRequest))
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.AccessApprovalPolicy).as("policyId"),
|
db.ref("id").withSchema(TableName.AccessApprovalPolicy).as("policyId"),
|
||||||
db.ref("name").withSchema(TableName.AccessApprovalPolicy).as("policyName"),
|
db.ref("name").withSchema(TableName.AccessApprovalPolicy).as("policyName"),
|
||||||
db.ref("approvals").withSchema(TableName.AccessApprovalPolicy).as("policyApprovals"),
|
db.ref("approvals").withSchema(TableName.AccessApprovalPolicy).as("policyApprovals"),
|
||||||
db.ref("secretPath").withSchema(TableName.AccessApprovalPolicy).as("policySecretPath"),
|
db.ref("secretPath").withSchema(TableName.AccessApprovalPolicy).as("policySecretPath"),
|
||||||
db.ref("enforcementLevel").withSchema(TableName.AccessApprovalPolicy).as("policyEnforcementLevel"),
|
db.ref("enforcementLevel").withSchema(TableName.AccessApprovalPolicy).as("policyEnforcementLevel"),
|
||||||
db.ref("allowedSelfApprovals").withSchema(TableName.AccessApprovalPolicy).as("policyAllowedSelfApprovals"),
|
db.ref("allowedSelfApprovals").withSchema(TableName.AccessApprovalPolicy).as("policyAllowedSelfApprovals"),
|
||||||
db.ref("envId").withSchema(TableName.AccessApprovalPolicy).as("policyEnvId"),
|
db.ref("envId").withSchema(TableName.AccessApprovalPolicy).as("policyEnvId"),
|
||||||
db.ref("deletedAt").withSchema(TableName.AccessApprovalPolicy).as("policyDeletedAt")
|
db.ref("deletedAt").withSchema(TableName.AccessApprovalPolicy).as("policyDeletedAt")
|
||||||
)
|
)
|
||||||
.select(db.ref("approverUserId").withSchema(TableName.AccessApprovalPolicyApprover))
|
.select(db.ref("approverUserId").withSchema(TableName.AccessApprovalPolicyApprover))
|
||||||
.select(db.ref("sequence").withSchema(TableName.AccessApprovalPolicyApprover).as("approverSequence"))
|
.select(db.ref("sequence").withSchema(TableName.AccessApprovalPolicyApprover).as("approverSequence"))
|
||||||
.select(db.ref("approvalsRequired").withSchema(TableName.AccessApprovalPolicyApprover))
|
.select(db.ref("approvalsRequired").withSchema(TableName.AccessApprovalPolicyApprover))
|
||||||
.select(db.ref("userId").withSchema(TableName.UserGroupMembership).as("approverGroupUserId"))
|
.select(db.ref("userId").withSchema(TableName.UserGroupMembership).as("approverGroupUserId"))
|
||||||
.select(db.ref("bypasserUserId").withSchema(TableName.AccessApprovalPolicyBypasser))
|
.select(db.ref("bypasserUserId").withSchema(TableName.AccessApprovalPolicyBypasser))
|
||||||
.select(db.ref("userId").withSchema("bypasserUserGroupMembership").as("bypasserGroupUserId"))
|
.select(db.ref("userId").withSchema("bypasserUserGroupMembership").as("bypasserGroupUserId"))
|
||||||
.select(
|
.select(
|
||||||
db.ref("email").withSchema("accessApprovalPolicyApproverUser").as("approverEmail"),
|
db.ref("email").withSchema("accessApprovalPolicyApproverUser").as("approverEmail"),
|
||||||
db.ref("email").withSchema(TableName.Users).as("approverGroupEmail"),
|
db.ref("email").withSchema(TableName.Users).as("approverGroupEmail"),
|
||||||
db.ref("username").withSchema("accessApprovalPolicyApproverUser").as("approverUsername"),
|
db.ref("username").withSchema("accessApprovalPolicyApproverUser").as("approverUsername"),
|
||||||
db.ref("username").withSchema(TableName.Users).as("approverGroupUsername")
|
db.ref("username").withSchema(TableName.Users).as("approverGroupUsername")
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("projectId").withSchema(TableName.Environment),
|
db.ref("projectId").withSchema(TableName.Environment),
|
||||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
||||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
db.ref("name").withSchema(TableName.Environment).as("envName")
|
||||||
)
|
)
|
||||||
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("reviewerUserId").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerUserId"),
|
db.ref("reviewerUserId").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerUserId"),
|
||||||
db.ref("status").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerStatus")
|
db.ref("status").withSchema(TableName.AccessApprovalRequestReviewer).as("reviewerStatus")
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: ADD SUPPORT FOR GROUPS!!!!
|
// TODO: ADD SUPPORT FOR GROUPS!!!!
|
||||||
.select(
|
.select(
|
||||||
db.ref("email").withSchema("requestedByUser").as("requestedByUserEmail"),
|
db.ref("email").withSchema("requestedByUser").as("requestedByUserEmail"),
|
||||||
db.ref("username").withSchema("requestedByUser").as("requestedByUserUsername"),
|
db.ref("username").withSchema("requestedByUser").as("requestedByUserUsername"),
|
||||||
db.ref("firstName").withSchema("requestedByUser").as("requestedByUserFirstName"),
|
db.ref("firstName").withSchema("requestedByUser").as("requestedByUserFirstName"),
|
||||||
db.ref("lastName").withSchema("requestedByUser").as("requestedByUserLastName"),
|
db.ref("lastName").withSchema("requestedByUser").as("requestedByUserLastName"),
|
||||||
|
|
||||||
db.ref("userId").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeUserId"),
|
db.ref("userId").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeUserId"),
|
||||||
db.ref("projectId").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeMembershipId"),
|
db.ref("projectId").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeMembershipId"),
|
||||||
|
|
||||||
db.ref("isTemporary").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeIsTemporary"),
|
db.ref("isTemporary").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeIsTemporary"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeTemporaryMode"),
|
db.ref("temporaryMode").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeTemporaryMode"),
|
||||||
db.ref("temporaryRange").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeTemporaryRange"),
|
db.ref("temporaryRange").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegeTemporaryRange"),
|
||||||
db
|
db
|
||||||
.ref("temporaryAccessStartTime")
|
.ref("temporaryAccessStartTime")
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
||||||
.as("privilegeTemporaryAccessStartTime"),
|
.as("privilegeTemporaryAccessStartTime"),
|
||||||
db
|
db
|
||||||
.ref("temporaryAccessEndTime")
|
.ref("temporaryAccessEndTime")
|
||||||
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
.withSchema(TableName.ProjectUserAdditionalPrivilege)
|
||||||
.as("privilegeTemporaryAccessEndTime"),
|
.as("privilegeTemporaryAccessEndTime"),
|
||||||
|
|
||||||
db.ref("permissions").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegePermissions")
|
db.ref("permissions").withSchema(TableName.ProjectUserAdditionalPrivilege).as("privilegePermissions")
|
||||||
)
|
)
|
||||||
.orderBy(`${TableName.AccessApprovalRequest}.createdAt`, "desc");
|
.orderBy(`${TableName.AccessApprovalRequest}.createdAt`, "desc");
|
||||||
|
|
||||||
const formattedDocs = sqlNestRelationships({
|
const formattedDocs = sqlNestRelationships({
|
||||||
data: docs,
|
data: docs,
|
||||||
key: "id",
|
key: "id",
|
||||||
parentMapper: (doc) => ({
|
parentMapper: (doc) => ({
|
||||||
...AccessApprovalRequestsSchema.parse(doc),
|
...AccessApprovalRequestsSchema.parse(doc),
|
||||||
projectId: doc.projectId,
|
projectId: doc.projectId,
|
||||||
environment: doc.envSlug,
|
environment: doc.envSlug,
|
||||||
environmentName: doc.envName,
|
environmentName: doc.envName,
|
||||||
|
policy: {
|
||||||
|
id: doc.policyId,
|
||||||
|
name: doc.policyName,
|
||||||
|
approvals: doc.policyApprovals,
|
||||||
|
secretPath: doc.policySecretPath,
|
||||||
|
enforcementLevel: doc.policyEnforcementLevel,
|
||||||
|
allowedSelfApprovals: doc.policyAllowedSelfApprovals,
|
||||||
|
envId: doc.policyEnvId,
|
||||||
|
deletedAt: doc.policyDeletedAt
|
||||||
|
},
|
||||||
|
requestedByUser: {
|
||||||
|
userId: doc.requestedByUserId,
|
||||||
|
email: doc.requestedByUserEmail,
|
||||||
|
firstName: doc.requestedByUserFirstName,
|
||||||
|
lastName: doc.requestedByUserLastName,
|
||||||
|
username: doc.requestedByUserUsername
|
||||||
|
},
|
||||||
|
privilege: doc.privilegeId
|
||||||
|
? {
|
||||||
|
membershipId: doc.privilegeMembershipId,
|
||||||
|
userId: doc.privilegeUserId,
|
||||||
|
projectId: doc.projectId,
|
||||||
|
isTemporary: doc.privilegeIsTemporary,
|
||||||
|
temporaryMode: doc.privilegeTemporaryMode,
|
||||||
|
temporaryRange: doc.privilegeTemporaryRange,
|
||||||
|
temporaryAccessStartTime: doc.privilegeTemporaryAccessStartTime,
|
||||||
|
temporaryAccessEndTime: doc.privilegeTemporaryAccessEndTime,
|
||||||
|
permissions: doc.privilegePermissions
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
isApproved: doc.status === ApprovalStatus.APPROVED
|
||||||
|
}),
|
||||||
|
childrenMapper: [
|
||||||
|
{
|
||||||
|
key: "reviewerUserId",
|
||||||
|
label: "reviewers" as const,
|
||||||
|
mapper: ({ reviewerUserId: userId, reviewerStatus: status }) => (userId ? { userId, status } : undefined)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "approverUserId",
|
||||||
|
label: "approvers" as const,
|
||||||
|
mapper: ({ approverUserId, approverSequence, approvalsRequired, approverUsername, approverEmail }) => ({
|
||||||
|
userId: approverUserId,
|
||||||
|
sequence: approverSequence,
|
||||||
|
approvalsRequired,
|
||||||
|
email: approverEmail,
|
||||||
|
username: approverUsername
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "approverGroupUserId",
|
||||||
|
label: "approvers" as const,
|
||||||
|
mapper: ({
|
||||||
|
approverGroupUserId,
|
||||||
|
approverSequence,
|
||||||
|
approvalsRequired,
|
||||||
|
approverGroupEmail,
|
||||||
|
approverGroupUsername
|
||||||
|
}) => ({
|
||||||
|
userId: approverGroupUserId,
|
||||||
|
sequence: approverSequence,
|
||||||
|
approvalsRequired,
|
||||||
|
email: approverGroupEmail,
|
||||||
|
username: approverGroupUsername
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ key: "bypasserUserId", label: "bypassers" as const, mapper: ({ bypasserUserId }) => bypasserUserId },
|
||||||
|
{
|
||||||
|
key: "bypasserGroupUserId",
|
||||||
|
label: "bypassers" as const,
|
||||||
|
mapper: ({ bypasserGroupUserId }) => bypasserGroupUserId
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!formattedDocs) return [];
|
||||||
|
|
||||||
|
return formattedDocs.map((doc) => ({
|
||||||
|
...doc,
|
||||||
policy: {
|
policy: {
|
||||||
id: doc.policyId,
|
...doc.policy,
|
||||||
name: doc.policyName,
|
approvers: doc.approvers.filter((el) => el.userId).sort((a, b) => (a.sequence || 0) - (b.sequence || 0)),
|
||||||
approvals: doc.policyApprovals,
|
bypassers: doc.bypassers
|
||||||
secretPath: doc.policySecretPath,
|
|
||||||
enforcementLevel: doc.policyEnforcementLevel,
|
|
||||||
allowedSelfApprovals: doc.policyAllowedSelfApprovals,
|
|
||||||
envId: doc.policyEnvId,
|
|
||||||
deletedAt: doc.policyDeletedAt
|
|
||||||
},
|
|
||||||
requestedByUser: {
|
|
||||||
userId: doc.requestedByUserId,
|
|
||||||
email: doc.requestedByUserEmail,
|
|
||||||
firstName: doc.requestedByUserFirstName,
|
|
||||||
lastName: doc.requestedByUserLastName,
|
|
||||||
username: doc.requestedByUserUsername
|
|
||||||
},
|
|
||||||
privilege: doc.privilegeId
|
|
||||||
? {
|
|
||||||
membershipId: doc.privilegeMembershipId,
|
|
||||||
userId: doc.privilegeUserId,
|
|
||||||
projectId: doc.projectId,
|
|
||||||
isTemporary: doc.privilegeIsTemporary,
|
|
||||||
temporaryMode: doc.privilegeTemporaryMode,
|
|
||||||
temporaryRange: doc.privilegeTemporaryRange,
|
|
||||||
temporaryAccessStartTime: doc.privilegeTemporaryAccessStartTime,
|
|
||||||
temporaryAccessEndTime: doc.privilegeTemporaryAccessEndTime,
|
|
||||||
permissions: doc.privilegePermissions
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
isApproved: doc.status === ApprovalStatus.APPROVED
|
|
||||||
}),
|
|
||||||
childrenMapper: [
|
|
||||||
{
|
|
||||||
key: "reviewerUserId",
|
|
||||||
label: "reviewers" as const,
|
|
||||||
mapper: ({ reviewerUserId: userId, reviewerStatus: status }) => (userId ? { userId, status } : undefined)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "approverUserId",
|
|
||||||
label: "approvers" as const,
|
|
||||||
mapper: ({ approverUserId, approverSequence, approvalsRequired, approverUsername, approverEmail }) => ({
|
|
||||||
userId: approverUserId,
|
|
||||||
sequence: approverSequence,
|
|
||||||
approvalsRequired,
|
|
||||||
email: approverEmail,
|
|
||||||
username: approverUsername
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "approverGroupUserId",
|
|
||||||
label: "approvers" as const,
|
|
||||||
mapper: ({
|
|
||||||
approverGroupUserId,
|
|
||||||
approverSequence,
|
|
||||||
approvalsRequired,
|
|
||||||
approverGroupEmail,
|
|
||||||
approverGroupUsername
|
|
||||||
}) => ({
|
|
||||||
userId: approverGroupUserId,
|
|
||||||
sequence: approverSequence,
|
|
||||||
approvalsRequired,
|
|
||||||
email: approverGroupEmail,
|
|
||||||
username: approverGroupUsername
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{ key: "bypasserUserId", label: "bypassers" as const, mapper: ({ bypasserUserId }) => bypasserUserId },
|
|
||||||
{
|
|
||||||
key: "bypasserGroupUserId",
|
|
||||||
label: "bypassers" as const,
|
|
||||||
mapper: ({ bypasserGroupUserId }) => bypasserGroupUserId
|
|
||||||
}
|
}
|
||||||
]
|
}));
|
||||||
});
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "FindRequestsWithPrivilege" });
|
||||||
if (!formattedDocs) return [];
|
}
|
||||||
|
};
|
||||||
return formattedDocs.map((doc) => ({
|
|
||||||
...doc,
|
|
||||||
policy: {
|
|
||||||
...doc.policy,
|
|
||||||
approvers: doc.approvers.filter((el) => el.userId).sort((a, b) => (a.sequence || 0) - (b.sequence || 0)),
|
|
||||||
bypassers: doc.bypassers
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "FindRequestsWithPrivilege" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const findQuery = (filter: TFindFilter<TAccessApprovalRequests>, tx: Knex) =>
|
const findQuery = (filter: TFindFilter<TAccessApprovalRequests>, tx: Knex) =>
|
||||||
tx(TableName.AccessApprovalRequest)
|
tx(TableName.AccessApprovalRequest)
|
||||||
@@ -354,7 +567,7 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
tx.ref("deletedAt").withSchema(TableName.AccessApprovalPolicy).as("policyDeletedAt")
|
tx.ref("deletedAt").withSchema(TableName.AccessApprovalPolicy).as("policyDeletedAt")
|
||||||
);
|
);
|
||||||
|
|
||||||
const findById = async (id: string, tx?: Knex) => {
|
const findById: TAccessApprovalRequestDALFactory["findById"] = async (id, tx) => {
|
||||||
try {
|
try {
|
||||||
const sql = findQuery({ [`${TableName.AccessApprovalRequest}.id` as "id"]: id }, tx || db.replicaNode());
|
const sql = findQuery({ [`${TableName.AccessApprovalRequest}.id` as "id"]: id }, tx || db.replicaNode());
|
||||||
const docs = await sql;
|
const docs = await sql;
|
||||||
@@ -489,7 +702,7 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCount = async ({ projectId }: { projectId: string }) => {
|
const getCount: TAccessApprovalRequestDALFactory["getCount"] = async ({ projectId }) => {
|
||||||
try {
|
try {
|
||||||
const accessRequests = await db
|
const accessRequests = await db
|
||||||
.replicaNode()(TableName.AccessApprovalRequest)
|
.replicaNode()(TableName.AccessApprovalRequest)
|
||||||
@@ -555,7 +768,7 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetReviewByPolicyId = async (policyId: string, tx?: Knex) => {
|
const resetReviewByPolicyId: TAccessApprovalRequestDALFactory["resetReviewByPolicyId"] = async (policyId, tx) => {
|
||||||
try {
|
try {
|
||||||
await (tx || db)(TableName.AccessApprovalRequestReviewer)
|
await (tx || db)(TableName.AccessApprovalRequestReviewer)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
|
|||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TAccessApprovalRequestReviewerDALFactory = ReturnType<typeof accessApprovalRequestReviewerDALFactory>;
|
export type TAccessApprovalRequestReviewerDALFactory = TOrmify<TableName.AccessApprovalRequestReviewer>;
|
||||||
|
|
||||||
export const accessApprovalRequestReviewerDALFactory = (db: TDbClient) => {
|
export const accessApprovalRequestReviewerDALFactory = (db: TDbClient): TAccessApprovalRequestReviewerDALFactory => {
|
||||||
const secretApprovalRequestReviewerOrm = ormify(db, TableName.AccessApprovalRequestReviewer);
|
const secretApprovalRequestReviewerOrm = ormify(db, TableName.AccessApprovalRequestReviewer);
|
||||||
return secretApprovalRequestReviewerOrm;
|
return secretApprovalRequestReviewerOrm;
|
||||||
};
|
};
|
||||||
|
|||||||
+16
-18
@@ -23,19 +23,13 @@ import { TUserDALFactory } from "@app/services/user/user-dal";
|
|||||||
import { TAccessApprovalPolicyApproverDALFactory } from "../access-approval-policy/access-approval-policy-approver-dal";
|
import { TAccessApprovalPolicyApproverDALFactory } from "../access-approval-policy/access-approval-policy-approver-dal";
|
||||||
import { TAccessApprovalPolicyDALFactory } from "../access-approval-policy/access-approval-policy-dal";
|
import { TAccessApprovalPolicyDALFactory } from "../access-approval-policy/access-approval-policy-dal";
|
||||||
import { TGroupDALFactory } from "../group/group-dal";
|
import { TGroupDALFactory } from "../group/group-dal";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TProjectUserAdditionalPrivilegeDALFactory } from "../project-user-additional-privilege/project-user-additional-privilege-dal";
|
import { TProjectUserAdditionalPrivilegeDALFactory } from "../project-user-additional-privilege/project-user-additional-privilege-dal";
|
||||||
import { ProjectUserAdditionalPrivilegeTemporaryMode } from "../project-user-additional-privilege/project-user-additional-privilege-types";
|
import { ProjectUserAdditionalPrivilegeTemporaryMode } from "../project-user-additional-privilege/project-user-additional-privilege-types";
|
||||||
import { TAccessApprovalRequestDALFactory } from "./access-approval-request-dal";
|
import { TAccessApprovalRequestDALFactory } from "./access-approval-request-dal";
|
||||||
import { verifyRequestedPermissions } from "./access-approval-request-fns";
|
import { verifyRequestedPermissions } from "./access-approval-request-fns";
|
||||||
import { TAccessApprovalRequestReviewerDALFactory } from "./access-approval-request-reviewer-dal";
|
import { TAccessApprovalRequestReviewerDALFactory } from "./access-approval-request-reviewer-dal";
|
||||||
import {
|
import { ApprovalStatus, TAccessApprovalRequestServiceFactory } from "./access-approval-request-types";
|
||||||
ApprovalStatus,
|
|
||||||
TCreateAccessApprovalRequestDTO,
|
|
||||||
TGetAccessRequestCountDTO,
|
|
||||||
TListApprovalRequestsDTO,
|
|
||||||
TReviewAccessRequestDTO
|
|
||||||
} from "./access-approval-request-types";
|
|
||||||
|
|
||||||
type TSecretApprovalRequestServiceFactoryDep = {
|
type TSecretApprovalRequestServiceFactoryDep = {
|
||||||
additionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "create" | "findById">;
|
additionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "create" | "findById">;
|
||||||
@@ -75,8 +69,6 @@ type TSecretApprovalRequestServiceFactoryDep = {
|
|||||||
projectMicrosoftTeamsConfigDAL: Pick<TProjectMicrosoftTeamsConfigDALFactory, "getIntegrationDetailsByProject">;
|
projectMicrosoftTeamsConfigDAL: Pick<TProjectMicrosoftTeamsConfigDALFactory, "getIntegrationDetailsByProject">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAccessApprovalRequestServiceFactory = ReturnType<typeof accessApprovalRequestServiceFactory>;
|
|
||||||
|
|
||||||
export const accessApprovalRequestServiceFactory = ({
|
export const accessApprovalRequestServiceFactory = ({
|
||||||
groupDAL,
|
groupDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
@@ -93,8 +85,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
microsoftTeamsService,
|
microsoftTeamsService,
|
||||||
projectMicrosoftTeamsConfigDAL,
|
projectMicrosoftTeamsConfigDAL,
|
||||||
projectSlackConfigDAL
|
projectSlackConfigDAL
|
||||||
}: TSecretApprovalRequestServiceFactoryDep) => {
|
}: TSecretApprovalRequestServiceFactoryDep): TAccessApprovalRequestServiceFactory => {
|
||||||
const createAccessApprovalRequest = async ({
|
const createAccessApprovalRequest: TAccessApprovalRequestServiceFactory["createAccessApprovalRequest"] = async ({
|
||||||
isTemporary,
|
isTemporary,
|
||||||
temporaryRange,
|
temporaryRange,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -104,7 +96,7 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
projectSlug,
|
projectSlug,
|
||||||
note
|
note
|
||||||
}: TCreateAccessApprovalRequestDTO) => {
|
}) => {
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
@@ -281,7 +273,7 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
return { request: approval };
|
return { request: approval };
|
||||||
};
|
};
|
||||||
|
|
||||||
const listApprovalRequests = async ({
|
const listApprovalRequests: TAccessApprovalRequestServiceFactory["listApprovalRequests"] = async ({
|
||||||
projectSlug,
|
projectSlug,
|
||||||
authorProjectMembershipId,
|
authorProjectMembershipId,
|
||||||
envSlug,
|
envSlug,
|
||||||
@@ -289,7 +281,7 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorId,
|
actorId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TListApprovalRequestsDTO) => {
|
}) => {
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
|
|
||||||
@@ -319,7 +311,7 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
return { requests };
|
return { requests };
|
||||||
};
|
};
|
||||||
|
|
||||||
const reviewAccessRequest = async ({
|
const reviewAccessRequest: TAccessApprovalRequestServiceFactory["reviewAccessRequest"] = async ({
|
||||||
requestId,
|
requestId,
|
||||||
actor,
|
actor,
|
||||||
status,
|
status,
|
||||||
@@ -327,7 +319,7 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
bypassReason
|
bypassReason
|
||||||
}: TReviewAccessRequestDTO) => {
|
}) => {
|
||||||
const accessApprovalRequest = await accessApprovalRequestDAL.findById(requestId);
|
const accessApprovalRequest = await accessApprovalRequestDAL.findById(requestId);
|
||||||
if (!accessApprovalRequest) {
|
if (!accessApprovalRequest) {
|
||||||
throw new NotFoundError({ message: `Secret approval request with ID '${requestId}' not found` });
|
throw new NotFoundError({ message: `Secret approval request with ID '${requestId}' not found` });
|
||||||
@@ -566,7 +558,13 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
return reviewStatus;
|
return reviewStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getCount = async ({ projectSlug, actor, actorAuthMethod, actorId, actorOrgId }: TGetAccessRequestCountDTO) => {
|
const getCount: TAccessApprovalRequestServiceFactory["getCount"] = async ({
|
||||||
|
projectSlug,
|
||||||
|
actor,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorId,
|
||||||
|
actorOrgId
|
||||||
|
}) => {
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
|
|
||||||
|
|||||||
@@ -34,3 +34,124 @@ export type TListApprovalRequestsDTO = {
|
|||||||
authorProjectMembershipId?: string;
|
authorProjectMembershipId?: string;
|
||||||
envSlug?: string;
|
envSlug?: string;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export interface TAccessApprovalRequestServiceFactory {
|
||||||
|
createAccessApprovalRequest: (arg: TCreateAccessApprovalRequestDTO) => Promise<{
|
||||||
|
request: {
|
||||||
|
status: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
policyId: string;
|
||||||
|
isTemporary: boolean;
|
||||||
|
requestedByUserId: string;
|
||||||
|
privilegeId?: string | null | undefined;
|
||||||
|
requestedBy?: string | null | undefined;
|
||||||
|
temporaryRange?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
note?: string | null | undefined;
|
||||||
|
privilegeDeletedAt?: Date | null | undefined;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
listApprovalRequests: (arg: TListApprovalRequestsDTO) => Promise<{
|
||||||
|
requests: {
|
||||||
|
policy: {
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
bypassers: string[];
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
approvals: number;
|
||||||
|
secretPath: string | null | undefined;
|
||||||
|
enforcementLevel: string;
|
||||||
|
allowedSelfApprovals: boolean;
|
||||||
|
envId: string;
|
||||||
|
deletedAt: Date | null | undefined;
|
||||||
|
};
|
||||||
|
projectId: string;
|
||||||
|
environment: string;
|
||||||
|
environmentName: string;
|
||||||
|
requestedByUser: {
|
||||||
|
userId: string;
|
||||||
|
email: string | null | undefined;
|
||||||
|
firstName: string | null | undefined;
|
||||||
|
lastName: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
};
|
||||||
|
privilege: {
|
||||||
|
membershipId: string;
|
||||||
|
userId: string;
|
||||||
|
projectId: string;
|
||||||
|
isTemporary: boolean;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
permissions: unknown;
|
||||||
|
} | null;
|
||||||
|
isApproved: boolean;
|
||||||
|
status: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
policyId: string;
|
||||||
|
isTemporary: boolean;
|
||||||
|
requestedByUserId: string;
|
||||||
|
privilegeId?: string | null | undefined;
|
||||||
|
requestedBy?: string | null | undefined;
|
||||||
|
temporaryRange?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
note?: string | null | undefined;
|
||||||
|
privilegeDeletedAt?: Date | null | undefined;
|
||||||
|
reviewers: {
|
||||||
|
userId: string;
|
||||||
|
status: string;
|
||||||
|
}[];
|
||||||
|
approvers: (
|
||||||
|
| {
|
||||||
|
userId: string | null | undefined;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
userId: string;
|
||||||
|
sequence: number | null | undefined;
|
||||||
|
approvalsRequired: number | null | undefined;
|
||||||
|
email: string | null | undefined;
|
||||||
|
username: string;
|
||||||
|
}
|
||||||
|
)[];
|
||||||
|
bypassers: string[];
|
||||||
|
}[];
|
||||||
|
}>;
|
||||||
|
reviewAccessRequest: (arg: TReviewAccessRequestDTO) => Promise<{
|
||||||
|
id: string;
|
||||||
|
requestId: string;
|
||||||
|
reviewerUserId: string;
|
||||||
|
status: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}>;
|
||||||
|
getCount: (arg: TGetAccessRequestCountDTO) => Promise<{
|
||||||
|
count: {
|
||||||
|
pendingCount: number;
|
||||||
|
finalizedCount: number;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,29 +7,30 @@ import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
|||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionIdentityActions,
|
ProjectPermissionIdentityActions,
|
||||||
ProjectPermissionMemberActions,
|
ProjectPermissionMemberActions,
|
||||||
ProjectPermissionSub
|
ProjectPermissionSub
|
||||||
} from "../permission/project-permission";
|
} from "../permission/project-permission";
|
||||||
import { TAssumeProjectPrivilegeDTO } from "./assume-privilege-types";
|
import { TAssumePrivilegeServiceFactory } from "./assume-privilege-types";
|
||||||
|
|
||||||
type TAssumePrivilegeServiceFactoryDep = {
|
type TAssumePrivilegeServiceFactoryDep = {
|
||||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAssumePrivilegeServiceFactory = ReturnType<typeof assumePrivilegeServiceFactory>;
|
export const assumePrivilegeServiceFactory = ({
|
||||||
|
projectDAL,
|
||||||
export const assumePrivilegeServiceFactory = ({ projectDAL, permissionService }: TAssumePrivilegeServiceFactoryDep) => {
|
permissionService
|
||||||
const assumeProjectPrivileges = async ({
|
}: TAssumePrivilegeServiceFactoryDep): TAssumePrivilegeServiceFactory => {
|
||||||
|
const assumeProjectPrivileges: TAssumePrivilegeServiceFactory["assumeProjectPrivileges"] = async ({
|
||||||
targetActorType,
|
targetActorType,
|
||||||
targetActorId,
|
targetActorId,
|
||||||
projectId,
|
projectId,
|
||||||
actorPermissionDetails,
|
actorPermissionDetails,
|
||||||
tokenVersionId
|
tokenVersionId
|
||||||
}: TAssumeProjectPrivilegeDTO) => {
|
}) => {
|
||||||
const project = await projectDAL.findById(projectId);
|
const project = await projectDAL.findById(projectId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with ID '${projectId}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with ID '${projectId}' not found` });
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
@@ -79,7 +80,10 @@ export const assumePrivilegeServiceFactory = ({ projectDAL, permissionService }:
|
|||||||
return { actorType: targetActorType, actorId: targetActorId, projectId, assumePrivilegesToken };
|
return { actorType: targetActorType, actorId: targetActorId, projectId, assumePrivilegesToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
const verifyAssumePrivilegeToken = (token: string, tokenVersionId: string) => {
|
const verifyAssumePrivilegeToken: TAssumePrivilegeServiceFactory["verifyAssumePrivilegeToken"] = (
|
||||||
|
token,
|
||||||
|
tokenVersionId
|
||||||
|
) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const decodedToken = jwt.verify(token, appCfg.AUTH_SECRET) as {
|
const decodedToken = jwt.verify(token, appCfg.AUTH_SECRET) as {
|
||||||
tokenVersionId: string;
|
tokenVersionId: string;
|
||||||
|
|||||||
@@ -8,3 +8,28 @@ export type TAssumeProjectPrivilegeDTO = {
|
|||||||
tokenVersionId: string;
|
tokenVersionId: string;
|
||||||
actorPermissionDetails: OrgServiceActor;
|
actorPermissionDetails: OrgServiceActor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface TAssumePrivilegeServiceFactory {
|
||||||
|
assumeProjectPrivileges: ({
|
||||||
|
targetActorType,
|
||||||
|
targetActorId,
|
||||||
|
projectId,
|
||||||
|
actorPermissionDetails,
|
||||||
|
tokenVersionId
|
||||||
|
}: TAssumeProjectPrivilegeDTO) => Promise<{
|
||||||
|
actorType: ActorType.USER | ActorType.IDENTITY;
|
||||||
|
actorId: string;
|
||||||
|
projectId: string;
|
||||||
|
assumePrivilegesToken: string;
|
||||||
|
}>;
|
||||||
|
verifyAssumePrivilegeToken: (
|
||||||
|
token: string,
|
||||||
|
tokenVersionId: string
|
||||||
|
) => {
|
||||||
|
tokenVersionId: string;
|
||||||
|
projectId: string;
|
||||||
|
requesterId: string;
|
||||||
|
actorType: ActorType;
|
||||||
|
actorId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TAuditLogStreamDALFactory = ReturnType<typeof auditLogStreamDALFactory>;
|
export type TAuditLogStreamDALFactory = TOrmify<TableName.AuditLogStream>;
|
||||||
|
|
||||||
export const auditLogStreamDALFactory = (db: TDbClient) => {
|
export const auditLogStreamDALFactory = (db: TDbClient): TAuditLogStreamDALFactory => {
|
||||||
const orm = ormify(db, TableName.AuditLogStream);
|
const orm = ormify(db, TableName.AuditLogStream);
|
||||||
|
|
||||||
return orm;
|
return orm;
|
||||||
|
|||||||
@@ -11,16 +11,9 @@ import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
|||||||
import { AUDIT_LOG_STREAM_TIMEOUT } from "../audit-log/audit-log-queue";
|
import { AUDIT_LOG_STREAM_TIMEOUT } from "../audit-log/audit-log-queue";
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TAuditLogStreamDALFactory } from "./audit-log-stream-dal";
|
import { TAuditLogStreamDALFactory } from "./audit-log-stream-dal";
|
||||||
import {
|
import { LogStreamHeaders, TAuditLogStreamServiceFactory } from "./audit-log-stream-types";
|
||||||
LogStreamHeaders,
|
|
||||||
TCreateAuditLogStreamDTO,
|
|
||||||
TDeleteAuditLogStreamDTO,
|
|
||||||
TGetDetailsAuditLogStreamDTO,
|
|
||||||
TListAuditLogStreamDTO,
|
|
||||||
TUpdateAuditLogStreamDTO
|
|
||||||
} from "./audit-log-stream-types";
|
|
||||||
|
|
||||||
type TAuditLogStreamServiceFactoryDep = {
|
type TAuditLogStreamServiceFactoryDep = {
|
||||||
auditLogStreamDAL: TAuditLogStreamDALFactory;
|
auditLogStreamDAL: TAuditLogStreamDALFactory;
|
||||||
@@ -28,21 +21,19 @@ type TAuditLogStreamServiceFactoryDep = {
|
|||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAuditLogStreamServiceFactory = ReturnType<typeof auditLogStreamServiceFactory>;
|
|
||||||
|
|
||||||
export const auditLogStreamServiceFactory = ({
|
export const auditLogStreamServiceFactory = ({
|
||||||
auditLogStreamDAL,
|
auditLogStreamDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
licenseService
|
licenseService
|
||||||
}: TAuditLogStreamServiceFactoryDep) => {
|
}: TAuditLogStreamServiceFactoryDep): TAuditLogStreamServiceFactory => {
|
||||||
const create = async ({
|
const create: TAuditLogStreamServiceFactory["create"] = async ({
|
||||||
url,
|
url,
|
||||||
actor,
|
actor,
|
||||||
headers = [],
|
headers = [],
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TCreateAuditLogStreamDTO) => {
|
}) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID attached to authentication token" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID attached to authentication token" });
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
@@ -110,7 +101,7 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
return logStream;
|
return logStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateById = async ({
|
const updateById: TAuditLogStreamServiceFactory["updateById"] = async ({
|
||||||
id,
|
id,
|
||||||
url,
|
url,
|
||||||
actor,
|
actor,
|
||||||
@@ -118,7 +109,7 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TUpdateAuditLogStreamDTO) => {
|
}) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID attached to authentication token" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID attached to authentication token" });
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
@@ -175,7 +166,13 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
return updatedLogStream;
|
return updatedLogStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteById = async ({ id, actor, actorId, actorOrgId, actorAuthMethod }: TDeleteAuditLogStreamDTO) => {
|
const deleteById: TAuditLogStreamServiceFactory["deleteById"] = async ({
|
||||||
|
id,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod
|
||||||
|
}) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID attached to authentication token" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID attached to authentication token" });
|
||||||
|
|
||||||
const logStream = await auditLogStreamDAL.findById(id);
|
const logStream = await auditLogStreamDAL.findById(id);
|
||||||
@@ -189,7 +186,13 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
return deletedLogStream;
|
return deletedLogStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getById = async ({ id, actor, actorId, actorOrgId, actorAuthMethod }: TGetDetailsAuditLogStreamDTO) => {
|
const getById: TAuditLogStreamServiceFactory["getById"] = async ({
|
||||||
|
id,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod
|
||||||
|
}) => {
|
||||||
const logStream = await auditLogStreamDAL.findById(id);
|
const logStream = await auditLogStreamDAL.findById(id);
|
||||||
if (!logStream) throw new NotFoundError({ message: `Audit log stream with ID '${id}' not found` });
|
if (!logStream) throw new NotFoundError({ message: `Audit log stream with ID '${id}' not found` });
|
||||||
|
|
||||||
@@ -212,7 +215,7 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
return { ...logStream, headers };
|
return { ...logStream, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const list = async ({ actor, actorId, actorOrgId, actorAuthMethod }: TListAuditLogStreamDTO) => {
|
const list: TAuditLogStreamServiceFactory["list"] = async ({ actor, actorId, actorOrgId, actorAuthMethod }) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { TAuditLogStreams } from "@app/db/schemas";
|
||||||
import { TOrgPermission } from "@app/lib/types";
|
import { TOrgPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export type LogStreamHeaders = {
|
export type LogStreamHeaders = {
|
||||||
@@ -25,3 +26,23 @@ export type TListAuditLogStreamDTO = Omit<TOrgPermission, "orgId">;
|
|||||||
export type TGetDetailsAuditLogStreamDTO = Omit<TOrgPermission, "orgId"> & {
|
export type TGetDetailsAuditLogStreamDTO = Omit<TOrgPermission, "orgId"> & {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TAuditLogStreamServiceFactory = {
|
||||||
|
create: (arg: TCreateAuditLogStreamDTO) => Promise<TAuditLogStreams>;
|
||||||
|
updateById: (arg: TUpdateAuditLogStreamDTO) => Promise<TAuditLogStreams>;
|
||||||
|
deleteById: (arg: TDeleteAuditLogStreamDTO) => Promise<TAuditLogStreams>;
|
||||||
|
getById: (arg: TGetDetailsAuditLogStreamDTO) => Promise<{
|
||||||
|
headers: LogStreamHeaders[] | undefined;
|
||||||
|
orgId: string;
|
||||||
|
url: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
encryptedHeadersCiphertext?: string | null | undefined;
|
||||||
|
encryptedHeadersIV?: string | null | undefined;
|
||||||
|
encryptedHeadersTag?: string | null | undefined;
|
||||||
|
encryptedHeadersAlgorithm?: string | null | undefined;
|
||||||
|
encryptedHeadersKeyEncoding?: string | null | undefined;
|
||||||
|
}>;
|
||||||
|
list: (arg: TListAuditLogStreamDTO) => Promise<TAuditLogStreams[]>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,16 +2,29 @@
|
|||||||
import knex from "knex";
|
import knex from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName, TAuditLogs } from "@app/db/schemas";
|
||||||
import { DatabaseError, GatewayTimeoutError } from "@app/lib/errors";
|
import { DatabaseError, GatewayTimeoutError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
import { ormify, selectAllTableCols, TOrmify } from "@app/lib/knex";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { QueueName } from "@app/queue";
|
import { QueueName } from "@app/queue";
|
||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
import { EventType, filterableSecretEvents } from "./audit-log-types";
|
import { EventType, filterableSecretEvents } from "./audit-log-types";
|
||||||
|
|
||||||
export type TAuditLogDALFactory = ReturnType<typeof auditLogDALFactory>;
|
export interface TAuditLogDALFactory extends Omit<TOrmify<TableName.AuditLog>, "find"> {
|
||||||
|
pruneAuditLog: (tx?: knex.Knex) => Promise<void>;
|
||||||
|
find: (
|
||||||
|
arg: Omit<TFindQuery, "actor" | "eventType"> & {
|
||||||
|
actorId?: string | undefined;
|
||||||
|
actorType?: ActorType | undefined;
|
||||||
|
secretPath?: string | undefined;
|
||||||
|
secretKey?: string | undefined;
|
||||||
|
eventType?: EventType[] | undefined;
|
||||||
|
eventMetadata?: Record<string, string> | undefined;
|
||||||
|
},
|
||||||
|
tx?: knex.Knex
|
||||||
|
) => Promise<TAuditLogs[]>;
|
||||||
|
}
|
||||||
|
|
||||||
type TFindQuery = {
|
type TFindQuery = {
|
||||||
actor?: string;
|
actor?: string;
|
||||||
@@ -29,7 +42,7 @@ type TFindQuery = {
|
|||||||
export const auditLogDALFactory = (db: TDbClient) => {
|
export const auditLogDALFactory = (db: TDbClient) => {
|
||||||
const auditLogOrm = ormify(db, TableName.AuditLog);
|
const auditLogOrm = ormify(db, TableName.AuditLog);
|
||||||
|
|
||||||
const find = async (
|
const find: TAuditLogDALFactory["find"] = async (
|
||||||
{
|
{
|
||||||
orgId,
|
orgId,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -45,15 +58,8 @@ export const auditLogDALFactory = (db: TDbClient) => {
|
|||||||
secretKey,
|
secretKey,
|
||||||
eventType,
|
eventType,
|
||||||
eventMetadata
|
eventMetadata
|
||||||
}: Omit<TFindQuery, "actor" | "eventType"> & {
|
|
||||||
actorId?: string;
|
|
||||||
actorType?: ActorType;
|
|
||||||
secretPath?: string;
|
|
||||||
secretKey?: string;
|
|
||||||
eventType?: EventType[];
|
|
||||||
eventMetadata?: Record<string, string>;
|
|
||||||
},
|
},
|
||||||
tx?: knex.Knex
|
tx
|
||||||
) => {
|
) => {
|
||||||
if (!orgId && !projectId) {
|
if (!orgId && !projectId) {
|
||||||
throw new Error("Either orgId or projectId must be provided");
|
throw new Error("Either orgId or projectId must be provided");
|
||||||
@@ -154,7 +160,7 @@ export const auditLogDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// delete all audit log that have expired
|
// delete all audit log that have expired
|
||||||
const pruneAuditLog = async (tx?: knex.Knex) => {
|
const pruneAuditLog: TAuditLogDALFactory["pruneAuditLog"] = async (tx) => {
|
||||||
const AUDIT_LOG_PRUNE_BATCH_SIZE = 10000;
|
const AUDIT_LOG_PRUNE_BATCH_SIZE = 10000;
|
||||||
const MAX_RETRY_ON_FAILURE = 3;
|
const MAX_RETRY_ON_FAILURE = 3;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ type TAuditLogQueueServiceFactoryDep = {
|
|||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAuditLogQueueServiceFactory = Awaited<ReturnType<typeof auditLogQueueServiceFactory>>;
|
export type TAuditLogQueueServiceFactory = {
|
||||||
|
pushToLog: (data: TCreateAuditLogDTO) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
// keep this timeout 5s it must be fast because else the queue will take time to finish
|
// keep this timeout 5s it must be fast because else the queue will take time to finish
|
||||||
// audit log is a crowded queue thus needs to be fast
|
// audit log is a crowded queue thus needs to be fast
|
||||||
@@ -33,7 +35,7 @@ export const auditLogQueueServiceFactory = async ({
|
|||||||
projectDAL,
|
projectDAL,
|
||||||
licenseService,
|
licenseService,
|
||||||
auditLogStreamDAL
|
auditLogStreamDAL
|
||||||
}: TAuditLogQueueServiceFactoryDep) => {
|
}: TAuditLogQueueServiceFactoryDep): Promise<TAuditLogQueueServiceFactory> => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const pushToLog = async (data: TCreateAuditLogDTO) => {
|
const pushToLog = async (data: TCreateAuditLogDTO) => {
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import { BadRequestError } from "@app/lib/errors";
|
|||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||||
import { TAuditLogDALFactory } from "./audit-log-dal";
|
import { TAuditLogDALFactory } from "./audit-log-dal";
|
||||||
import { TAuditLogQueueServiceFactory } from "./audit-log-queue";
|
import { TAuditLogQueueServiceFactory } from "./audit-log-queue";
|
||||||
import { EventType, TCreateAuditLogDTO, TListProjectAuditLogDTO } from "./audit-log-types";
|
import { EventType, TAuditLogServiceFactory } from "./audit-log-types";
|
||||||
|
|
||||||
type TAuditLogServiceFactoryDep = {
|
type TAuditLogServiceFactoryDep = {
|
||||||
auditLogDAL: TAuditLogDALFactory;
|
auditLogDAL: TAuditLogDALFactory;
|
||||||
@@ -19,14 +19,18 @@ type TAuditLogServiceFactoryDep = {
|
|||||||
auditLogQueue: TAuditLogQueueServiceFactory;
|
auditLogQueue: TAuditLogQueueServiceFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAuditLogServiceFactory = ReturnType<typeof auditLogServiceFactory>;
|
|
||||||
|
|
||||||
export const auditLogServiceFactory = ({
|
export const auditLogServiceFactory = ({
|
||||||
auditLogDAL,
|
auditLogDAL,
|
||||||
auditLogQueue,
|
auditLogQueue,
|
||||||
permissionService
|
permissionService
|
||||||
}: TAuditLogServiceFactoryDep) => {
|
}: TAuditLogServiceFactoryDep): TAuditLogServiceFactory => {
|
||||||
const listAuditLogs = async ({ actorAuthMethod, actorId, actorOrgId, actor, filter }: TListProjectAuditLogDTO) => {
|
const listAuditLogs: TAuditLogServiceFactory["listAuditLogs"] = async ({
|
||||||
|
actorAuthMethod,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actor,
|
||||||
|
filter
|
||||||
|
}) => {
|
||||||
// Filter logs for specific project
|
// Filter logs for specific project
|
||||||
if (filter.projectId) {
|
if (filter.projectId) {
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
@@ -75,7 +79,7 @@ export const auditLogServiceFactory = ({
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const createAuditLog = async (data: TCreateAuditLogDTO) => {
|
const createAuditLog: TAuditLogServiceFactory["createAuditLog"] = async (data) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
if (appCfg.DISABLE_AUDIT_LOG_GENERATION) {
|
if (appCfg.DISABLE_AUDIT_LOG_GENERATION) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -82,6 +82,32 @@ export type TCreateAuditLogDTO = {
|
|||||||
projectId?: string;
|
projectId?: string;
|
||||||
} & BaseAuthData;
|
} & BaseAuthData;
|
||||||
|
|
||||||
|
export type TAuditLogServiceFactory = {
|
||||||
|
createAuditLog: (data: TCreateAuditLogDTO) => Promise<void>;
|
||||||
|
listAuditLogs: (arg: TListProjectAuditLogDTO) => Promise<
|
||||||
|
{
|
||||||
|
event: {
|
||||||
|
type: string;
|
||||||
|
metadata: unknown;
|
||||||
|
};
|
||||||
|
actor: {
|
||||||
|
type: string;
|
||||||
|
metadata: unknown;
|
||||||
|
};
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
orgId?: string | null | undefined;
|
||||||
|
userAgent?: string | null | undefined;
|
||||||
|
expiresAt?: Date | null | undefined;
|
||||||
|
ipAddress?: string | null | undefined;
|
||||||
|
userAgentType?: string | null | undefined;
|
||||||
|
projectId?: string | null | undefined;
|
||||||
|
projectName?: string | null | undefined;
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
export type AuditLogInfo = Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">;
|
export type AuditLogInfo = Pick<TCreateAuditLogDTO, "userAgent" | "userAgentType" | "ipAddress" | "actor">;
|
||||||
|
|
||||||
interface BaseAuthData {
|
interface BaseAuthData {
|
||||||
@@ -754,6 +780,7 @@ interface CreateIdentityEvent {
|
|||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
hasDeleteProtection: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,6 +789,7 @@ interface UpdateIdentityEvent {
|
|||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
hasDeleteProtection?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TCertificateAuthorityCrlDALFactory = ReturnType<typeof certificateAuthorityCrlDALFactory>;
|
export type TCertificateAuthorityCrlDALFactory = TOrmify<TableName.CertificateAuthorityCrl>;
|
||||||
|
|
||||||
export const certificateAuthorityCrlDALFactory = (db: TDbClient) => {
|
export const certificateAuthorityCrlDALFactory = (db: TDbClient): TCertificateAuthorityCrlDALFactory => {
|
||||||
const caCrlOrm = ormify(db, TableName.CertificateAuthorityCrl);
|
const caCrlOrm = ormify(db, TableName.CertificateAuthorityCrl);
|
||||||
return caCrlOrm;
|
return caCrlOrm;
|
||||||
};
|
};
|
||||||
|
|||||||
+11
-7
@@ -3,7 +3,7 @@ import * as x509 from "@peculiar/x509";
|
|||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
|
import { TCertificateAuthorityCrlDALFactory } from "@app/ee/services/certificate-authority-crl/certificate-authority-crl-dal";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { NotFoundError } from "@app/lib/errors";
|
import { NotFoundError } from "@app/lib/errors";
|
||||||
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal";
|
||||||
@@ -12,7 +12,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
|||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
||||||
|
|
||||||
import { TGetCaCrlsDTO, TGetCrlById } from "./certificate-authority-crl-types";
|
import { TCertificateAuthorityCrlServiceFactory } from "./certificate-authority-crl-types";
|
||||||
|
|
||||||
type TCertificateAuthorityCrlServiceFactoryDep = {
|
type TCertificateAuthorityCrlServiceFactoryDep = {
|
||||||
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findByIdWithAssociatedCa">;
|
certificateAuthorityDAL: Pick<TCertificateAuthorityDALFactory, "findByIdWithAssociatedCa">;
|
||||||
@@ -22,19 +22,17 @@ type TCertificateAuthorityCrlServiceFactoryDep = {
|
|||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCertificateAuthorityCrlServiceFactory = ReturnType<typeof certificateAuthorityCrlServiceFactory>;
|
|
||||||
|
|
||||||
export const certificateAuthorityCrlServiceFactory = ({
|
export const certificateAuthorityCrlServiceFactory = ({
|
||||||
certificateAuthorityDAL,
|
certificateAuthorityDAL,
|
||||||
certificateAuthorityCrlDAL,
|
certificateAuthorityCrlDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
kmsService,
|
kmsService,
|
||||||
permissionService // licenseService
|
permissionService // licenseService
|
||||||
}: TCertificateAuthorityCrlServiceFactoryDep) => {
|
}: TCertificateAuthorityCrlServiceFactoryDep): TCertificateAuthorityCrlServiceFactory => {
|
||||||
/**
|
/**
|
||||||
* Return CRL with id [crlId]
|
* Return CRL with id [crlId]
|
||||||
*/
|
*/
|
||||||
const getCrlById = async (crlId: TGetCrlById) => {
|
const getCrlById: TCertificateAuthorityCrlServiceFactory["getCrlById"] = async (crlId) => {
|
||||||
const caCrl = await certificateAuthorityCrlDAL.findById(crlId);
|
const caCrl = await certificateAuthorityCrlDAL.findById(crlId);
|
||||||
if (!caCrl) throw new NotFoundError({ message: `CRL with ID '${crlId}' not found` });
|
if (!caCrl) throw new NotFoundError({ message: `CRL with ID '${crlId}' not found` });
|
||||||
|
|
||||||
@@ -65,7 +63,13 @@ export const certificateAuthorityCrlServiceFactory = ({
|
|||||||
/**
|
/**
|
||||||
* Returns a list of CRL ids for CA with id [caId]
|
* Returns a list of CRL ids for CA with id [caId]
|
||||||
*/
|
*/
|
||||||
const getCaCrls = async ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaCrlsDTO) => {
|
const getCaCrls: TCertificateAuthorityCrlServiceFactory["getCaCrls"] = async ({
|
||||||
|
caId,
|
||||||
|
actorId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actor,
|
||||||
|
actorOrgId
|
||||||
|
}) => {
|
||||||
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
|
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(caId);
|
||||||
if (!ca?.internalCa?.id) throw new NotFoundError({ message: `Internal CA with ID '${caId}' not found` });
|
if (!ca?.internalCa?.id) throw new NotFoundError({ message: `Internal CA with ID '${caId}' not found` });
|
||||||
|
|
||||||
|
|||||||
@@ -5,3 +5,137 @@ export type TGetCrlById = string;
|
|||||||
export type TGetCaCrlsDTO = {
|
export type TGetCaCrlsDTO = {
|
||||||
caId: string;
|
caId: string;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TCertificateAuthorityCrlServiceFactory = {
|
||||||
|
getCrlById: (crlId: TGetCrlById) => Promise<{
|
||||||
|
ca: {
|
||||||
|
readonly requireTemplateForIssuance: boolean;
|
||||||
|
readonly internalCa:
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
parentCaId: string | null | undefined;
|
||||||
|
type: string;
|
||||||
|
friendlyName: string;
|
||||||
|
organization: string;
|
||||||
|
ou: string;
|
||||||
|
country: string;
|
||||||
|
province: string;
|
||||||
|
locality: string;
|
||||||
|
commonName: string;
|
||||||
|
dn: string;
|
||||||
|
serialNumber: string | null | undefined;
|
||||||
|
maxPathLength: number | null | undefined;
|
||||||
|
keyAlgorithm: string;
|
||||||
|
notBefore: string | undefined;
|
||||||
|
notAfter: string | undefined;
|
||||||
|
activeCaCertId: string | null | undefined;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
readonly externalCa:
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
configuration: unknown;
|
||||||
|
dnsAppConnectionId: string | null | undefined;
|
||||||
|
appConnectionId: string | null | undefined;
|
||||||
|
credentials: Buffer | null | undefined;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
readonly name: string;
|
||||||
|
readonly status: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly createdAt: Date;
|
||||||
|
readonly updatedAt: Date;
|
||||||
|
readonly projectId: string;
|
||||||
|
readonly enableDirectIssuance: boolean;
|
||||||
|
readonly parentCaId: string | null | undefined;
|
||||||
|
readonly type: string;
|
||||||
|
readonly friendlyName: string;
|
||||||
|
readonly organization: string;
|
||||||
|
readonly ou: string;
|
||||||
|
readonly country: string;
|
||||||
|
readonly province: string;
|
||||||
|
readonly locality: string;
|
||||||
|
readonly commonName: string;
|
||||||
|
readonly dn: string;
|
||||||
|
readonly serialNumber: string | null | undefined;
|
||||||
|
readonly maxPathLength: number | null | undefined;
|
||||||
|
readonly keyAlgorithm: string;
|
||||||
|
readonly notBefore: string | undefined;
|
||||||
|
readonly notAfter: string | undefined;
|
||||||
|
readonly activeCaCertId: string | null | undefined;
|
||||||
|
};
|
||||||
|
caCrl: {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
caId: string;
|
||||||
|
caSecretId: string;
|
||||||
|
encryptedCrl: Buffer;
|
||||||
|
};
|
||||||
|
crl: ArrayBuffer;
|
||||||
|
}>;
|
||||||
|
getCaCrls: ({ caId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCaCrlsDTO) => Promise<{
|
||||||
|
ca: {
|
||||||
|
readonly requireTemplateForIssuance: boolean;
|
||||||
|
readonly internalCa:
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
parentCaId: string | null | undefined;
|
||||||
|
type: string;
|
||||||
|
friendlyName: string;
|
||||||
|
organization: string;
|
||||||
|
ou: string;
|
||||||
|
country: string;
|
||||||
|
province: string;
|
||||||
|
locality: string;
|
||||||
|
commonName: string;
|
||||||
|
dn: string;
|
||||||
|
serialNumber: string | null | undefined;
|
||||||
|
maxPathLength: number | null | undefined;
|
||||||
|
keyAlgorithm: string;
|
||||||
|
notBefore: string | undefined;
|
||||||
|
notAfter: string | undefined;
|
||||||
|
activeCaCertId: string | null | undefined;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
readonly externalCa:
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
configuration: unknown;
|
||||||
|
dnsAppConnectionId: string | null | undefined;
|
||||||
|
appConnectionId: string | null | undefined;
|
||||||
|
credentials: Buffer | null | undefined;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
readonly name: string;
|
||||||
|
readonly status: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly createdAt: Date;
|
||||||
|
readonly updatedAt: Date;
|
||||||
|
readonly projectId: string;
|
||||||
|
readonly enableDirectIssuance: boolean;
|
||||||
|
readonly parentCaId: string | null | undefined;
|
||||||
|
readonly type: string;
|
||||||
|
readonly friendlyName: string;
|
||||||
|
readonly organization: string;
|
||||||
|
readonly ou: string;
|
||||||
|
readonly country: string;
|
||||||
|
readonly province: string;
|
||||||
|
readonly locality: string;
|
||||||
|
readonly commonName: string;
|
||||||
|
readonly dn: string;
|
||||||
|
readonly serialNumber: string | null | undefined;
|
||||||
|
readonly maxPathLength: number | null | undefined;
|
||||||
|
readonly keyAlgorithm: string;
|
||||||
|
readonly notBefore: string | undefined;
|
||||||
|
readonly notAfter: string | undefined;
|
||||||
|
readonly activeCaCertId: string | null | undefined;
|
||||||
|
};
|
||||||
|
crls: {
|
||||||
|
id: string;
|
||||||
|
crl: string;
|
||||||
|
}[];
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import RE2 from "re2";
|
|||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionDynamicSecretActions,
|
ProjectPermissionDynamicSecretActions,
|
||||||
ProjectPermissionSub
|
ProjectPermissionSub
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability";
|
|||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionDynamicSecretActions,
|
ProjectPermissionDynamicSecretActions,
|
||||||
ProjectPermissionSub
|
ProjectPermissionSub
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { KmsDataKey, KmsKeyUsage } from "@app/services/kms/kms-types";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TExternalKmsDALFactory } from "./external-kms-dal";
|
import { TExternalKmsDALFactory } from "./external-kms-dal";
|
||||||
import {
|
import {
|
||||||
TCreateExternalKmsDTO,
|
TCreateExternalKmsDTO,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { KmsDataKey } from "@app/services/kms/kms-types";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionGatewayActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionGatewayActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TGatewayDALFactory } from "./gateway-dal";
|
import { TGatewayDALFactory } from "./gateway-dal";
|
||||||
import {
|
import {
|
||||||
TExchangeAllocatedRelayAddressDTO,
|
TExchangeAllocatedRelayAddressDTO,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { TGroupDALFactory } from "../group/group-dal";
|
|||||||
import { TUserGroupMembershipDALFactory } from "../group/user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "../group/user-group-membership-dal";
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TGithubOrgSyncDALFactory } from "./github-org-sync-dal";
|
import { TGithubOrgSyncDALFactory } from "./github-org-sync-dal";
|
||||||
import { TCreateGithubOrgSyncDTO, TDeleteGithubOrgSyncDTO, TUpdateGithubOrgSyncDTO } from "./github-org-sync-types";
|
import { TCreateGithubOrgSyncDTO, TDeleteGithubOrgSyncDTO, TUpdateGithubOrgSyncDTO } from "./github-org-sync-types";
|
||||||
|
|
||||||
|
|||||||
@@ -169,11 +169,29 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findById = async (id: string, tx?: Knex) => {
|
||||||
|
try {
|
||||||
|
const doc = await (tx || db.replicaNode())(TableName.Groups)
|
||||||
|
.leftJoin(TableName.OrgRoles, `${TableName.Groups}.roleId`, `${TableName.OrgRoles}.id`)
|
||||||
|
.where(`${TableName.Groups}.id`, id)
|
||||||
|
.select(
|
||||||
|
selectAllTableCols(TableName.Groups),
|
||||||
|
db.ref("slug").as("customRoleSlug").withSchema(TableName.OrgRoles)
|
||||||
|
)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Find by id" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
...groupOrm,
|
||||||
findGroups,
|
findGroups,
|
||||||
findByOrgId,
|
findByOrgId,
|
||||||
findAllGroupPossibleMembers,
|
findAllGroupPossibleMembers,
|
||||||
findGroupsByProjectId,
|
findGroupsByProjectId,
|
||||||
...groupOrm
|
findById
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { TUserDALFactory } from "@app/services/user/user-dal";
|
|||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionGroupActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionGroupActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TGroupDALFactory } from "./group-dal";
|
import { TGroupDALFactory } from "./group-dal";
|
||||||
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "./group-fns";
|
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "./group-fns";
|
||||||
import {
|
import {
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import { TIdentityProjectDALFactory } from "@app/services/identity-project/ident
|
|||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { ProjectPermissionIdentityActions, ProjectPermissionSub } from "../permission/project-permission";
|
import { ProjectPermissionIdentityActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||||
import { TIdentityProjectAdditionalPrivilegeV2DALFactory } from "./identity-project-additional-privilege-v2-dal";
|
import { TIdentityProjectAdditionalPrivilegeV2DALFactory } from "./identity-project-additional-privilege-v2-dal";
|
||||||
import {
|
import {
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ import { TIdentityProjectDALFactory } from "@app/services/identity-project/ident
|
|||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionIdentityActions,
|
ProjectPermissionIdentityActions,
|
||||||
ProjectPermissionSet,
|
ProjectPermissionSet,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { KmsKeyUsage } from "@app/services/kms/kms-types";
|
|||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TKmipClientDALFactory } from "./kmip-client-dal";
|
import { TKmipClientDALFactory } from "./kmip-client-dal";
|
||||||
import { KmipPermission } from "./kmip-enum";
|
import { KmipPermission } from "./kmip-enum";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { KmsDataKey } from "@app/services/kms/kms-types";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionKmipActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { ProjectPermissionKmipActions, ProjectPermissionSub } from "../permission/project-permission";
|
import { ProjectPermissionKmipActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||||
import { TKmipClientCertificateDALFactory } from "./kmip-client-certificate-dal";
|
import { TKmipClientCertificateDALFactory } from "./kmip-client-certificate-dal";
|
||||||
import { TKmipClientDALFactory } from "./kmip-client-dal";
|
import { TKmipClientDALFactory } from "./kmip-client-dal";
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { UserAliasType } from "@app/services/user-alias/user-alias-types";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TLdapConfigDALFactory } from "./ldap-config-dal";
|
import { TLdapConfigDALFactory } from "./ldap-config-dal";
|
||||||
import {
|
import {
|
||||||
TCreateLdapCfgDTO,
|
TCreateLdapCfgDTO,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { TOrgDALFactory } from "@app/services/org/org-dal";
|
|||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { OrgPermissionBillingActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionBillingActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { BillingPlanRows, BillingPlanTableHead } from "./licence-enums";
|
import { BillingPlanRows, BillingPlanTableHead } from "./licence-enums";
|
||||||
import { TLicenseDALFactory } from "./license-dal";
|
import { TLicenseDALFactory } from "./license-dal";
|
||||||
import { getDefaultOnPremFeatures, setupLicenseRequestWithStore } from "./license-fns";
|
import { getDefaultOnPremFeatures, setupLicenseRequestWithStore } from "./license-fns";
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ import { Issuer, Issuer as OpenIdIssuer, Strategy as OpenIdStrategy, TokenSet }
|
|||||||
|
|
||||||
import { OrgMembershipStatus, TableName, TUsers } from "@app/db/schemas";
|
import { OrgMembershipStatus, TableName, TUsers } from "@app/db/schemas";
|
||||||
import { TOidcConfigsUpdate } from "@app/db/schemas/oidc-configs";
|
import { TOidcConfigsUpdate } from "@app/db/schemas/oidc-configs";
|
||||||
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
|
||||||
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
|
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
|
||||||
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError, OidcAuthError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError, OidcAuthError } from "@app/lib/errors";
|
||||||
import { OrgServiceActor } from "@app/lib/types";
|
import { OrgServiceActor } from "@app/lib/types";
|
||||||
|
|||||||
@@ -6,16 +6,312 @@ import {
|
|||||||
OrgMembershipRole,
|
OrgMembershipRole,
|
||||||
OrgMembershipsSchema,
|
OrgMembershipsSchema,
|
||||||
TableName,
|
TableName,
|
||||||
|
TIdentityOrgMemberships,
|
||||||
TProjectRoles,
|
TProjectRoles,
|
||||||
TProjects
|
TProjects
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TPermissionDALFactory = ReturnType<typeof permissionDALFactory>;
|
export interface TPermissionDALFactory {
|
||||||
|
getOrgPermission: (
|
||||||
|
userId: string,
|
||||||
|
orgId: string
|
||||||
|
) => Promise<
|
||||||
|
{
|
||||||
|
status: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
role: string;
|
||||||
|
isActive: boolean;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
bypassOrgAuthEnabled: boolean;
|
||||||
|
permissions?: unknown;
|
||||||
|
userId?: string | null | undefined;
|
||||||
|
roleId?: string | null | undefined;
|
||||||
|
inviteEmail?: string | null | undefined;
|
||||||
|
projectFavorites?: string[] | null | undefined;
|
||||||
|
customRoleSlug?: string | null | undefined;
|
||||||
|
orgAuthEnforced?: boolean | null | undefined;
|
||||||
|
} & {
|
||||||
|
groups: {
|
||||||
|
id: string;
|
||||||
|
updatedAt: Date;
|
||||||
|
createdAt: Date;
|
||||||
|
role: string;
|
||||||
|
roleId: string | null | undefined;
|
||||||
|
customRolePermission: unknown;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
orgId: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
getOrgIdentityPermission: (
|
||||||
|
identityId: string,
|
||||||
|
orgId: string
|
||||||
|
) => Promise<
|
||||||
|
| (TIdentityOrgMemberships & {
|
||||||
|
orgAuthEnforced: boolean | null | undefined;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
permissions?: unknown;
|
||||||
|
})
|
||||||
|
| undefined
|
||||||
|
>;
|
||||||
|
getProjectPermission: (
|
||||||
|
userId: string,
|
||||||
|
projectId: string
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
roles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
additionalPrivileges: {
|
||||||
|
id: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
orgId: string;
|
||||||
|
orgAuthEnforced: boolean | null | undefined;
|
||||||
|
orgRole: OrgMembershipRole;
|
||||||
|
userId: string;
|
||||||
|
projectId: string;
|
||||||
|
username: string;
|
||||||
|
projectType: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
bypassOrgAuthEnabled: boolean;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
userGroupRoles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
projecMembershiptRoles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
>;
|
||||||
|
getProjectIdentityPermission: (
|
||||||
|
identityId: string,
|
||||||
|
projectId: string
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
roles: {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
isTemporary: boolean;
|
||||||
|
role: string;
|
||||||
|
projectMembershipId: string;
|
||||||
|
temporaryRange?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
customRoleId?: string | null | undefined;
|
||||||
|
temporaryMode?: string | null | undefined;
|
||||||
|
temporaryAccessStartTime?: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime?: Date | null | undefined;
|
||||||
|
customRoleSlug?: string | null | undefined;
|
||||||
|
}[];
|
||||||
|
additionalPrivileges: {
|
||||||
|
id: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
id: string;
|
||||||
|
identityId: string;
|
||||||
|
username: string;
|
||||||
|
projectId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
orgId: string;
|
||||||
|
projectType: string;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
orgAuthEnforced: boolean;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
>;
|
||||||
|
getProjectUserPermissions: (projectId: string) => Promise<
|
||||||
|
{
|
||||||
|
roles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
additionalPrivileges: {
|
||||||
|
id: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
orgId: string;
|
||||||
|
orgAuthEnforced: boolean | null | undefined;
|
||||||
|
userId: string;
|
||||||
|
projectId: string;
|
||||||
|
username: string;
|
||||||
|
projectType: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
userGroupRoles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
projectMembershipRoles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
getProjectIdentityPermissions: (projectId: string) => Promise<
|
||||||
|
{
|
||||||
|
roles: {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
isTemporary: boolean;
|
||||||
|
role: string;
|
||||||
|
projectMembershipId: string;
|
||||||
|
temporaryRange?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
customRoleId?: string | null | undefined;
|
||||||
|
temporaryMode?: string | null | undefined;
|
||||||
|
temporaryAccessStartTime?: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime?: Date | null | undefined;
|
||||||
|
customRoleSlug?: string | null | undefined;
|
||||||
|
}[];
|
||||||
|
additionalPrivileges: {
|
||||||
|
id: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
id: string;
|
||||||
|
identityId: string;
|
||||||
|
username: string;
|
||||||
|
projectId: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
orgId: string;
|
||||||
|
projectType: string;
|
||||||
|
orgAuthEnforced: boolean;
|
||||||
|
metadata: {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
getProjectGroupPermissions: (
|
||||||
|
projectId: string,
|
||||||
|
filterGroupId?: string
|
||||||
|
) => Promise<
|
||||||
|
{
|
||||||
|
roles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
groupId: string;
|
||||||
|
username: string;
|
||||||
|
id: string;
|
||||||
|
groupRoles: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
customRoleSlug: string;
|
||||||
|
permissions: unknown;
|
||||||
|
temporaryRange: string | null | undefined;
|
||||||
|
temporaryMode: string | null | undefined;
|
||||||
|
temporaryAccessStartTime: Date | null | undefined;
|
||||||
|
temporaryAccessEndTime: Date | null | undefined;
|
||||||
|
isTemporary: boolean;
|
||||||
|
}[];
|
||||||
|
}[]
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
export const permissionDALFactory = (db: TDbClient) => {
|
export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
||||||
const getOrgPermission = async (userId: string, orgId: string) => {
|
const getOrgPermission: TPermissionDALFactory["getOrgPermission"] = async (userId: string, orgId: string) => {
|
||||||
try {
|
try {
|
||||||
const groupSubQuery = db(TableName.Groups)
|
const groupSubQuery = db(TableName.Groups)
|
||||||
.where(`${TableName.Groups}.orgId`, orgId)
|
.where(`${TableName.Groups}.orgId`, orgId)
|
||||||
@@ -112,7 +408,10 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOrgIdentityPermission = async (identityId: string, orgId: string) => {
|
const getOrgIdentityPermission: TPermissionDALFactory["getOrgIdentityPermission"] = async (
|
||||||
|
identityId: string,
|
||||||
|
orgId: string
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const membership = await db
|
const membership = await db
|
||||||
.replicaNode()(TableName.IdentityOrgMembership)
|
.replicaNode()(TableName.IdentityOrgMembership)
|
||||||
@@ -132,7 +431,10 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectGroupPermissions = async (projectId: string, filterGroupId?: string) => {
|
const getProjectGroupPermissions: TPermissionDALFactory["getProjectGroupPermissions"] = async (
|
||||||
|
projectId: string,
|
||||||
|
filterGroupId?: string
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.GroupProjectMembership)
|
.replicaNode()(TableName.GroupProjectMembership)
|
||||||
@@ -245,7 +547,7 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectUserPermissions = async (projectId: string) => {
|
const getProjectUserPermissions: TPermissionDALFactory["getProjectUserPermissions"] = async (projectId: string) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.Users)
|
.replicaNode()(TableName.Users)
|
||||||
@@ -535,7 +837,10 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermission = async (userId: string, projectId: string) => {
|
const getProjectPermission: TPermissionDALFactory["getProjectPermission"] = async (
|
||||||
|
userId: string,
|
||||||
|
projectId: string
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const subQueryUserGroups = db(TableName.UserGroupMembership).where("userId", userId).select("groupId");
|
const subQueryUserGroups = db(TableName.UserGroupMembership).where("userId", userId).select("groupId");
|
||||||
const docs = await db
|
const docs = await db
|
||||||
@@ -838,7 +1143,9 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectIdentityPermissions = async (projectId: string) => {
|
const getProjectIdentityPermissions: TPermissionDALFactory["getProjectIdentityPermissions"] = async (
|
||||||
|
projectId: string
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.IdentityProjectMembership)
|
.replicaNode()(TableName.IdentityProjectMembership)
|
||||||
@@ -995,7 +1302,10 @@ export const permissionDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectIdentityPermission = async (identityId: string, projectId: string) => {
|
const getProjectIdentityPermission: TPermissionDALFactory["getProjectIdentityPermission"] = async (
|
||||||
|
identityId,
|
||||||
|
projectId
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.IdentityProjectMembership)
|
.replicaNode()(TableName.IdentityProjectMembership)
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
|
import { MongoAbility, RawRuleOf } from "@casl/ability";
|
||||||
|
import { MongoQuery } from "@ucast/mongo2js";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
import { OrgPermissionSet } from "./org-permission";
|
||||||
|
import { ProjectPermissionSet } from "./project-permission";
|
||||||
|
|
||||||
export type TBuildProjectPermissionDTO = {
|
export type TBuildProjectPermissionDTO = {
|
||||||
permissions?: unknown;
|
permissions?: unknown;
|
||||||
role: string;
|
role: string;
|
||||||
@@ -41,3 +47,240 @@ export type TGetProjectPermissionArg = {
|
|||||||
actorOrgId?: string;
|
actorOrgId?: string;
|
||||||
actionProjectType: ActionProjectType;
|
actionProjectType: ActionProjectType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TPermissionServiceFactory = {
|
||||||
|
getUserOrgPermission: (
|
||||||
|
userId: string,
|
||||||
|
orgId: string,
|
||||||
|
authMethod: ActorAuthMethod,
|
||||||
|
userOrgId?: string
|
||||||
|
) => Promise<{
|
||||||
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
|
membership: {
|
||||||
|
status: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
role: string;
|
||||||
|
isActive: boolean;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
bypassOrgAuthEnabled: boolean;
|
||||||
|
permissions?: unknown;
|
||||||
|
userId?: string | null | undefined;
|
||||||
|
roleId?: string | null | undefined;
|
||||||
|
inviteEmail?: string | null | undefined;
|
||||||
|
projectFavorites?: string[] | null | undefined;
|
||||||
|
customRoleSlug?: string | null | undefined;
|
||||||
|
orgAuthEnforced?: boolean | null | undefined;
|
||||||
|
} & {
|
||||||
|
groups: {
|
||||||
|
id: string;
|
||||||
|
updatedAt: Date;
|
||||||
|
createdAt: Date;
|
||||||
|
role: string;
|
||||||
|
roleId: string | null | undefined;
|
||||||
|
customRolePermission: unknown;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
orgId: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
getOrgPermission: (
|
||||||
|
type: ActorType,
|
||||||
|
id: string,
|
||||||
|
orgId: string,
|
||||||
|
authMethod: ActorAuthMethod,
|
||||||
|
actorOrgId: string | undefined
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
|
membership: {
|
||||||
|
status: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
role: string;
|
||||||
|
isActive: boolean;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
bypassOrgAuthEnabled: boolean;
|
||||||
|
permissions?: unknown;
|
||||||
|
userId?: string | null | undefined;
|
||||||
|
roleId?: string | null | undefined;
|
||||||
|
inviteEmail?: string | null | undefined;
|
||||||
|
projectFavorites?: string[] | null | undefined;
|
||||||
|
customRoleSlug?: string | null | undefined;
|
||||||
|
orgAuthEnforced?: boolean | null | undefined;
|
||||||
|
} & {
|
||||||
|
groups: {
|
||||||
|
id: string;
|
||||||
|
updatedAt: Date;
|
||||||
|
createdAt: Date;
|
||||||
|
role: string;
|
||||||
|
roleId: string | null | undefined;
|
||||||
|
customRolePermission: unknown;
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
orgId: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
|
membership: {
|
||||||
|
id: string;
|
||||||
|
role: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
orgId: string;
|
||||||
|
roleId?: string | null | undefined;
|
||||||
|
permissions?: unknown;
|
||||||
|
identityId: string;
|
||||||
|
orgAuthEnforced: boolean | null | undefined;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
getUserProjectPermission: ({
|
||||||
|
userId,
|
||||||
|
projectId,
|
||||||
|
authMethod,
|
||||||
|
userOrgId,
|
||||||
|
actionProjectType
|
||||||
|
}: TGetUserProjectPermissionArg) => Promise<{
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
membership: {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
userId: string;
|
||||||
|
projectId: string;
|
||||||
|
} & {
|
||||||
|
orgAuthEnforced: boolean | null | undefined;
|
||||||
|
orgId: string;
|
||||||
|
roles: Array<{
|
||||||
|
role: string;
|
||||||
|
}>;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
};
|
||||||
|
hasRole: (role: string) => boolean;
|
||||||
|
}>;
|
||||||
|
getProjectPermission: <T extends ActorType>(
|
||||||
|
arg: TGetProjectPermissionArg
|
||||||
|
) => Promise<
|
||||||
|
T extends ActorType.SERVICE
|
||||||
|
? {
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
membership: {
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
};
|
||||||
|
hasRole: (arg: string) => boolean;
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
membership: (T extends ActorType.USER
|
||||||
|
? {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
userId: string;
|
||||||
|
projectId: string;
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
projectId: string;
|
||||||
|
identityId: string;
|
||||||
|
}) & {
|
||||||
|
orgAuthEnforced: boolean | null | undefined;
|
||||||
|
orgId: string;
|
||||||
|
roles: Array<{
|
||||||
|
role: string;
|
||||||
|
}>;
|
||||||
|
shouldUseNewPrivilegeSystem: boolean;
|
||||||
|
};
|
||||||
|
hasRole: (role: string) => boolean;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
getProjectPermissions: (projectId: string) => Promise<{
|
||||||
|
userPermissions: {
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
membershipId: string;
|
||||||
|
}[];
|
||||||
|
identityPermissions: {
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
membershipId: string;
|
||||||
|
}[];
|
||||||
|
groupPermissions: {
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
membershipId: string;
|
||||||
|
}[];
|
||||||
|
}>;
|
||||||
|
getOrgPermissionByRole: (
|
||||||
|
role: string,
|
||||||
|
orgId: string
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
|
role: {
|
||||||
|
name: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
slug: string;
|
||||||
|
permissions?: unknown;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
|
role?: undefined;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
getProjectPermissionByRole: (
|
||||||
|
role: string,
|
||||||
|
projectId: string
|
||||||
|
) => Promise<
|
||||||
|
| {
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
role: {
|
||||||
|
name: string;
|
||||||
|
version: number;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
projectId: string;
|
||||||
|
slug: string;
|
||||||
|
permissions?: unknown;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
|
||||||
|
role?: undefined;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
buildOrgPermission: (orgUserRoles: TBuildOrgPermissionDTO) => MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
|
buildProjectPermissionRules: (
|
||||||
|
projectUserRoles: TBuildProjectPermissionDTO
|
||||||
|
) => RawRuleOf<MongoAbility<ProjectPermissionSet>>[];
|
||||||
|
checkGroupProjectPermission: ({
|
||||||
|
groupId,
|
||||||
|
projectId,
|
||||||
|
checkPermissions
|
||||||
|
}: {
|
||||||
|
groupId: string;
|
||||||
|
projectId: string;
|
||||||
|
checkPermissions: ProjectPermissionSet;
|
||||||
|
}) => Promise<boolean>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import {
|
|||||||
import { conditionsMatcher } from "@app/lib/casl";
|
import { conditionsMatcher } from "@app/lib/casl";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { objectify } from "@app/lib/fn";
|
import { objectify } from "@app/lib/fn";
|
||||||
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
import { TOrgRoleDALFactory } from "@app/services/org/org-role-dal";
|
import { TOrgRoleDALFactory } from "@app/services/org/org-role-dal";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
import { TProjectRoleDALFactory } from "@app/services/project-role/project-role-dal";
|
import { TProjectRoleDALFactory } from "@app/services/project-role/project-role-dal";
|
||||||
@@ -38,7 +38,8 @@ import {
|
|||||||
TGetIdentityProjectPermissionArg,
|
TGetIdentityProjectPermissionArg,
|
||||||
TGetProjectPermissionArg,
|
TGetProjectPermissionArg,
|
||||||
TGetServiceTokenProjectPermissionArg,
|
TGetServiceTokenProjectPermissionArg,
|
||||||
TGetUserProjectPermissionArg
|
TGetUserProjectPermissionArg,
|
||||||
|
TPermissionServiceFactory
|
||||||
} from "./permission-service-types";
|
} from "./permission-service-types";
|
||||||
import { buildServiceTokenProjectPermission, ProjectPermissionSet } from "./project-permission";
|
import { buildServiceTokenProjectPermission, ProjectPermissionSet } from "./project-permission";
|
||||||
|
|
||||||
@@ -50,15 +51,13 @@ type TPermissionServiceFactoryDep = {
|
|||||||
permissionDAL: TPermissionDALFactory;
|
permissionDAL: TPermissionDALFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TPermissionServiceFactory = ReturnType<typeof permissionServiceFactory>;
|
|
||||||
|
|
||||||
export const permissionServiceFactory = ({
|
export const permissionServiceFactory = ({
|
||||||
permissionDAL,
|
permissionDAL,
|
||||||
orgRoleDAL,
|
orgRoleDAL,
|
||||||
projectRoleDAL,
|
projectRoleDAL,
|
||||||
serviceTokenDAL,
|
serviceTokenDAL,
|
||||||
projectDAL
|
projectDAL
|
||||||
}: TPermissionServiceFactoryDep) => {
|
}: TPermissionServiceFactoryDep): TPermissionServiceFactory => {
|
||||||
const buildOrgPermission = (orgUserRoles: TBuildOrgPermissionDTO) => {
|
const buildOrgPermission = (orgUserRoles: TBuildOrgPermissionDTO) => {
|
||||||
const rules = orgUserRoles
|
const rules = orgUserRoles
|
||||||
.map(({ role, permissions }) => {
|
.map(({ role, permissions }) => {
|
||||||
@@ -120,11 +119,11 @@ export const permissionServiceFactory = ({
|
|||||||
/*
|
/*
|
||||||
* Get user permission in an organization
|
* Get user permission in an organization
|
||||||
*/
|
*/
|
||||||
const getUserOrgPermission = async (
|
const getUserOrgPermission: TPermissionServiceFactory["getUserOrgPermission"] = async (
|
||||||
userId: string,
|
userId,
|
||||||
orgId: string,
|
orgId,
|
||||||
authMethod: ActorAuthMethod,
|
authMethod,
|
||||||
userOrgId?: string
|
userOrgId
|
||||||
) => {
|
) => {
|
||||||
// when token is scoped, ensure the passed org id is same as user org id
|
// when token is scoped, ensure the passed org id is same as user org id
|
||||||
if (userOrgId && userOrgId !== orgId)
|
if (userOrgId && userOrgId !== orgId)
|
||||||
@@ -172,12 +171,12 @@ export const permissionServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOrgPermission = async (
|
const getOrgPermission: TPermissionServiceFactory["getOrgPermission"] = async (
|
||||||
type: ActorType,
|
type,
|
||||||
id: string,
|
id,
|
||||||
orgId: string,
|
orgId,
|
||||||
authMethod: ActorAuthMethod,
|
authMethod,
|
||||||
actorOrgId: string | undefined
|
actorOrgId
|
||||||
) => {
|
) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ActorType.USER:
|
case ActorType.USER:
|
||||||
@@ -194,7 +193,7 @@ export const permissionServiceFactory = ({
|
|||||||
|
|
||||||
// instead of actor type this will fetch by role slug. meaning it can be the pre defined slugs like
|
// instead of actor type this will fetch by role slug. meaning it can be the pre defined slugs like
|
||||||
// admin member or user defined ones like biller etc
|
// admin member or user defined ones like biller etc
|
||||||
const getOrgPermissionByRole = async (role: string, orgId: string) => {
|
const getOrgPermissionByRole: TPermissionServiceFactory["getOrgPermissionByRole"] = async (role, orgId) => {
|
||||||
const isCustomRole = !Object.values(OrgMembershipRole).includes(role as OrgMembershipRole);
|
const isCustomRole = !Object.values(OrgMembershipRole).includes(role as OrgMembershipRole);
|
||||||
if (isCustomRole) {
|
if (isCustomRole) {
|
||||||
const orgRole = await orgRoleDAL.findOne({ slug: role, orgId });
|
const orgRole = await orgRoleDAL.findOne({ slug: role, orgId });
|
||||||
@@ -437,7 +436,7 @@ export const permissionServiceFactory = ({
|
|||||||
hasRole: (role: string) => boolean;
|
hasRole: (role: string) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermissions = async (projectId: string) => {
|
const getProjectPermissions: TPermissionServiceFactory["getProjectPermissions"] = async (projectId) => {
|
||||||
// fetch user permissions
|
// fetch user permissions
|
||||||
const rawUserProjectPermissions = await permissionDAL.getProjectUserPermissions(projectId);
|
const rawUserProjectPermissions = await permissionDAL.getProjectUserPermissions(projectId);
|
||||||
const userPermissions = rawUserProjectPermissions.map((userProjectPermission) => {
|
const userPermissions = rawUserProjectPermissions.map((userProjectPermission) => {
|
||||||
@@ -607,7 +606,10 @@ export const permissionServiceFactory = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectPermissionByRole = async (role: string, projectId: string) => {
|
const getProjectPermissionByRole: TPermissionServiceFactory["getProjectPermissionByRole"] = async (
|
||||||
|
role,
|
||||||
|
projectId
|
||||||
|
) => {
|
||||||
const isCustomRole = !Object.values(ProjectMembershipRole).includes(role as ProjectMembershipRole);
|
const isCustomRole = !Object.values(ProjectMembershipRole).includes(role as ProjectMembershipRole);
|
||||||
if (isCustomRole) {
|
if (isCustomRole) {
|
||||||
const projectRole = await projectRoleDAL.findOne({ slug: role, projectId });
|
const projectRole = await projectRoleDAL.findOne({ slug: role, projectId });
|
||||||
@@ -630,14 +632,10 @@ export const permissionServiceFactory = ({
|
|||||||
return { permission };
|
return { permission };
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkGroupProjectPermission = async ({
|
const checkGroupProjectPermission: TPermissionServiceFactory["checkGroupProjectPermission"] = async ({
|
||||||
groupId,
|
groupId,
|
||||||
projectId,
|
projectId,
|
||||||
checkPermissions
|
checkPermissions
|
||||||
}: {
|
|
||||||
groupId: string;
|
|
||||||
projectId: string;
|
|
||||||
checkPermissions: ProjectPermissionSet;
|
|
||||||
}) => {
|
}) => {
|
||||||
const rawGroupProjectPermissions = await permissionDAL.getProjectGroupPermissions(projectId, groupId);
|
const rawGroupProjectPermissions = await permissionDAL.getProjectGroupPermissions(projectId, groupId);
|
||||||
const groupPermissions = rawGroupProjectPermissions.map((groupProjectPermission) => {
|
const groupPermissions = rawGroupProjectPermissions.map((groupProjectPermission) => {
|
||||||
|
|||||||
@@ -211,6 +211,11 @@ export type SecretFolderSubjectFields = {
|
|||||||
secretPath: string;
|
secretPath: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type SecretSyncSubjectFields = {
|
||||||
|
environment: string;
|
||||||
|
secretPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type DynamicSecretSubjectFields = {
|
export type DynamicSecretSubjectFields = {
|
||||||
environment: string;
|
environment: string;
|
||||||
secretPath: string;
|
secretPath: string;
|
||||||
@@ -267,6 +272,10 @@ export type ProjectPermissionSet =
|
|||||||
| (ForcedSubject<ProjectPermissionSub.DynamicSecrets> & DynamicSecretSubjectFields)
|
| (ForcedSubject<ProjectPermissionSub.DynamicSecrets> & DynamicSecretSubjectFields)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
| [
|
||||||
|
ProjectPermissionSecretSyncActions,
|
||||||
|
ProjectPermissionSub.SecretSyncs | (ForcedSubject<ProjectPermissionSub.SecretSyncs> & SecretSyncSubjectFields)
|
||||||
|
]
|
||||||
| [
|
| [
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
(
|
(
|
||||||
@@ -323,7 +332,6 @@ export type ProjectPermissionSet =
|
|||||||
| [ProjectPermissionActions, ProjectPermissionSub.SshHostGroups]
|
| [ProjectPermissionActions, ProjectPermissionSub.SshHostGroups]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
||||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
||||||
| [ProjectPermissionSecretSyncActions, ProjectPermissionSub.SecretSyncs]
|
|
||||||
| [ProjectPermissionKmipActions, ProjectPermissionSub.Kmip]
|
| [ProjectPermissionKmipActions, ProjectPermissionSub.Kmip]
|
||||||
| [ProjectPermissionCmekActions, ProjectPermissionSub.Cmek]
|
| [ProjectPermissionCmekActions, ProjectPermissionSub.Cmek]
|
||||||
| [ProjectPermissionActions.Delete, ProjectPermissionSub.Project]
|
| [ProjectPermissionActions.Delete, ProjectPermissionSub.Project]
|
||||||
@@ -412,6 +420,23 @@ const DynamicSecretConditionV2Schema = z
|
|||||||
})
|
})
|
||||||
.partial();
|
.partial();
|
||||||
|
|
||||||
|
const SecretSyncConditionV2Schema = z
|
||||||
|
.object({
|
||||||
|
environment: z.union([
|
||||||
|
z.string(),
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
[PermissionConditionOperators.$EQ]: PermissionConditionSchema[PermissionConditionOperators.$EQ],
|
||||||
|
[PermissionConditionOperators.$NEQ]: PermissionConditionSchema[PermissionConditionOperators.$NEQ],
|
||||||
|
[PermissionConditionOperators.$IN]: PermissionConditionSchema[PermissionConditionOperators.$IN],
|
||||||
|
[PermissionConditionOperators.$GLOB]: PermissionConditionSchema[PermissionConditionOperators.$GLOB]
|
||||||
|
})
|
||||||
|
.partial()
|
||||||
|
]),
|
||||||
|
secretPath: SECRET_PATH_PERMISSION_OPERATOR_SCHEMA
|
||||||
|
})
|
||||||
|
.partial();
|
||||||
|
|
||||||
const SecretImportConditionSchema = z
|
const SecretImportConditionSchema = z
|
||||||
.object({
|
.object({
|
||||||
environment: z.union([
|
environment: z.union([
|
||||||
@@ -671,12 +696,6 @@ const GeneralPermissionSchema = [
|
|||||||
"Describe what action an entity can take."
|
"Describe what action an entity can take."
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
z.object({
|
|
||||||
subject: z.literal(ProjectPermissionSub.SecretSyncs).describe("The entity this permission pertains to."),
|
|
||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionSecretSyncActions).describe(
|
|
||||||
"Describe what action an entity can take."
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
z.object({
|
z.object({
|
||||||
subject: z.literal(ProjectPermissionSub.Kmip).describe("The entity this permission pertains to."),
|
subject: z.literal(ProjectPermissionSub.Kmip).describe("The entity this permission pertains to."),
|
||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionKmipActions).describe(
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionKmipActions).describe(
|
||||||
@@ -836,6 +855,16 @@ export const ProjectPermissionV2Schema = z.discriminatedUnion("subject", [
|
|||||||
"When specified, only matching conditions will be allowed to access given resource."
|
"When specified, only matching conditions will be allowed to access given resource."
|
||||||
).optional()
|
).optional()
|
||||||
}),
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z.literal(ProjectPermissionSub.SecretSyncs).describe("The entity this permission pertains to."),
|
||||||
|
inverted: z.boolean().optional().describe("Whether rule allows or forbids."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionSecretSyncActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
),
|
||||||
|
conditions: SecretSyncConditionV2Schema.describe(
|
||||||
|
"When specified, only matching conditions will be allowed to access given resource."
|
||||||
|
).optional()
|
||||||
|
}),
|
||||||
|
|
||||||
...GeneralPermissionSchema
|
...GeneralPermissionSchema
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { TSecretServiceFactory } from "@app/services/secret/secret-service";
|
|||||||
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
||||||
import { TSecretFolderServiceFactory } from "@app/services/secret-folder/secret-folder-service";
|
import { TSecretFolderServiceFactory } from "@app/services/secret-folder/secret-folder-service";
|
||||||
|
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
|
|
||||||
type TPitServiceFactoryDep = {
|
type TPitServiceFactoryDep = {
|
||||||
folderCommitService: TFolderCommitServiceFactory;
|
folderCommitService: TFolderCommitServiceFactory;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TProjectTemplateDALFactory = ReturnType<typeof projectTemplateDALFactory>;
|
export type TProjectTemplateDALFactory = TOrmify<TableName.ProjectTemplates>;
|
||||||
|
|
||||||
export const projectTemplateDALFactory = (db: TDbClient) => ormify(db, TableName.ProjectTemplates);
|
export const projectTemplateDALFactory = (db: TDbClient): TProjectTemplateDALFactory =>
|
||||||
|
ormify(db, TableName.ProjectTemplates);
|
||||||
|
|||||||
@@ -4,18 +4,16 @@ import { packRules } from "@casl/ability/extra";
|
|||||||
import { ProjectType, TProjectTemplates } from "@app/db/schemas";
|
import { ProjectType, TProjectTemplates } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectTemplateDefaultEnvironments } from "@app/ee/services/project-template/project-template-constants";
|
import { ProjectTemplateDefaultEnvironments } from "@app/ee/services/project-template/project-template-constants";
|
||||||
import { getDefaultProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
import { getDefaultProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
||||||
import {
|
import {
|
||||||
TCreateProjectTemplateDTO,
|
|
||||||
TProjectTemplateEnvironment,
|
TProjectTemplateEnvironment,
|
||||||
TProjectTemplateRole,
|
TProjectTemplateRole,
|
||||||
TUnpackedPermission,
|
TProjectTemplateServiceFactory,
|
||||||
TUpdateProjectTemplateDTO
|
TUnpackedPermission
|
||||||
} from "@app/ee/services/project-template/project-template-types";
|
} from "@app/ee/services/project-template/project-template-types";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { OrgServiceActor } from "@app/lib/types";
|
|
||||||
import { unpackPermissions } from "@app/server/routes/sanitizedSchema/permission";
|
import { unpackPermissions } from "@app/server/routes/sanitizedSchema/permission";
|
||||||
import { getPredefinedRoles } from "@app/services/project-role/project-role-fns";
|
import { getPredefinedRoles } from "@app/services/project-role/project-role-fns";
|
||||||
|
|
||||||
@@ -27,8 +25,6 @@ type TProjectTemplatesServiceFactoryDep = {
|
|||||||
projectTemplateDAL: TProjectTemplateDALFactory;
|
projectTemplateDAL: TProjectTemplateDALFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TProjectTemplateServiceFactory = ReturnType<typeof projectTemplateServiceFactory>;
|
|
||||||
|
|
||||||
const $unpackProjectTemplate = ({ roles, environments, ...rest }: TProjectTemplates) => ({
|
const $unpackProjectTemplate = ({ roles, environments, ...rest }: TProjectTemplates) => ({
|
||||||
...rest,
|
...rest,
|
||||||
environments: environments as TProjectTemplateEnvironment[],
|
environments: environments as TProjectTemplateEnvironment[],
|
||||||
@@ -51,8 +47,11 @@ export const projectTemplateServiceFactory = ({
|
|||||||
licenseService,
|
licenseService,
|
||||||
permissionService,
|
permissionService,
|
||||||
projectTemplateDAL
|
projectTemplateDAL
|
||||||
}: TProjectTemplatesServiceFactoryDep) => {
|
}: TProjectTemplatesServiceFactoryDep): TProjectTemplateServiceFactory => {
|
||||||
const listProjectTemplatesByOrg = async (actor: OrgServiceActor, type?: ProjectType) => {
|
const listProjectTemplatesByOrg: TProjectTemplateServiceFactory["listProjectTemplatesByOrg"] = async (
|
||||||
|
actor,
|
||||||
|
type
|
||||||
|
) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
|
|
||||||
if (!plan.projectTemplates)
|
if (!plan.projectTemplates)
|
||||||
@@ -83,7 +82,10 @@ export const projectTemplateServiceFactory = ({
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const findProjectTemplateByName = async (name: string, actor: OrgServiceActor) => {
|
const findProjectTemplateByName: TProjectTemplateServiceFactory["findProjectTemplateByName"] = async (
|
||||||
|
name,
|
||||||
|
actor
|
||||||
|
) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
|
|
||||||
if (!plan.projectTemplates)
|
if (!plan.projectTemplates)
|
||||||
@@ -111,7 +113,7 @@ export const projectTemplateServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const findProjectTemplateById = async (id: string, actor: OrgServiceActor) => {
|
const findProjectTemplateById: TProjectTemplateServiceFactory["findProjectTemplateById"] = async (id, actor) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
|
|
||||||
if (!plan.projectTemplates)
|
if (!plan.projectTemplates)
|
||||||
@@ -139,9 +141,9 @@ export const projectTemplateServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createProjectTemplate = async (
|
const createProjectTemplate: TProjectTemplateServiceFactory["createProjectTemplate"] = async (
|
||||||
{ roles, environments, type, ...params }: TCreateProjectTemplateDTO,
|
{ roles, environments, type, ...params },
|
||||||
actor: OrgServiceActor
|
actor
|
||||||
) => {
|
) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
|
|
||||||
@@ -195,10 +197,10 @@ export const projectTemplateServiceFactory = ({
|
|||||||
return $unpackProjectTemplate(projectTemplate);
|
return $unpackProjectTemplate(projectTemplate);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateProjectTemplateById = async (
|
const updateProjectTemplateById: TProjectTemplateServiceFactory["updateProjectTemplateById"] = async (
|
||||||
id: string,
|
id,
|
||||||
{ roles, environments, ...params }: TUpdateProjectTemplateDTO,
|
{ roles, environments, ...params },
|
||||||
actor: OrgServiceActor
|
actor
|
||||||
) => {
|
) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
|
|
||||||
@@ -259,7 +261,7 @@ export const projectTemplateServiceFactory = ({
|
|||||||
return $unpackProjectTemplate(updatedProjectTemplate);
|
return $unpackProjectTemplate(updatedProjectTemplate);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteProjectTemplateById = async (id: string, actor: OrgServiceActor) => {
|
const deleteProjectTemplateById: TProjectTemplateServiceFactory["deleteProjectTemplateById"] = async (id, actor) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
|
|
||||||
if (!plan.projectTemplates)
|
if (!plan.projectTemplates)
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectType, TProjectEnvironments } from "@app/db/schemas";
|
import { ProjectMembershipRole, ProjectType, TProjectEnvironments } from "@app/db/schemas";
|
||||||
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
|
import { OrgServiceActor } from "@app/lib/types";
|
||||||
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
|
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
|
||||||
|
|
||||||
export type TProjectTemplateEnvironment = Pick<TProjectEnvironments, "name" | "slug" | "position">;
|
export type TProjectTemplateEnvironment = Pick<TProjectEnvironments, "name" | "slug" | "position">;
|
||||||
@@ -27,3 +28,177 @@ export type TUnpackedPermission = z.infer<typeof UnpackedPermissionSchema>;
|
|||||||
export enum InfisicalProjectTemplate {
|
export enum InfisicalProjectTemplate {
|
||||||
Default = "default"
|
Default = "default"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TProjectTemplateServiceFactory = {
|
||||||
|
listProjectTemplatesByOrg: (
|
||||||
|
actor: OrgServiceActor,
|
||||||
|
type?: ProjectType
|
||||||
|
) => Promise<
|
||||||
|
(
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
type: ProjectType;
|
||||||
|
name: InfisicalProjectTemplate;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description: string;
|
||||||
|
environments:
|
||||||
|
| {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
position: number;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
roles: {
|
||||||
|
name: string;
|
||||||
|
slug: ProjectMembershipRole;
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
orgId: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
environments: TProjectTemplateEnvironment[];
|
||||||
|
roles: {
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
}
|
||||||
|
)[]
|
||||||
|
>;
|
||||||
|
createProjectTemplate: (
|
||||||
|
arg: TCreateProjectTemplateDTO,
|
||||||
|
actor: OrgServiceActor
|
||||||
|
) => Promise<{
|
||||||
|
environments: TProjectTemplateEnvironment[];
|
||||||
|
roles: {
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
}>;
|
||||||
|
updateProjectTemplateById: (
|
||||||
|
id: string,
|
||||||
|
{ roles, environments, ...params }: TUpdateProjectTemplateDTO,
|
||||||
|
actor: OrgServiceActor
|
||||||
|
) => Promise<{
|
||||||
|
environments: TProjectTemplateEnvironment[];
|
||||||
|
roles: {
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
}>;
|
||||||
|
deleteProjectTemplateById: (
|
||||||
|
id: string,
|
||||||
|
actor: OrgServiceActor
|
||||||
|
) => Promise<{
|
||||||
|
environments: TProjectTemplateEnvironment[];
|
||||||
|
roles: {
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
}>;
|
||||||
|
findProjectTemplateById: (
|
||||||
|
id: string,
|
||||||
|
actor: OrgServiceActor
|
||||||
|
) => Promise<{
|
||||||
|
packedRoles: TProjectTemplateRole[];
|
||||||
|
environments: TProjectTemplateEnvironment[];
|
||||||
|
roles: {
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
}>;
|
||||||
|
findProjectTemplateByName: (
|
||||||
|
name: string,
|
||||||
|
actor: OrgServiceActor
|
||||||
|
) => Promise<{
|
||||||
|
packedRoles: TProjectTemplateRole[];
|
||||||
|
environments: TProjectTemplateEnvironment[];
|
||||||
|
roles: {
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description?: string | null | undefined;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TProjectUserAdditionalPrivilegeDALFactory = ReturnType<typeof projectUserAdditionalPrivilegeDALFactory>;
|
export type TProjectUserAdditionalPrivilegeDALFactory = TOrmify<TableName.ProjectUserAdditionalPrivilege>;
|
||||||
|
|
||||||
export const projectUserAdditionalPrivilegeDALFactory = (db: TDbClient) => {
|
export const projectUserAdditionalPrivilegeDALFactory = (db: TDbClient): TProjectUserAdditionalPrivilegeDALFactory => {
|
||||||
const orm = ormify(db, TableName.ProjectUserAdditionalPrivilege);
|
const orm = ormify(db, TableName.ProjectUserAdditionalPrivilege);
|
||||||
return orm;
|
return orm;
|
||||||
};
|
};
|
||||||
|
|||||||
+18
-20
@@ -11,7 +11,7 @@ import { TProjectMembershipDALFactory } from "@app/services/project-membership/p
|
|||||||
|
|
||||||
import { TAccessApprovalRequestDALFactory } from "../access-approval-request/access-approval-request-dal";
|
import { TAccessApprovalRequestDALFactory } from "../access-approval-request/access-approval-request-dal";
|
||||||
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
import { constructPermissionErrorMessage, validatePrivilegeChangeOperation } from "../permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionMemberActions,
|
ProjectPermissionMemberActions,
|
||||||
ProjectPermissionSet,
|
ProjectPermissionSet,
|
||||||
@@ -21,11 +21,7 @@ import { ApprovalStatus } from "../secret-approval-request/secret-approval-reque
|
|||||||
import { TProjectUserAdditionalPrivilegeDALFactory } from "./project-user-additional-privilege-dal";
|
import { TProjectUserAdditionalPrivilegeDALFactory } from "./project-user-additional-privilege-dal";
|
||||||
import {
|
import {
|
||||||
ProjectUserAdditionalPrivilegeTemporaryMode,
|
ProjectUserAdditionalPrivilegeTemporaryMode,
|
||||||
TCreateUserPrivilegeDTO,
|
TProjectUserAdditionalPrivilegeServiceFactory
|
||||||
TDeleteUserPrivilegeDTO,
|
|
||||||
TGetUserPrivilegeDetailsDTO,
|
|
||||||
TListUserPrivilegesDTO,
|
|
||||||
TUpdateUserPrivilegeDTO
|
|
||||||
} from "./project-user-additional-privilege-types";
|
} from "./project-user-additional-privilege-types";
|
||||||
|
|
||||||
type TProjectUserAdditionalPrivilegeServiceFactoryDep = {
|
type TProjectUserAdditionalPrivilegeServiceFactoryDep = {
|
||||||
@@ -35,10 +31,6 @@ type TProjectUserAdditionalPrivilegeServiceFactoryDep = {
|
|||||||
accessApprovalRequestDAL: Pick<TAccessApprovalRequestDALFactory, "update">;
|
accessApprovalRequestDAL: Pick<TAccessApprovalRequestDALFactory, "update">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TProjectUserAdditionalPrivilegeServiceFactory = ReturnType<
|
|
||||||
typeof projectUserAdditionalPrivilegeServiceFactory
|
|
||||||
>;
|
|
||||||
|
|
||||||
const unpackPermissions = (permissions: unknown) =>
|
const unpackPermissions = (permissions: unknown) =>
|
||||||
UnpackedPermissionSchema.array().parse(
|
UnpackedPermissionSchema.array().parse(
|
||||||
unpackRules((permissions || []) as PackRule<RawRuleOf<MongoAbility<ProjectPermissionSet>>>[])
|
unpackRules((permissions || []) as PackRule<RawRuleOf<MongoAbility<ProjectPermissionSet>>>[])
|
||||||
@@ -49,8 +41,8 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
projectMembershipDAL,
|
projectMembershipDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
accessApprovalRequestDAL
|
accessApprovalRequestDAL
|
||||||
}: TProjectUserAdditionalPrivilegeServiceFactoryDep) => {
|
}: TProjectUserAdditionalPrivilegeServiceFactoryDep): TProjectUserAdditionalPrivilegeServiceFactory => {
|
||||||
const create = async ({
|
const create: TProjectUserAdditionalPrivilegeServiceFactory["create"] = async ({
|
||||||
slug,
|
slug,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -59,7 +51,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
projectMembershipId,
|
projectMembershipId,
|
||||||
...dto
|
...dto
|
||||||
}: TCreateUserPrivilegeDTO) => {
|
}) => {
|
||||||
const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
|
const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
|
||||||
if (!projectMembership)
|
if (!projectMembership)
|
||||||
throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} found` });
|
throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} found` });
|
||||||
@@ -147,14 +139,14 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateById = async ({
|
const updateById: TProjectUserAdditionalPrivilegeServiceFactory["updateById"] = async ({
|
||||||
privilegeId,
|
privilegeId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
...dto
|
...dto
|
||||||
}: TUpdateUserPrivilegeDTO) => {
|
}) => {
|
||||||
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
|
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
|
||||||
if (!userPrivilege)
|
if (!userPrivilege)
|
||||||
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
|
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
|
||||||
@@ -259,7 +251,13 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteById = async ({ actorId, actor, actorOrgId, actorAuthMethod, privilegeId }: TDeleteUserPrivilegeDTO) => {
|
const deleteById: TProjectUserAdditionalPrivilegeServiceFactory["deleteById"] = async ({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
privilegeId
|
||||||
|
}) => {
|
||||||
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
|
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
|
||||||
if (!userPrivilege)
|
if (!userPrivilege)
|
||||||
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
|
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
|
||||||
@@ -299,13 +297,13 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getPrivilegeDetailsById = async ({
|
const getPrivilegeDetailsById: TProjectUserAdditionalPrivilegeServiceFactory["getPrivilegeDetailsById"] = async ({
|
||||||
privilegeId,
|
privilegeId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TGetUserPrivilegeDetailsDTO) => {
|
}) => {
|
||||||
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
|
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
|
||||||
if (!userPrivilege)
|
if (!userPrivilege)
|
||||||
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
|
throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
|
||||||
@@ -335,13 +333,13 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const listPrivileges = async ({
|
const listPrivileges: TProjectUserAdditionalPrivilegeServiceFactory["listPrivileges"] = async ({
|
||||||
projectMembershipId,
|
projectMembershipId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TListUserPrivilegesDTO) => {
|
}) => {
|
||||||
const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
|
const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
|
||||||
if (!projectMembership)
|
if (!projectMembership)
|
||||||
throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} not found` });
|
throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} not found` });
|
||||||
|
|||||||
+18
@@ -1,3 +1,4 @@
|
|||||||
|
import { TProjectUserAdditionalPrivilege } from "@app/db/schemas";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
import { TProjectPermissionV2Schema } from "../permission/project-permission";
|
import { TProjectPermissionV2Schema } from "../permission/project-permission";
|
||||||
@@ -40,3 +41,20 @@ export type TDeleteUserPrivilegeDTO = Omit<TProjectPermission, "projectId"> & {
|
|||||||
export type TGetUserPrivilegeDetailsDTO = Omit<TProjectPermission, "projectId"> & { privilegeId: string };
|
export type TGetUserPrivilegeDetailsDTO = Omit<TProjectPermission, "projectId"> & { privilegeId: string };
|
||||||
|
|
||||||
export type TListUserPrivilegesDTO = Omit<TProjectPermission, "projectId"> & { projectMembershipId: string };
|
export type TListUserPrivilegesDTO = Omit<TProjectPermission, "projectId"> & { projectMembershipId: string };
|
||||||
|
|
||||||
|
interface TAdditionalPrivilege extends TProjectUserAdditionalPrivilege {
|
||||||
|
permissions: {
|
||||||
|
action: string[];
|
||||||
|
subject?: string | undefined;
|
||||||
|
conditions?: unknown;
|
||||||
|
inverted?: boolean | undefined;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TProjectUserAdditionalPrivilegeServiceFactory = {
|
||||||
|
create: (arg: TCreateUserPrivilegeDTO) => Promise<TAdditionalPrivilege>;
|
||||||
|
updateById: (arg: TUpdateUserPrivilegeDTO) => Promise<TAdditionalPrivilege>;
|
||||||
|
deleteById: (arg: TDeleteUserPrivilegeDTO) => Promise<TAdditionalPrivilege>;
|
||||||
|
getPrivilegeDetailsById: (arg: TGetUserPrivilegeDetailsDTO) => Promise<TAdditionalPrivilege>;
|
||||||
|
listPrivileges: (arg: TListUserPrivilegesDTO) => Promise<TProjectUserAdditionalPrivilege[]>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TRateLimitDALFactory = ReturnType<typeof rateLimitDALFactory>;
|
export type TRateLimitDALFactory = TOrmify<TableName.RateLimit>;
|
||||||
|
|
||||||
export const rateLimitDALFactory = (db: TDbClient) => ormify(db, TableName.RateLimit, {});
|
export const rateLimitDALFactory = (db: TDbClient): TRateLimitDALFactory => ormify(db, TableName.RateLimit, {});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { logger } from "@app/lib/logger";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { TRateLimitDALFactory } from "./rate-limit-dal";
|
import { TRateLimitDALFactory } from "./rate-limit-dal";
|
||||||
import { RateLimitConfiguration, TRateLimit, TRateLimitUpdateDTO } from "./rate-limit-types";
|
import { RateLimitConfiguration, TRateLimit, TRateLimitServiceFactory } from "./rate-limit-types";
|
||||||
|
|
||||||
let rateLimitMaxConfiguration: RateLimitConfiguration = {
|
let rateLimitMaxConfiguration: RateLimitConfiguration = {
|
||||||
readLimit: 60,
|
readLimit: 60,
|
||||||
@@ -27,12 +27,13 @@ type TRateLimitServiceFactoryDep = {
|
|||||||
licenseService: Pick<TLicenseServiceFactory, "onPremFeatures">;
|
licenseService: Pick<TLicenseServiceFactory, "onPremFeatures">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TRateLimitServiceFactory = ReturnType<typeof rateLimitServiceFactory>;
|
export const rateLimitServiceFactory = ({
|
||||||
|
rateLimitDAL,
|
||||||
export const rateLimitServiceFactory = ({ rateLimitDAL, licenseService }: TRateLimitServiceFactoryDep) => {
|
licenseService
|
||||||
|
}: TRateLimitServiceFactoryDep): TRateLimitServiceFactory => {
|
||||||
const DEFAULT_RATE_LIMIT_CONFIG_ID = "00000000-0000-0000-0000-000000000000";
|
const DEFAULT_RATE_LIMIT_CONFIG_ID = "00000000-0000-0000-0000-000000000000";
|
||||||
|
|
||||||
const getRateLimits = async (): Promise<TRateLimit | undefined> => {
|
const getRateLimits: TRateLimitServiceFactory["getRateLimits"] = async () => {
|
||||||
let rateLimit: TRateLimit;
|
let rateLimit: TRateLimit;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -51,11 +52,11 @@ export const rateLimitServiceFactory = ({ rateLimitDAL, licenseService }: TRateL
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRateLimit = async (updates: TRateLimitUpdateDTO): Promise<TRateLimit> => {
|
const updateRateLimit: TRateLimitServiceFactory["updateRateLimit"] = async (updates) => {
|
||||||
return rateLimitDAL.updateById(DEFAULT_RATE_LIMIT_CONFIG_ID, updates);
|
return rateLimitDAL.updateById(DEFAULT_RATE_LIMIT_CONFIG_ID, updates);
|
||||||
};
|
};
|
||||||
|
|
||||||
const syncRateLimitConfiguration = async () => {
|
const syncRateLimitConfiguration: TRateLimitServiceFactory["syncRateLimitConfiguration"] = async () => {
|
||||||
try {
|
try {
|
||||||
const rateLimit = await getRateLimits();
|
const rateLimit = await getRateLimits();
|
||||||
if (rateLimit) {
|
if (rateLimit) {
|
||||||
@@ -78,7 +79,7 @@ export const rateLimitServiceFactory = ({ rateLimitDAL, licenseService }: TRateL
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeBackgroundSync = async () => {
|
const initializeBackgroundSync: TRateLimitServiceFactory["initializeBackgroundSync"] = async () => {
|
||||||
if (!licenseService.onPremFeatures.customRateLimits) {
|
if (!licenseService.onPremFeatures.customRateLimits) {
|
||||||
logger.info("Current license does not support custom rate limit configuration");
|
logger.info("Current license does not support custom rate limit configuration");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { CronJob } from "cron";
|
||||||
|
|
||||||
export type TRateLimitUpdateDTO = {
|
export type TRateLimitUpdateDTO = {
|
||||||
readRateLimit: number;
|
readRateLimit: number;
|
||||||
writeRateLimit: number;
|
writeRateLimit: number;
|
||||||
@@ -23,3 +25,10 @@ export type RateLimitConfiguration = {
|
|||||||
inviteUserRateLimit: number;
|
inviteUserRateLimit: number;
|
||||||
mfaRateLimit: number;
|
mfaRateLimit: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TRateLimitServiceFactory = {
|
||||||
|
getRateLimits: () => Promise<TRateLimit | undefined>;
|
||||||
|
updateRateLimit: (updates: TRateLimitUpdateDTO) => Promise<TRateLimit>;
|
||||||
|
initializeBackgroundSync: () => Promise<CronJob<null, null> | undefined>;
|
||||||
|
syncRateLimitConfiguration: () => Promise<void>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TSamlConfigDALFactory = ReturnType<typeof samlConfigDALFactory>;
|
export type TSamlConfigDALFactory = TOrmify<TableName.SamlConfig>;
|
||||||
|
|
||||||
export const samlConfigDALFactory = (db: TDbClient) => {
|
export const samlConfigDALFactory = (db: TDbClient): TSamlConfigDALFactory => {
|
||||||
const samlCfgOrm = ormify(db, TableName.SamlConfig);
|
const samlCfgOrm = ormify(db, TableName.SamlConfig);
|
||||||
|
|
||||||
return samlCfgOrm;
|
return samlCfgOrm;
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ import { UserAliasType } from "@app/services/user-alias/user-alias-types";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TSamlConfigDALFactory } from "./saml-config-dal";
|
import { TSamlConfigDALFactory } from "./saml-config-dal";
|
||||||
import { TCreateSamlCfgDTO, TGetSamlCfgDTO, TSamlLoginDTO, TUpdateSamlCfgDTO } from "./saml-config-types";
|
import { TSamlConfigServiceFactory } from "./saml-config-types";
|
||||||
|
|
||||||
type TSamlConfigServiceFactoryDep = {
|
type TSamlConfigServiceFactoryDep = {
|
||||||
samlConfigDAL: Pick<TSamlConfigDALFactory, "create" | "findOne" | "update" | "findById">;
|
samlConfigDAL: Pick<TSamlConfigDALFactory, "create" | "findOne" | "update" | "findById">;
|
||||||
@@ -47,8 +47,6 @@ type TSamlConfigServiceFactoryDep = {
|
|||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TSamlConfigServiceFactory = ReturnType<typeof samlConfigServiceFactory>;
|
|
||||||
|
|
||||||
export const samlConfigServiceFactory = ({
|
export const samlConfigServiceFactory = ({
|
||||||
samlConfigDAL,
|
samlConfigDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
@@ -61,8 +59,8 @@ export const samlConfigServiceFactory = ({
|
|||||||
smtpService,
|
smtpService,
|
||||||
identityMetadataDAL,
|
identityMetadataDAL,
|
||||||
kmsService
|
kmsService
|
||||||
}: TSamlConfigServiceFactoryDep) => {
|
}: TSamlConfigServiceFactoryDep): TSamlConfigServiceFactory => {
|
||||||
const createSamlCfg = async ({
|
const createSamlCfg: TSamlConfigServiceFactory["createSamlCfg"] = async ({
|
||||||
idpCert,
|
idpCert,
|
||||||
actor,
|
actor,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
@@ -73,7 +71,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
isActive,
|
isActive,
|
||||||
entryPoint,
|
entryPoint,
|
||||||
authProvider
|
authProvider
|
||||||
}: TCreateSamlCfgDTO) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
|
||||||
|
|
||||||
@@ -101,7 +99,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
return samlConfig;
|
return samlConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSamlCfg = async ({
|
const updateSamlCfg: TSamlConfigServiceFactory["updateSamlCfg"] = async ({
|
||||||
orgId,
|
orgId,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
@@ -112,7 +110,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
isActive,
|
isActive,
|
||||||
entryPoint,
|
entryPoint,
|
||||||
authProvider
|
authProvider
|
||||||
}: TUpdateSamlCfgDTO) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -146,7 +144,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
return ssoConfig;
|
return ssoConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSaml = async (dto: TGetSamlCfgDTO) => {
|
const getSaml: TSamlConfigServiceFactory["getSaml"] = async (dto) => {
|
||||||
let samlConfig: TSamlConfigs | undefined;
|
let samlConfig: TSamlConfigs | undefined;
|
||||||
if (dto.type === "org") {
|
if (dto.type === "org") {
|
||||||
samlConfig = await samlConfigDAL.findOne({ orgId: dto.orgId });
|
samlConfig = await samlConfigDAL.findOne({ orgId: dto.orgId });
|
||||||
@@ -221,7 +219,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const samlLogin = async ({
|
const samlLogin: TSamlConfigServiceFactory["samlLogin"] = async ({
|
||||||
externalId,
|
externalId,
|
||||||
email,
|
email,
|
||||||
firstName,
|
firstName,
|
||||||
@@ -230,7 +228,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
orgId,
|
orgId,
|
||||||
relayState,
|
relayState,
|
||||||
metadata
|
metadata
|
||||||
}: TSamlLoginDTO) => {
|
}) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const serverCfg = await getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { TSamlConfigs } from "@app/db/schemas";
|
||||||
import { TOrgPermission } from "@app/lib/types";
|
import { TOrgPermission } from "@app/lib/types";
|
||||||
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
@@ -56,3 +57,26 @@ export type TSamlLoginDTO = {
|
|||||||
relayState?: string;
|
relayState?: string;
|
||||||
metadata?: { key: string; value: string }[];
|
metadata?: { key: string; value: string }[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TSamlConfigServiceFactory = {
|
||||||
|
createSamlCfg: (arg: TCreateSamlCfgDTO) => Promise<TSamlConfigs>;
|
||||||
|
updateSamlCfg: (arg: TUpdateSamlCfgDTO) => Promise<TSamlConfigs>;
|
||||||
|
getSaml: (arg: TGetSamlCfgDTO) => Promise<
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
organization: string;
|
||||||
|
orgId: string;
|
||||||
|
authProvider: string;
|
||||||
|
isActive: boolean;
|
||||||
|
entryPoint: string;
|
||||||
|
issuer: string;
|
||||||
|
cert: string;
|
||||||
|
lastUsed: Date | null | undefined;
|
||||||
|
}
|
||||||
|
| undefined
|
||||||
|
>;
|
||||||
|
samlLogin: (arg: TSamlLoginDTO) => Promise<{
|
||||||
|
isUserCompleted: boolean;
|
||||||
|
providerAuthToken: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TScimDALFactory = ReturnType<typeof scimDALFactory>;
|
export type TScimDALFactory = TOrmify<TableName.ScimToken>;
|
||||||
|
|
||||||
export const scimDALFactory = (db: TDbClient) => {
|
export const scimDALFactory = (db: TDbClient): TScimDALFactory => {
|
||||||
const scimTokenOrm = ormify(db, TableName.ScimToken);
|
const scimTokenOrm = ormify(db, TableName.ScimToken);
|
||||||
return scimTokenOrm;
|
return scimTokenOrm;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { TScimDALFactory } from "@app/ee/services/scim/scim-dal";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError, NotFoundError, ScimRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError, ScimRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
import { TOrgPermission } from "@app/lib/types";
|
|
||||||
import { AuthTokenType } from "@app/services/auth/auth-type";
|
import { AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
import { TExternalGroupOrgRoleMappingDALFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-dal";
|
import { TExternalGroupOrgRoleMappingDALFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-dal";
|
||||||
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
||||||
@@ -33,28 +32,10 @@ import { UserAliasType } from "@app/services/user-alias/user-alias-types";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { TProjectUserAdditionalPrivilegeDALFactory } from "../project-user-additional-privilege/project-user-additional-privilege-dal";
|
import { TProjectUserAdditionalPrivilegeDALFactory } from "../project-user-additional-privilege/project-user-additional-privilege-dal";
|
||||||
import { buildScimGroup, buildScimGroupList, buildScimUser, buildScimUserList, parseScimFilter } from "./scim-fns";
|
import { buildScimGroup, buildScimGroupList, buildScimUser, buildScimUserList, parseScimFilter } from "./scim-fns";
|
||||||
import {
|
import { TScimGroup, TScimServiceFactory } from "./scim-types";
|
||||||
TCreateScimGroupDTO,
|
|
||||||
TCreateScimTokenDTO,
|
|
||||||
TCreateScimUserDTO,
|
|
||||||
TDeleteScimGroupDTO,
|
|
||||||
TDeleteScimTokenDTO,
|
|
||||||
TDeleteScimUserDTO,
|
|
||||||
TGetScimGroupDTO,
|
|
||||||
TGetScimUserDTO,
|
|
||||||
TListScimGroupsDTO,
|
|
||||||
TListScimUsers,
|
|
||||||
TListScimUsersDTO,
|
|
||||||
TReplaceScimUserDTO,
|
|
||||||
TScimGroup,
|
|
||||||
TScimTokenJwtPayload,
|
|
||||||
TUpdateScimGroupNamePatchDTO,
|
|
||||||
TUpdateScimGroupNamePutDTO,
|
|
||||||
TUpdateScimUserDTO
|
|
||||||
} from "./scim-types";
|
|
||||||
|
|
||||||
type TScimServiceFactoryDep = {
|
type TScimServiceFactoryDep = {
|
||||||
scimDAL: Pick<TScimDALFactory, "create" | "find" | "findById" | "deleteById">;
|
scimDAL: Pick<TScimDALFactory, "create" | "find" | "findById" | "deleteById">;
|
||||||
@@ -111,8 +92,6 @@ type TScimServiceFactoryDep = {
|
|||||||
externalGroupOrgRoleMappingDAL: TExternalGroupOrgRoleMappingDALFactory;
|
externalGroupOrgRoleMappingDAL: TExternalGroupOrgRoleMappingDALFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TScimServiceFactory = ReturnType<typeof scimServiceFactory>;
|
|
||||||
|
|
||||||
export const scimServiceFactory = ({
|
export const scimServiceFactory = ({
|
||||||
licenseService,
|
licenseService,
|
||||||
scimDAL,
|
scimDAL,
|
||||||
@@ -131,8 +110,8 @@ export const scimServiceFactory = ({
|
|||||||
projectUserAdditionalPrivilegeDAL,
|
projectUserAdditionalPrivilegeDAL,
|
||||||
smtpService,
|
smtpService,
|
||||||
externalGroupOrgRoleMappingDAL
|
externalGroupOrgRoleMappingDAL
|
||||||
}: TScimServiceFactoryDep) => {
|
}: TScimServiceFactoryDep): TScimServiceFactory => {
|
||||||
const createScimToken = async ({
|
const createScimToken: TScimServiceFactory["createScimToken"] = async ({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
@@ -140,7 +119,7 @@ export const scimServiceFactory = ({
|
|||||||
orgId,
|
orgId,
|
||||||
description,
|
description,
|
||||||
ttlDays
|
ttlDays
|
||||||
}: TCreateScimTokenDTO) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Scim);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Scim);
|
||||||
|
|
||||||
@@ -169,7 +148,13 @@ export const scimServiceFactory = ({
|
|||||||
return { scimToken };
|
return { scimToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
const listScimTokens = async ({ actor, actorId, actorOrgId, actorAuthMethod, orgId }: TOrgPermission) => {
|
const listScimTokens: TScimServiceFactory["listScimTokens"] = async ({
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
orgId
|
||||||
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Scim);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Scim);
|
||||||
|
|
||||||
@@ -183,7 +168,13 @@ export const scimServiceFactory = ({
|
|||||||
return scimTokens;
|
return scimTokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteScimToken = async ({ scimTokenId, actor, actorId, actorAuthMethod, actorOrgId }: TDeleteScimTokenDTO) => {
|
const deleteScimToken: TScimServiceFactory["deleteScimToken"] = async ({
|
||||||
|
scimTokenId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}) => {
|
||||||
let scimToken = await scimDAL.findById(scimTokenId);
|
let scimToken = await scimDAL.findById(scimTokenId);
|
||||||
if (!scimToken) throw new NotFoundError({ message: `SCIM token with ID '${scimTokenId}' not found` });
|
if (!scimToken) throw new NotFoundError({ message: `SCIM token with ID '${scimTokenId}' not found` });
|
||||||
|
|
||||||
@@ -208,12 +199,12 @@ export const scimServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// SCIM server endpoints
|
// SCIM server endpoints
|
||||||
const listScimUsers = async ({
|
const listScimUsers: TScimServiceFactory["listScimUsers"] = async ({
|
||||||
startIndex = 0,
|
startIndex = 0,
|
||||||
limit = 100,
|
limit = 100,
|
||||||
filter,
|
filter,
|
||||||
orgId
|
orgId
|
||||||
}: TListScimUsersDTO): Promise<TListScimUsers> => {
|
}) => {
|
||||||
const org = await orgDAL.findById(orgId);
|
const org = await orgDAL.findById(orgId);
|
||||||
|
|
||||||
if (!org.scimEnabled)
|
if (!org.scimEnabled)
|
||||||
@@ -250,7 +241,7 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getScimUser = async ({ orgMembershipId, orgId }: TGetScimUserDTO) => {
|
const getScimUser: TScimServiceFactory["getScimUser"] = async ({ orgMembershipId, orgId }) => {
|
||||||
const [membership] = await orgDAL
|
const [membership] = await orgDAL
|
||||||
.findMembership({
|
.findMembership({
|
||||||
[`${TableName.OrgMembership}.id` as "id"]: orgMembershipId,
|
[`${TableName.OrgMembership}.id` as "id"]: orgMembershipId,
|
||||||
@@ -287,7 +278,13 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const createScimUser = async ({ externalId, email, firstName, lastName, orgId }: TCreateScimUserDTO) => {
|
const createScimUser: TScimServiceFactory["createScimUser"] = async ({
|
||||||
|
externalId,
|
||||||
|
email,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
orgId
|
||||||
|
}) => {
|
||||||
if (!email) throw new ScimRequestError({ detail: "Invalid request. Missing email.", status: 400 });
|
if (!email) throw new ScimRequestError({ detail: "Invalid request. Missing email.", status: 400 });
|
||||||
|
|
||||||
const org = await orgDAL.findOrgById(orgId);
|
const org = await orgDAL.findOrgById(orgId);
|
||||||
@@ -467,7 +464,7 @@ export const scimServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// partial
|
// partial
|
||||||
const updateScimUser = async ({ orgMembershipId, orgId, operations }: TUpdateScimUserDTO) => {
|
const updateScimUser: TScimServiceFactory["updateScimUser"] = async ({ orgMembershipId, orgId, operations }) => {
|
||||||
const org = await orgDAL.findOrgById(orgId);
|
const org = await orgDAL.findOrgById(orgId);
|
||||||
if (!org.orgAuthMethod) {
|
if (!org.orgAuthMethod) {
|
||||||
throw new ScimRequestError({
|
throw new ScimRequestError({
|
||||||
@@ -540,7 +537,7 @@ export const scimServiceFactory = ({
|
|||||||
return scimUser;
|
return scimUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
const replaceScimUser = async ({
|
const replaceScimUser: TScimServiceFactory["replaceScimUser"] = async ({
|
||||||
orgMembershipId,
|
orgMembershipId,
|
||||||
active,
|
active,
|
||||||
orgId,
|
orgId,
|
||||||
@@ -548,7 +545,7 @@ export const scimServiceFactory = ({
|
|||||||
firstName,
|
firstName,
|
||||||
email,
|
email,
|
||||||
externalId
|
externalId
|
||||||
}: TReplaceScimUserDTO) => {
|
}) => {
|
||||||
const org = await orgDAL.findOrgById(orgId);
|
const org = await orgDAL.findOrgById(orgId);
|
||||||
if (!org.orgAuthMethod) {
|
if (!org.orgAuthMethod) {
|
||||||
throw new ScimRequestError({
|
throw new ScimRequestError({
|
||||||
@@ -627,7 +624,7 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteScimUser = async ({ orgMembershipId, orgId }: TDeleteScimUserDTO) => {
|
const deleteScimUser: TScimServiceFactory["deleteScimUser"] = async ({ orgMembershipId, orgId }) => {
|
||||||
const [membership] = await orgDAL.findMembership({
|
const [membership] = await orgDAL.findMembership({
|
||||||
[`${TableName.OrgMembership}.id` as "id"]: orgMembershipId,
|
[`${TableName.OrgMembership}.id` as "id"]: orgMembershipId,
|
||||||
[`${TableName.OrgMembership}.orgId` as "orgId"]: orgId
|
[`${TableName.OrgMembership}.orgId` as "orgId"]: orgId
|
||||||
@@ -660,7 +657,13 @@ export const scimServiceFactory = ({
|
|||||||
return {}; // intentionally return empty object upon success
|
return {}; // intentionally return empty object upon success
|
||||||
};
|
};
|
||||||
|
|
||||||
const listScimGroups = async ({ orgId, startIndex, limit, filter, isMembersExcluded }: TListScimGroupsDTO) => {
|
const listScimGroups: TScimServiceFactory["listScimGroups"] = async ({
|
||||||
|
orgId,
|
||||||
|
startIndex,
|
||||||
|
limit,
|
||||||
|
filter,
|
||||||
|
isMembersExcluded
|
||||||
|
}) => {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.groups)
|
if (!plan.groups)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -768,7 +771,7 @@ export const scimServiceFactory = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const createScimGroup = async ({ displayName, orgId, members }: TCreateScimGroupDTO) => {
|
const createScimGroup: TScimServiceFactory["createScimGroup"] = async ({ displayName, orgId, members }) => {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.groups)
|
if (!plan.groups)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -863,7 +866,7 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getScimGroup = async ({ groupId, orgId }: TGetScimGroupDTO) => {
|
const getScimGroup: TScimServiceFactory["getScimGroup"] = async ({ groupId, orgId }) => {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.groups)
|
if (!plan.groups)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -1011,7 +1014,12 @@ export const scimServiceFactory = ({
|
|||||||
return updatedGroup;
|
return updatedGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
const replaceScimGroup = async ({ groupId, orgId, displayName, members }: TUpdateScimGroupNamePutDTO) => {
|
const replaceScimGroup: TScimServiceFactory["replaceScimGroup"] = async ({
|
||||||
|
groupId,
|
||||||
|
orgId,
|
||||||
|
displayName,
|
||||||
|
members
|
||||||
|
}) => {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.groups)
|
if (!plan.groups)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -1043,7 +1051,7 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateScimGroup = async ({ groupId, orgId, operations }: TUpdateScimGroupNamePatchDTO) => {
|
const updateScimGroup: TScimServiceFactory["updateScimGroup"] = async ({ groupId, orgId, operations }) => {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.groups)
|
if (!plan.groups)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -1101,7 +1109,7 @@ export const scimServiceFactory = ({
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteScimGroup = async ({ groupId, orgId }: TDeleteScimGroupDTO) => {
|
const deleteScimGroup: TScimServiceFactory["deleteScimGroup"] = async ({ groupId, orgId }) => {
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.groups)
|
if (!plan.groups)
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -1137,7 +1145,7 @@ export const scimServiceFactory = ({
|
|||||||
return {}; // intentionally return empty object upon success
|
return {}; // intentionally return empty object upon success
|
||||||
};
|
};
|
||||||
|
|
||||||
const fnValidateScimToken = async (token: TScimTokenJwtPayload) => {
|
const fnValidateScimToken: TScimServiceFactory["fnValidateScimToken"] = async (token) => {
|
||||||
const scimToken = await scimDAL.findById(token.scimTokenId);
|
const scimToken = await scimDAL.findById(token.scimTokenId);
|
||||||
if (!scimToken) throw new UnauthorizedError();
|
if (!scimToken) throw new UnauthorizedError();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ScimPatchOperation } from "scim-patch";
|
import { ScimPatchOperation } from "scim-patch";
|
||||||
|
|
||||||
|
import { TScimTokens } from "@app/db/schemas";
|
||||||
import { TOrgPermission } from "@app/lib/types";
|
import { TOrgPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export type TCreateScimTokenDTO = {
|
export type TCreateScimTokenDTO = {
|
||||||
@@ -156,3 +157,47 @@ export type TScimGroup = {
|
|||||||
lastModified: Date;
|
lastModified: Date;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TScimServiceFactory = {
|
||||||
|
createScimToken: (arg: TCreateScimTokenDTO) => Promise<{
|
||||||
|
scimToken: string;
|
||||||
|
}>;
|
||||||
|
listScimTokens: (arg: TOrgPermission) => Promise<TScimTokens[]>;
|
||||||
|
deleteScimToken: (arg: TDeleteScimTokenDTO) => Promise<{
|
||||||
|
orgId: string;
|
||||||
|
id: string;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
description: string;
|
||||||
|
ttlDays: number;
|
||||||
|
}>;
|
||||||
|
listScimUsers: (arg: TListScimUsersDTO) => Promise<TListScimUsers>;
|
||||||
|
getScimUser: (arg: TGetScimUserDTO) => Promise<TScimUser>;
|
||||||
|
createScimUser: (arg: TCreateScimUserDTO) => Promise<TScimUser>;
|
||||||
|
updateScimUser: (arg: TUpdateScimUserDTO) => Promise<TScimUser>;
|
||||||
|
replaceScimUser: (arg: TReplaceScimUserDTO) => Promise<TScimUser>;
|
||||||
|
deleteScimUser: (arg: TDeleteScimUserDTO) => Promise<object>;
|
||||||
|
listScimGroups: (arg: TListScimGroupsDTO) => Promise<TListScimGroups>;
|
||||||
|
createScimGroup: (arg: TCreateScimGroupDTO) => Promise<TScimGroup>;
|
||||||
|
getScimGroup: (arg: TGetScimGroupDTO) => Promise<TScimGroup>;
|
||||||
|
deleteScimGroup: (arg: TDeleteScimGroupDTO) => Promise<object>;
|
||||||
|
replaceScimGroup: (arg: TUpdateScimGroupNamePutDTO) => Promise<TScimGroup>;
|
||||||
|
updateScimGroup: (arg: TUpdateScimGroupNamePatchDTO) => Promise<{
|
||||||
|
members: {
|
||||||
|
value: string;
|
||||||
|
display: string;
|
||||||
|
}[];
|
||||||
|
schemas: string[];
|
||||||
|
id: string;
|
||||||
|
displayName: string;
|
||||||
|
meta: {
|
||||||
|
resourceType: string;
|
||||||
|
created: Date;
|
||||||
|
lastModified: Date;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
fnValidateScimToken: (token: TScimTokenJwtPayload) => Promise<{
|
||||||
|
scimTokenId: string;
|
||||||
|
orgId: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import picomatch from "picomatch";
|
import picomatch from "picomatch";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { removeTrailingSlash } from "@app/lib/fn";
|
import { removeTrailingSlash } from "@app/lib/fn";
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ import {
|
|||||||
fnSecretBulkDelete,
|
fnSecretBulkDelete,
|
||||||
fnSecretBulkInsert,
|
fnSecretBulkInsert,
|
||||||
fnSecretBulkUpdate,
|
fnSecretBulkUpdate,
|
||||||
getAllNestedSecretReferences
|
getAllNestedSecretReferences,
|
||||||
|
INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
} from "@app/services/secret/secret-fns";
|
} from "@app/services/secret/secret-fns";
|
||||||
import { TSecretQueueFactory } from "@app/services/secret/secret-queue";
|
import { TSecretQueueFactory } from "@app/services/secret/secret-queue";
|
||||||
import { SecretOperations } from "@app/services/secret/secret-types";
|
import { SecretOperations } from "@app/services/secret/secret-types";
|
||||||
@@ -63,7 +64,7 @@ import { TUserDALFactory } from "@app/services/user/user-dal";
|
|||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { throwIfMissingSecretReadValueOrDescribePermission } from "../permission/permission-fns";
|
import { throwIfMissingSecretReadValueOrDescribePermission } from "../permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { ProjectPermissionSecretActions, ProjectPermissionSub } from "../permission/project-permission";
|
import { ProjectPermissionSecretActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||||
import { TSecretApprovalPolicyDALFactory } from "../secret-approval-policy/secret-approval-policy-dal";
|
import { TSecretApprovalPolicyDALFactory } from "../secret-approval-policy/secret-approval-policy-dal";
|
||||||
import { TSecretSnapshotServiceFactory } from "../secret-snapshot/secret-snapshot-service";
|
import { TSecretSnapshotServiceFactory } from "../secret-snapshot/secret-snapshot-service";
|
||||||
@@ -267,7 +268,6 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
ProjectPermissionSecretActions.DescribeAndReadValue,
|
ProjectPermissionSecretActions.DescribeAndReadValue,
|
||||||
ProjectPermissionSub.Secrets
|
ProjectPermissionSub.Secrets
|
||||||
);
|
);
|
||||||
const hiddenSecretValue = "******";
|
|
||||||
|
|
||||||
let secrets;
|
let secrets;
|
||||||
if (shouldUseSecretV2Bridge) {
|
if (shouldUseSecretV2Bridge) {
|
||||||
@@ -285,8 +285,9 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
version: el.version,
|
version: el.version,
|
||||||
secretMetadata: el.secretMetadata as ResourceMetadataDTO,
|
secretMetadata: el.secretMetadata as ResourceMetadataDTO,
|
||||||
isRotatedSecret: el.secret?.isRotatedSecret ?? false,
|
isRotatedSecret: el.secret?.isRotatedSecret ?? false,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
secretValue: !hasSecretReadAccess
|
secretValue: !hasSecretReadAccess
|
||||||
? hiddenSecretValue
|
? INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
: el.secret && el.secret.isRotatedSecret
|
: el.secret && el.secret.isRotatedSecret
|
||||||
? undefined
|
? undefined
|
||||||
: el.encryptedValue
|
: el.encryptedValue
|
||||||
@@ -300,8 +301,9 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretKey: el.secret.key,
|
secretKey: el.secret.key,
|
||||||
id: el.secret.id,
|
id: el.secret.id,
|
||||||
version: el.secret.version,
|
version: el.secret.version,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
secretValue: !hasSecretReadAccess
|
secretValue: !hasSecretReadAccess
|
||||||
? hiddenSecretValue
|
? INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
: el.secret.encryptedValue
|
: el.secret.encryptedValue
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.secret.encryptedValue }).toString()
|
? secretManagerDecryptor({ cipherTextBlob: el.secret.encryptedValue }).toString()
|
||||||
: "",
|
: "",
|
||||||
@@ -315,8 +317,9 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
secretKey: el.secretVersion.key,
|
secretKey: el.secretVersion.key,
|
||||||
id: el.secretVersion.id,
|
id: el.secretVersion.id,
|
||||||
version: el.secretVersion.version,
|
version: el.secretVersion.version,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
secretValue: !hasSecretReadAccess
|
secretValue: !hasSecretReadAccess
|
||||||
? hiddenSecretValue
|
? INFISICAL_SECRET_VALUE_HIDDEN_MASK
|
||||||
: el.secretVersion.encryptedValue
|
: el.secretVersion.encryptedValue
|
||||||
? secretManagerDecryptor({ cipherTextBlob: el.secretVersion.encryptedValue }).toString()
|
? secretManagerDecryptor({ cipherTextBlob: el.secretVersion.encryptedValue }).toString()
|
||||||
: "",
|
: "",
|
||||||
@@ -333,11 +336,13 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
const encryptedSecrets = await secretApprovalRequestSecretDAL.findByRequestId(secretApprovalRequest.id);
|
const encryptedSecrets = await secretApprovalRequestSecretDAL.findByRequestId(secretApprovalRequest.id);
|
||||||
secrets = encryptedSecrets.map((el) => ({
|
secrets = encryptedSecrets.map((el) => ({
|
||||||
...el,
|
...el,
|
||||||
|
secretValueHidden: !hasSecretReadAccess,
|
||||||
...decryptSecretWithBot(el, botKey),
|
...decryptSecretWithBot(el, botKey),
|
||||||
secret: el.secret
|
secret: el.secret
|
||||||
? {
|
? {
|
||||||
id: el.secret.id,
|
id: el.secret.id,
|
||||||
version: el.secret.version,
|
version: el.secret.version,
|
||||||
|
secretValueHidden: false,
|
||||||
...decryptSecretWithBot(el.secret, botKey)
|
...decryptSecretWithBot(el.secret, botKey)
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
@@ -345,6 +350,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
? {
|
? {
|
||||||
id: el.secretVersion.id,
|
id: el.secretVersion.id,
|
||||||
version: el.secretVersion.version,
|
version: el.secretVersion.version,
|
||||||
|
secretValueHidden: false,
|
||||||
...decryptSecretWithBot(el.secretVersion, botKey)
|
...decryptSecretWithBot(el.secretVersion, botKey)
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
@@ -353,6 +359,7 @@ export const secretApprovalRequestServiceFactory = ({
|
|||||||
const secretPath = await folderDAL.findSecretPathByFolderIds(secretApprovalRequest.projectId, [
|
const secretPath = await folderDAL.findSecretPathByFolderIds(secretApprovalRequest.projectId, [
|
||||||
secretApprovalRequest.folderId
|
secretApprovalRequest.folderId
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return { ...secretApprovalRequest, secretPath: secretPath?.[0]?.path || "/", commits: secrets };
|
return { ...secretApprovalRequest, secretPath: secretPath?.[0]?.path || "/", commits: secrets };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ import { Knex } from "knex";
|
|||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
|
|
||||||
import { ActionProjectType, SecretType, TableName } from "@app/db/schemas";
|
import { ActionProjectType, SecretType, TableName } from "@app/db/schemas";
|
||||||
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { hasSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
|
import { hasSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionSecretActions,
|
ProjectPermissionSecretActions,
|
||||||
ProjectPermissionSecretRotationActions,
|
ProjectPermissionSecretRotationActions,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-fold
|
|||||||
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
import { TSecretV2BridgeDALFactory } from "@app/services/secret-v2-bridge/secret-v2-bridge-dal";
|
||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionSecretActions,
|
ProjectPermissionSecretActions,
|
||||||
ProjectPermissionSecretRotationActions,
|
ProjectPermissionSecretRotationActions,
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
import { ProjectMembershipRole, TSecretScanningFindings } from "@app/db/schemas";
|
import { ProjectMembershipRole, TSecretScanningFindings } from "@app/db/schemas";
|
||||||
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
|
||||||
import {
|
import {
|
||||||
createTempFolder,
|
createTempFolder,
|
||||||
deleteTempFolder,
|
deleteTempFolder,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { join } from "path";
|
|||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionSecretScanningConfigActions,
|
ProjectPermissionSecretScanningConfigActions,
|
||||||
ProjectPermissionSecretScanningDataSourceActions,
|
ProjectPermissionSecretScanningDataSourceActions,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { WebhookEventMap } from "@octokit/webhooks-types";
|
|||||||
import { ProbotOctokit } from "probot";
|
import { ProbotOctokit } from "probot";
|
||||||
|
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { NotFoundError } from "@app/lib/errors";
|
import { NotFoundError } from "@app/lib/errors";
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
hasSecretReadValueOrDescribePermission,
|
hasSecretReadValueOrDescribePermission,
|
||||||
throwIfMissingSecretReadValueOrDescribePermission
|
throwIfMissingSecretReadValueOrDescribePermission
|
||||||
} from "../permission/permission-fns";
|
} from "../permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSecretActions,
|
ProjectPermissionSecretActions,
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal";
|
import { TSshHostDALFactory } from "@app/ee/services/ssh-host/ssh-host-dal";
|
||||||
import { TSshHostLoginUserMappingDALFactory } from "@app/ee/services/ssh-host/ssh-host-login-user-mapping-dal";
|
import { TSshHostLoginUserMappingDALFactory } from "@app/ee/services/ssh-host/ssh-host-login-user-mapping-dal";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ForbiddenError, subject } from "@casl/ability";
|
|||||||
|
|
||||||
import { ActionProjectType, ProjectType } from "@app/db/schemas";
|
import { ActionProjectType, ProjectType } from "@app/db/schemas";
|
||||||
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
||||||
import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { TSshHostLoginUserMappingDALFactory } from "@app/ee/services/ssh-host/ssh-host-login-user-mapping-dal";
|
import { TSshHostLoginUserMappingDALFactory } from "@app/ee/services/ssh-host/ssh-host-login-user-mapping-dal";
|
||||||
import { TSshHostLoginUserDALFactory } from "@app/ee/services/ssh-host/ssh-login-user-dal";
|
import { TSshHostLoginUserDALFactory } from "@app/ee/services/ssh-host/ssh-login-user-dal";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||||
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
||||||
import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName } from "@app/db/schemas";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify, TOrmify } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TTrustedIpDALFactory = ReturnType<typeof trustedIpDALFactory>;
|
export type TTrustedIpDALFactory = TOrmify<TableName.TrustedIps>;
|
||||||
|
|
||||||
export const trustedIpDALFactory = (db: TDbClient) => {
|
export const trustedIpDALFactory = (db: TDbClient): TTrustedIpDALFactory => {
|
||||||
const trustedIpOrm = ormify(db, TableName.TrustedIps);
|
const trustedIpOrm = ormify(db, TableName.TrustedIps);
|
||||||
return trustedIpOrm;
|
return trustedIpOrm;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType } from "@app/db/schemas";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||||
import { TTrustedIpDALFactory } from "./trusted-ip-dal";
|
import { TTrustedIpDALFactory } from "./trusted-ip-dal";
|
||||||
import { TCreateIpDTO, TDeleteIpDTO, TUpdateIpDTO } from "./trusted-ip-types";
|
import { TTrustedIpServiceFactory } from "./trusted-ip-types";
|
||||||
|
|
||||||
type TTrustedIpServiceFactoryDep = {
|
type TTrustedIpServiceFactoryDep = {
|
||||||
trustedIpDAL: TTrustedIpDALFactory;
|
trustedIpDAL: TTrustedIpDALFactory;
|
||||||
@@ -19,15 +18,19 @@ type TTrustedIpServiceFactoryDep = {
|
|||||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TTrustedIpServiceFactory = ReturnType<typeof trustedIpServiceFactory>;
|
|
||||||
|
|
||||||
export const trustedIpServiceFactory = ({
|
export const trustedIpServiceFactory = ({
|
||||||
trustedIpDAL,
|
trustedIpDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
licenseService,
|
licenseService,
|
||||||
projectDAL
|
projectDAL
|
||||||
}: TTrustedIpServiceFactoryDep) => {
|
}: TTrustedIpServiceFactoryDep): TTrustedIpServiceFactory => {
|
||||||
const listIpsByProjectId = async ({ projectId, actor, actorId, actorAuthMethod, actorOrgId }: TProjectPermission) => {
|
const listIpsByProjectId: TTrustedIpServiceFactory["listIpsByProjectId"] = async ({
|
||||||
|
projectId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}) => {
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -43,7 +46,7 @@ export const trustedIpServiceFactory = ({
|
|||||||
return trustedIps;
|
return trustedIps;
|
||||||
};
|
};
|
||||||
|
|
||||||
const addProjectIp = async ({
|
const addProjectIp: TTrustedIpServiceFactory["addProjectIp"] = async ({
|
||||||
projectId,
|
projectId,
|
||||||
actorId,
|
actorId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
@@ -52,7 +55,7 @@ export const trustedIpServiceFactory = ({
|
|||||||
ipAddress: ip,
|
ipAddress: ip,
|
||||||
comment,
|
comment,
|
||||||
isActive
|
isActive
|
||||||
}: TCreateIpDTO) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -89,7 +92,7 @@ export const trustedIpServiceFactory = ({
|
|||||||
return { trustedIp, project }; // for audit log
|
return { trustedIp, project }; // for audit log
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateProjectIp = async ({
|
const updateProjectIp: TTrustedIpServiceFactory["updateProjectIp"] = async ({
|
||||||
projectId,
|
projectId,
|
||||||
actorId,
|
actorId,
|
||||||
actor,
|
actor,
|
||||||
@@ -98,7 +101,7 @@ export const trustedIpServiceFactory = ({
|
|||||||
ipAddress: ip,
|
ipAddress: ip,
|
||||||
comment,
|
comment,
|
||||||
trustedIpId
|
trustedIpId
|
||||||
}: TUpdateIpDTO) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -137,14 +140,14 @@ export const trustedIpServiceFactory = ({
|
|||||||
return { trustedIp, project }; // for audit log
|
return { trustedIp, project }; // for audit log
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteProjectIp = async ({
|
const deleteProjectIp: TTrustedIpServiceFactory["deleteProjectIp"] = async ({
|
||||||
projectId,
|
projectId,
|
||||||
actorId,
|
actorId,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
trustedIpId
|
trustedIpId
|
||||||
}: TDeleteIpDTO) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { TProjects, TTrustedIps } from "@app/db/schemas";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export type TCreateIpDTO = TProjectPermission & {
|
export type TCreateIpDTO = TProjectPermission & {
|
||||||
@@ -15,3 +16,19 @@ export type TUpdateIpDTO = TProjectPermission & {
|
|||||||
export type TDeleteIpDTO = TProjectPermission & {
|
export type TDeleteIpDTO = TProjectPermission & {
|
||||||
trustedIpId: string;
|
trustedIpId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TTrustedIpServiceFactory = {
|
||||||
|
listIpsByProjectId: (arg: TProjectPermission) => Promise<TTrustedIps[]>;
|
||||||
|
addProjectIp: (arg: TCreateIpDTO) => Promise<{
|
||||||
|
trustedIp: TTrustedIps;
|
||||||
|
project: TProjects;
|
||||||
|
}>;
|
||||||
|
updateProjectIp: (arg: TUpdateIpDTO) => Promise<{
|
||||||
|
trustedIp: TTrustedIps;
|
||||||
|
project: TProjects;
|
||||||
|
}>;
|
||||||
|
deleteProjectIp: (arg: TDeleteIpDTO) => Promise<{
|
||||||
|
trustedIp: TTrustedIps;
|
||||||
|
project: TProjects;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { buildRedisFromConfig, TRedisConfigKeys } from "@app/lib/config/redis";
|
|||||||
import { pgAdvisoryLockHashText } from "@app/lib/crypto/hashtext";
|
import { pgAdvisoryLockHashText } from "@app/lib/crypto/hashtext";
|
||||||
import { applyJitter } from "@app/lib/dates";
|
import { applyJitter } from "@app/lib/dates";
|
||||||
import { delay as delayMs } from "@app/lib/delay";
|
import { delay as delayMs } from "@app/lib/delay";
|
||||||
import { Redlock, Settings } from "@app/lib/red-lock";
|
import { ExecutionResult, Redlock, Settings } from "@app/lib/red-lock";
|
||||||
|
|
||||||
export const PgSqlLock = {
|
export const PgSqlLock = {
|
||||||
BootUpMigration: 2023,
|
BootUpMigration: 2023,
|
||||||
@@ -14,8 +14,6 @@ export const PgSqlLock = {
|
|||||||
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`)
|
CreateProject: (orgId: string) => pgAdvisoryLockHashText(`create-project:${orgId}`)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type TKeyStoreFactory = ReturnType<typeof keyStoreFactory>;
|
|
||||||
|
|
||||||
// all the key prefixes used must be set here to avoid conflict
|
// all the key prefixes used must be set here to avoid conflict
|
||||||
export const KeyStorePrefixes = {
|
export const KeyStorePrefixes = {
|
||||||
SecretReplication: "secret-replication-import-lock",
|
SecretReplication: "secret-replication-import-lock",
|
||||||
@@ -71,7 +69,28 @@ type TWaitTillReady = {
|
|||||||
jitter?: number;
|
jitter?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys) => {
|
export type TKeyStoreFactory = {
|
||||||
|
setItem: (key: string, value: string | number | Buffer, prefix?: string) => Promise<"OK">;
|
||||||
|
getItem: (key: string, prefix?: string) => Promise<string | null>;
|
||||||
|
setExpiry: (key: string, expiryInSeconds: number) => Promise<number>;
|
||||||
|
setItemWithExpiry: (
|
||||||
|
key: string,
|
||||||
|
expiryInSeconds: number | string,
|
||||||
|
value: string | number | Buffer,
|
||||||
|
prefix?: string
|
||||||
|
) => Promise<"OK">;
|
||||||
|
deleteItem: (key: string) => Promise<number>;
|
||||||
|
deleteItems: (arg: TDeleteItems) => Promise<number>;
|
||||||
|
incrementBy: (key: string, value: number) => Promise<number>;
|
||||||
|
acquireLock(
|
||||||
|
resources: string[],
|
||||||
|
duration: number,
|
||||||
|
settings?: Partial<Settings>
|
||||||
|
): Promise<{ release: () => Promise<ExecutionResult> }>;
|
||||||
|
waitTillReady: ({ key, waitingCb, keyCheckCb, waitIteration, delay, jitter }: TWaitTillReady) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys): TKeyStoreFactory => {
|
||||||
const redis = buildRedisFromConfig(redisConfigKeys);
|
const redis = buildRedisFromConfig(redisConfigKeys);
|
||||||
const redisLock = new Redlock([redis], { retryCount: 2, retryDelay: 200 });
|
const redisLock = new Redlock([redis], { retryCount: 2, retryDelay: 200 });
|
||||||
|
|
||||||
@@ -108,7 +127,6 @@ export const keyStoreFactory = (redisConfigKeys: TRedisConfigKeys) => {
|
|||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await pipeline.exec();
|
await pipeline.exec();
|
||||||
totalDeleted += batch.length;
|
totalDeleted += batch.length;
|
||||||
console.log("BATCH DONE");
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await delayMs(Math.max(0, applyJitter(delay, jitter)));
|
await delayMs(Math.max(0, applyJitter(delay, jitter)));
|
||||||
|
|||||||
@@ -111,12 +111,14 @@ export const IDENTITIES = {
|
|||||||
CREATE: {
|
CREATE: {
|
||||||
name: "The name of the identity to create.",
|
name: "The name of the identity to create.",
|
||||||
organizationId: "The organization ID to which the identity belongs.",
|
organizationId: "The organization ID to which the identity belongs.",
|
||||||
role: "The role of the identity. Possible values are 'no-access', 'member', and 'admin'."
|
role: "The role of the identity. Possible values are 'no-access', 'member', and 'admin'.",
|
||||||
|
hasDeleteProtection: "Prevents deletion of the identity when enabled."
|
||||||
},
|
},
|
||||||
UPDATE: {
|
UPDATE: {
|
||||||
identityId: "The ID of the identity to update.",
|
identityId: "The ID of the identity to update.",
|
||||||
name: "The new name of the identity.",
|
name: "The new name of the identity.",
|
||||||
role: "The new role of the identity."
|
role: "The new role of the identity.",
|
||||||
|
hasDeleteProtection: "Prevents deletion of the identity when enabled."
|
||||||
},
|
},
|
||||||
DELETE: {
|
DELETE: {
|
||||||
identityId: "The ID of the identity to delete."
|
identityId: "The ID of the identity to delete."
|
||||||
@@ -2223,6 +2225,9 @@ export const AppConnections = {
|
|||||||
ONEPASS: {
|
ONEPASS: {
|
||||||
instanceUrl: "The URL of the 1Password Connect Server instance to authenticate with.",
|
instanceUrl: "The URL of the 1Password Connect Server instance to authenticate with.",
|
||||||
apiToken: "The API token used to access the 1Password Connect Server."
|
apiToken: "The API token used to access the 1Password Connect Server."
|
||||||
|
},
|
||||||
|
FLYIO: {
|
||||||
|
accessToken: "The Access Token used to access fly.io."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -2389,6 +2394,9 @@ export const SecretSyncs = {
|
|||||||
serviceId: "The ID of the Render service to sync secrets to.",
|
serviceId: "The ID of the Render service to sync secrets to.",
|
||||||
scope: "The Render scope that secrets should be synced to.",
|
scope: "The Render scope that secrets should be synced to.",
|
||||||
type: "The type of Render resource to sync secrets to."
|
type: "The type of Render resource to sync secrets to."
|
||||||
|
},
|
||||||
|
FLYIO: {
|
||||||
|
appId: "The ID of the Fly.io app to sync secrets to."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -262,8 +262,8 @@ const envSchema = z
|
|||||||
DATADOG_HOSTNAME: zpStr(z.string().optional()),
|
DATADOG_HOSTNAME: zpStr(z.string().optional()),
|
||||||
|
|
||||||
// PIT
|
// PIT
|
||||||
PIT_CHECKPOINT_WINDOW: zpStr(z.string().optional().default("2")),
|
PIT_CHECKPOINT_WINDOW: zpStr(z.string().optional().default("100")),
|
||||||
PIT_TREE_CHECKPOINT_WINDOW: zpStr(z.string().optional().default("30")),
|
PIT_TREE_CHECKPOINT_WINDOW: zpStr(z.string().optional().default("200")),
|
||||||
|
|
||||||
/* CORS ----------------------------------------------------------------------------- */
|
/* CORS ----------------------------------------------------------------------------- */
|
||||||
CORS_ALLOWED_ORIGINS: zpStr(
|
CORS_ALLOWED_ORIGINS: zpStr(
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ export const buildFindFilter =
|
|||||||
return bd;
|
return bd;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TFindReturn<TQuery extends Knex.QueryBuilder, TCount extends boolean = false> = Array<
|
export type TFindReturn<Tname extends keyof Tables, TCount extends boolean = false> = Array<
|
||||||
Awaited<TQuery>[0] &
|
Tables[Tname]["base"] &
|
||||||
(TCount extends true
|
(TCount extends true
|
||||||
? {
|
? {
|
||||||
count: string;
|
count: string;
|
||||||
@@ -94,40 +94,82 @@ export type TFindOpt<
|
|||||||
tx?: Knex;
|
tx?: Knex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TOrmify<Tname extends keyof Tables> = {
|
||||||
|
transaction: <T>(cb: (tx: Knex) => Promise<T>) => Promise<T>;
|
||||||
|
findById: (id: string, tx?: Knex) => Promise<Tables[Tname]["base"]>;
|
||||||
|
find: <TCount extends boolean = false, TCountDistinct extends keyof Tables[Tname]["base"] | undefined = undefined>(
|
||||||
|
filter: TFindFilter<Tables[Tname]["base"]>,
|
||||||
|
{ offset, limit, sort, count, tx, countDistinct }?: TFindOpt<Tables[Tname]["base"], TCount, TCountDistinct>
|
||||||
|
) => Promise<TFindReturn<Tname, TCountDistinct extends undefined ? TCount : true>>;
|
||||||
|
findOne: (filter: Partial<Tables[Tname]["base"]>, tx?: Knex) => Promise<Tables[Tname]["base"]>;
|
||||||
|
create: (data: Tables[Tname]["insert"], tx?: Knex) => Promise<Tables[Tname]["base"]>;
|
||||||
|
insertMany: (data: readonly Tables[Tname]["insert"][], tx?: Knex) => Promise<Tables[Tname]["base"][]>;
|
||||||
|
batchInsert: (data: readonly Tables[Tname]["insert"][], tx?: Knex) => Promise<Tables[Tname]["base"][]>;
|
||||||
|
upsert: (
|
||||||
|
data: readonly Tables[Tname]["insert"][],
|
||||||
|
onConflictField: keyof Tables[Tname]["base"] | Array<keyof Tables[Tname]["base"]>,
|
||||||
|
tx?: Knex,
|
||||||
|
mergeColumns?: (keyof Knex.ResolveTableType<Knex.TableType<Tname>, "update">)[] | undefined
|
||||||
|
) => Promise<Tables[Tname]["base"][]>;
|
||||||
|
updateById: (
|
||||||
|
id: string,
|
||||||
|
{
|
||||||
|
$incr,
|
||||||
|
$decr,
|
||||||
|
...data
|
||||||
|
}: Tables[Tname]["update"] & {
|
||||||
|
$incr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
||||||
|
$decr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
||||||
|
},
|
||||||
|
tx?: Knex
|
||||||
|
) => Promise<Tables[Tname]["base"]>;
|
||||||
|
update: (
|
||||||
|
filter: TFindFilter<Tables[Tname]["base"]>,
|
||||||
|
{
|
||||||
|
$incr,
|
||||||
|
$decr,
|
||||||
|
...data
|
||||||
|
}: Tables[Tname]["update"] & {
|
||||||
|
$incr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
||||||
|
$decr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
||||||
|
},
|
||||||
|
tx?: Knex
|
||||||
|
) => Promise<Tables[Tname]["base"][]>;
|
||||||
|
deleteById: (id: string, tx?: Knex) => Promise<Tables[Tname]["base"]>;
|
||||||
|
countDocuments: (tx?: Knex) => Promise<number>;
|
||||||
|
delete: (filter: TFindFilter<Tables[Tname]["base"]>, tx?: Knex) => Promise<Tables[Tname]["base"][]>;
|
||||||
|
};
|
||||||
|
|
||||||
// What is ormify
|
// What is ormify
|
||||||
// It is to inject typical operations like find, findOne, update, delete, create
|
// It is to inject typical operations like find, findOne, update, delete, create
|
||||||
// This will avoid writing most common ones each time
|
// This will avoid writing most common ones each time
|
||||||
export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Knex, tableName: Tname, dal?: DbOps) => ({
|
export const ormify = <DbOps extends object, Tname extends keyof Tables>(
|
||||||
|
db: Knex,
|
||||||
|
tableName: Tname,
|
||||||
|
dal?: DbOps
|
||||||
|
): TOrmify<Tname> => ({
|
||||||
transaction: async <T>(cb: (tx: Knex) => Promise<T>) =>
|
transaction: async <T>(cb: (tx: Knex) => Promise<T>) =>
|
||||||
db.transaction(async (trx) => {
|
db.transaction(async (trx) => {
|
||||||
const res = await cb(trx);
|
const res = await cb(trx);
|
||||||
return res;
|
return res;
|
||||||
}),
|
}),
|
||||||
findById: async (id: string, tx?: Knex) => {
|
findById: async (id, tx): Promise<Tables[Tname]["base"]> => {
|
||||||
try {
|
try {
|
||||||
const result = await (tx || db.replicaNode())(tableName)
|
const result = await (tx || db.replicaNode())(tableName)
|
||||||
.where({ id } as never)
|
.where({ id } as never)
|
||||||
.first("*");
|
.first("*");
|
||||||
return result;
|
return result as Tables[Tname]["base"];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find by id" });
|
throw new DatabaseError({ error, name: "Find by id" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
findOne: async (filter: Partial<Tables[Tname]["base"]>, tx?: Knex) => {
|
|
||||||
try {
|
|
||||||
const res = await (tx || db.replicaNode())(tableName).where(filter).first("*");
|
|
||||||
return res;
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "Find one" });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
find: async <
|
find: async <
|
||||||
TCount extends boolean = false,
|
TCount extends boolean = false,
|
||||||
TCountDistinct extends keyof Tables[Tname]["base"] | undefined = undefined
|
TCountDistinct extends keyof Tables[Tname]["base"] | undefined = undefined
|
||||||
>(
|
>(
|
||||||
filter: TFindFilter<Tables[Tname]["base"]>,
|
filter: TFindFilter<Tables[Tname]["base"]>,
|
||||||
{ offset, limit, sort, count, tx, countDistinct }: TFindOpt<Tables[Tname]["base"], TCount, TCountDistinct> = {}
|
{ offset, limit, sort, count, tx, countDistinct }: TFindOpt<Tables[Tname]["base"], TCount, TCountDistinct> = {}
|
||||||
) => {
|
): Promise<TFindReturn<Tname, TCountDistinct extends undefined ? TCount : true>> => {
|
||||||
try {
|
try {
|
||||||
const query = (tx || db.replicaNode())(tableName).where(buildFindFilter(filter));
|
const query = (tx || db.replicaNode())(tableName).where(buildFindFilter(filter));
|
||||||
if (countDistinct) {
|
if (countDistinct) {
|
||||||
@@ -142,35 +184,43 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Kne
|
|||||||
void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })));
|
void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = (await query) as TFindReturn<typeof query, TCountDistinct extends undefined ? TCount : true>;
|
const res = await query;
|
||||||
return res;
|
return res as TFindReturn<Tname, TCountDistinct extends undefined ? TCount : true>;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find one" });
|
throw new DatabaseError({ error, name: "Find one" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
create: async (data: Tables[Tname]["insert"], tx?: Knex) => {
|
findOne: async (filter, tx): Promise<Tables[Tname]["base"]> => {
|
||||||
|
try {
|
||||||
|
const res = await (tx || db.replicaNode())(tableName).where(filter).first("*");
|
||||||
|
return res as Tables[Tname]["base"];
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Find one" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
create: async (data, tx): Promise<Tables[Tname]["base"]> => {
|
||||||
try {
|
try {
|
||||||
const [res] = await (tx || db)(tableName)
|
const [res] = await (tx || db)(tableName)
|
||||||
.insert(data as never)
|
.insert(data as never)
|
||||||
.returning("*");
|
.returning("*");
|
||||||
return res;
|
return res as Tables[Tname]["base"];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Create" });
|
throw new DatabaseError({ error, name: "Create" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
insertMany: async (data: readonly Tables[Tname]["insert"][], tx?: Knex) => {
|
insertMany: async (data, tx?): Promise<Tables[Tname]["base"][]> => {
|
||||||
try {
|
try {
|
||||||
if (!data.length) return [];
|
if (!data.length) return [];
|
||||||
const res = await (tx || db)(tableName)
|
const res = await (tx || db)(tableName)
|
||||||
.insert(data as never)
|
.insert(data as never)
|
||||||
.returning("*");
|
.returning("*");
|
||||||
return res;
|
return res as Tables[Tname]["base"][];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Create" });
|
throw new DatabaseError({ error, name: "Create" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// This spilit the insert into multiple chunk
|
// This spilit the insert into multiple chunk
|
||||||
batchInsert: async (data: readonly Tables[Tname]["insert"][], tx?: Knex) => {
|
batchInsert: async (data, tx): Promise<Tables[Tname]["base"][]> => {
|
||||||
try {
|
try {
|
||||||
if (!data.length) return [];
|
if (!data.length) return [];
|
||||||
const res = await (tx || db).batchInsert(tableName, data as never).returning("*");
|
const res = await (tx || db).batchInsert(tableName, data as never).returning("*");
|
||||||
@@ -179,12 +229,7 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Kne
|
|||||||
throw new DatabaseError({ error, name: "batchInsert" });
|
throw new DatabaseError({ error, name: "batchInsert" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
upsert: async (
|
upsert: async (data, onConflictField, tx, mergeColumns): Promise<Tables[Tname]["base"][]> => {
|
||||||
data: readonly Tables[Tname]["insert"][],
|
|
||||||
onConflictField: keyof Tables[Tname]["base"] | Array<keyof Tables[Tname]["base"]>,
|
|
||||||
tx?: Knex,
|
|
||||||
mergeColumns?: (keyof Knex.ResolveTableType<Knex.TableType<Tname>, "update">)[] | undefined
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
if (!data.length) return [];
|
if (!data.length) return [];
|
||||||
const res = await (tx || db)(tableName)
|
const res = await (tx || db)(tableName)
|
||||||
@@ -192,23 +237,12 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Kne
|
|||||||
.onConflict(onConflictField as never)
|
.onConflict(onConflictField as never)
|
||||||
.merge(mergeColumns)
|
.merge(mergeColumns)
|
||||||
.returning("*");
|
.returning("*");
|
||||||
return res;
|
return res as Tables[Tname]["base"][];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Create" });
|
throw new DatabaseError({ error, name: "Create" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateById: async (
|
updateById: async (id, { $incr, $decr, ...data }, tx): Promise<Tables[Tname]["base"]> => {
|
||||||
id: string,
|
|
||||||
{
|
|
||||||
$incr,
|
|
||||||
$decr,
|
|
||||||
...data
|
|
||||||
}: Tables[Tname]["update"] & {
|
|
||||||
$incr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
|
||||||
$decr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
|
||||||
},
|
|
||||||
tx?: Knex
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const query = (tx || db)(tableName)
|
const query = (tx || db)(tableName)
|
||||||
.where({ id } as never)
|
.where({ id } as never)
|
||||||
@@ -225,23 +259,12 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Kne
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const [docs] = await query;
|
const [docs] = await query;
|
||||||
return docs;
|
return docs as Tables[Tname]["base"];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Update by id" });
|
throw new DatabaseError({ error, name: "Update by id" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: async (
|
update: async (filter, { $incr, $decr, ...data }, tx): Promise<Tables[Tname]["base"][]> => {
|
||||||
filter: TFindFilter<Tables[Tname]["base"]>,
|
|
||||||
{
|
|
||||||
$incr,
|
|
||||||
$decr,
|
|
||||||
...data
|
|
||||||
}: Tables[Tname]["update"] & {
|
|
||||||
$incr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
|
||||||
$decr?: { [x in keyof Partial<Tables[Tname]["base"]>]: number };
|
|
||||||
},
|
|
||||||
tx?: Knex
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
const query = (tx || db)(tableName)
|
const query = (tx || db)(tableName)
|
||||||
.where(buildFindFilter(filter))
|
.where(buildFindFilter(filter))
|
||||||
@@ -258,26 +281,34 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Kne
|
|||||||
void query.increment(incrementField, incrementValue);
|
void query.increment(incrementField, incrementValue);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return await query;
|
return (await query) as Tables[Tname]["base"][];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Update" });
|
throw new DatabaseError({ error, name: "Update" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteById: async (id: string, tx?: Knex) => {
|
deleteById: async (id, tx): Promise<Tables[Tname]["base"]> => {
|
||||||
try {
|
try {
|
||||||
const [res] = await (tx || db)(tableName)
|
const [res] = await (tx || db)(tableName)
|
||||||
.where({ id } as never)
|
.where({ id } as never)
|
||||||
.delete()
|
.delete()
|
||||||
.returning("*");
|
.returning("*");
|
||||||
return res;
|
return res as Tables[Tname]["base"];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Delete by id" });
|
throw new DatabaseError({ error, name: "Delete by id" });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
delete: async (filter: TFindFilter<Tables[Tname]["base"]>, tx?: Knex) => {
|
countDocuments: async (tx): Promise<number> => {
|
||||||
|
try {
|
||||||
|
const [res] = await (tx || db)(tableName).count({ count: "*" }).returning("*");
|
||||||
|
return Number((res as { count: number }).count || 0);
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Delete by id" });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delete: async (filter, tx): Promise<Tables[Tname]["base"][]> => {
|
||||||
try {
|
try {
|
||||||
const res = await (tx || db)(tableName).where(buildFindFilter(filter)).delete().returning("*");
|
const res = await (tx || db)(tableName).where(buildFindFilter(filter)).delete().returning("*");
|
||||||
return res;
|
return res as Tables[Tname]["base"][];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Delete" });
|
throw new DatabaseError({ error, name: "Delete" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,11 +325,69 @@ const isQueueEnabled = (name: QueueName) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TQueueServiceFactory = ReturnType<typeof queueServiceFactory>;
|
export type TQueueServiceFactory = {
|
||||||
|
initialize: () => Promise<void>;
|
||||||
|
start: <T extends QueueName>(
|
||||||
|
name: T,
|
||||||
|
jobFn: (job: Job<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>, token?: string) => Promise<void>,
|
||||||
|
queueSettings?: Omit<QueueOptions, "connection">
|
||||||
|
) => void;
|
||||||
|
startPg: <T extends QueueName>(
|
||||||
|
jobName: QueueJobs,
|
||||||
|
jobsFn: (jobs: PgBoss.JobWithMetadata<TQueueJobTypes[T]["payload"]>[]) => Promise<void>,
|
||||||
|
options: WorkOptions & {
|
||||||
|
workerCount: number;
|
||||||
|
}
|
||||||
|
) => Promise<void>;
|
||||||
|
listen: <
|
||||||
|
T extends QueueName,
|
||||||
|
U extends keyof WorkerListener<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>
|
||||||
|
>(
|
||||||
|
name: T,
|
||||||
|
event: U,
|
||||||
|
listener: WorkerListener<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>[U]
|
||||||
|
) => void;
|
||||||
|
queue: <T extends QueueName>(
|
||||||
|
name: T,
|
||||||
|
job: TQueueJobTypes[T]["name"],
|
||||||
|
data: TQueueJobTypes[T]["payload"],
|
||||||
|
opts?: JobsOptions & {
|
||||||
|
jobId?: string;
|
||||||
|
}
|
||||||
|
) => Promise<void>;
|
||||||
|
queuePg: <T extends QueueName>(
|
||||||
|
job: TQueueJobTypes[T]["name"],
|
||||||
|
data: TQueueJobTypes[T]["payload"],
|
||||||
|
opts?: PgBoss.SendOptions & { jobId?: string }
|
||||||
|
) => Promise<void>;
|
||||||
|
schedulePg: <T extends QueueName>(
|
||||||
|
job: TQueueJobTypes[T]["name"],
|
||||||
|
cron: string,
|
||||||
|
data: TQueueJobTypes[T]["payload"],
|
||||||
|
opts?: PgBoss.ScheduleOptions & { jobId?: string }
|
||||||
|
) => Promise<void>;
|
||||||
|
shutdown: () => Promise<void>;
|
||||||
|
stopRepeatableJob: <T extends QueueName>(
|
||||||
|
name: T,
|
||||||
|
job: TQueueJobTypes[T]["name"],
|
||||||
|
repeatOpt: RepeatOptions,
|
||||||
|
jobId?: string
|
||||||
|
) => Promise<boolean | undefined>;
|
||||||
|
stopRepeatableJobByJobId: <T extends QueueName>(name: T, jobId: string) => Promise<boolean>;
|
||||||
|
stopRepeatableJobByKey: <T extends QueueName>(name: T, repeatJobKey: string) => Promise<boolean>;
|
||||||
|
clearQueue: (name: QueueName) => Promise<void>;
|
||||||
|
stopJobById: <T extends QueueName>(name: T, jobId: string) => Promise<void | undefined>;
|
||||||
|
getRepeatableJobs: (
|
||||||
|
name: QueueName,
|
||||||
|
startOffset?: number,
|
||||||
|
endOffset?: number
|
||||||
|
) => Promise<{ key: string; name: string; id: string | null }[]>;
|
||||||
|
};
|
||||||
|
|
||||||
export const queueServiceFactory = (
|
export const queueServiceFactory = (
|
||||||
redisCfg: TRedisConfigKeys,
|
redisCfg: TRedisConfigKeys,
|
||||||
{ dbConnectionUrl, dbRootCert }: { dbConnectionUrl: string; dbRootCert?: string }
|
{ dbConnectionUrl, dbRootCert }: { dbConnectionUrl: string; dbRootCert?: string }
|
||||||
) => {
|
): TQueueServiceFactory => {
|
||||||
const connection = buildRedisFromConfig(redisCfg);
|
const connection = buildRedisFromConfig(redisCfg);
|
||||||
const queueContainer = {} as Record<
|
const queueContainer = {} as Record<
|
||||||
QueueName,
|
QueueName,
|
||||||
@@ -366,36 +424,26 @@ export const queueServiceFactory = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const start = <T extends QueueName>(
|
const start: TQueueServiceFactory["start"] = (name, jobFn, queueSettings) => {
|
||||||
name: T,
|
|
||||||
jobFn: (job: Job<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>, token?: string) => Promise<void>,
|
|
||||||
queueSettings: Omit<QueueOptions, "connection"> = {}
|
|
||||||
) => {
|
|
||||||
if (queueContainer[name]) {
|
if (queueContainer[name]) {
|
||||||
throw new Error(`${name} queue is already initialized`);
|
throw new Error(`${name} queue is already initialized`);
|
||||||
}
|
}
|
||||||
|
|
||||||
queueContainer[name] = new Queue<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>(name as string, {
|
queueContainer[name] = new Queue(name as string, {
|
||||||
...queueSettings,
|
...queueSettings,
|
||||||
connection
|
connection
|
||||||
});
|
});
|
||||||
|
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
if (appCfg.QUEUE_WORKERS_ENABLED && isQueueEnabled(name)) {
|
if (appCfg.QUEUE_WORKERS_ENABLED && isQueueEnabled(name)) {
|
||||||
workerContainer[name] = new Worker<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>(name, jobFn, {
|
workerContainer[name] = new Worker(name, jobFn, {
|
||||||
...queueSettings,
|
...queueSettings,
|
||||||
connection
|
connection
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const startPg = async <T extends QueueName>(
|
const startPg: TQueueServiceFactory["startPg"] = async (jobName, jobsFn, options) => {
|
||||||
jobName: QueueJobs,
|
|
||||||
jobsFn: (jobs: PgBoss.JobWithMetadata<TQueueJobTypes[T]["payload"]>[]) => Promise<void>,
|
|
||||||
options: WorkOptions & {
|
|
||||||
workerCount: number;
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
if (queueContainerPg[jobName]) {
|
if (queueContainerPg[jobName]) {
|
||||||
throw new Error(`${jobName} queue is already initialized`);
|
throw new Error(`${jobName} queue is already initialized`);
|
||||||
}
|
}
|
||||||
@@ -429,19 +477,12 @@ export const queueServiceFactory = (
|
|||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Array.from({ length: options.workerCount }).map(() =>
|
Array.from({ length: options.workerCount }).map(() =>
|
||||||
pgBoss.work<TQueueJobTypes[T]["payload"]>(jobName, { ...options, includeMetadata: true }, jobsFn)
|
pgBoss.work(jobName, { ...options, includeMetadata: true }, jobsFn)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const listen = <
|
const listen: TQueueServiceFactory["listen"] = (name, event, listener) => {
|
||||||
T extends QueueName,
|
|
||||||
U extends keyof WorkerListener<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>
|
|
||||||
>(
|
|
||||||
name: T,
|
|
||||||
event: U,
|
|
||||||
listener: WorkerListener<TQueueJobTypes[T]["payload"], void, TQueueJobTypes[T]["name"]>[U]
|
|
||||||
) => {
|
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
if (!appCfg.QUEUE_WORKERS_ENABLED || !isQueueEnabled(name)) {
|
if (!appCfg.QUEUE_WORKERS_ENABLED || !isQueueEnabled(name)) {
|
||||||
return;
|
return;
|
||||||
@@ -451,12 +492,7 @@ export const queueServiceFactory = (
|
|||||||
worker.on(event, listener);
|
worker.on(event, listener);
|
||||||
};
|
};
|
||||||
|
|
||||||
const queue = async <T extends QueueName>(
|
const queue: TQueueServiceFactory["queue"] = async (name, job, data, opts) => {
|
||||||
name: T,
|
|
||||||
job: TQueueJobTypes[T]["name"],
|
|
||||||
data: TQueueJobTypes[T]["payload"],
|
|
||||||
opts?: JobsOptions & { jobId?: string }
|
|
||||||
) => {
|
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
|
|
||||||
await q.add(job, data, opts);
|
await q.add(job, data, opts);
|
||||||
@@ -474,35 +510,25 @@ export const queueServiceFactory = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const schedulePg = async <T extends QueueName>(
|
const schedulePg: TQueueServiceFactory["schedulePg"] = async (job, cron, data, opts) => {
|
||||||
job: TQueueJobTypes[T]["name"],
|
|
||||||
cron: string,
|
|
||||||
data: TQueueJobTypes[T]["payload"],
|
|
||||||
opts?: PgBoss.ScheduleOptions & { jobId?: string }
|
|
||||||
) => {
|
|
||||||
await pgBoss.schedule(job, cron, data, opts);
|
await pgBoss.schedule(job, cron, data, opts);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopRepeatableJob = async <T extends QueueName>(
|
const stopRepeatableJob: TQueueServiceFactory["stopRepeatableJob"] = async (name, job, repeatOpt, jobId) => {
|
||||||
name: T,
|
|
||||||
job: TQueueJobTypes[T]["name"],
|
|
||||||
repeatOpt: RepeatOptions,
|
|
||||||
jobId?: string
|
|
||||||
) => {
|
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
if (q) {
|
if (q) {
|
||||||
return q.removeRepeatable(job, repeatOpt, jobId);
|
return q.removeRepeatable(job, repeatOpt, jobId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRepeatableJobs = (name: QueueName, startOffset?: number, endOffset?: number) => {
|
const getRepeatableJobs: TQueueServiceFactory["getRepeatableJobs"] = (name, startOffset, endOffset) => {
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
if (!q) throw new Error(`Queue '${name}' not initialized`);
|
if (!q) throw new Error(`Queue '${name}' not initialized`);
|
||||||
|
|
||||||
return q.getRepeatableJobs(startOffset, endOffset);
|
return q.getRepeatableJobs(startOffset, endOffset);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopRepeatableJobByJobId = async <T extends QueueName>(name: T, jobId: string) => {
|
const stopRepeatableJobByJobId: TQueueServiceFactory["stopRepeatableJobByJobId"] = async (name, jobId) => {
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
const job = await q.getJob(jobId);
|
const job = await q.getJob(jobId);
|
||||||
if (!job) return true;
|
if (!job) return true;
|
||||||
@@ -511,23 +537,23 @@ export const queueServiceFactory = (
|
|||||||
return q.removeRepeatableByKey(job.repeatJobKey);
|
return q.removeRepeatableByKey(job.repeatJobKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopRepeatableJobByKey = async <T extends QueueName>(name: T, repeatJobKey: string) => {
|
const stopRepeatableJobByKey: TQueueServiceFactory["stopRepeatableJobByKey"] = async (name, repeatJobKey) => {
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
return q.removeRepeatableByKey(repeatJobKey);
|
return q.removeRepeatableByKey(repeatJobKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopJobById = async <T extends QueueName>(name: T, jobId: string) => {
|
const stopJobById: TQueueServiceFactory["stopJobById"] = async (name, jobId) => {
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
const job = await q.getJob(jobId);
|
const job = await q.getJob(jobId);
|
||||||
return job?.remove().catch(() => undefined);
|
return job?.remove().catch(() => undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearQueue = async (name: QueueName) => {
|
const clearQueue: TQueueServiceFactory["clearQueue"] = async (name) => {
|
||||||
const q = queueContainer[name];
|
const q = queueContainer[name];
|
||||||
await q.drain();
|
await q.drain();
|
||||||
};
|
};
|
||||||
|
|
||||||
const shutdown = async () => {
|
const shutdown: TQueueServiceFactory["shutdown"] = async () => {
|
||||||
await Promise.all(Object.values(workerContainer).map((worker) => worker.close()));
|
await Promise.all(Object.values(workerContainer).map((worker) => worker.close()));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {
|
|||||||
DatabricksConnectionListItemSchema,
|
DatabricksConnectionListItemSchema,
|
||||||
SanitizedDatabricksConnectionSchema
|
SanitizedDatabricksConnectionSchema
|
||||||
} from "@app/services/app-connection/databricks";
|
} from "@app/services/app-connection/databricks";
|
||||||
|
import { FlyioConnectionListItemSchema, SanitizedFlyioConnectionSchema } from "@app/services/app-connection/flyio";
|
||||||
import { GcpConnectionListItemSchema, SanitizedGcpConnectionSchema } from "@app/services/app-connection/gcp";
|
import { GcpConnectionListItemSchema, SanitizedGcpConnectionSchema } from "@app/services/app-connection/gcp";
|
||||||
import { GitHubConnectionListItemSchema, SanitizedGitHubConnectionSchema } from "@app/services/app-connection/github";
|
import { GitHubConnectionListItemSchema, SanitizedGitHubConnectionSchema } from "@app/services/app-connection/github";
|
||||||
import {
|
import {
|
||||||
@@ -105,7 +106,8 @@ const SanitizedAppConnectionSchema = z.union([
|
|||||||
...SanitizedOCIConnectionSchema.options,
|
...SanitizedOCIConnectionSchema.options,
|
||||||
...SanitizedOracleDBConnectionSchema.options,
|
...SanitizedOracleDBConnectionSchema.options,
|
||||||
...SanitizedOnePassConnectionSchema.options,
|
...SanitizedOnePassConnectionSchema.options,
|
||||||
...SanitizedRenderConnectionSchema.options
|
...SanitizedRenderConnectionSchema.options,
|
||||||
|
...SanitizedFlyioConnectionSchema.options
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
||||||
@@ -133,7 +135,8 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
|||||||
OCIConnectionListItemSchema,
|
OCIConnectionListItemSchema,
|
||||||
OracleDBConnectionListItemSchema,
|
OracleDBConnectionListItemSchema,
|
||||||
OnePassConnectionListItemSchema,
|
OnePassConnectionListItemSchema,
|
||||||
RenderConnectionListItemSchema
|
RenderConnectionListItemSchema,
|
||||||
|
FlyioConnectionListItemSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
|
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { readLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import {
|
||||||
|
CreateFlyioConnectionSchema,
|
||||||
|
SanitizedFlyioConnectionSchema,
|
||||||
|
UpdateFlyioConnectionSchema
|
||||||
|
} from "@app/services/app-connection/flyio";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
|
||||||
|
|
||||||
|
export const registerFlyioConnectionRouter = async (server: FastifyZodProvider) => {
|
||||||
|
registerAppConnectionEndpoints({
|
||||||
|
app: AppConnection.Flyio,
|
||||||
|
server,
|
||||||
|
sanitizedResponseSchema: SanitizedFlyioConnectionSchema,
|
||||||
|
createSchema: CreateFlyioConnectionSchema,
|
||||||
|
updateSchema: UpdateFlyioConnectionSchema
|
||||||
|
});
|
||||||
|
|
||||||
|
// The following endpoints are for internal Infisical App use only and not part of the public API
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: `/:connectionId/apps`,
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
connectionId: z.string().uuid()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { connectionId } = req.params;
|
||||||
|
const apps = await server.services.appConnection.flyio.listApps(connectionId, req.permission);
|
||||||
|
return apps;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -11,6 +11,7 @@ import { registerAzureDevOpsConnectionRouter } from "./azure-devops-connection-r
|
|||||||
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
|
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
|
||||||
import { registerCamundaConnectionRouter } from "./camunda-connection-router";
|
import { registerCamundaConnectionRouter } from "./camunda-connection-router";
|
||||||
import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
|
import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
|
||||||
|
import { registerFlyioConnectionRouter } from "./flyio-connection-router";
|
||||||
import { registerGcpConnectionRouter } from "./gcp-connection-router";
|
import { registerGcpConnectionRouter } from "./gcp-connection-router";
|
||||||
import { registerGitHubConnectionRouter } from "./github-connection-router";
|
import { registerGitHubConnectionRouter } from "./github-connection-router";
|
||||||
import { registerGitHubRadarConnectionRouter } from "./github-radar-connection-router";
|
import { registerGitHubRadarConnectionRouter } from "./github-radar-connection-router";
|
||||||
@@ -54,5 +55,6 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
|
|||||||
[AppConnection.OCI]: registerOCIConnectionRouter,
|
[AppConnection.OCI]: registerOCIConnectionRouter,
|
||||||
[AppConnection.OracleDB]: registerOracleDBConnectionRouter,
|
[AppConnection.OracleDB]: registerOracleDBConnectionRouter,
|
||||||
[AppConnection.OnePass]: registerOnePassConnectionRouter,
|
[AppConnection.OnePass]: registerOnePassConnectionRouter,
|
||||||
[AppConnection.Render]: registerRenderConnectionRouter
|
[AppConnection.Render]: registerRenderConnectionRouter,
|
||||||
|
[AppConnection.Flyio]: registerFlyioConnectionRouter
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
name: z.string().trim().describe(IDENTITIES.CREATE.name),
|
name: z.string().trim().describe(IDENTITIES.CREATE.name),
|
||||||
organizationId: z.string().trim().describe(IDENTITIES.CREATE.organizationId),
|
organizationId: z.string().trim().describe(IDENTITIES.CREATE.organizationId),
|
||||||
role: z.string().trim().min(1).default(OrgMembershipRole.NoAccess).describe(IDENTITIES.CREATE.role),
|
role: z.string().trim().min(1).default(OrgMembershipRole.NoAccess).describe(IDENTITIES.CREATE.role),
|
||||||
|
hasDeleteProtection: z.boolean().default(false).describe(IDENTITIES.CREATE.hasDeleteProtection),
|
||||||
metadata: z
|
metadata: z
|
||||||
.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })
|
.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })
|
||||||
.array()
|
.array()
|
||||||
@@ -75,6 +76,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
type: EventType.CREATE_IDENTITY,
|
type: EventType.CREATE_IDENTITY,
|
||||||
metadata: {
|
metadata: {
|
||||||
name: identity.name,
|
name: identity.name,
|
||||||
|
hasDeleteProtection: identity.hasDeleteProtection,
|
||||||
identityId: identity.id
|
identityId: identity.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,6 +88,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
properties: {
|
properties: {
|
||||||
orgId: req.body.organizationId,
|
orgId: req.body.organizationId,
|
||||||
name: identity.name,
|
name: identity.name,
|
||||||
|
hasDeleteProtection: identity.hasDeleteProtection,
|
||||||
identityId: identity.id,
|
identityId: identity.id,
|
||||||
...req.auditLogInfo
|
...req.auditLogInfo
|
||||||
}
|
}
|
||||||
@@ -117,6 +120,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
name: z.string().trim().optional().describe(IDENTITIES.UPDATE.name),
|
name: z.string().trim().optional().describe(IDENTITIES.UPDATE.name),
|
||||||
role: z.string().trim().min(1).optional().describe(IDENTITIES.UPDATE.role),
|
role: z.string().trim().min(1).optional().describe(IDENTITIES.UPDATE.role),
|
||||||
|
hasDeleteProtection: z.boolean().optional().describe(IDENTITIES.UPDATE.hasDeleteProtection),
|
||||||
metadata: z
|
metadata: z
|
||||||
.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })
|
.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) })
|
||||||
.array()
|
.array()
|
||||||
@@ -148,6 +152,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
type: EventType.UPDATE_IDENTITY,
|
type: EventType.UPDATE_IDENTITY,
|
||||||
metadata: {
|
metadata: {
|
||||||
name: identity.name,
|
name: identity.name,
|
||||||
|
hasDeleteProtection: identity.hasDeleteProtection,
|
||||||
identityId: identity.id
|
identityId: identity.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +248,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
permissions: true,
|
permissions: true,
|
||||||
description: true
|
description: true
|
||||||
}).optional(),
|
}).optional(),
|
||||||
identity: IdentitiesSchema.pick({ name: true, id: true }).extend({
|
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
||||||
authMethods: z.array(z.string())
|
authMethods: z.array(z.string())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -292,7 +297,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
permissions: true,
|
permissions: true,
|
||||||
description: true
|
description: true
|
||||||
}).optional(),
|
}).optional(),
|
||||||
identity: IdentitiesSchema.pick({ name: true, id: true }).extend({
|
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
||||||
authMethods: z.array(z.string())
|
authMethods: z.array(z.string())
|
||||||
})
|
})
|
||||||
}).array(),
|
}).array(),
|
||||||
@@ -386,7 +391,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
permissions: true,
|
permissions: true,
|
||||||
description: true
|
description: true
|
||||||
}).optional(),
|
}).optional(),
|
||||||
identity: IdentitiesSchema.pick({ name: true, id: true }).extend({
|
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
||||||
authMethods: z.array(z.string())
|
authMethods: z.array(z.string())
|
||||||
})
|
})
|
||||||
}).array(),
|
}).array(),
|
||||||
@@ -451,7 +456,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
temporaryAccessEndTime: z.date().nullable().optional()
|
temporaryAccessEndTime: z.date().nullable().optional()
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
identity: IdentitiesSchema.pick({ name: true, id: true }).extend({
|
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
||||||
authMethods: z.array(z.string())
|
authMethods: z.array(z.string())
|
||||||
}),
|
}),
|
||||||
project: SanitizedProjectSchema.pick({ name: true, id: true, type: true })
|
project: SanitizedProjectSchema.pick({ name: true, id: true, type: true })
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { CreateFlyioSyncSchema, FlyioSyncSchema, UpdateFlyioSyncSchema } from "@app/services/secret-sync/flyio";
|
||||||
|
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||||
|
|
||||||
|
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
|
||||||
|
|
||||||
|
export const registerFlyioSyncRouter = async (server: FastifyZodProvider) =>
|
||||||
|
registerSyncSecretsEndpoints({
|
||||||
|
destination: SecretSync.Flyio,
|
||||||
|
server,
|
||||||
|
responseSchema: FlyioSyncSchema,
|
||||||
|
createSchema: CreateFlyioSyncSchema,
|
||||||
|
updateSchema: UpdateFlyioSyncSchema
|
||||||
|
});
|
||||||
@@ -9,6 +9,7 @@ import { registerAzureDevOpsSyncRouter } from "./azure-devops-sync-router";
|
|||||||
import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router";
|
import { registerAzureKeyVaultSyncRouter } from "./azure-key-vault-sync-router";
|
||||||
import { registerCamundaSyncRouter } from "./camunda-sync-router";
|
import { registerCamundaSyncRouter } from "./camunda-sync-router";
|
||||||
import { registerDatabricksSyncRouter } from "./databricks-sync-router";
|
import { registerDatabricksSyncRouter } from "./databricks-sync-router";
|
||||||
|
import { registerFlyioSyncRouter } from "./flyio-sync-router";
|
||||||
import { registerGcpSyncRouter } from "./gcp-sync-router";
|
import { registerGcpSyncRouter } from "./gcp-sync-router";
|
||||||
import { registerGitHubSyncRouter } from "./github-sync-router";
|
import { registerGitHubSyncRouter } from "./github-sync-router";
|
||||||
import { registerHCVaultSyncRouter } from "./hc-vault-sync-router";
|
import { registerHCVaultSyncRouter } from "./hc-vault-sync-router";
|
||||||
@@ -39,5 +40,6 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
|
|||||||
[SecretSync.TeamCity]: registerTeamCitySyncRouter,
|
[SecretSync.TeamCity]: registerTeamCitySyncRouter,
|
||||||
[SecretSync.OCIVault]: registerOCIVaultSyncRouter,
|
[SecretSync.OCIVault]: registerOCIVaultSyncRouter,
|
||||||
[SecretSync.OnePass]: registerOnePassSyncRouter,
|
[SecretSync.OnePass]: registerOnePassSyncRouter,
|
||||||
[SecretSync.Render]: registerRenderSyncRouter
|
[SecretSync.Render]: registerRenderSyncRouter,
|
||||||
|
[SecretSync.Flyio]: registerFlyioSyncRouter
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { AzureDevOpsSyncListItemSchema, AzureDevOpsSyncSchema } from "@app/servi
|
|||||||
import { AzureKeyVaultSyncListItemSchema, AzureKeyVaultSyncSchema } from "@app/services/secret-sync/azure-key-vault";
|
import { AzureKeyVaultSyncListItemSchema, AzureKeyVaultSyncSchema } from "@app/services/secret-sync/azure-key-vault";
|
||||||
import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secret-sync/camunda";
|
import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secret-sync/camunda";
|
||||||
import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks";
|
import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks";
|
||||||
|
import { FlyioSyncListItemSchema, FlyioSyncSchema } from "@app/services/secret-sync/flyio";
|
||||||
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
|
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
|
||||||
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
|
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
|
||||||
import { HCVaultSyncListItemSchema, HCVaultSyncSchema } from "@app/services/secret-sync/hc-vault";
|
import { HCVaultSyncListItemSchema, HCVaultSyncSchema } from "@app/services/secret-sync/hc-vault";
|
||||||
@@ -51,7 +52,8 @@ const SecretSyncSchema = z.discriminatedUnion("destination", [
|
|||||||
TeamCitySyncSchema,
|
TeamCitySyncSchema,
|
||||||
OCIVaultSyncSchema,
|
OCIVaultSyncSchema,
|
||||||
OnePassSyncSchema,
|
OnePassSyncSchema,
|
||||||
RenderSyncSchema
|
RenderSyncSchema,
|
||||||
|
FlyioSyncSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
|
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
|
||||||
@@ -72,7 +74,8 @@ const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
|
|||||||
TeamCitySyncListItemSchema,
|
TeamCitySyncListItemSchema,
|
||||||
OCIVaultSyncListItemSchema,
|
OCIVaultSyncListItemSchema,
|
||||||
OnePassSyncListItemSchema,
|
OnePassSyncListItemSchema,
|
||||||
RenderSyncListItemSchema
|
RenderSyncListItemSchema,
|
||||||
|
FlyioSyncListItemSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {
|
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ export enum AppConnection {
|
|||||||
OCI = "oci",
|
OCI = "oci",
|
||||||
OracleDB = "oracledb",
|
OracleDB = "oracledb",
|
||||||
OnePass = "1password",
|
OnePass = "1password",
|
||||||
Render = "render"
|
Render = "render",
|
||||||
|
Flyio = "flyio"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AWSRegion {
|
export enum AWSRegion {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import {
|
|||||||
getDatabricksConnectionListItem,
|
getDatabricksConnectionListItem,
|
||||||
validateDatabricksConnectionCredentials
|
validateDatabricksConnectionCredentials
|
||||||
} from "./databricks";
|
} from "./databricks";
|
||||||
|
import { FlyioConnectionMethod, getFlyioConnectionListItem, validateFlyioConnectionCredentials } from "./flyio";
|
||||||
import { GcpConnectionMethod, getGcpConnectionListItem, validateGcpConnectionCredentials } from "./gcp";
|
import { GcpConnectionMethod, getGcpConnectionListItem, validateGcpConnectionCredentials } from "./gcp";
|
||||||
import { getGitHubConnectionListItem, GitHubConnectionMethod, validateGitHubConnectionCredentials } from "./github";
|
import { getGitHubConnectionListItem, GitHubConnectionMethod, validateGitHubConnectionCredentials } from "./github";
|
||||||
import {
|
import {
|
||||||
@@ -124,7 +125,8 @@ export const listAppConnectionOptions = () => {
|
|||||||
getOCIConnectionListItem(),
|
getOCIConnectionListItem(),
|
||||||
getOracleDBConnectionListItem(),
|
getOracleDBConnectionListItem(),
|
||||||
getOnePassConnectionListItem(),
|
getOnePassConnectionListItem(),
|
||||||
getRenderConnectionListItem()
|
getRenderConnectionListItem(),
|
||||||
|
getFlyioConnectionListItem()
|
||||||
].sort((a, b) => a.name.localeCompare(b.name));
|
].sort((a, b) => a.name.localeCompare(b.name));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -200,7 +202,8 @@ export const validateAppConnectionCredentials = async (
|
|||||||
[AppConnection.OCI]: validateOCIConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.OCI]: validateOCIConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.OracleDB]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.OracleDB]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.OnePass]: validateOnePassConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.OnePass]: validateOnePassConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.Render]: validateRenderConnectionCredentials as TAppConnectionCredentialsValidator
|
[AppConnection.Render]: validateRenderConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
|
[AppConnection.Flyio]: validateFlyioConnectionCredentials as TAppConnectionCredentialsValidator
|
||||||
};
|
};
|
||||||
|
|
||||||
return VALIDATE_APP_CONNECTION_CREDENTIALS_MAP[appConnection.app](appConnection);
|
return VALIDATE_APP_CONNECTION_CREDENTIALS_MAP[appConnection.app](appConnection);
|
||||||
@@ -242,6 +245,7 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
|||||||
case HCVaultConnectionMethod.AccessToken:
|
case HCVaultConnectionMethod.AccessToken:
|
||||||
case TeamCityConnectionMethod.AccessToken:
|
case TeamCityConnectionMethod.AccessToken:
|
||||||
case AzureDevOpsConnectionMethod.AccessToken:
|
case AzureDevOpsConnectionMethod.AccessToken:
|
||||||
|
case FlyioConnectionMethod.AccessToken:
|
||||||
return "Access Token";
|
return "Access Token";
|
||||||
case Auth0ConnectionMethod.ClientCredentials:
|
case Auth0ConnectionMethod.ClientCredentials:
|
||||||
return "Client Credentials";
|
return "Client Credentials";
|
||||||
@@ -306,7 +310,8 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
|
|||||||
[AppConnection.OCI]: platformManagedCredentialsNotSupported,
|
[AppConnection.OCI]: platformManagedCredentialsNotSupported,
|
||||||
[AppConnection.OracleDB]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
[AppConnection.OracleDB]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
||||||
[AppConnection.OnePass]: platformManagedCredentialsNotSupported,
|
[AppConnection.OnePass]: platformManagedCredentialsNotSupported,
|
||||||
[AppConnection.Render]: platformManagedCredentialsNotSupported
|
[AppConnection.Render]: platformManagedCredentialsNotSupported,
|
||||||
|
[AppConnection.Flyio]: platformManagedCredentialsNotSupported
|
||||||
};
|
};
|
||||||
|
|
||||||
export const enterpriseAppCheck = async (
|
export const enterpriseAppCheck = async (
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
|||||||
[AppConnection.OCI]: "OCI",
|
[AppConnection.OCI]: "OCI",
|
||||||
[AppConnection.OracleDB]: "OracleDB",
|
[AppConnection.OracleDB]: "OracleDB",
|
||||||
[AppConnection.OnePass]: "1Password",
|
[AppConnection.OnePass]: "1Password",
|
||||||
[AppConnection.Render]: "Render"
|
[AppConnection.Render]: "Render",
|
||||||
|
[AppConnection.Flyio]: "Fly.io"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanType> = {
|
export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanType> = {
|
||||||
@@ -53,5 +54,6 @@ export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanTyp
|
|||||||
[AppConnection.OracleDB]: AppConnectionPlanType.Enterprise,
|
[AppConnection.OracleDB]: AppConnectionPlanType.Enterprise,
|
||||||
[AppConnection.OnePass]: AppConnectionPlanType.Regular,
|
[AppConnection.OnePass]: AppConnectionPlanType.Regular,
|
||||||
[AppConnection.MySql]: AppConnectionPlanType.Regular,
|
[AppConnection.MySql]: AppConnectionPlanType.Regular,
|
||||||
[AppConnection.Render]: AppConnectionPlanType.Regular
|
[AppConnection.Render]: AppConnectionPlanType.Regular,
|
||||||
|
[AppConnection.Flyio]: AppConnectionPlanType.Regular
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ociConnectionService } from "@app/ee/services/app-connections/oci/oci-c
|
|||||||
import { ValidateOracleDBConnectionCredentialsSchema } from "@app/ee/services/app-connections/oracledb";
|
import { ValidateOracleDBConnectionCredentialsSchema } from "@app/ee/services/app-connections/oracledb";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionAppConnectionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionAppConnectionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { generateHash } from "@app/lib/crypto/encryption";
|
import { generateHash } from "@app/lib/crypto/encryption";
|
||||||
import { DatabaseErrorCode } from "@app/lib/error-codes";
|
import { DatabaseErrorCode } from "@app/lib/error-codes";
|
||||||
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
|
||||||
@@ -49,6 +49,8 @@ import { ValidateCamundaConnectionCredentialsSchema } from "./camunda";
|
|||||||
import { camundaConnectionService } from "./camunda/camunda-connection-service";
|
import { camundaConnectionService } from "./camunda/camunda-connection-service";
|
||||||
import { ValidateDatabricksConnectionCredentialsSchema } from "./databricks";
|
import { ValidateDatabricksConnectionCredentialsSchema } from "./databricks";
|
||||||
import { databricksConnectionService } from "./databricks/databricks-connection-service";
|
import { databricksConnectionService } from "./databricks/databricks-connection-service";
|
||||||
|
import { ValidateFlyioConnectionCredentialsSchema } from "./flyio";
|
||||||
|
import { flyioConnectionService } from "./flyio/flyio-connection-service";
|
||||||
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
|
import { ValidateGcpConnectionCredentialsSchema } from "./gcp";
|
||||||
import { gcpConnectionService } from "./gcp/gcp-connection-service";
|
import { gcpConnectionService } from "./gcp/gcp-connection-service";
|
||||||
import { ValidateGitHubConnectionCredentialsSchema } from "./github";
|
import { ValidateGitHubConnectionCredentialsSchema } from "./github";
|
||||||
@@ -107,7 +109,8 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
|
|||||||
[AppConnection.OCI]: ValidateOCIConnectionCredentialsSchema,
|
[AppConnection.OCI]: ValidateOCIConnectionCredentialsSchema,
|
||||||
[AppConnection.OracleDB]: ValidateOracleDBConnectionCredentialsSchema,
|
[AppConnection.OracleDB]: ValidateOracleDBConnectionCredentialsSchema,
|
||||||
[AppConnection.OnePass]: ValidateOnePassConnectionCredentialsSchema,
|
[AppConnection.OnePass]: ValidateOnePassConnectionCredentialsSchema,
|
||||||
[AppConnection.Render]: ValidateRenderConnectionCredentialsSchema
|
[AppConnection.Render]: ValidateRenderConnectionCredentialsSchema,
|
||||||
|
[AppConnection.Flyio]: ValidateFlyioConnectionCredentialsSchema
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appConnectionServiceFactory = ({
|
export const appConnectionServiceFactory = ({
|
||||||
@@ -513,6 +516,7 @@ export const appConnectionServiceFactory = ({
|
|||||||
teamcity: teamcityConnectionService(connectAppConnectionById),
|
teamcity: teamcityConnectionService(connectAppConnectionById),
|
||||||
oci: ociConnectionService(connectAppConnectionById, licenseService),
|
oci: ociConnectionService(connectAppConnectionById, licenseService),
|
||||||
onepass: onePassConnectionService(connectAppConnectionById),
|
onepass: onePassConnectionService(connectAppConnectionById),
|
||||||
render: renderConnectionService(connectAppConnectionById)
|
render: renderConnectionService(connectAppConnectionById),
|
||||||
|
flyio: flyioConnectionService(connectAppConnectionById)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ import {
|
|||||||
TDatabricksConnectionInput,
|
TDatabricksConnectionInput,
|
||||||
TValidateDatabricksConnectionCredentialsSchema
|
TValidateDatabricksConnectionCredentialsSchema
|
||||||
} from "./databricks";
|
} from "./databricks";
|
||||||
|
import {
|
||||||
|
TFlyioConnection,
|
||||||
|
TFlyioConnectionConfig,
|
||||||
|
TFlyioConnectionInput,
|
||||||
|
TValidateFlyioConnectionCredentialsSchema
|
||||||
|
} from "./flyio";
|
||||||
import {
|
import {
|
||||||
TGcpConnection,
|
TGcpConnection,
|
||||||
TGcpConnectionConfig,
|
TGcpConnectionConfig,
|
||||||
@@ -168,6 +174,7 @@ export type TAppConnection = { id: string } & (
|
|||||||
| TOracleDBConnection
|
| TOracleDBConnection
|
||||||
| TOnePassConnection
|
| TOnePassConnection
|
||||||
| TRenderConnection
|
| TRenderConnection
|
||||||
|
| TFlyioConnection
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
||||||
@@ -200,6 +207,7 @@ export type TAppConnectionInput = { id: string } & (
|
|||||||
| TOracleDBConnectionInput
|
| TOracleDBConnectionInput
|
||||||
| TOnePassConnectionInput
|
| TOnePassConnectionInput
|
||||||
| TRenderConnectionInput
|
| TRenderConnectionInput
|
||||||
|
| TFlyioConnectionInput
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TSqlConnectionInput =
|
export type TSqlConnectionInput =
|
||||||
@@ -239,7 +247,8 @@ export type TAppConnectionConfig =
|
|||||||
| TTeamCityConnectionConfig
|
| TTeamCityConnectionConfig
|
||||||
| TOCIConnectionConfig
|
| TOCIConnectionConfig
|
||||||
| TOnePassConnectionConfig
|
| TOnePassConnectionConfig
|
||||||
| TRenderConnectionConfig;
|
| TRenderConnectionConfig
|
||||||
|
| TFlyioConnectionConfig;
|
||||||
|
|
||||||
export type TValidateAppConnectionCredentialsSchema =
|
export type TValidateAppConnectionCredentialsSchema =
|
||||||
| TValidateAwsConnectionCredentialsSchema
|
| TValidateAwsConnectionCredentialsSchema
|
||||||
@@ -266,7 +275,8 @@ export type TValidateAppConnectionCredentialsSchema =
|
|||||||
| TValidateOCIConnectionCredentialsSchema
|
| TValidateOCIConnectionCredentialsSchema
|
||||||
| TValidateOracleDBConnectionCredentialsSchema
|
| TValidateOracleDBConnectionCredentialsSchema
|
||||||
| TValidateOnePassConnectionCredentialsSchema
|
| TValidateOnePassConnectionCredentialsSchema
|
||||||
| TValidateRenderConnectionCredentialsSchema;
|
| TValidateRenderConnectionCredentialsSchema
|
||||||
|
| TValidateFlyioConnectionCredentialsSchema;
|
||||||
|
|
||||||
export type TListAwsConnectionKmsKeys = {
|
export type TListAwsConnectionKmsKeys = {
|
||||||
connectionId: string;
|
connectionId: string;
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export enum FlyioConnectionMethod {
|
||||||
|
AccessToken = "access-token"
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
|
import { request } from "@app/lib/config/request";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
|
|
||||||
|
import { FlyioConnectionMethod } from "./flyio-connection-enums";
|
||||||
|
import { TFlyioApp, TFlyioConnection, TFlyioConnectionConfig } from "./flyio-connection-types";
|
||||||
|
|
||||||
|
export const getFlyioConnectionListItem = () => {
|
||||||
|
return {
|
||||||
|
name: "Fly.io" as const,
|
||||||
|
app: AppConnection.Flyio as const,
|
||||||
|
methods: Object.values(FlyioConnectionMethod) as [FlyioConnectionMethod.AccessToken]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validateFlyioConnectionCredentials = async (config: TFlyioConnectionConfig) => {
|
||||||
|
const { accessToken } = config.credentials;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp = await request.post<{ data: { viewer: { id: string | null; email: string } } | null }>(
|
||||||
|
IntegrationUrls.FLYIO_API_URL,
|
||||||
|
{ query: "query { viewer { id email } }" },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resp.data.data === null) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Unable to validate connection: Invalid access token provided."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof AxiosError) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Failed to validate credentials: ${error.message || "Unknown error"}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Unable to validate connection: verify credentials"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.credentials;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const listFlyioApps = async (appConnection: TFlyioConnection) => {
|
||||||
|
const { accessToken } = appConnection.credentials;
|
||||||
|
|
||||||
|
const resp = await request.post<{ data: { apps: { nodes: TFlyioApp[] } } }>(
|
||||||
|
IntegrationUrls.FLYIO_API_URL,
|
||||||
|
{
|
||||||
|
query:
|
||||||
|
"query GetApps { apps { nodes { id name hostname status organization { id slug } currentRelease { version status createdAt } } } }"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Accept: "application/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return resp.data.data.apps.nodes;
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { AppConnections } from "@app/lib/api-docs";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import {
|
||||||
|
BaseAppConnectionSchema,
|
||||||
|
GenericCreateAppConnectionFieldsSchema,
|
||||||
|
GenericUpdateAppConnectionFieldsSchema
|
||||||
|
} from "@app/services/app-connection/app-connection-schemas";
|
||||||
|
|
||||||
|
import { FlyioConnectionMethod } from "./flyio-connection-enums";
|
||||||
|
|
||||||
|
export const FlyioConnectionAccessTokenCredentialsSchema = z.object({
|
||||||
|
accessToken: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(1, "Access Token required")
|
||||||
|
.max(1000)
|
||||||
|
.startsWith("FlyV1", "Token must start with 'FlyV1'")
|
||||||
|
.describe(AppConnections.CREDENTIALS.FLYIO.accessToken)
|
||||||
|
});
|
||||||
|
|
||||||
|
const BaseFlyioConnectionSchema = BaseAppConnectionSchema.extend({ app: z.literal(AppConnection.Flyio) });
|
||||||
|
|
||||||
|
export const FlyioConnectionSchema = BaseFlyioConnectionSchema.extend({
|
||||||
|
method: z.literal(FlyioConnectionMethod.AccessToken),
|
||||||
|
credentials: FlyioConnectionAccessTokenCredentialsSchema
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SanitizedFlyioConnectionSchema = z.discriminatedUnion("method", [
|
||||||
|
BaseFlyioConnectionSchema.extend({
|
||||||
|
method: z.literal(FlyioConnectionMethod.AccessToken),
|
||||||
|
credentials: FlyioConnectionAccessTokenCredentialsSchema.pick({})
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const ValidateFlyioConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||||
|
z.object({
|
||||||
|
method: z.literal(FlyioConnectionMethod.AccessToken).describe(AppConnections.CREATE(AppConnection.Flyio).method),
|
||||||
|
credentials: FlyioConnectionAccessTokenCredentialsSchema.describe(
|
||||||
|
AppConnections.CREATE(AppConnection.Flyio).credentials
|
||||||
|
)
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const CreateFlyioConnectionSchema = ValidateFlyioConnectionCredentialsSchema.and(
|
||||||
|
GenericCreateAppConnectionFieldsSchema(AppConnection.Flyio)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const UpdateFlyioConnectionSchema = z
|
||||||
|
.object({
|
||||||
|
credentials: FlyioConnectionAccessTokenCredentialsSchema.optional().describe(
|
||||||
|
AppConnections.UPDATE(AppConnection.Flyio).credentials
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.Flyio));
|
||||||
|
|
||||||
|
export const FlyioConnectionListItemSchema = z.object({
|
||||||
|
name: z.literal("Fly.io"),
|
||||||
|
app: z.literal(AppConnection.Flyio),
|
||||||
|
methods: z.nativeEnum(FlyioConnectionMethod).array()
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { logger } from "@app/lib/logger";
|
||||||
|
import { OrgServiceActor } from "@app/lib/types";
|
||||||
|
|
||||||
|
import { AppConnection } from "../app-connection-enums";
|
||||||
|
import { listFlyioApps } from "./flyio-connection-fns";
|
||||||
|
import { TFlyioConnection } from "./flyio-connection-types";
|
||||||
|
|
||||||
|
type TGetAppConnectionFunc = (
|
||||||
|
app: AppConnection,
|
||||||
|
connectionId: string,
|
||||||
|
actor: OrgServiceActor
|
||||||
|
) => Promise<TFlyioConnection>;
|
||||||
|
|
||||||
|
export const flyioConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
|
||||||
|
const listApps = async (connectionId: string, actor: OrgServiceActor) => {
|
||||||
|
const appConnection = await getAppConnection(AppConnection.Flyio, connectionId, actor);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const apps = await listFlyioApps(appConnection);
|
||||||
|
return apps;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error, "Failed to establish connection with fly.io");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
listApps
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { DiscriminativePick } from "@app/lib/types";
|
||||||
|
|
||||||
|
import { AppConnection } from "../app-connection-enums";
|
||||||
|
import {
|
||||||
|
CreateFlyioConnectionSchema,
|
||||||
|
FlyioConnectionSchema,
|
||||||
|
ValidateFlyioConnectionCredentialsSchema
|
||||||
|
} from "./flyio-connection-schemas";
|
||||||
|
|
||||||
|
export type TFlyioConnection = z.infer<typeof FlyioConnectionSchema>;
|
||||||
|
|
||||||
|
export type TFlyioConnectionInput = z.infer<typeof CreateFlyioConnectionSchema> & {
|
||||||
|
app: AppConnection.Flyio;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TValidateFlyioConnectionCredentialsSchema = typeof ValidateFlyioConnectionCredentialsSchema;
|
||||||
|
|
||||||
|
export type TFlyioConnectionConfig = DiscriminativePick<TFlyioConnectionInput, "method" | "app" | "credentials"> & {
|
||||||
|
orgId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TFlyioApp = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export * from "./flyio-connection-enums";
|
||||||
|
export * from "./flyio-connection-fns";
|
||||||
|
export * from "./flyio-connection-schemas";
|
||||||
|
export * from "./flyio-connection-types";
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user