Răsfoiți Sursa

show hipaa check status on the compliance dashboard (#4227)

ianedwards 2 ani în urmă
părinte
comite
8d57c45961

+ 17 - 1
api/server/handlers/cluster/compliance_checks.go

@@ -33,7 +33,8 @@ func NewListComplianceChecksHandler(
 
 // ListComplianceChecksRequest is the expected format for a request to /compliance/checks
 type ListComplianceChecksRequest struct {
-	Vendor compliance.Vendor `schema:"vendor"`
+	Vendor  compliance.Vendor  `schema:"vendor"`
+	Profile compliance.Profile `schema:"profile"`
 }
 
 // ListComplianceChecksResponse is the expected format for a response from /compliance/checks
@@ -69,10 +70,25 @@ func (c *ListComplianceChecksHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 		}
 	}
 
+	var profile porterv1.EnumComplianceProfile
+	if request.Profile != "" {
+		switch request.Profile {
+		case compliance.Profile_SOC2:
+			profile = porterv1.EnumComplianceProfile_ENUM_COMPLIANCE_PROFILE_SOC2
+		case compliance.Profile_HIPAA:
+			profile = porterv1.EnumComplianceProfile_ENUM_COMPLIANCE_PROFILE_HIPAA
+		default:
+			err := telemetry.Error(ctx, span, nil, "invalid profile")
+			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
+			return
+		}
+	}
+
 	req := connect.NewRequest(&porterv1.ContractComplianceChecksRequest{
 		ProjectId: int64(project.ID),
 		ClusterId: int64(cluster.ID),
 		Vendor:    vendor,
+		Profile:   profile,
 	})
 
 	ccpResp, err := c.Config().ClusterControlPlaneClient.ContractComplianceChecks(ctx, req)

+ 7 - 7
dashboard/package-lock.json

@@ -95,7 +95,7 @@
         "@babel/preset-typescript": "^7.15.0",
         "@ianvs/prettier-plugin-sort-imports": "^4.1.1",
         "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
-        "@porter-dev/api-contracts": "^0.2.84",
+        "@porter-dev/api-contracts": "^0.2.97",
         "@testing-library/jest-dom": "^4.2.4",
         "@testing-library/react": "^9.3.2",
         "@testing-library/user-event": "^7.1.2",
@@ -2754,9 +2754,9 @@
       }
     },
     "node_modules/@porter-dev/api-contracts": {
-      "version": "0.2.84",
-      "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.84.tgz",
-      "integrity": "sha512-KNwaVBLkW95LQSxkxs+mwtJp8MIArS0X9ZODpVPjW/ZPjQ+PvCWoOsyNShoyOp2YrzaByKcXBDeKCsT2ZCgdCw==",
+      "version": "0.2.97",
+      "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.97.tgz",
+      "integrity": "sha512-LceOZWw1zjWH3E/i9GO6cRfc9KSP68ofR0YTxmIruAg3V2xCjvtW762r9NrXzJE4TkJryodCE+e7ZE2J0LVJPg==",
       "dev": true,
       "dependencies": {
         "@bufbuild/protobuf": "^1.1.0"
@@ -20056,9 +20056,9 @@
       "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
     },
     "@porter-dev/api-contracts": {
-      "version": "0.2.84",
-      "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.84.tgz",
-      "integrity": "sha512-KNwaVBLkW95LQSxkxs+mwtJp8MIArS0X9ZODpVPjW/ZPjQ+PvCWoOsyNShoyOp2YrzaByKcXBDeKCsT2ZCgdCw==",
+      "version": "0.2.97",
+      "resolved": "https://registry.npmjs.org/@porter-dev/api-contracts/-/api-contracts-0.2.97.tgz",
+      "integrity": "sha512-LceOZWw1zjWH3E/i9GO6cRfc9KSP68ofR0YTxmIruAg3V2xCjvtW762r9NrXzJE4TkJryodCE+e7ZE2J0LVJPg==",
       "dev": true,
       "requires": {
         "@bufbuild/protobuf": "^1.1.0"

+ 1 - 1
dashboard/package.json

@@ -102,7 +102,7 @@
     "@babel/preset-typescript": "^7.15.0",
     "@ianvs/prettier-plugin-sort-imports": "^4.1.1",
     "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
-    "@porter-dev/api-contracts": "^0.2.84",
+    "@porter-dev/api-contracts": "^0.2.97",
     "@testing-library/jest-dom": "^4.2.4",
     "@testing-library/react": "^9.3.2",
     "@testing-library/user-event": "^7.1.2",

+ 26 - 14
dashboard/src/main/home/compliance-dashboard/ActionBanner.tsx

@@ -1,5 +1,6 @@
 import React, { useMemo, type Dispatch, type SetStateAction } from "react";
 import { useHistory } from "react-router";
+import { match } from "ts-pattern";
 
 import Banner from "components/porter/Banner";
 import Image from "components/porter/Image";
@@ -20,10 +21,11 @@ export const ActionBanner: React.FC<ActionBannerProps> = ({
 }) => {
   const history = useHistory();
   const {
+    profile,
     updateInProgress,
     latestContractDB,
     latestContractProto,
-    updateContractWithSOC2,
+    updateContractWithProfile,
   } = useCompliance();
 
   const provisioningStatus = useMemo(() => {
@@ -60,21 +62,30 @@ export const ActionBanner: React.FC<ActionBannerProps> = ({
     return provisioningStatus.state === "pending" || updateInProgress;
   }, [provisioningStatus.state, updateInProgress]);
 
+  const complianceEnabled = match(profile)
+    .with("soc2", () => latestContractProto?.complianceProfiles?.soc2)
+    .with("hipaa", () => latestContractProto?.complianceProfiles?.hipaa)
+    .exhaustive();
+
   // check if compliance has not been enable or if not all checks have passed
   const actionRequredWithoutProvisioningError = useMemo(() => {
     return (
-      provisioningStatus.state === "compliance_error" ||
-      !latestContractProto?.cluster?.isSoc2Compliant
+      provisioningStatus.state === "compliance_error" || !complianceEnabled
     );
-  }, [provisioningStatus.state, latestContractProto?.toJsonString()]);
+  }, [
+    provisioningStatus.state,
+    latestContractProto?.toJsonString(),
+    complianceEnabled,
+  ]);
 
   // check if provisioning error is due to compliance update
   const provisioningErrorWithComplianceEnabled = useMemo(() => {
-    return (
-      provisioningStatus.state === "failed" &&
-      latestContractProto?.cluster?.isSoc2Compliant
-    );
-  }, [provisioningStatus.state, latestContractProto?.toJsonString()]);
+    return provisioningStatus.state === "failed" && complianceEnabled;
+  }, [
+    provisioningStatus.state,
+    latestContractProto?.toJsonString(),
+    complianceEnabled,
+  ]);
 
   if (isInfraPending) {
     return (
@@ -83,8 +94,8 @@ export const ActionBanner: React.FC<ActionBannerProps> = ({
           <Image src={loading_img} style={{ height: "16px", width: "16px" }} />
         }
       >
-        SOC 2 infrastructure controls are being enabled. Note: This may take up
-        to 30 minutes.
+        Infrastructure controls are being enabled. Note: This may take up to 30
+        minutes.
       </Banner>
     );
   }
@@ -101,7 +112,7 @@ export const ActionBanner: React.FC<ActionBannerProps> = ({
               cursor: "pointer",
             }}
             onClick={() => {
-              void updateContractWithSOC2();
+              void updateContractWithProfile();
             }}
           >
             Re-run infrastructure controls
@@ -116,7 +127,8 @@ export const ActionBanner: React.FC<ActionBannerProps> = ({
               setShowCostConsentModal(true);
             }}
           >
-            Enable SOC 2 infrastructure controls
+            Enable {profile === "soc2" ? "SOC2" : "HIPAA"} infrastructure
+            controls
           </Text>
         )}
       </Banner>
@@ -146,7 +158,7 @@ export const ActionBanner: React.FC<ActionBannerProps> = ({
             cursor: "pointer",
           }}
           onClick={() => {
-            void updateContractWithSOC2();
+            void updateContractWithProfile();
           }}
         >
           <Image src={refresh} size={12} style={{ marginBottom: "-2px" }} />

+ 33 - 6
dashboard/src/main/home/compliance-dashboard/ComplianceContext.tsx

@@ -1,5 +1,17 @@
-import React, { createContext, useContext, useMemo, useState } from "react";
-import { Contract, EKS, EKSLogging } from "@porter-dev/api-contracts";
+import React, {
+  createContext,
+  useContext,
+  useMemo,
+  useState,
+  type Dispatch,
+  type SetStateAction,
+} from "react";
+import {
+  ComplianceProfile,
+  Contract,
+  EKS,
+  EKSLogging,
+} from "@porter-dev/api-contracts";
 import { useQuery, useQueryClient } from "@tanstack/react-query";
 import { match } from "ts-pattern";
 import { z } from "zod";
@@ -15,6 +27,8 @@ import {
   type VendorCheck,
 } from "./types";
 
+type ComplianceProfileType = "soc2" | "hipaa";
+
 type ProjectComplianceContextType = {
   projectId: number;
   clusterId: number;
@@ -25,7 +39,9 @@ type ProjectComplianceContextType = {
   checksLoading: boolean;
   contractLoading: boolean;
   updateInProgress: boolean;
-  updateContractWithSOC2: () => Promise<void>;
+  profile: ComplianceProfileType;
+  setProfile: Dispatch<SetStateAction<ComplianceProfileType>>;
+  updateContractWithProfile: () => Promise<void>;
 };
 
 const ProjectComplianceContext =
@@ -52,6 +68,7 @@ export const ProjectComplianceProvider: React.FC<
 > = ({ projectId, clusterId, children }) => {
   const queryClient = useQueryClient();
   const [updateInProgress, setUpdateInProgress] = useState(false);
+  const [profile, setProfile] = useState<ComplianceProfileType>("soc2");
 
   const { data: baseContract, isLoading: contractLoading } = useQuery(
     [projectId, clusterId, "getContracts"],
@@ -80,13 +97,14 @@ export const ProjectComplianceProvider: React.FC<
         projectId,
         clusterId,
         condition: baseContract?.condition ?? "",
+        profile,
         name: "getComplianceChecks",
       },
     ],
     async () => {
       const res = await api.getComplianceChecks(
         "<token>",
-        { vendor: "vanta" },
+        { vendor: "vanta", profile },
         { projectId, clusterId }
       );
 
@@ -114,7 +132,7 @@ export const ProjectComplianceProvider: React.FC<
     });
   }, [baseContract?.base64_contract]);
 
-  const updateContractWithSOC2 = async (): Promise<void> => {
+  const updateContractWithProfile = async (): Promise<void> => {
     try {
       setUpdateInProgress(true);
 
@@ -141,6 +159,12 @@ export const ProjectComplianceProvider: React.FC<
         }))
         .otherwise((kind) => kind);
 
+      const complianceProfiles = new ComplianceProfile({
+        ...latestContract.complianceProfiles,
+        ...(profile === "soc2" && { soc2: true }),
+        ...(profile === "hipaa" && { hipaa: true }),
+      });
+
       const updatedContract = new Contract({
         ...latestContract,
         cluster: {
@@ -148,6 +172,7 @@ export const ProjectComplianceProvider: React.FC<
           kindValues: updatedKindValues,
           isSoc2Compliant: true,
         },
+        complianceProfiles,
       });
 
       await api.createContract("<token>", updatedContract, {
@@ -176,7 +201,9 @@ export const ProjectComplianceProvider: React.FC<
         checksLoading,
         contractLoading,
         updateInProgress,
-        updateContractWithSOC2,
+        profile,
+        setProfile,
+        updateContractWithProfile,
       }}
     >
       {children}

+ 2 - 27
dashboard/src/main/home/compliance-dashboard/ComplianceDashboard.tsx

@@ -2,20 +2,16 @@ import React, { useContext, useState } from "react";
 import styled from "styled-components";
 
 import ClusterProvisioningPlaceholder from "components/ClusterProvisioningPlaceholder";
-import Container from "components/porter/Container";
-import Image from "components/porter/Image";
 import Spacer from "components/porter/Spacer";
-import Text from "components/porter/Text";
 import DashboardHeader from "main/home/cluster-dashboard/DashboardHeader";
 
 import { Context } from "shared/Context";
 import compliance from "assets/compliance.svg";
-import linkExternal from "assets/link-external.svg";
-import vanta from "assets/vanta.svg";
 
 import { ActionBanner } from "./ActionBanner";
 import { ProjectComplianceProvider } from "./ComplianceContext";
 import { ConfigSelectors } from "./ConfigSelectors";
+import { ProfileHeader } from "./ProfileHeader";
 import { SOC2CostConsent } from "./SOC2CostConsent";
 import { VendorChecksList } from "./VendorChecksList";
 
@@ -46,29 +42,8 @@ const ComplianceDashboard: React.FC = () => {
           <>
             <ConfigSelectors />
             <Spacer y={1} />
-            <Container row>
-              <Image src={vanta} size={25} />
-              <Spacer inline x={1} />
-              <Text
-                size={21}
-                additionalStyles=":hover { text-decoration: underline } cursor: pointer;"
-                onClick={() => {
-                  window.open(
-                    "https://app.vanta.com/tests?framework=soc2&service=aws&taskType=TEST",
-                    "_blank"
-                  );
-                }}
-              >
-                AWS SOC 2 Controls (Vanta)
-                <Spacer inline x={0.5} />
-                <Image
-                  src={linkExternal}
-                  size={16}
-                  additionalStyles="margin-bottom: -2px"
-                />
-              </Text>
-            </Container>
 
+            <ProfileHeader />
             <Spacer y={1} />
 
             <ActionBanner setShowCostConsentModal={setShowCostConsentModal} />

+ 14 - 6
dashboard/src/main/home/compliance-dashboard/ConfigSelectors.tsx

@@ -11,22 +11,30 @@ import provider from "assets/provider.svg";
 import typeSvg from "assets/type.svg";
 import vanta from "assets/vanta.svg";
 
+import { useCompliance } from "./ComplianceContext";
+
 export const ConfigSelectors: React.FC = () => {
-  // to be made selectable with state living in context
+  const { profile, setProfile } = useCompliance();
   return (
     <Container row>
       <Select
         options={[
-          { value: "soc-2", label: "SOC 2" },
+          { value: "soc2", label: "SOC 2" },
           {
             value: "hipaa",
-            label: "HIPAA (request access)",
-            disabled: true,
+            label: "HIPAA",
           },
         ]}
         width="200px"
-        value={"soc-2"}
-        setValue={() => {}}
+        value={profile}
+        setValue={(value) => {
+          if (value === "soc2") {
+            setProfile("soc2");
+            return;
+          }
+
+          setProfile("hipaa");
+        }}
         prefix={
           <Container row>
             <Image src={framework} size={15} opacity={0.6} />

+ 51 - 0
dashboard/src/main/home/compliance-dashboard/ProfileHeader.tsx

@@ -0,0 +1,51 @@
+import React, { useMemo } from "react";
+import { match } from "ts-pattern";
+
+import Container from "components/porter/Container";
+import Image from "components/porter/Image";
+import Spacer from "components/porter/Spacer";
+import Text from "components/porter/Text";
+
+import linkExternal from "assets/link-external.svg";
+import vanta from "assets/vanta.svg";
+
+import { useCompliance } from "./ComplianceContext";
+
+export const ProfileHeader: React.FC = () => {
+  const { profile } = useCompliance();
+
+  const header = useMemo(() => {
+    return match(profile)
+      .with("soc2", () => ({
+        text: "AWS SOC 2 Controls (Vanta)",
+        link: "https://app.vanta.com/tests?framework=soc2&service=aws&taskType=TEST",
+      }))
+      .with("hipaa", () => ({
+        text: "AWS HIPAA Controls (Vanta)",
+        link: "https://app.vanta.com/tests?framework=hipaa&service=aws&taskType=TEST",
+      }))
+      .exhaustive();
+  }, [profile]);
+
+  return (
+    <Container row>
+      <Image src={vanta} size={25} />
+      <Spacer inline x={1} />
+      <Text
+        size={21}
+        additionalStyles=":hover { text-decoration: underline } cursor: pointer;"
+        onClick={() => {
+          window.open(header.link, "_blank");
+        }}
+      >
+        {header.text}
+        <Spacer inline x={0.5} />
+        <Image
+          src={linkExternal}
+          size={16}
+          additionalStyles="margin-bottom: -2px"
+        />
+      </Text>
+    </Container>
+  );
+};

+ 21 - 11
dashboard/src/main/home/compliance-dashboard/SOC2CostConsent.tsx

@@ -16,7 +16,10 @@ type Props = {
 export const SOC2CostConsent: React.FC<Props> = ({
   setShowCostConsentModal,
 }) => {
-  const { updateInProgress, updateContractWithSOC2 } = useCompliance();
+  const { profile, updateInProgress, updateContractWithProfile } =
+    useCompliance();
+
+  const profileText = profile === "soc2" ? "SOC-2" : "HIPAA";
 
   return (
     <Modal
@@ -24,12 +27,15 @@ export const SOC2CostConsent: React.FC<Props> = ({
         setShowCostConsentModal(false);
       }}
     >
-      <Text size={16}>Enable SOC-2</Text>
+      <Text size={16}>
+        Enable
+        {profileText}
+      </Text>
       <Spacer height="15px" />
       <Text color="helper">
         Porter will update the underlying infrastructure in your own AWS account
-        to ensure compliance with any automated SOC-2 controls. Additional costs
-        may apply.
+        to ensure compliance with any automated {profileText} controls.
+        Additional costs may apply.
       </Text>
       <Spacer y={1} />
       <ExpandableSection
@@ -38,7 +44,7 @@ export const SOC2CostConsent: React.FC<Props> = ({
         collapseText="[-] Hide details"
         Header={
           <Text size={20} weight={600}>
-            Additional updates for SOC-2
+            Additional updates for {profileText}
           </Text>
         }
         isInitiallyExpanded
@@ -46,14 +52,18 @@ export const SOC2CostConsent: React.FC<Props> = ({
           <>
             <Spacer height="15px" />
             <Fieldset background="#1b1d2688">
-              • GuardDuty (threat detection)
-              <Spacer height="15px" />
               • CloudTrail (audit logs) and CloudWatch (monitoring)
               <Spacer height="15px" />
               • KMS encrypted secrets
               <Spacer height="15px" />
-              • Container vulnerability scanning
-              <Spacer height="15px" />
+              {profile === "soc2" && (
+                <>
+                  • Container vulnerability scanning
+                  <Spacer height="15px" />
+                  • GuardDuty (threat detection)
+                  <Spacer height="15px" />
+                </>
+              )}
             </Fieldset>
           </>
         }
@@ -61,13 +71,13 @@ export const SOC2CostConsent: React.FC<Props> = ({
       <Spacer y={1} />
       <Button
         onClick={() => {
-          void updateContractWithSOC2();
+          void updateContractWithProfile();
           setShowCostConsentModal(false);
         }}
         status={updateInProgress ? "loading" : undefined}
         disabled={updateInProgress}
       >
-        Enable SOC 2 infra controls
+        Enable {profileText} infra controls
       </Button>
     </Modal>
   );

+ 14 - 2
dashboard/src/main/home/compliance-dashboard/VendorChecksList.tsx

@@ -20,7 +20,7 @@ import { type VendorCheck } from "./types";
 type Filter = "all" | "passing" | "action-required" | "not-applicable";
 
 export const VendorChecksList: React.FC = () => {
-  const { vendorChecks, latestContractProto } = useCompliance();
+  const { profile, vendorChecks, latestContractProto } = useCompliance();
   const { showIntercomWithMessage } = useIntercom();
 
   const [statusFilter, setStatusFilter] = useState<Filter>("all");
@@ -31,7 +31,7 @@ export const VendorChecksList: React.FC = () => {
       return null;
     }
 
-    if (!latestContractProto?.cluster?.isSoc2Compliant) {
+    if (profile === "soc2" && !latestContractProto?.complianceProfiles?.soc2) {
       return (
         <Text color="helper">
           SOC-2 compliance is not enabled for this cluster. Re-provisioning your
@@ -40,6 +40,18 @@ export const VendorChecksList: React.FC = () => {
         </Text>
       );
     }
+    if (
+      profile === "hipaa" &&
+      !latestContractProto?.complianceProfiles?.hipaa
+    ) {
+      return (
+        <Text color="helper">
+          HIPAA compliance is not enabled for this cluster. Re-provisioning your
+          infrastructure above will enable necessary security controls to ensure
+          compliance.
+        </Text>
+      );
+    }
 
     return (
       <Text color="helper">

+ 1 - 1
dashboard/src/shared/api.tsx

@@ -1565,7 +1565,7 @@ const getClusterState = baseApi<{}, { project_id: number; cluster_id: number }>(
 );
 
 const getComplianceChecks = baseApi<
-  { vendor: "vanta" },
+  { vendor: "vanta", profile: "soc2" | "hipaa" },
   { projectId: number; clusterId: number }
 >("GET", ({ projectId, clusterId }) => {
   return `/api/projects/${projectId}/clusters/${clusterId}/compliance/checks`;

+ 1 - 1
go.mod

@@ -83,7 +83,7 @@ require (
 	github.com/matryer/is v1.4.0
 	github.com/nats-io/nats.go v1.24.0
 	github.com/open-policy-agent/opa v0.44.0
-	github.com/porter-dev/api-contracts v0.2.96
+	github.com/porter-dev/api-contracts v0.2.97
 	github.com/riandyrn/otelchi v0.5.1
 	github.com/santhosh-tekuri/jsonschema/v5 v5.0.1
 	github.com/stefanmcshane/helm v0.0.0-20221213002717-88a4a2c6e77d

+ 2 - 8
go.sum

@@ -1523,14 +1523,8 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
-github.com/porter-dev/api-contracts v0.2.90 h1:0ceIXz0xWNQpqVqhUMt3/RDeEawccfXx3KgM/tRg638=
-github.com/porter-dev/api-contracts v0.2.90/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
-github.com/porter-dev/api-contracts v0.2.91 h1:jiFWQ+WISAtfjXalOmWJdSr1ZOm7/ov+3ozrCeYA9Ws=
-github.com/porter-dev/api-contracts v0.2.91/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
-github.com/porter-dev/api-contracts v0.2.95 h1:QsTwEpdLm+yx3PWJ5FERpB5rWwV7mvEp2CpV4QAC5Xo=
-github.com/porter-dev/api-contracts v0.2.95/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
-github.com/porter-dev/api-contracts v0.2.96 h1:r380Tn23daY+fH7REDZf+HlH6PcG0cihrZxMibmATT4=
-github.com/porter-dev/api-contracts v0.2.96/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
+github.com/porter-dev/api-contracts v0.2.97 h1:JXxg/b0R8hL2IurJAnSakRRSHx4zT9ZQDCqe1gvR0Uc=
+github.com/porter-dev/api-contracts v0.2.97/go.mod h1:fX6JmP5QuzxDLvqP3evFOTXjI4dHxsG0+VKNTjImZU8=
 github.com/porter-dev/switchboard v0.0.3 h1:dBuYkiVLa5Ce7059d6qTe9a1C2XEORFEanhbtV92R+M=
 github.com/porter-dev/switchboard v0.0.3/go.mod h1:xSPzqSFMQ6OSbp42fhCi4AbGbQbsm6nRvOkrblFeXU4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=

+ 10 - 0
internal/compliance/convert.go

@@ -59,6 +59,16 @@ const (
 	Vendor_Vanta Vendor = "vanta"
 )
 
+// Profile is used to indicate which compliance profile the compliance check results are from
+type Profile string
+
+const (
+	// Profile_SOC2 is used to indicate that the check results are for the SOC2 compliance profile
+	Profile_SOC2 Profile = "soc2"
+	// Profile_HIPAA is used to indicate that the check results are for the HIPAA compliance profile
+	Profile_HIPAA Profile = "hipaa"
+)
+
 // CheckGroupsFromProto converts the compliance check group proto to the internal representation
 func CheckGroupsFromProto(ctx context.Context, checkGroups []*porterv1.ContractComplianceCheckGroup) ([]CheckGroup, error) {
 	ctx, span := telemetry.NewSpan(ctx, "compliance-checks-from-proto")