From 6eb3332103aef44bb88dda687a2022d0eb1f98d3 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Tue, 27 May 2025 20:07:15 -0700 Subject: [PATCH] Add new url fields to vendors Signed-off-by: Sacha Al Himdani --- .../organizations/vendors/ListVendorView.tsx | 8 +- .../organizations/vendors/VendorView.tsx | 122 +++++++++++ ...tVendorViewCreateVendorMutation.graphql.ts | 4 +- .../VendorViewAssessVendorMutation.graphql.ts | 24 ++- .../__generated__/VendorViewQuery.graphql.ts | 170 ++++++++------- .../VendorViewUpdateVendorMutation.graphql.ts | 26 ++- pkg/agents/vendor_assessment.go | 36 ++-- pkg/coredata/migrations/20250528T001641Z.sql | 86 ++++++++ pkg/coredata/vendor.go | 136 ++++++------ pkg/probo/vendor_service.go | 148 +++++++------ pkg/server/api/console/v1/schema.graphql | 6 + pkg/server/api/console/v1/schema/schema.go | 204 +++++++++++++++--- pkg/server/api/console/v1/types/types.go | 118 +++++----- pkg/server/api/console/v1/types/vendor.go | 36 ++-- pkg/server/api/console/v1/v1_resolver.go | 72 ++++--- 15 files changed, 837 insertions(+), 359 deletions(-) create mode 100644 pkg/coredata/migrations/20250528T001641Z.sql diff --git a/apps/console/src/pages/organizations/vendors/ListVendorView.tsx b/apps/console/src/pages/organizations/vendors/ListVendorView.tsx index 8d3282ca6..a038730c3 100644 --- a/apps/console/src/pages/organizations/vendors/ListVendorView.tsx +++ b/apps/console/src/pages/organizations/vendors/ListVendorView.tsx @@ -387,10 +387,10 @@ function ListVendorContent({ websiteUrl: vendor.websiteUrl, category: vendor.category as VendorCategory || null, privacyPolicyUrl: vendor.privacyPolicyUrl, - serviceLevelAgreementUrl: - vendor.serviceLevelAgreementUrl, - dataProcessingAgreementUrl: - vendor.dataProcessingAgreementUrl, + serviceLevelAgreementUrl: vendor.serviceLevelAgreementUrl, + dataProcessingAgreementUrl: vendor.dataProcessingAgreementUrl, + businessAssociateAgreementUrl: vendor.businessAssociateAgreementUrl, + subprocessorsListUrl: vendor.subprocessorsListUrl, certifications: vendor.certifications, securityPageUrl: vendor.securityPageUrl, trustPageUrl: vendor.trustPageUrl, diff --git a/apps/console/src/pages/organizations/vendors/VendorView.tsx b/apps/console/src/pages/organizations/vendors/VendorView.tsx index 9829e30c3..7b9fb437a 100644 --- a/apps/console/src/pages/organizations/vendors/VendorView.tsx +++ b/apps/console/src/pages/organizations/vendors/VendorView.tsx @@ -76,6 +76,8 @@ const vendorViewQuery = graphql` privacyPolicyUrl serviceLevelAgreementUrl dataProcessingAgreementUrl + businessAssociateAgreementUrl + subprocessorsListUrl securityPageUrl trustPageUrl certifications @@ -152,6 +154,8 @@ const updateVendorMutation = graphql` privacyPolicyUrl serviceLevelAgreementUrl dataProcessingAgreementUrl + businessAssociateAgreementUrl + subprocessorsListUrl securityPageUrl trustPageUrl certifications @@ -242,6 +246,8 @@ const assessVendorMutation = graphql` privacyPolicyUrl serviceLevelAgreementUrl dataProcessingAgreementUrl + businessAssociateAgreementUrl + subprocessorsListUrl securityPageUrl trustPageUrl certifications @@ -1440,6 +1446,8 @@ function VendorViewContent({ privacyPolicyUrl: data.node.privacyPolicyUrl || "", serviceLevelAgreementUrl: data.node.serviceLevelAgreementUrl || "", dataProcessingAgreementUrl: data.node.dataProcessingAgreementUrl || "", + businessAssociateAgreementUrl: data.node.businessAssociateAgreementUrl || "", + subprocessorsListUrl: data.node.subprocessorsListUrl || "", securityPageUrl: data.node.securityPageUrl || "", trustPageUrl: data.node.trustPageUrl || "", certifications: data.node.certifications || [], @@ -1583,6 +1591,8 @@ function VendorViewContent({ privacyPolicyUrl: data.node.privacyPolicyUrl || "", serviceLevelAgreementUrl: data.node.serviceLevelAgreementUrl || "", dataProcessingAgreementUrl: data.node.dataProcessingAgreementUrl || "", + businessAssociateAgreementUrl: data.node.businessAssociateAgreementUrl || "", + subprocessorsListUrl: data.node.subprocessorsListUrl || "", securityPageUrl: data.node.securityPageUrl || "", trustPageUrl: data.node.trustPageUrl || "", certifications: data.node.certifications || [], @@ -2188,6 +2198,116 @@ function VendorViewContent({ )} +
+

+ Business Associate Agreement URL +

+
+ + handleFieldChange( + "businessAssociateAgreementUrl", + e.target.value, + ) + } + className="border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 flex-1" + /> + {formData.businessAssociateAgreementUrl && ( + + + + + + + + )} +
+
+
+

+ Subprocessors List URL +

+
+ + handleFieldChange( + "subprocessorsListUrl", + e.target.value, + ) + } + className="border-0 bg-transparent p-0 shadow-none focus-visible:ring-0 flex-1" + /> + {formData.subprocessorsListUrl && ( + + + + + + + + )} +
+

Data Processing Agreement URL @@ -2434,6 +2554,8 @@ function VendorViewContent({ privacyPolicyUrl: newData.privacyPolicyUrl || prevData.privacyPolicyUrl, serviceLevelAgreementUrl: newData.serviceLevelAgreementUrl || prevData.serviceLevelAgreementUrl, dataProcessingAgreementUrl: newData.dataProcessingAgreementUrl || prevData.dataProcessingAgreementUrl, + businessAssociateAgreementUrl: newData.businessAssociateAgreementUrl || prevData.businessAssociateAgreementUrl, + subprocessorsListUrl: newData.subprocessorsListUrl || prevData.subprocessorsListUrl, securityPageUrl: newData.securityPageUrl || prevData.securityPageUrl, trustPageUrl: newData.trustPageUrl || prevData.trustPageUrl, certifications: newData.certifications || prevData.certifications, diff --git a/apps/console/src/pages/organizations/vendors/__generated__/ListVendorViewCreateVendorMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/ListVendorViewCreateVendorMutation.graphql.ts index 7a144a0fc..e703ace6b 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/ListVendorViewCreateVendorMutation.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/ListVendorViewCreateVendorMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -11,6 +11,7 @@ import { ConcreteRequest } from 'relay-runtime'; export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL"; export type CreateVendorInput = { + businessAssociateAgreementUrl?: string | null | undefined; businessOwnerId?: string | null | undefined; category?: VendorCategory | null | undefined; certifications?: ReadonlyArray | null | undefined; @@ -25,6 +26,7 @@ export type CreateVendorInput = { securityPageUrl?: string | null | undefined; serviceLevelAgreementUrl?: string | null | undefined; statusPageUrl?: string | null | undefined; + subprocessorsListUrl?: string | null | undefined; termsOfServiceUrl?: string | null | undefined; trustPageUrl?: string | null | undefined; websiteUrl?: string | null | undefined; diff --git a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewAssessVendorMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewAssessVendorMutation.graphql.ts index 3fba3ffb5..05e0556fd 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewAssessVendorMutation.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewAssessVendorMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<8469b802866967389dde2e2a5aa02584>> * @lightSyntaxTransform * @nogrep */ @@ -20,6 +20,7 @@ export type VendorViewAssessVendorMutation$variables = { export type VendorViewAssessVendorMutation$data = { readonly assessVendor: { readonly vendor: { + readonly businessAssociateAgreementUrl: string | null | undefined; readonly businessOwner: { readonly fullName: string; readonly id: string; @@ -40,6 +41,7 @@ export type VendorViewAssessVendorMutation$data = { readonly securityPageUrl: string | null | undefined; readonly serviceLevelAgreementUrl: string | null | undefined; readonly statusPageUrl: string | null | undefined; + readonly subprocessorsListUrl: string | null | undefined; readonly termsOfServiceUrl: string | null | undefined; readonly trustPageUrl: string | null | undefined; readonly updatedAt: string; @@ -150,6 +152,20 @@ v3 = [ "name": "dataProcessingAgreementUrl", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "businessAssociateAgreementUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "subprocessorsListUrl", + "storageKey": null + }, { "alias": null, "args": null, @@ -251,16 +267,16 @@ return { "selections": (v3/*: any*/) }, "params": { - "cacheID": "592ee741d52ee98a1e10330e97a14707", + "cacheID": "01d19edac3190732f32c6be16df0ce72", "id": null, "metadata": {}, "name": "VendorViewAssessVendorMutation", "operationKind": "mutation", - "text": "mutation VendorViewAssessVendorMutation(\n $input: AssessVendorInput!\n) {\n assessVendor(input: $input) {\n vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n category\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n updatedAt\n }\n }\n}\n" + "text": "mutation VendorViewAssessVendorMutation(\n $input: AssessVendorInput!\n) {\n assessVendor(input: $input) {\n vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n businessAssociateAgreementUrl\n subprocessorsListUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n category\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n updatedAt\n }\n }\n}\n" } }; })(); -(node as any).hash = "8dddda77f031533f207ac903d883a902"; +(node as any).hash = "e0398e78ad6679a42adfdf2817588c3f"; export default node; diff --git a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts index 895ea0f5a..9f18190c0 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<6aeb4bc16ba7ab84d3c9dc07b88f0e62>> * @lightSyntaxTransform * @nogrep */ @@ -19,6 +19,7 @@ export type VendorViewQuery$variables = { }; export type VendorViewQuery$data = { readonly node: { + readonly businessAssociateAgreementUrl?: string | null | undefined; readonly businessOwner?: { readonly fullName: string; readonly id: string; @@ -70,6 +71,7 @@ export type VendorViewQuery$data = { readonly securityPageUrl?: string | null | undefined; readonly serviceLevelAgreementUrl?: string | null | undefined; readonly statusPageUrl?: string | null | undefined; + readonly subprocessorsListUrl?: string | null | undefined; readonly termsOfServiceUrl?: string | null | undefined; readonly trustPageUrl?: string | null | undefined; readonly updatedAt?: string; @@ -169,111 +171,125 @@ v11 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "securityPageUrl", + "name": "businessAssociateAgreementUrl", "storageKey": null }, v12 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "trustPageUrl", + "name": "subprocessorsListUrl", "storageKey": null }, v13 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "certifications", + "name": "securityPageUrl", "storageKey": null }, v14 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "headquarterAddress", + "name": "trustPageUrl", "storageKey": null }, v15 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "legalName", + "name": "certifications", "storageKey": null }, v16 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "websiteUrl", + "name": "headquarterAddress", "storageKey": null }, v17 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "category", + "name": "legalName", "storageKey": null }, v18 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "websiteUrl", + "storageKey": null +}, +v19 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "category", + "storageKey": null +}, +v20 = { "alias": null, "args": null, "kind": "ScalarField", "name": "fullName", "storageKey": null }, -v19 = [ +v21 = [ (v3/*: any*/), - (v18/*: any*/) + (v20/*: any*/) ], -v20 = { +v22 = { "alias": null, "args": null, "concreteType": "People", "kind": "LinkedField", "name": "businessOwner", "plural": false, - "selections": (v19/*: any*/), + "selections": (v21/*: any*/), "storageKey": null }, -v21 = { +v23 = { "alias": null, "args": null, "concreteType": "People", "kind": "LinkedField", "name": "securityOwner", "plural": false, - "selections": (v19/*: any*/), - "storageKey": null -}, -v22 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null -}, -v23 = { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "updatedAt", + "selections": (v21/*: any*/), "storageKey": null }, v24 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "__typename", + "name": "createdAt", "storageKey": null }, v25 = { "alias": null, "args": null, "kind": "ScalarField", - "name": "cursor", + "name": "updatedAt", "storageKey": null }, v26 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}, +v27 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "cursor", + "storageKey": null +}, +v28 = { "alias": null, "args": null, "concreteType": "PageInfo", @@ -298,7 +314,7 @@ v26 = { ], "storageKey": null }, -v27 = [ +v29 = [ { "alias": null, "args": null, @@ -351,18 +367,18 @@ v27 = [ "name": "fileSize", "storageKey": null }, - (v22/*: any*/), - (v24/*: any*/) + (v24/*: any*/), + (v26/*: any*/) ], "storageKey": null }, - (v25/*: any*/) + (v27/*: any*/) ], "storageKey": null }, - (v26/*: any*/) + (v28/*: any*/) ], -v28 = [ +v30 = [ { "alias": null, "args": null, @@ -422,28 +438,28 @@ v28 = [ "kind": "LinkedField", "name": "assessedBy", "plural": false, - "selections": (v19/*: any*/), + "selections": (v21/*: any*/), "storageKey": null }, - (v22/*: any*/), - (v24/*: any*/) + (v24/*: any*/), + (v26/*: any*/) ], "storageKey": null }, - (v25/*: any*/) + (v27/*: any*/) ], "storageKey": null }, - (v26/*: any*/) + (v28/*: any*/) ], -v29 = [ +v31 = [ { "kind": "Variable", "name": "id", "variableName": "organizationId" } ], -v30 = { +v32 = { "alias": null, "args": [ { @@ -461,16 +477,16 @@ v30 = { ], "storageKey": null }, -v31 = { +v33 = { "kind": "Literal", "name": "first", "value": 100 }, -v32 = [ - (v31/*: any*/) +v34 = [ + (v33/*: any*/) ], -v33 = [ - (v31/*: any*/), +v35 = [ + (v33/*: any*/), { "kind": "Literal", "name": "orderBy", @@ -516,10 +532,12 @@ return { (v15/*: any*/), (v16/*: any*/), (v17/*: any*/), - (v20/*: any*/), - (v21/*: any*/), + (v18/*: any*/), + (v19/*: any*/), (v22/*: any*/), (v23/*: any*/), + (v24/*: any*/), + (v25/*: any*/), { "alias": "complianceReports", "args": null, @@ -527,7 +545,7 @@ return { "kind": "LinkedField", "name": "__VendorView_complianceReports_connection", "plural": false, - "selections": (v27/*: any*/), + "selections": (v29/*: any*/), "storageKey": null }, { @@ -537,7 +555,7 @@ return { "kind": "LinkedField", "name": "__VendorView_riskAssessments_connection", "plural": false, - "selections": (v28/*: any*/), + "selections": (v30/*: any*/), "storageKey": null } ], @@ -549,7 +567,7 @@ return { }, { "alias": "organization", - "args": (v29/*: any*/), + "args": (v31/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", @@ -579,7 +597,7 @@ return { "name": "user", "plural": false, "selections": [ - (v30/*: any*/) + (v32/*: any*/) ], "storageKey": null } @@ -607,7 +625,7 @@ return { "name": "node", "plural": false, "selections": [ - (v24/*: any*/), + (v26/*: any*/), (v3/*: any*/), { "kind": "InlineFragment", @@ -626,23 +644,25 @@ return { (v15/*: any*/), (v16/*: any*/), (v17/*: any*/), - (v20/*: any*/), - (v21/*: any*/), + (v18/*: any*/), + (v19/*: any*/), (v22/*: any*/), (v23/*: any*/), + (v24/*: any*/), + (v25/*: any*/), { "alias": null, - "args": (v32/*: any*/), + "args": (v34/*: any*/), "concreteType": "VendorComplianceReportConnection", "kind": "LinkedField", "name": "complianceReports", "plural": false, - "selections": (v27/*: any*/), + "selections": (v29/*: any*/), "storageKey": "complianceReports(first:100)" }, { "alias": null, - "args": (v32/*: any*/), + "args": (v34/*: any*/), "filters": null, "handle": "connection", "key": "VendorView_complianceReports", @@ -651,17 +671,17 @@ return { }, { "alias": null, - "args": (v32/*: any*/), + "args": (v34/*: any*/), "concreteType": "VendorRiskAssessmentConnection", "kind": "LinkedField", "name": "riskAssessments", "plural": false, - "selections": (v28/*: any*/), + "selections": (v30/*: any*/), "storageKey": "riskAssessments(first:100)" }, { "alias": null, - "args": (v32/*: any*/), + "args": (v34/*: any*/), "filters": null, "handle": "connection", "key": "VendorView_riskAssessments", @@ -677,20 +697,20 @@ return { }, { "alias": "organization", - "args": (v29/*: any*/), + "args": (v31/*: any*/), "concreteType": null, "kind": "LinkedField", "name": "node", "plural": false, "selections": [ - (v24/*: any*/), + (v26/*: any*/), (v3/*: any*/), { "kind": "InlineFragment", "selections": [ { "alias": null, - "args": (v33/*: any*/), + "args": (v35/*: any*/), "concreteType": "PeopleConnection", "kind": "LinkedField", "name": "peoples", @@ -713,7 +733,7 @@ return { "plural": false, "selections": [ (v3/*: any*/), - (v18/*: any*/), + (v20/*: any*/), { "alias": null, "args": null, @@ -721,21 +741,21 @@ return { "name": "primaryEmailAddress", "storageKey": null }, - (v24/*: any*/) + (v26/*: any*/) ], "storageKey": null }, - (v25/*: any*/) + (v27/*: any*/) ], "storageKey": null }, - (v26/*: any*/) + (v28/*: any*/) ], "storageKey": "peoples(first:100,orderBy:{\"direction\":\"ASC\",\"field\":\"FULL_NAME\"})" }, { "alias": null, - "args": (v33/*: any*/), + "args": (v35/*: any*/), "filters": [ "orderBy" ], @@ -767,7 +787,7 @@ return { "name": "user", "plural": false, "selections": [ - (v30/*: any*/), + (v32/*: any*/), (v3/*: any*/) ], "storageKey": null @@ -779,7 +799,7 @@ return { ] }, "params": { - "cacheID": "83601f58c499976a22f7dec4312d147b", + "cacheID": "031a80a31c3e3d6254e949069860c988", "id": null, "metadata": { "connection": [ @@ -805,11 +825,11 @@ return { }, "name": "VendorViewQuery", "operationKind": "query", - "text": "query VendorViewQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n category\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n riskAssessments(first: 100) {\n edges {\n node {\n id\n assessedAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n assessedBy {\n id\n fullName\n }\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" + "text": "query VendorViewQuery(\n $vendorId: ID!\n $organizationId: ID!\n) {\n node(id: $vendorId) {\n __typename\n ... on Vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n businessAssociateAgreementUrl\n subprocessorsListUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n category\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n createdAt\n updatedAt\n complianceReports(first: 100) {\n edges {\n node {\n id\n reportName\n reportDate\n validUntil\n fileUrl\n fileSize\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n riskAssessments(first: 100) {\n edges {\n node {\n id\n assessedAt\n expiresAt\n dataSensitivity\n businessImpact\n notes\n assessedBy {\n id\n fullName\n }\n createdAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n organization: node(id: $organizationId) {\n __typename\n ...PeopleSelector_organization\n id\n }\n viewer {\n user {\n people(organizationId: $organizationId) {\n id\n }\n id\n }\n id\n }\n}\n\nfragment PeopleSelector_organization on Organization {\n id\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n" } }; })(); -(node as any).hash = "812a334dc26fb2961aae24862496ff0c"; +(node as any).hash = "8a9a11b173a6ff4db496c888cb3f0842"; export default node; diff --git a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts index 5b42b048a..63fd64645 100644 --- a/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts +++ b/apps/console/src/pages/organizations/vendors/__generated__/VendorViewUpdateVendorMutation.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<687421f6528edb3fe7623b14cda888d7>> + * @generated SignedSource<<1869215126a875b4693649fdbd2fdd9c>> * @lightSyntaxTransform * @nogrep */ @@ -11,6 +11,7 @@ import { ConcreteRequest } from 'relay-runtime'; export type VendorCategory = "ANALYTICS" | "CLOUD_MONITORING" | "CLOUD_PROVIDER" | "COLLABORATION" | "CUSTOMER_SUPPORT" | "DATA_STORAGE_AND_PROCESSING" | "DOCUMENT_MANAGEMENT" | "EMPLOYEE_MANAGEMENT" | "ENGINEERING" | "FINANCE" | "IDENTITY_PROVIDER" | "IT" | "MARKETING" | "OFFICE_OPERATIONS" | "OTHER" | "PASSWORD_MANAGEMENT" | "PRODUCT_AND_DESIGN" | "PROFESSIONAL_SERVICES" | "RECRUITING" | "SALES" | "SECURITY" | "VERSION_CONTROL"; export type UpdateVendorInput = { + businessAssociateAgreementUrl?: string | null | undefined; businessOwnerId?: string | null | undefined; category?: VendorCategory | null | undefined; certifications?: ReadonlyArray | null | undefined; @@ -25,6 +26,7 @@ export type UpdateVendorInput = { securityPageUrl?: string | null | undefined; serviceLevelAgreementUrl?: string | null | undefined; statusPageUrl?: string | null | undefined; + subprocessorsListUrl?: string | null | undefined; termsOfServiceUrl?: string | null | undefined; trustPageUrl?: string | null | undefined; websiteUrl?: string | null | undefined; @@ -35,6 +37,7 @@ export type VendorViewUpdateVendorMutation$variables = { export type VendorViewUpdateVendorMutation$data = { readonly updateVendor: { readonly vendor: { + readonly businessAssociateAgreementUrl: string | null | undefined; readonly businessOwner: { readonly fullName: string; readonly id: string; @@ -55,6 +58,7 @@ export type VendorViewUpdateVendorMutation$data = { readonly securityPageUrl: string | null | undefined; readonly serviceLevelAgreementUrl: string | null | undefined; readonly statusPageUrl: string | null | undefined; + readonly subprocessorsListUrl: string | null | undefined; readonly termsOfServiceUrl: string | null | undefined; readonly trustPageUrl: string | null | undefined; readonly updatedAt: string; @@ -165,6 +169,20 @@ v3 = [ "name": "dataProcessingAgreementUrl", "storageKey": null }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "businessAssociateAgreementUrl", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "subprocessorsListUrl", + "storageKey": null + }, { "alias": null, "args": null, @@ -266,16 +284,16 @@ return { "selections": (v3/*: any*/) }, "params": { - "cacheID": "8ead09e0003d808fcf2d2bc8ca19c8b2", + "cacheID": "dd590c1e78969f50f0f36352d70e0aa2", "id": null, "metadata": {}, "name": "VendorViewUpdateVendorMutation", "operationKind": "mutation", - "text": "mutation VendorViewUpdateVendorMutation(\n $input: UpdateVendorInput!\n) {\n updateVendor(input: $input) {\n vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n category\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n updatedAt\n }\n }\n}\n" + "text": "mutation VendorViewUpdateVendorMutation(\n $input: UpdateVendorInput!\n) {\n updateVendor(input: $input) {\n vendor {\n id\n name\n description\n statusPageUrl\n termsOfServiceUrl\n privacyPolicyUrl\n serviceLevelAgreementUrl\n dataProcessingAgreementUrl\n businessAssociateAgreementUrl\n subprocessorsListUrl\n securityPageUrl\n trustPageUrl\n certifications\n headquarterAddress\n legalName\n websiteUrl\n category\n businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n updatedAt\n }\n }\n}\n" } }; })(); -(node as any).hash = "90aa0b06cde30ea8a7deb711d5ba0c69"; +(node as any).hash = "61c12bb5fe14c4499601363ae8070e6d"; export default node; diff --git a/pkg/agents/vendor_assessment.go b/pkg/agents/vendor_assessment.go index cf5e00f50..b1358cc34 100644 --- a/pkg/agents/vendor_assessment.go +++ b/pkg/agents/vendor_assessment.go @@ -39,19 +39,21 @@ type ( } vendorInfo struct { - Name string `json:"name"` - Description string `json:"description"` - Category string `json:"category"` - HeadquarterAddress string `json:"headquarter_address"` - LegalName string `json:"legal_name"` - PrivacyPolicyURL string `json:"privacy_policy_url"` - ServiceLevelAgreementURL string `json:"service_level_agreement_url"` - DataProcessingAgreementURL string `json:"data_processing_agreement_url"` - SecurityPageURL string `json:"security_page_url"` - TrustPageURL string `json:"trust_page_url"` - TermsOfServiceURL string `json:"terms_of_service_url"` - StatusPageURL string `json:"status_page_url"` - Certifications []string `json:"certifications"` + Name string `json:"name"` + Description string `json:"description"` + Category string `json:"category"` + HeadquarterAddress string `json:"headquarter_address"` + LegalName string `json:"legal_name"` + PrivacyPolicyURL string `json:"privacy_policy_url"` + ServiceLevelAgreementURL string `json:"service_level_agreement_url"` + DataProcessingAgreementURL string `json:"data_processing_agreement_url"` + BusinessAssociateAgreementURL string `json:"business_associate_agreement_url"` + SubprocessorsListURL string `json:"subprocessors_list_url"` + SecurityPageURL string `json:"security_page_url"` + TrustPageURL string `json:"trust_page_url"` + TermsOfServiceURL string `json:"terms_of_service_url"` + StatusPageURL string `json:"status_page_url"` + Certifications []string `json:"certifications"` } ) @@ -70,6 +72,8 @@ const ( - privacy_policy_url: URL to privacy policy page - service_level_agreement_url: URL to SLA page - data_processing_agreement_url: URL to DPA page + - business_associate_agreement_url: URL to BAA page + - subprocessors_list_url: URL to subprocessors/subcontractors list page - security_page_url: URL to security information page - trust_page_url: URL to trust/compliance page - terms_of_service_url: URL to terms of service page @@ -116,11 +120,15 @@ const ( "privacy_policy_url": "https://stripe.com/privacy", "service_level_agreement_url": "https://stripe.com/sla", "data_processing_agreement_url": "https://stripe.com/dpa", + "business_associate_agreement_url": "https://stripe.com/baa", + "subprocessors_list_url": "https://stripe.com/subprocessors", "security_page_url": "https://stripe.com/security", "trust_page_url": "https://stripe.com/trust", "terms_of_service_url": "https://stripe.com/terms", "status_page_url": "https://status.stripe.com", - "certifications": ["SOC1", "SOC2", "PCI DSS Level 1", "ISO 27001"], + "business_associate_agreement_url": "https://stripe.com/baa", + "subprocessors_list_url": "https://stripe.com/subprocessors", + "certifications": ["SOC1", "SOC2", "PCI DSS Level 1", "ISO 27001"] "category": "FINANCE" } diff --git a/pkg/coredata/migrations/20250528T001641Z.sql b/pkg/coredata/migrations/20250528T001641Z.sql new file mode 100644 index 000000000..adc02de9a --- /dev/null +++ b/pkg/coredata/migrations/20250528T001641Z.sql @@ -0,0 +1,86 @@ +ALTER TABLE vendors + ADD COLUMN business_associate_agreement_url TEXT, + ADD COLUMN subprocessors_list_url TEXT; + +UPDATE vendors SET + business_associate_agreement_url = CASE name + WHEN 'Notion' THEN 'https://www.notion.so/notion/Business-Associate-Agreement-909d9f4ccca041b1a23d0fe6e56fa111' + WHEN 'OpenAI' THEN 'https://openai.com/policies/business-terms/' + WHEN 'Amazon Web Services (AWS)' THEN 'https://aws.amazon.com/compliance/hipaa-compliance/' + WHEN 'Google Cloud Platform' THEN 'https://cloud.google.com/terms/hipaa-baa' + WHEN 'Microsoft Azure' THEN 'https://learn.microsoft.com/en-us/compliance/regulatory/offering-hipaa-hitech' + WHEN 'Cal.com' THEN 'https://app.cal.com/apps/baa-for-hipaa' + WHEN 'Fly.io' THEN 'https://fly.io/documents' + WHEN 'New Relic' THEN 'https://newrelic.com/termsandconditions/hipaabaafaq' + WHEN 'Gusto' THEN 'https://support.gusto.com/article/152166121100000/The-Health-Insurance-Portability-and-Accountability-Act-of-1996-HIPAA' + WHEN 'Microsoft 365' THEN 'https://learn.microsoft.com/en-us/compliance/regulatory/offering-hipaa-hitech' + WHEN 'Monday.com' THEN 'https://monday.com/l/privacy/hipaa-baa' + WHEN 'Atlassian' THEN 'https://www.atlassian.com/legal/business-associate-agreement' + WHEN 'Resend' THEN 'https://newrelic.com/termsandconditions/hipaabaafaq' + END, + subprocessors_list_url = CASE name + WHEN 'Github' THEN 'https://docs.github.com/en/site-policy/privacy-policies/github-subprocessors' + WHEN 'Notion' THEN 'https://www.notion.so/notion/Notion-s-List-of-Subprocessors-268fa5bcfa0f46b6bc29436b21676734' + WHEN 'Mintlify' THEN 'https://security.mintlify.com' + WHEN 'Segment' THEN 'https://www.twilio.com/en-us/legal/sub-processors' + WHEN 'Heroku' THEN 'https://www.salesforce.com/en-us/wp-content/uploads/sites/4/documents/legal/misc/salesforce-infrastructure-and-subprocessors.pdf' + WHEN 'Linear' THEN 'https://linear.app/dpa' + WHEN 'Hubspot' THEN 'https://legal.hubspot.com/sub-processors-page' + WHEN 'Google Workspace' THEN 'https://workspace.google.com/terms/subprocessors/' + WHEN 'Algolia' THEN 'https://www.algolia.com/policies/infrastructure-and-sub-processors' + WHEN 'PostHog' THEN 'https://posthog.com/dpa' + WHEN 'Airtable' THEN 'https://www.airtable.com/company/subprocessors' + WHEN 'OpenAI' THEN 'https://openai.com/policies/sub-processor-list/' + WHEN 'Anthropic' THEN 'https://trust.anthropic.com/subprocessors' + WHEN 'Amazon Web Services (AWS)' THEN 'https://aws.amazon.com/compliance/sub-processors/' + WHEN 'Calendly' THEN 'https://help.calendly.com/hc/en-us/articles/360047345493-Calendly-sub-processors-GDPR-CCPA' + WHEN 'jsDelivr' THEN 'https://www.jsdelivr.com/terms/sub-processors' + WHEN 'Clerk' THEN 'https://clerk.com/legal/subprocessors' + WHEN 'Plausible Analytics' THEN 'https://plausible.io/privacy' + WHEN 'Docker' THEN 'https://www.docker.com/trust/privacy/sub-processors/' + WHEN 'Brex' THEN 'https://trust-portal.brex.com' + WHEN 'Ramp' THEN 'https://trust.ramp.com/' + WHEN 'ClickHouse' THEN 'https://clickhouse.com/legal/agreements/subprocessors' + WHEN 'Tailscale' THEN 'https://tailscale.com/dpa-subprocessors' + WHEN 'Probo' THEN 'https://www.getprobo.com/subprocessors' + WHEN 'folk' THEN 'https://www.folk.app/privacy-policy#3-list-of-sub-processors' + WHEN 'Claap' THEN 'https://www.claap.io/legal/privacy-policy#sub-processors' + WHEN 'Pitch' THEN 'https://pitch.com/dpa#annex-7-2' + WHEN 'Spendesk' THEN 'https://www.spendesk.com/legals/subprocessors/' + WHEN 'Lever' THEN 'https://www.lever.co/subprocessors-archive-june-2023/' + WHEN 'Google Cloud Platform' THEN 'https://cloud.google.com/terms/subprocessors' + WHEN 'Microsoft Azure' THEN 'https://www.microsoft.com/en-us/download/details.aspx?id=50426' + WHEN 'Fly.io' THEN 'https://fly.io/legal/sub-processors/' + WHEN 'Upstash' THEN 'https://trust.upstash.com/subprocessors' + WHEN 'bunny.net' THEN 'https://bunny.net/gdpr/sub-processors/' + WHEN 'ClickUp' THEN 'https://clickup.com/terms/dpa/subprocessors' + WHEN 'New Relic' THEN 'https://newrelic.com/sub-processors' + WHEN 'Pylon' THEN 'https://usepylon.com/subprocessors' + WHEN 'Loops' THEN 'https://loops.so/subprocessors' + WHEN 'Perplexity' THEN 'https://trust.perplexity.ai/' + WHEN 'Mailchimp' THEN 'https://mailchimp.com/legal/subprocessors/' + WHEN 'Otter.ai' THEN 'https://otter.ai/subprocessors' + WHEN 'Resend' THEN 'https://newrelic.com/sub-processors' + WHEN 'OVHcloud global' THEN 'https://www.ovh.ie/support/termsofservice/OVH%20IE%20Sub%20processors.pdf' + WHEN 'OVHcloud US' THEN 'https://storage.gra.cloud.ovh.net/v1/AUTH_325716a587c64897acbef9a4a4726e38/contracts/30c4ab8-OVH_Sub_processors-IE-2.0.pdf' + WHEN 'Pipedrive' THEN 'https://www.pipedrive.com/en/subprocessors' + WHEN 'Plesk' THEN 'https://www.plesk.com/wp-content/uploads/legal/gdpr3.pdf' + WHEN 'Brevo' THEN 'https://www.brevo.com/legal/termsofuse/#sub-processors' + WHEN 'Better Stack' THEN 'https://betterstack.com/dpa/schedules' + WHEN 'PlanetScale' THEN 'https://planetscale.com/legal/subprocessors' + WHEN 'Microsoft 365' THEN 'https://www.microsoft.com/en-us/download/details.aspx?id=50426' + WHEN 'Bitwarden' THEN 'https://bitwarden.com/help/subprocessors/' + WHEN 'Framer' THEN 'https://www.framer.com/legal/sub-processors/' + WHEN 'Cal.com' THEN 'https://security.cal.com/?itemUid=e3fae2ca-94a9-416b-b577-5c90e382df57' + WHEN 'monday.com' THEN 'https://monday.com/l/privacy/sub-processors-subsidiaries-support' + WHEN 'Carta' THEN 'https://carta.com/legal/carta-europe/data-processor-agreement/' + WHEN 'Apollo.io' THEN 'https://trust.apollo.io/' + WHEN 'Atlassian' THEN 'https://www.atlassian.com/legal/sub-processors' + WHEN 'Webflow' THEN 'https://uploads-ssl.webflow.com/5d80c03f1edd7bd68fcdb623/657c411c020d1ee5f047f6ab_20231207%20-%20List%20of%20approved%20Sub-processors.pdf' + WHEN '1Password' THEN 'https://1passwordstatic.com/files/legal-center/notice-of-updates-to-the-1password-subprocessor-list.pdf' + WHEN 'Checkr' THEN 'https://checkr.com/sub-processor-list' + WHEN 'Rippling' THEN 'https://app.rippling.com/legal/subprocessors' + WHEN 'Twilio' THEN 'https://www.twilio.com/en-us/legal/sub-processors' + WHEN 'Cursor' THEN 'https://trust.cursor.com/subprocessors' + WHEN 'Pulley' THEN 'https://large-walk-bd5.notion.site/6449d3ecd2854af0a313b6e8679b5795?v=d61abc36355842bb939d49544f18dc95' + END; diff --git a/pkg/coredata/vendor.go b/pkg/coredata/vendor.go index c05a251e2..a9dbb285f 100644 --- a/pkg/coredata/vendor.go +++ b/pkg/coredata/vendor.go @@ -28,26 +28,28 @@ import ( type ( Vendor struct { - ID gid.GID `db:"id"` - OrganizationID gid.GID `db:"organization_id"` - Name string `db:"name"` - Description *string `db:"description"` - Category VendorCategory `db:"category"` - HeadquarterAddress *string `db:"headquarter_address"` - LegalName *string `db:"legal_name"` - WebsiteURL *string `db:"website_url"` - PrivacyPolicyURL *string `db:"privacy_policy_url"` - ServiceLevelAgreementURL *string `db:"service_level_agreement_url"` - DataProcessingAgreementURL *string `db:"data_processing_agreement_url"` - Certifications []string `db:"certifications"` - BusinessOwnerID *gid.GID `db:"business_owner_id"` - SecurityOwnerID *gid.GID `db:"security_owner_id"` - StatusPageURL *string `db:"status_page_url"` - TermsOfServiceURL *string `db:"terms_of_service_url"` - SecurityPageURL *string `db:"security_page_url"` - TrustPageURL *string `db:"trust_page_url"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID gid.GID `db:"id"` + OrganizationID gid.GID `db:"organization_id"` + Name string `db:"name"` + Description *string `db:"description"` + Category VendorCategory `db:"category"` + HeadquarterAddress *string `db:"headquarter_address"` + LegalName *string `db:"legal_name"` + WebsiteURL *string `db:"website_url"` + PrivacyPolicyURL *string `db:"privacy_policy_url"` + ServiceLevelAgreementURL *string `db:"service_level_agreement_url"` + DataProcessingAgreementURL *string `db:"data_processing_agreement_url"` + BusinessAssociateAgreementURL *string `db:"business_associate_agreement_url"` + SubprocessorsListURL *string `db:"subprocessors_list_url"` + Certifications []string `db:"certifications"` + BusinessOwnerID *gid.GID `db:"business_owner_id"` + SecurityOwnerID *gid.GID `db:"security_owner_id"` + StatusPageURL *string `db:"status_page_url"` + TermsOfServiceURL *string `db:"terms_of_service_url"` + SecurityPageURL *string `db:"security_page_url"` + TrustPageURL *string `db:"trust_page_url"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } Vendors []*Vendor @@ -83,6 +85,8 @@ SELECT privacy_policy_url, service_level_agreement_url, data_processing_agreement_url, + business_associate_agreement_url, + subprocessors_list_url, certifications, business_owner_id, security_owner_id, @@ -141,6 +145,8 @@ INSERT INTO privacy_policy_url, service_level_agreement_url, data_processing_agreement_url, + business_associate_agreement_url, + subprocessors_list_url, certifications, business_owner_id, security_owner_id, @@ -164,6 +170,8 @@ VALUES ( @privacy_policy_url, @service_level_agreement_url, @data_processing_agreement_url, + @business_associate_agreement_url, + @subprocessors_list_url, @certifications, @business_owner_id, @security_owner_id, @@ -177,27 +185,29 @@ VALUES ( ` args := pgx.StrictNamedArgs{ - "tenant_id": scope.GetTenantID(), - "vendor_id": v.ID, - "organization_id": v.OrganizationID, - "name": v.Name, - "description": v.Description, - "category": v.Category, - "headquarter_address": v.HeadquarterAddress, - "legal_name": v.LegalName, - "website_url": v.WebsiteURL, - "privacy_policy_url": v.PrivacyPolicyURL, - "service_level_agreement_url": v.ServiceLevelAgreementURL, - "data_processing_agreement_url": v.DataProcessingAgreementURL, - "certifications": v.Certifications, - "business_owner_id": v.BusinessOwnerID, - "security_owner_id": v.SecurityOwnerID, - "status_page_url": v.StatusPageURL, - "terms_of_service_url": v.TermsOfServiceURL, - "security_page_url": v.SecurityPageURL, - "trust_page_url": v.TrustPageURL, - "created_at": v.CreatedAt, - "updated_at": v.UpdatedAt, + "tenant_id": scope.GetTenantID(), + "vendor_id": v.ID, + "organization_id": v.OrganizationID, + "name": v.Name, + "description": v.Description, + "category": v.Category, + "headquarter_address": v.HeadquarterAddress, + "legal_name": v.LegalName, + "website_url": v.WebsiteURL, + "privacy_policy_url": v.PrivacyPolicyURL, + "service_level_agreement_url": v.ServiceLevelAgreementURL, + "data_processing_agreement_url": v.DataProcessingAgreementURL, + "business_associate_agreement_url": v.BusinessAssociateAgreementURL, + "subprocessors_list_url": v.SubprocessorsListURL, + "certifications": v.Certifications, + "business_owner_id": v.BusinessOwnerID, + "security_owner_id": v.SecurityOwnerID, + "status_page_url": v.StatusPageURL, + "terms_of_service_url": v.TermsOfServiceURL, + "security_page_url": v.SecurityPageURL, + "trust_page_url": v.TrustPageURL, + "created_at": v.CreatedAt, + "updated_at": v.UpdatedAt, } _, err := conn.Exec(ctx, q, args) return err @@ -241,6 +251,8 @@ SELECT privacy_policy_url, service_level_agreement_url, data_processing_agreement_url, + business_associate_agreement_url, + subprocessors_list_url, certifications, business_owner_id, security_owner_id, @@ -295,6 +307,8 @@ SET privacy_policy_url = @privacy_policy_url, service_level_agreement_url = @service_level_agreement_url, data_processing_agreement_url = @data_processing_agreement_url, + business_associate_agreement_url = @business_associate_agreement_url, + subprocessors_list_url = @subprocessors_list_url, certifications = @certifications, status_page_url = @status_page_url, terms_of_service_url = @terms_of_service_url, @@ -309,24 +323,26 @@ WHERE %s q = fmt.Sprintf(q, scope.SQLFragment()) args := pgx.StrictNamedArgs{ - "vendor_id": v.ID, - "updated_at": time.Now(), - "name": v.Name, - "description": v.Description, - "category": v.Category, - "headquarter_address": v.HeadquarterAddress, - "legal_name": v.LegalName, - "website_url": v.WebsiteURL, - "privacy_policy_url": v.PrivacyPolicyURL, - "service_level_agreement_url": v.ServiceLevelAgreementURL, - "data_processing_agreement_url": v.DataProcessingAgreementURL, - "certifications": v.Certifications, - "status_page_url": v.StatusPageURL, - "terms_of_service_url": v.TermsOfServiceURL, - "security_page_url": v.SecurityPageURL, - "trust_page_url": v.TrustPageURL, - "business_owner_id": v.BusinessOwnerID, - "security_owner_id": v.SecurityOwnerID, + "vendor_id": v.ID, + "updated_at": time.Now(), + "name": v.Name, + "description": v.Description, + "category": v.Category, + "headquarter_address": v.HeadquarterAddress, + "legal_name": v.LegalName, + "website_url": v.WebsiteURL, + "privacy_policy_url": v.PrivacyPolicyURL, + "service_level_agreement_url": v.ServiceLevelAgreementURL, + "data_processing_agreement_url": v.DataProcessingAgreementURL, + "business_associate_agreement_url": v.BusinessAssociateAgreementURL, + "subprocessors_list_url": v.SubprocessorsListURL, + "certifications": v.Certifications, + "status_page_url": v.StatusPageURL, + "terms_of_service_url": v.TermsOfServiceURL, + "security_page_url": v.SecurityPageURL, + "trust_page_url": v.TrustPageURL, + "business_owner_id": v.BusinessOwnerID, + "security_owner_id": v.SecurityOwnerID, } maps.Copy(args, scope.SQLArguments()) @@ -344,7 +360,7 @@ func (v Vendor) ExpireNonExpiredRiskAssessments( q := ` UPDATE vendor_risk_assessments - SET + SET expires_at = @now, updated_at = @now WHERE diff --git a/pkg/probo/vendor_service.go b/pkg/probo/vendor_service.go index ffd7b3b56..447dcb54b 100644 --- a/pkg/probo/vendor_service.go +++ b/pkg/probo/vendor_service.go @@ -31,43 +31,47 @@ type ( } CreateVendorRequest struct { - OrganizationID gid.GID - Name string - Description *string - HeadquarterAddress *string - LegalName *string - WebsiteURL *string - Category *coredata.VendorCategory - PrivacyPolicyURL *string - ServiceLevelAgreementURL *string - DataProcessingAgreementURL *string - Certifications []string - SecurityPageURL *string - TrustPageURL *string - TermsOfServiceURL *string - StatusPageURL *string - BusinessOwnerID *gid.GID - SecurityOwnerID *gid.GID + OrganizationID gid.GID + Name string + Description *string + HeadquarterAddress *string + LegalName *string + WebsiteURL *string + Category *coredata.VendorCategory + PrivacyPolicyURL *string + ServiceLevelAgreementURL *string + DataProcessingAgreementURL *string + BusinessAssociateAgreementURL *string + SubprocessorsListURL *string + Certifications []string + SecurityPageURL *string + TrustPageURL *string + TermsOfServiceURL *string + StatusPageURL *string + BusinessOwnerID *gid.GID + SecurityOwnerID *gid.GID } UpdateVendorRequest struct { - ID gid.GID - Name *string - Description *string - HeadquarterAddress *string - LegalName *string - WebsiteURL *string - TermsOfServiceURL *string - Category *coredata.VendorCategory - PrivacyPolicyURL *string - ServiceLevelAgreementURL *string - DataProcessingAgreementURL *string - Certifications []string - SecurityPageURL *string - TrustPageURL *string - StatusPageURL *string - BusinessOwnerID *gid.GID - SecurityOwnerID *gid.GID + ID gid.GID + Name *string + Description *string + HeadquarterAddress *string + LegalName *string + WebsiteURL *string + TermsOfServiceURL *string + Category *coredata.VendorCategory + PrivacyPolicyURL *string + ServiceLevelAgreementURL *string + DataProcessingAgreementURL *string + BusinessAssociateAgreementURL *string + SubprocessorsListURL *string + Certifications []string + SecurityPageURL *string + TrustPageURL *string + StatusPageURL *string + BusinessOwnerID *gid.GID + SecurityOwnerID *gid.GID } AssessVendorRequest struct { @@ -158,6 +162,14 @@ func (s VendorService) Update( vendor.DataProcessingAgreementURL = req.DataProcessingAgreementURL } + if req.BusinessAssociateAgreementURL != nil { + vendor.BusinessAssociateAgreementURL = req.BusinessAssociateAgreementURL + } + + if req.SubprocessorsListURL != nil { + vendor.SubprocessorsListURL = req.SubprocessorsListURL + } + if req.Category != nil { vendor.Category = *req.Category } else { @@ -276,22 +288,24 @@ func (s VendorService) Create( ) (*coredata.Vendor, error) { now := time.Now() vendor := &coredata.Vendor{ - ID: gid.New(s.svc.scope.GetTenantID(), coredata.VendorEntityType), - Name: req.Name, - CreatedAt: now, - UpdatedAt: now, - Description: req.Description, - HeadquarterAddress: req.HeadquarterAddress, - LegalName: req.LegalName, - WebsiteURL: req.WebsiteURL, - PrivacyPolicyURL: req.PrivacyPolicyURL, - ServiceLevelAgreementURL: req.ServiceLevelAgreementURL, - DataProcessingAgreementURL: req.DataProcessingAgreementURL, - Certifications: req.Certifications, - SecurityPageURL: req.SecurityPageURL, - TrustPageURL: req.TrustPageURL, - StatusPageURL: req.StatusPageURL, - TermsOfServiceURL: req.TermsOfServiceURL, + ID: gid.New(s.svc.scope.GetTenantID(), coredata.VendorEntityType), + Name: req.Name, + CreatedAt: now, + UpdatedAt: now, + Description: req.Description, + HeadquarterAddress: req.HeadquarterAddress, + LegalName: req.LegalName, + WebsiteURL: req.WebsiteURL, + PrivacyPolicyURL: req.PrivacyPolicyURL, + ServiceLevelAgreementURL: req.ServiceLevelAgreementURL, + DataProcessingAgreementURL: req.DataProcessingAgreementURL, + BusinessAssociateAgreementURL: req.BusinessAssociateAgreementURL, + SubprocessorsListURL: req.SubprocessorsListURL, + Certifications: req.Certifications, + SecurityPageURL: req.SecurityPageURL, + TrustPageURL: req.TrustPageURL, + StatusPageURL: req.StatusPageURL, + TermsOfServiceURL: req.TermsOfServiceURL, } err := s.svc.pg.WithTx( @@ -439,22 +453,24 @@ func (s VendorService) Assess( } vendor := &coredata.Vendor{ - ID: req.ID, - Name: vendorInfo.Name, - WebsiteURL: &req.WebsiteURL, - Description: &vendorInfo.Description, - Category: coredata.VendorCategory(vendorInfo.Category), - HeadquarterAddress: &vendorInfo.HeadquarterAddress, - LegalName: &vendorInfo.LegalName, - PrivacyPolicyURL: &vendorInfo.PrivacyPolicyURL, - ServiceLevelAgreementURL: &vendorInfo.ServiceLevelAgreementURL, - DataProcessingAgreementURL: &vendorInfo.DataProcessingAgreementURL, - SecurityPageURL: &vendorInfo.SecurityPageURL, - TrustPageURL: &vendorInfo.TrustPageURL, - TermsOfServiceURL: &vendorInfo.TermsOfServiceURL, - StatusPageURL: &vendorInfo.StatusPageURL, - Certifications: vendorInfo.Certifications, - UpdatedAt: time.Now(), + ID: req.ID, + Name: vendorInfo.Name, + WebsiteURL: &req.WebsiteURL, + Description: &vendorInfo.Description, + Category: coredata.VendorCategory(vendorInfo.Category), + HeadquarterAddress: &vendorInfo.HeadquarterAddress, + LegalName: &vendorInfo.LegalName, + PrivacyPolicyURL: &vendorInfo.PrivacyPolicyURL, + ServiceLevelAgreementURL: &vendorInfo.ServiceLevelAgreementURL, + DataProcessingAgreementURL: &vendorInfo.DataProcessingAgreementURL, + BusinessAssociateAgreementURL: &vendorInfo.BusinessAssociateAgreementURL, + SubprocessorsListURL: &vendorInfo.SubprocessorsListURL, + SecurityPageURL: &vendorInfo.SecurityPageURL, + TrustPageURL: &vendorInfo.TrustPageURL, + TermsOfServiceURL: &vendorInfo.TermsOfServiceURL, + StatusPageURL: &vendorInfo.StatusPageURL, + Certifications: vendorInfo.Certifications, + UpdatedAt: time.Now(), } return vendor, nil diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index 3def945b7..c67deec54 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -593,6 +593,8 @@ type Vendor implements Node { privacyPolicyUrl: String serviceLevelAgreementUrl: String dataProcessingAgreementUrl: String + businessAssociateAgreementUrl: String + subprocessorsListUrl: String certifications: [String!]! securityPageUrl: String trustPageUrl: String @@ -1144,6 +1146,8 @@ input CreateVendorInput { category: VendorCategory serviceLevelAgreementUrl: String dataProcessingAgreementUrl: String + businessAssociateAgreementUrl: String + subprocessorsListUrl: String certifications: [String!] securityPageUrl: String trustPageUrl: String @@ -1162,6 +1166,8 @@ input UpdateVendorInput { privacyPolicyUrl: String serviceLevelAgreementUrl: String dataProcessingAgreementUrl: String + businessAssociateAgreementUrl: String + subprocessorsListUrl: String websiteUrl: String legalName: String headquarterAddress: String diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 6e8b4f3fd..aed85121f 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -673,28 +673,30 @@ type ComplexityRoot struct { } Vendor struct { - BusinessOwner func(childComplexity int) int - Category func(childComplexity int) int - Certifications func(childComplexity int) int - ComplianceReports func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) int - CreatedAt func(childComplexity int) int - DataProcessingAgreementURL func(childComplexity int) int - Description func(childComplexity int) int - HeadquarterAddress func(childComplexity int) int - ID func(childComplexity int) int - LegalName func(childComplexity int) int - Name func(childComplexity int) int - Organization func(childComplexity int) int - PrivacyPolicyURL func(childComplexity int) int - RiskAssessments func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) int - SecurityOwner func(childComplexity int) int - SecurityPageURL func(childComplexity int) int - ServiceLevelAgreementURL func(childComplexity int) int - StatusPageURL func(childComplexity int) int - TermsOfServiceURL func(childComplexity int) int - TrustPageURL func(childComplexity int) int - UpdatedAt func(childComplexity int) int - WebsiteURL func(childComplexity int) int + BusinessAssociateAgreementURL func(childComplexity int) int + BusinessOwner func(childComplexity int) int + Category func(childComplexity int) int + Certifications func(childComplexity int) int + ComplianceReports func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) int + CreatedAt func(childComplexity int) int + DataProcessingAgreementURL func(childComplexity int) int + Description func(childComplexity int) int + HeadquarterAddress func(childComplexity int) int + ID func(childComplexity int) int + LegalName func(childComplexity int) int + Name func(childComplexity int) int + Organization func(childComplexity int) int + PrivacyPolicyURL func(childComplexity int) int + RiskAssessments func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) int + SecurityOwner func(childComplexity int) int + SecurityPageURL func(childComplexity int) int + ServiceLevelAgreementURL func(childComplexity int) int + StatusPageURL func(childComplexity int) int + SubprocessorsListURL func(childComplexity int) int + TermsOfServiceURL func(childComplexity int) int + TrustPageURL func(childComplexity int) int + UpdatedAt func(childComplexity int) int + WebsiteURL func(childComplexity int) int } VendorComplianceReport struct { @@ -3507,6 +3509,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.UserEdge.Node(childComplexity), true + case "Vendor.businessAssociateAgreementUrl": + if e.complexity.Vendor.BusinessAssociateAgreementURL == nil { + break + } + + return e.complexity.Vendor.BusinessAssociateAgreementURL(childComplexity), true + case "Vendor.businessOwner": if e.complexity.Vendor.BusinessOwner == nil { break @@ -3643,6 +3652,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Vendor.StatusPageURL(childComplexity), true + case "Vendor.subprocessorsListUrl": + if e.complexity.Vendor.SubprocessorsListURL == nil { + break + } + + return e.complexity.Vendor.SubprocessorsListURL(childComplexity), true + case "Vendor.termsOfServiceUrl": if e.complexity.Vendor.TermsOfServiceURL == nil { break @@ -4686,6 +4702,8 @@ type Vendor implements Node { privacyPolicyUrl: String serviceLevelAgreementUrl: String dataProcessingAgreementUrl: String + businessAssociateAgreementUrl: String + subprocessorsListUrl: String certifications: [String!]! securityPageUrl: String trustPageUrl: String @@ -5237,6 +5255,8 @@ input CreateVendorInput { category: VendorCategory serviceLevelAgreementUrl: String dataProcessingAgreementUrl: String + businessAssociateAgreementUrl: String + subprocessorsListUrl: String certifications: [String!] securityPageUrl: String trustPageUrl: String @@ -5255,6 +5275,8 @@ input UpdateVendorInput { privacyPolicyUrl: String serviceLevelAgreementUrl: String dataProcessingAgreementUrl: String + businessAssociateAgreementUrl: String + subprocessorsListUrl: String websiteUrl: String legalName: String headquarterAddress: String @@ -9860,6 +9882,10 @@ func (ec *executionContext) fieldContext_AssessVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field) case "dataProcessingAgreementUrl": return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field) + case "businessAssociateAgreementUrl": + return ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + case "subprocessorsListUrl": + return ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) case "certifications": return ec.fieldContext_Vendor_certifications(ctx, field) case "securityPageUrl": @@ -25673,6 +25699,10 @@ func (ec *executionContext) fieldContext_UpdateVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field) case "dataProcessingAgreementUrl": return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field) + case "businessAssociateAgreementUrl": + return ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + case "subprocessorsListUrl": + return ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) case "certifications": return ec.fieldContext_Vendor_certifications(ctx, field) case "securityPageUrl": @@ -27046,6 +27076,88 @@ func (ec *executionContext) fieldContext_Vendor_dataProcessingAgreementUrl(_ con return fc, nil } +func (ec *executionContext) _Vendor_businessAssociateAgreementUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.BusinessAssociateAgreementURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Vendor_businessAssociateAgreementUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Vendor", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Vendor_subprocessorsListUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) { + ctx = rctx // use context from middleware stack in children + return obj.SubprocessorsListURL, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Vendor_subprocessorsListUrl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Vendor", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Vendor_certifications(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Vendor_certifications(ctx, field) if err != nil { @@ -27494,6 +27606,10 @@ func (ec *executionContext) fieldContext_VendorComplianceReport_vendor(_ context return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field) case "dataProcessingAgreementUrl": return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field) + case "businessAssociateAgreementUrl": + return ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + case "subprocessorsListUrl": + return ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) case "certifications": return ec.fieldContext_Vendor_certifications(ctx, field) case "securityPageUrl": @@ -28249,6 +28365,10 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field) case "dataProcessingAgreementUrl": return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field) + case "businessAssociateAgreementUrl": + return ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + case "subprocessorsListUrl": + return ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) case "certifications": return ec.fieldContext_Vendor_certifications(ctx, field) case "securityPageUrl": @@ -28383,6 +28503,10 @@ func (ec *executionContext) fieldContext_VendorRiskAssessment_vendor(_ context.C return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field) case "dataProcessingAgreementUrl": return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field) + case "businessAssociateAgreementUrl": + return ec.fieldContext_Vendor_businessAssociateAgreementUrl(ctx, field) + case "subprocessorsListUrl": + return ec.fieldContext_Vendor_subprocessorsListUrl(ctx, field) case "certifications": return ec.fieldContext_Vendor_certifications(ctx, field) case "securityPageUrl": @@ -31899,7 +32023,7 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"organizationId", "name", "description", "headquarterAddress", "legalName", "websiteUrl", "privacyPolicyUrl", "category", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "certifications", "securityPageUrl", "trustPageUrl", "statusPageUrl", "termsOfServiceUrl", "businessOwnerId", "securityOwnerId"} + fieldsInOrder := [...]string{"organizationId", "name", "description", "headquarterAddress", "legalName", "websiteUrl", "privacyPolicyUrl", "category", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "businessAssociateAgreementUrl", "subprocessorsListUrl", "certifications", "securityPageUrl", "trustPageUrl", "statusPageUrl", "termsOfServiceUrl", "businessOwnerId", "securityOwnerId"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -31976,6 +32100,20 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, return it, err } it.DataProcessingAgreementURL = data + case "businessAssociateAgreementUrl": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("businessAssociateAgreementUrl")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.BusinessAssociateAgreementURL = data + case "subprocessorsListUrl": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("subprocessorsListUrl")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.SubprocessorsListURL = data case "certifications": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("certifications")) data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) @@ -33708,7 +33846,7 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"id", "name", "description", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "websiteUrl", "legalName", "headquarterAddress", "category", "certifications", "securityPageUrl", "trustPageUrl", "businessOwnerId", "securityOwnerId"} + fieldsInOrder := [...]string{"id", "name", "description", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "businessAssociateAgreementUrl", "subprocessorsListUrl", "websiteUrl", "legalName", "headquarterAddress", "category", "certifications", "securityPageUrl", "trustPageUrl", "businessOwnerId", "securityOwnerId"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -33771,6 +33909,20 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, return it, err } it.DataProcessingAgreementURL = data + case "businessAssociateAgreementUrl": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("businessAssociateAgreementUrl")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.BusinessAssociateAgreementURL = data + case "subprocessorsListUrl": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("subprocessorsListUrl")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.SubprocessorsListURL = data case "websiteUrl": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("websiteUrl")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) @@ -40749,6 +40901,10 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o out.Values[i] = ec._Vendor_serviceLevelAgreementUrl(ctx, field, obj) case "dataProcessingAgreementUrl": out.Values[i] = ec._Vendor_dataProcessingAgreementUrl(ctx, field, obj) + case "businessAssociateAgreementUrl": + out.Values[i] = ec._Vendor_businessAssociateAgreementUrl(ctx, field, obj) + case "subprocessorsListUrl": + out.Values[i] = ec._Vendor_subprocessorsListUrl(ctx, field, obj) case "certifications": out.Values[i] = ec._Vendor_certifications(ctx, field, obj) if out.Values[i] == graphql.Null { diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index 1f71ee282..324729f61 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -246,23 +246,25 @@ type CreateTaskPayload struct { } type CreateVendorInput struct { - OrganizationID gid.GID `json:"organizationId"` - Name string `json:"name"` - Description *string `json:"description,omitempty"` - HeadquarterAddress *string `json:"headquarterAddress,omitempty"` - LegalName *string `json:"legalName,omitempty"` - WebsiteURL *string `json:"websiteUrl,omitempty"` - PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` - Category *coredata.VendorCategory `json:"category,omitempty"` - ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` - DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` - Certifications []string `json:"certifications,omitempty"` - SecurityPageURL *string `json:"securityPageUrl,omitempty"` - TrustPageURL *string `json:"trustPageUrl,omitempty"` - StatusPageURL *string `json:"statusPageUrl,omitempty"` - TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` - BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` - SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` + OrganizationID gid.GID `json:"organizationId"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + HeadquarterAddress *string `json:"headquarterAddress,omitempty"` + LegalName *string `json:"legalName,omitempty"` + WebsiteURL *string `json:"websiteUrl,omitempty"` + PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` + Category *coredata.VendorCategory `json:"category,omitempty"` + ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` + DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` + BusinessAssociateAgreementURL *string `json:"businessAssociateAgreementUrl,omitempty"` + SubprocessorsListURL *string `json:"subprocessorsListUrl,omitempty"` + Certifications []string `json:"certifications,omitempty"` + SecurityPageURL *string `json:"securityPageUrl,omitempty"` + TrustPageURL *string `json:"trustPageUrl,omitempty"` + StatusPageURL *string `json:"statusPageUrl,omitempty"` + TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` + BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` + SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` } type CreateVendorPayload struct { @@ -909,23 +911,25 @@ type UpdateTaskPayload struct { } type UpdateVendorInput struct { - ID gid.GID `json:"id"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - StatusPageURL *string `json:"statusPageUrl,omitempty"` - TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` - PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` - ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` - DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` - WebsiteURL *string `json:"websiteUrl,omitempty"` - LegalName *string `json:"legalName,omitempty"` - HeadquarterAddress *string `json:"headquarterAddress,omitempty"` - Category *coredata.VendorCategory `json:"category,omitempty"` - Certifications []string `json:"certifications,omitempty"` - SecurityPageURL *string `json:"securityPageUrl,omitempty"` - TrustPageURL *string `json:"trustPageUrl,omitempty"` - BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` - SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` + ID gid.GID `json:"id"` + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + StatusPageURL *string `json:"statusPageUrl,omitempty"` + TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` + PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` + ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` + DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` + BusinessAssociateAgreementURL *string `json:"businessAssociateAgreementUrl,omitempty"` + SubprocessorsListURL *string `json:"subprocessorsListUrl,omitempty"` + WebsiteURL *string `json:"websiteUrl,omitempty"` + LegalName *string `json:"legalName,omitempty"` + HeadquarterAddress *string `json:"headquarterAddress,omitempty"` + Category *coredata.VendorCategory `json:"category,omitempty"` + Certifications []string `json:"certifications,omitempty"` + SecurityPageURL *string `json:"securityPageUrl,omitempty"` + TrustPageURL *string `json:"trustPageUrl,omitempty"` + BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` + SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` } type UpdateVendorPayload struct { @@ -985,28 +989,30 @@ type UserEdge struct { } type Vendor struct { - ID gid.GID `json:"id"` - Name string `json:"name"` - Category coredata.VendorCategory `json:"category"` - Description *string `json:"description,omitempty"` - Organization *Organization `json:"organization"` - ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"` - RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"` - BusinessOwner *People `json:"businessOwner,omitempty"` - SecurityOwner *People `json:"securityOwner,omitempty"` - StatusPageURL *string `json:"statusPageUrl,omitempty"` - TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` - PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` - ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` - DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` - Certifications []string `json:"certifications"` - SecurityPageURL *string `json:"securityPageUrl,omitempty"` - TrustPageURL *string `json:"trustPageUrl,omitempty"` - HeadquarterAddress *string `json:"headquarterAddress,omitempty"` - LegalName *string `json:"legalName,omitempty"` - WebsiteURL *string `json:"websiteUrl,omitempty"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` + ID gid.GID `json:"id"` + Name string `json:"name"` + Category coredata.VendorCategory `json:"category"` + Description *string `json:"description,omitempty"` + Organization *Organization `json:"organization"` + ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"` + RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"` + BusinessOwner *People `json:"businessOwner,omitempty"` + SecurityOwner *People `json:"securityOwner,omitempty"` + StatusPageURL *string `json:"statusPageUrl,omitempty"` + TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` + PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` + ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` + DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` + BusinessAssociateAgreementURL *string `json:"businessAssociateAgreementUrl,omitempty"` + SubprocessorsListURL *string `json:"subprocessorsListUrl,omitempty"` + Certifications []string `json:"certifications"` + SecurityPageURL *string `json:"securityPageUrl,omitempty"` + TrustPageURL *string `json:"trustPageUrl,omitempty"` + HeadquarterAddress *string `json:"headquarterAddress,omitempty"` + LegalName *string `json:"legalName,omitempty"` + WebsiteURL *string `json:"websiteUrl,omitempty"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` } func (Vendor) IsNode() {} diff --git a/pkg/server/api/console/v1/types/vendor.go b/pkg/server/api/console/v1/types/vendor.go index 93ca4aee0..17b615ea9 100644 --- a/pkg/server/api/console/v1/types/vendor.go +++ b/pkg/server/api/console/v1/types/vendor.go @@ -45,22 +45,24 @@ func NewVendorEdge(v *coredata.Vendor, orderBy coredata.VendorOrderField) *Vendo func NewVendor(v *coredata.Vendor) *Vendor { return &Vendor{ - ID: v.ID, - Name: v.Name, - Description: v.Description, - StatusPageURL: v.StatusPageURL, - TermsOfServiceURL: v.TermsOfServiceURL, - PrivacyPolicyURL: v.PrivacyPolicyURL, - ServiceLevelAgreementURL: v.ServiceLevelAgreementURL, - DataProcessingAgreementURL: v.DataProcessingAgreementURL, - Certifications: v.Certifications, - SecurityPageURL: v.SecurityPageURL, - TrustPageURL: v.TrustPageURL, - HeadquarterAddress: v.HeadquarterAddress, - LegalName: v.LegalName, - WebsiteURL: v.WebsiteURL, - Category: v.Category, - UpdatedAt: v.UpdatedAt, - CreatedAt: v.CreatedAt, + ID: v.ID, + Name: v.Name, + Description: v.Description, + StatusPageURL: v.StatusPageURL, + TermsOfServiceURL: v.TermsOfServiceURL, + PrivacyPolicyURL: v.PrivacyPolicyURL, + ServiceLevelAgreementURL: v.ServiceLevelAgreementURL, + DataProcessingAgreementURL: v.DataProcessingAgreementURL, + BusinessAssociateAgreementURL: v.BusinessAssociateAgreementURL, + SubprocessorsListURL: v.SubprocessorsListURL, + Certifications: v.Certifications, + SecurityPageURL: v.SecurityPageURL, + TrustPageURL: v.TrustPageURL, + HeadquarterAddress: v.HeadquarterAddress, + LegalName: v.LegalName, + WebsiteURL: v.WebsiteURL, + Category: v.Category, + UpdatedAt: v.UpdatedAt, + CreatedAt: v.CreatedAt, } } diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index bfe2e47da..a18180a98 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -482,23 +482,25 @@ func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateV vendor, err := svc.Vendors.Create( ctx, probo.CreateVendorRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - Description: input.Description, - StatusPageURL: input.StatusPageURL, - TermsOfServiceURL: input.TermsOfServiceURL, - PrivacyPolicyURL: input.PrivacyPolicyURL, - ServiceLevelAgreementURL: input.ServiceLevelAgreementURL, - LegalName: input.LegalName, - HeadquarterAddress: input.HeadquarterAddress, - WebsiteURL: input.WebsiteURL, - Category: input.Category, - DataProcessingAgreementURL: input.DataProcessingAgreementURL, - Certifications: input.Certifications, - SecurityPageURL: input.SecurityPageURL, - TrustPageURL: input.TrustPageURL, - BusinessOwnerID: input.BusinessOwnerID, - SecurityOwnerID: input.SecurityOwnerID, + OrganizationID: input.OrganizationID, + Name: input.Name, + Description: input.Description, + StatusPageURL: input.StatusPageURL, + TermsOfServiceURL: input.TermsOfServiceURL, + PrivacyPolicyURL: input.PrivacyPolicyURL, + ServiceLevelAgreementURL: input.ServiceLevelAgreementURL, + LegalName: input.LegalName, + HeadquarterAddress: input.HeadquarterAddress, + WebsiteURL: input.WebsiteURL, + Category: input.Category, + DataProcessingAgreementURL: input.DataProcessingAgreementURL, + BusinessAssociateAgreementURL: input.BusinessAssociateAgreementURL, + SubprocessorsListURL: input.SubprocessorsListURL, + Certifications: input.Certifications, + SecurityPageURL: input.SecurityPageURL, + TrustPageURL: input.TrustPageURL, + BusinessOwnerID: input.BusinessOwnerID, + SecurityOwnerID: input.SecurityOwnerID, }, ) if err != nil { @@ -514,23 +516,25 @@ func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateV svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID()) vendor, err := svc.Vendors.Update(ctx, probo.UpdateVendorRequest{ - ID: input.ID, - Name: input.Name, - Description: input.Description, - StatusPageURL: input.StatusPageURL, - TermsOfServiceURL: input.TermsOfServiceURL, - PrivacyPolicyURL: input.PrivacyPolicyURL, - ServiceLevelAgreementURL: input.ServiceLevelAgreementURL, - DataProcessingAgreementURL: input.DataProcessingAgreementURL, - SecurityPageURL: input.SecurityPageURL, - TrustPageURL: input.TrustPageURL, - HeadquarterAddress: input.HeadquarterAddress, - LegalName: input.LegalName, - WebsiteURL: input.WebsiteURL, - Category: input.Category, - Certifications: input.Certifications, - BusinessOwnerID: input.BusinessOwnerID, - SecurityOwnerID: input.SecurityOwnerID, + ID: input.ID, + Name: input.Name, + Description: input.Description, + StatusPageURL: input.StatusPageURL, + TermsOfServiceURL: input.TermsOfServiceURL, + PrivacyPolicyURL: input.PrivacyPolicyURL, + ServiceLevelAgreementURL: input.ServiceLevelAgreementURL, + DataProcessingAgreementURL: input.DataProcessingAgreementURL, + BusinessAssociateAgreementURL: input.BusinessAssociateAgreementURL, + SubprocessorsListURL: input.SubprocessorsListURL, + SecurityPageURL: input.SecurityPageURL, + TrustPageURL: input.TrustPageURL, + HeadquarterAddress: input.HeadquarterAddress, + LegalName: input.LegalName, + WebsiteURL: input.WebsiteURL, + Category: input.Category, + Certifications: input.Certifications, + BusinessOwnerID: input.BusinessOwnerID, + SecurityOwnerID: input.SecurityOwnerID, }) if err != nil { return nil, fmt.Errorf("cannot update vendor: %w", err)