File

src/compliance/compliance.service.ts

Index

Properties
Methods

Constructor

constructor(prismaService: PrismaService, temporalProvider: TemporalProvider, complianceRiskService: ComplianceRiskService, settingsService: SettingsService, policyService: PolicyService)
Parameters :
Name Type Optional
prismaService PrismaService No
temporalProvider TemporalProvider No
complianceRiskService ComplianceRiskService No
settingsService SettingsService No
policyService PolicyService No

Methods

Async findSubmission
findSubmission(id: number)

Find a compliance submission by id

Parameters :
Name Type Optional Description
id number No

submission id

compliance submission

Async generateRisks
generateRisks(submission: ComplianceSubmission, rules: any[])

Generate compliance risks for a submission

Parameters :
Name Type Optional Description
submission ComplianceSubmission No

submission

rules any[] No

list of rules

list of generated risks

Async getActiveSubmissionsForPolicy
getActiveSubmissionsForPolicy(policyId: number)
Parameters :
Name Type Optional
policyId number No
Async getComplianceUsers
getComplianceUsers(projectId: number)

Get compliance users with permissions

Parameters :
Name Type Optional Description
projectId number No

project id

Returns : Promise<any[]>

list of users with permissions

getLatestProjectDependentSubmissions
getLatestProjectDependentSubmissions(projectId: number)

Function to get the latest project dependent submission

Parameters :
Name Type Optional
projectId number No

Promise

Async submitCompliance
submitCompliance(submission: ComplianceSubmissionDto, submittedBy: string)

Submit a compliance submission

Parameters :
Name Type Optional Description
submission ComplianceSubmissionDto No

submission data

submittedBy string No

user who submitted the compliance

created submission

triggerSubmitComplianceWorkflow
triggerSubmitComplianceWorkflow(_submission: ComplianceSubmission)

Function to trigger the compliance submission workflow

Parameters :
Name Type Optional
_submission ComplianceSubmission No
Returns : Promise<string>

Promise workflow id

Async updateSubmissionStatus
updateSubmissionStatus(id: number, status: ComplianceSubmissionStatus)

Update a compliance submission status

Parameters :
Name Type Optional Description
id number No

submission id

status ComplianceSubmissionStatus No

new status

Returns : unknown

updated submission

Properties

Private COMPLIANCE_SUBMISSION_WORKFLOW
Type : string
Default value : "complianceSubmissionWorkflow"
import { PrismaService } from "../common/prisma/prisma.service";
import { Injectable } from "@nestjs/common";
import { ComplianceSubmissionDto } from "./dto/submission.dto";
import {
  ComplianceSubmission,
  ComplianceSubmissionStatus,
} from "./entities/submission.entity";
import { TemporalProvider } from "../providers/temporal/temporal.provider";
import { getUuidSlug } from "../common/helper";
import { ComplianceRisk } from "./entities/risk.entity";
import { ComplianceRiskStatus } from "./entities/compliance.types";
import { ComplianceRiskCreateInput } from "./dto/risk.dto";
import { ComplianceRiskService } from "./risk.service";
import { SettingsService } from "../project/settings/settings.service";
import { PolicyService } from "../iam";
import {
  COMPLIANCE_EVIDENCE_READ_ACTION,
  COMPLIANCE_EVIDENCE_SUBMIT_ACTION,
  COMPLIANCE_RESOURCE_NAME,
  COMPLIANCE_RISK_READ_ACTION,
  COMPLIANCE_RISK_SUBMIT_ACTION,
  COMPLIANCE_RISK_UPDATE_ACTION,
} from "./compliance.constants";

@Injectable()
export class ComplianceService {
  constructor(
    private readonly prismaService: PrismaService,
    private readonly temporalProvider: TemporalProvider,
    private readonly complianceRiskService: ComplianceRiskService,
    private readonly settingsService: SettingsService,
    private readonly policyService: PolicyService,
  ) {}

  private COMPLIANCE_SUBMISSION_WORKFLOW = "complianceSubmissionWorkflow";

  /**
   * Submit a compliance submission
   * @param {ComplianceSubmissionDto} submission submission data
   * @param {number} projectId project id
   * @param {string} submittedBy user who submitted the compliance
   * @returns {Promise<ComplianceSubmission>} created submission
   */
  async submitCompliance(
    submission: ComplianceSubmissionDto,
    submittedBy: string,
  ): Promise<ComplianceSubmission> {
    const policies = [
      ...submission.frameworkIds.map((id) => ({ id })),
      ...submission.policyIds.map((id) => ({ id })),
    ];
    const _submission = new ComplianceSubmission(
      await this.prismaService.complianceSubmission.create({
        data: {
          submittedBy: submittedBy,
          status: ComplianceSubmissionStatus.OPEN,
          jurisdictions: submission.jurisdictions,
          project: {
            connect: { id: submission.projectId },
          },
          policies: {
            connect: policies,
          },
        },
      }),
    );

    await this.triggerSubmitComplianceWorkflow(_submission);

    return _submission;
  }

  /**
   * Function to trigger the compliance submission workflow
   * @param _submission
   * @returns Promise<string> workflow id
   */
  triggerSubmitComplianceWorkflow(
    _submission: ComplianceSubmission,
  ): Promise<string> {
    return this.temporalProvider.runAsync(
      this.COMPLIANCE_SUBMISSION_WORKFLOW,
      [_submission.id],
      process.env.DEFAULT_QUEUE_NAME,
      `workflow-${this.COMPLIANCE_SUBMISSION_WORKFLOW}-${_submission.id}-${getUuidSlug()}`,
    );
  }

  /**
   * Get compliance users with permissions
   * @param projectId project id
   * @returns {Promise<any[]>} list of users with permissions
   */
  async getComplianceUsers(projectId: number): Promise<any[]> {
    // get project users
    const users = await this.settingsService.getProjectUsers(projectId);

    const promises = users.map(async (user) => {
      const userPermissions = await this.policyService.getUserPermissions(
        user.id,
      );
      return {
        ...user,
        permissions: {
          risk: {
            read: await this.policyService.checkPermission(
              userPermissions,
              projectId,
              COMPLIANCE_RESOURCE_NAME,
              COMPLIANCE_RISK_READ_ACTION,
            ),
            update: await this.policyService.checkPermission(
              userPermissions,
              projectId,
              COMPLIANCE_RESOURCE_NAME,
              COMPLIANCE_RISK_UPDATE_ACTION,
            ),
            submit: await this.policyService.checkPermission(
              userPermissions,
              projectId,
              COMPLIANCE_RESOURCE_NAME,
              COMPLIANCE_RISK_SUBMIT_ACTION,
            ),
          },
          evidence: {
            read: await this.policyService.checkPermission(
              userPermissions,
              projectId,
              COMPLIANCE_RESOURCE_NAME,
              COMPLIANCE_EVIDENCE_READ_ACTION,
            ),
            submit: await this.policyService.checkPermission(
              userPermissions,
              projectId,
              COMPLIANCE_RESOURCE_NAME,
              COMPLIANCE_EVIDENCE_SUBMIT_ACTION,
            ),
          },
        },
      };
    });

    return await Promise.all(promises);
  }

  /**
   * Find a compliance submission by id
   * @param {number} id submission id
   * @returns {Promise<ComplianceSubmission>} compliance submission
   */
  async findSubmission(id: number): Promise<ComplianceSubmission> {
    const submission = await this.prismaService.complianceSubmission.findUnique(
      {
        where: { id: id },
        include: { policies: true, project: true },
      },
    );

    return new ComplianceSubmission(submission);
  }

  /**
   * Update a compliance submission status
   * @param {number} id submission id
   * @param {ComplianceSubmissionStatus} status new status
   * @returns {Promise<ComplianceSubmission>} updated submission
   */
  async updateSubmissionStatus(id: number, status: ComplianceSubmissionStatus) {
    const submission = await this.prismaService.complianceSubmission.update({
      where: { id: id },
      data: { status: status },
    });

    return new ComplianceSubmission(submission);
  }

  /**
   * Generate compliance risks for a submission
   * @param {ComplianceSubmission} submission submission
   * @param {any[]} rules list of rules
   * @returns {Promise<ComplianceRisk[]>} list of generated risks
   */
  async generateRisks(
    submission: ComplianceSubmission,
    rules: any[],
  ): Promise<ComplianceRisk[]> {
    const existing = await this.complianceRiskService.findExisting({
      projectId: submission.project["id"],
      status: {
        notIn: [
          ComplianceRiskStatus.ARCHIVED,
          ComplianceRiskStatus.DELETED,
          ComplianceRiskStatus.MITIGATED,
        ],
      },
    });

    const riskToCreate = rules.filter(
      (rule) => !existing.some((risk) => risk.rule["id"] === rule.id),
    );

    const riskToDelete = existing.filter(
      (risk) => !rules.some((rule) => rule.id === risk.rule["id"]),
    );

    const risksCreateData = riskToCreate
      .map((rule) => {
        const risk: ComplianceRiskCreateInput = {
          ruleId: rule.id,
          projectId: submission.project["id"],
          complianceSubmissionId: submission.id,
          status: ComplianceRiskStatus.TODO,
        };
        return risk;
      })
      .filter(
        (risk, index, self) =>
          index === self.findIndex((r) => r.ruleId === risk.ruleId),
      );

    const risks = this.complianceRiskService.createComplianceRisks(
      submission.id,
      risksCreateData,
    );

    if (riskToDelete.length > 0) {
      await this.complianceRiskService.deleteDependentRisk(riskToDelete);
    }

    return risks;
  }

  /**
   * Function to get the latest project dependent submission
   * @param projectId
   * @returns Promise<ComplianceSubmission>
   */
  getLatestProjectDependentSubmissions(
    projectId: number,
  ): Promise<ComplianceSubmission> {
    return this.prismaService.complianceSubmission.findFirst({
      where: {
        projectId: projectId,
      },
      orderBy: {
        createdAt: "desc",
      },
    });
  }

  async getActiveSubmissionsForPolicy(policyId: number): Promise<ComplianceSubmission[]> {
    // get all submissions for the policy that are not in progress or open
    const submissions = await this.prismaService.complianceSubmission.findMany({
      where: {
        policies: {
          some: {
            id: policyId,
          },
        },
        status: {
          notIn: [ComplianceSubmissionStatus.IN_PROGRESS, ComplianceSubmissionStatus.OPEN],
        },
      },
      orderBy: [
        { projectId: 'asc' },
        { createdAt: 'desc' },
      ],
      distinct: ['projectId'],
      include: {
        policies: true,
        project: true,
      },
    });

    return submissions.map((submission) => new ComplianceSubmission(submission));
  }
}

results matching ""

    No results matching ""