Fetch vendor data with openai
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import type { VendorViewDeleteComplianceReportMutation as DeleteComplianceReport
|
|||||||
import type { VendorViewUploadComplianceReportMutation as UploadComplianceReportMutationType } from "./__generated__/VendorViewUploadComplianceReportMutation.graphql";
|
import type { VendorViewUploadComplianceReportMutation as UploadComplianceReportMutationType } from "./__generated__/VendorViewUploadComplianceReportMutation.graphql";
|
||||||
import type { VendorViewUpdateVendorMutation } from "./__generated__/VendorViewUpdateVendorMutation.graphql";
|
import type { VendorViewUpdateVendorMutation } from "./__generated__/VendorViewUpdateVendorMutation.graphql";
|
||||||
import type { VendorViewCreateRiskAssessmentMutation } from "./__generated__/VendorViewCreateRiskAssessmentMutation.graphql";
|
import type { VendorViewCreateRiskAssessmentMutation } from "./__generated__/VendorViewCreateRiskAssessmentMutation.graphql";
|
||||||
|
import type { VendorViewAssessVendorMutation } from "./__generated__/VendorViewAssessVendorMutation.graphql";
|
||||||
import type {
|
import type {
|
||||||
BusinessImpact,
|
BusinessImpact,
|
||||||
DataSensitivity,
|
DataSensitivity,
|
||||||
@@ -31,6 +32,7 @@ import { PageTemplate } from "@/components/PageTemplate";
|
|||||||
import { VendorViewSkeleton } from "./VendorPage";
|
import { VendorViewSkeleton } from "./VendorPage";
|
||||||
import PeopleSelector from "@/components/PeopleSelector";
|
import PeopleSelector from "@/components/PeopleSelector";
|
||||||
import { formatDistanceToNow, format, isPast } from "date-fns";
|
import { formatDistanceToNow, format, isPast } from "date-fns";
|
||||||
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||||
|
|
||||||
const vendorViewQuery = graphql`
|
const vendorViewQuery = graphql`
|
||||||
query VendorViewQuery($vendorId: ID!, $organizationId: ID!) {
|
query VendorViewQuery($vendorId: ID!, $organizationId: ID!) {
|
||||||
@@ -196,6 +198,38 @@ const createRiskAssessmentMutation = graphql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const assessVendorMutation = graphql`
|
||||||
|
mutation VendorViewAssessVendorMutation($input: AssessVendorInput!) {
|
||||||
|
assessVendor(input: $input) {
|
||||||
|
vendor {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
statusPageUrl
|
||||||
|
termsOfServiceUrl
|
||||||
|
privacyPolicyUrl
|
||||||
|
serviceLevelAgreementUrl
|
||||||
|
dataProcessingAgreementUrl
|
||||||
|
securityPageUrl
|
||||||
|
trustPageUrl
|
||||||
|
certifications
|
||||||
|
headquarterAddress
|
||||||
|
legalName
|
||||||
|
websiteUrl
|
||||||
|
businessOwner {
|
||||||
|
id
|
||||||
|
fullName
|
||||||
|
}
|
||||||
|
securityOwner {
|
||||||
|
id
|
||||||
|
fullName
|
||||||
|
}
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
// Format date for input field (YYYY-MM-DDTHH:mm)
|
// Format date for input field (YYYY-MM-DDTHH:mm)
|
||||||
function formatDateForInput(date: string | null | undefined): string {
|
function formatDateForInput(date: string | null | undefined): string {
|
||||||
if (!date) return "";
|
if (!date) return "";
|
||||||
@@ -1398,6 +1432,13 @@ function VendorViewContent({
|
|||||||
);
|
);
|
||||||
const [, loadQuery] = useQueryLoader<VendorViewQueryType>(vendorViewQuery);
|
const [, loadQuery] = useQueryLoader<VendorViewQueryType>(vendorViewQuery);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const [isAssessDialogOpen, setIsAssessDialogOpen] = useState(false);
|
||||||
|
|
||||||
|
const [websiteUrl, setWebsiteUrl] = useState("");
|
||||||
|
|
||||||
|
const [commitAssessVendor, isInFlight] = useMutation<VendorViewAssessVendorMutation>(
|
||||||
|
assessVendorMutation
|
||||||
|
);
|
||||||
|
|
||||||
const hasChanges = editedFields.size > 0;
|
const hasChanges = editedFields.size > 0;
|
||||||
|
|
||||||
@@ -2301,8 +2342,92 @@ function VendorViewContent({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAssessVendor = useCallback(() => {
|
||||||
|
if (!websiteUrl) {
|
||||||
|
toast({
|
||||||
|
title: "Error",
|
||||||
|
description: "Please enter a website URL",
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commitAssessVendor({
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id: data.node.id!,
|
||||||
|
websiteUrl,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onCompleted: (response) => {
|
||||||
|
const newData = response.assessVendor.vendor;
|
||||||
|
const changedFields = new Set<string>();
|
||||||
|
|
||||||
|
// Compare and track changes
|
||||||
|
Object.entries(newData).forEach(([key, value]) => {
|
||||||
|
if (value != null && key !== 'id' && formData[key as keyof typeof formData] !== value) {
|
||||||
|
changedFields.add(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setFormData(prevData => {
|
||||||
|
const newFormData = {
|
||||||
|
...prevData,
|
||||||
|
name: newData.name || prevData.name,
|
||||||
|
description: newData.description || prevData.description,
|
||||||
|
statusPageUrl: newData.statusPageUrl || prevData.statusPageUrl,
|
||||||
|
termsOfServiceUrl: newData.termsOfServiceUrl || prevData.termsOfServiceUrl,
|
||||||
|
privacyPolicyUrl: newData.privacyPolicyUrl || prevData.privacyPolicyUrl,
|
||||||
|
serviceLevelAgreementUrl: newData.serviceLevelAgreementUrl || prevData.serviceLevelAgreementUrl,
|
||||||
|
dataProcessingAgreementUrl: newData.dataProcessingAgreementUrl || prevData.dataProcessingAgreementUrl,
|
||||||
|
securityPageUrl: newData.securityPageUrl || prevData.securityPageUrl,
|
||||||
|
trustPageUrl: newData.trustPageUrl || prevData.trustPageUrl,
|
||||||
|
certifications: newData.certifications || prevData.certifications,
|
||||||
|
headquarterAddress: newData.headquarterAddress || prevData.headquarterAddress,
|
||||||
|
legalName: newData.legalName || prevData.legalName,
|
||||||
|
websiteUrl: newData.websiteUrl || prevData.websiteUrl,
|
||||||
|
};
|
||||||
|
return newFormData;
|
||||||
|
});
|
||||||
|
|
||||||
|
setEditedFields(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
changedFields.forEach(field => newSet.add(field));
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Success",
|
||||||
|
description: changedFields.size > 0
|
||||||
|
? "Vendor has been assessed. Review and save the changes."
|
||||||
|
: "Vendor data has been assessed. No changes were found.",
|
||||||
|
});
|
||||||
|
|
||||||
|
setIsAssessDialogOpen(false);
|
||||||
|
setWebsiteUrl("");
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast({
|
||||||
|
title: "Error",
|
||||||
|
description: error.message,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, [commitAssessVendor, data.node.id, websiteUrl, toast, formData]);
|
||||||
return (
|
return (
|
||||||
<PageTemplate title={formData.name}>
|
<PageTemplate
|
||||||
|
title={formData.name}
|
||||||
|
actions={
|
||||||
|
<Button
|
||||||
|
className="rounded-full bg-[rgba(0,39,0,0.05)] text-[#141E12] hover:bg-[rgba(0,39,0,0.08)] h-8 px-3"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setIsAssessDialogOpen(true)}
|
||||||
|
>
|
||||||
|
Assessement From Website
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
<div className="border-b mb-6">
|
<div className="border-b mb-6">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<button
|
<button
|
||||||
@@ -2377,12 +2502,71 @@ function VendorViewContent({
|
|||||||
onSubmit={handleRiskAssessmentSubmit}
|
onSubmit={handleRiskAssessmentSubmit}
|
||||||
businessOwnerId={formData.businessOwnerId}
|
businessOwnerId={formData.businessOwnerId}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Assessement From Website Modal */}
|
||||||
|
<Dialog open={isAssessDialogOpen} onOpenChange={setIsAssessDialogOpen}>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Assessement From Website</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<Input
|
||||||
|
placeholder="Enter website URL"
|
||||||
|
value={websiteUrl}
|
||||||
|
onChange={(e) => setWebsiteUrl(e.target.value)}
|
||||||
|
disabled={isInFlight}
|
||||||
|
/>
|
||||||
|
{isInFlight && (
|
||||||
|
<div className="flex items-center justify-center text-sm text-[#6B716A]">
|
||||||
|
<svg
|
||||||
|
className="animate-spin -ml-1 mr-3 h-5 w-5 text-[#054D05]"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
className="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="4"
|
||||||
|
></circle>
|
||||||
|
<path
|
||||||
|
className="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Assessing vendor data...
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setIsAssessDialogOpen(false)}
|
||||||
|
disabled={isInFlight}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleAssessVendor}
|
||||||
|
disabled={isInFlight}
|
||||||
|
className={isInFlight ? "opacity-50 cursor-not-allowed" : ""}
|
||||||
|
>
|
||||||
|
{isInFlight ? "Processing..." : "Assess"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</PageTemplate>
|
</PageTemplate>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function VendorView() {
|
export default function VendorView() {
|
||||||
const { vendorId, organizationId } = useParams();
|
const { vendorId, organizationId } = useParams();
|
||||||
|
|
||||||
const [queryRef, loadQuery] =
|
const [queryRef, loadQuery] =
|
||||||
useQueryLoader<VendorViewQueryType>(vendorViewQuery);
|
useQueryLoader<VendorViewQueryType>(vendorViewQuery);
|
||||||
|
|
||||||
|
|||||||
257
apps/console/src/pages/organizations/vendors/__generated__/VendorViewAssessVendorMutation.graphql.ts
generated
vendored
Normal file
257
apps/console/src/pages/organizations/vendors/__generated__/VendorViewAssessVendorMutation.graphql.ts
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<71c7ed1be8cf0477074d6cf130143626>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type AssessVendorInput = {
|
||||||
|
id: string;
|
||||||
|
websiteUrl: string;
|
||||||
|
};
|
||||||
|
export type VendorViewAssessVendorMutation$variables = {
|
||||||
|
input: AssessVendorInput;
|
||||||
|
};
|
||||||
|
export type VendorViewAssessVendorMutation$data = {
|
||||||
|
readonly assessVendor: {
|
||||||
|
readonly vendor: {
|
||||||
|
readonly businessOwner: {
|
||||||
|
readonly fullName: string;
|
||||||
|
readonly id: string;
|
||||||
|
} | null | undefined;
|
||||||
|
readonly certifications: ReadonlyArray<string>;
|
||||||
|
readonly dataProcessingAgreementUrl: string | null | undefined;
|
||||||
|
readonly description: string | null | undefined;
|
||||||
|
readonly headquarterAddress: string | null | undefined;
|
||||||
|
readonly id: string;
|
||||||
|
readonly legalName: string | null | undefined;
|
||||||
|
readonly name: string;
|
||||||
|
readonly privacyPolicyUrl: string | null | undefined;
|
||||||
|
readonly securityOwner: {
|
||||||
|
readonly fullName: string;
|
||||||
|
readonly id: string;
|
||||||
|
} | null | undefined;
|
||||||
|
readonly securityPageUrl: string | null | undefined;
|
||||||
|
readonly serviceLevelAgreementUrl: string | null | undefined;
|
||||||
|
readonly statusPageUrl: string | null | undefined;
|
||||||
|
readonly termsOfServiceUrl: string | null | undefined;
|
||||||
|
readonly trustPageUrl: string | null | undefined;
|
||||||
|
readonly updatedAt: string;
|
||||||
|
readonly websiteUrl: string | null | undefined;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type VendorViewAssessVendorMutation = {
|
||||||
|
response: VendorViewAssessVendorMutation$data;
|
||||||
|
variables: VendorViewAssessVendorMutation$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "input"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v1 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v2 = [
|
||||||
|
(v1/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "fullName",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v3 = [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "input",
|
||||||
|
"variableName": "input"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"concreteType": "AssessVendorPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "assessVendor",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Vendor",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "vendor",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v1/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "description",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "statusPageUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "termsOfServiceUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "privacyPolicyUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "serviceLevelAgreementUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "dataProcessingAgreementUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "securityPageUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "trustPageUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "certifications",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "headquarterAddress",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "legalName",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "websiteUrl",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "People",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "businessOwner",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v2/*: any*/),
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "People",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "securityOwner",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v2/*: any*/),
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "updatedAt",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "VendorViewAssessVendorMutation",
|
||||||
|
"selections": (v3/*: any*/),
|
||||||
|
"type": "Mutation",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "VendorViewAssessVendorMutation",
|
||||||
|
"selections": (v3/*: any*/)
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "ccc16b2de8f7f3936458cd4823a14992",
|
||||||
|
"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 businessOwner {\n id\n fullName\n }\n securityOwner {\n id\n fullName\n }\n updatedAt\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "ed23d00ce5a44aa6bfd43a072552ed1c";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -6,3 +6,7 @@ probod:
|
|||||||
access-key-id: "probod"
|
access-key-id: "probod"
|
||||||
secret-access-key: "thisisnotasecret"
|
secret-access-key: "thisisnotasecret"
|
||||||
endpoint: "http://127.0.0.1:9000"
|
endpoint: "http://127.0.0.1:9000"
|
||||||
|
openai:
|
||||||
|
api-key: "thisisnotasecret"
|
||||||
|
temperature: 0.1
|
||||||
|
model-name: "gpt-4o"
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -16,6 +16,7 @@ require (
|
|||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/jackc/pgx/v5 v5.7.4
|
github.com/jackc/pgx/v5 v5.7.4
|
||||||
github.com/jhillyerd/enmime v1.3.0
|
github.com/jhillyerd/enmime v1.3.0
|
||||||
|
github.com/openai/openai-go v1.1.0
|
||||||
github.com/prometheus/client_golang v1.22.0
|
github.com/prometheus/client_golang v1.22.0
|
||||||
github.com/vektah/gqlparser/v2 v2.5.27
|
github.com/vektah/gqlparser/v2 v2.5.27
|
||||||
go.gearno.de/crypto/uuid v0.1.0
|
go.gearno.de/crypto/uuid v0.1.0
|
||||||
@@ -64,6 +65,10 @@ require (
|
|||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sosodev/duration v1.3.1 // indirect
|
github.com/sosodev/duration v1.3.1 // indirect
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
|
github.com/tidwall/gjson v1.18.0 // indirect
|
||||||
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
|
github.com/tidwall/sjson v1.2.5 // indirect
|
||||||
github.com/urfave/cli/v2 v2.27.6 // indirect
|
github.com/urfave/cli/v2 v2.27.6 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||||
go.gearno.de/x/panicf v0.1.1 // indirect
|
go.gearno.de/x/panicf v0.1.1 // indirect
|
||||||
|
|||||||
12
go.sum
12
go.sum
@@ -108,6 +108,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
|
|||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
|
github.com/openai/openai-go v1.1.0 h1:daSn+y+3QJUmLV1xfh7B8QtgJYRw1hg3yWxKtQDfROE=
|
||||||
|
github.com/openai/openai-go v1.1.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -140,6 +142,16 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||||
|
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
|
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||||
|
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||||
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
||||||
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s=
|
github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s=
|
||||||
|
|||||||
137
pkg/agents/vendor_assessment.go
Normal file
137
pkg/agents/vendor_assessment.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
package agents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/openai/openai-go"
|
||||||
|
"github.com/openai/openai-go/option"
|
||||||
|
"github.com/openai/openai-go/packages/param"
|
||||||
|
"go.gearno.de/kit/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
VendorAssessment struct {
|
||||||
|
l *log.Logger
|
||||||
|
cfg Config
|
||||||
|
client *openai.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
Config struct {
|
||||||
|
OpenAIAPIKey string
|
||||||
|
Temperature float64
|
||||||
|
ModelName string
|
||||||
|
}
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
systemPrompt = `
|
||||||
|
# Role: You are a compliance assistant.
|
||||||
|
|
||||||
|
# Objective
|
||||||
|
Your task is to fetch the provided company URL and to return comprehensive company information.
|
||||||
|
|
||||||
|
# For the company url, return the following fields in structured JSON format:
|
||||||
|
- name: The company's commonly used name
|
||||||
|
- description: One-sentence summary of the company's core offering
|
||||||
|
- headquarter_address: Company's main headquarter full address
|
||||||
|
- legal_name: Official registered company name
|
||||||
|
- privacy_policy_url: URL to privacy policy page
|
||||||
|
- service_level_agreement_url: URL to SLA page
|
||||||
|
- data_processing_agreement_url: URL to DPA 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
|
||||||
|
- status_page_url: URL to system status page
|
||||||
|
- certifications: Array of security/compliance certifications (e.g., ["SOC2", "ISO27001"])
|
||||||
|
|
||||||
|
# SOP
|
||||||
|
- Please ensure the output is clean, standardized JSON.
|
||||||
|
- Use web search to gather info, if you cannot find what you are looking for, just return an empty string instead
|
||||||
|
- For URLs, return the full URL if found, otherwise an empty string
|
||||||
|
- For certifications, return an empty array if none found
|
||||||
|
|
||||||
|
# **Example output format:**
|
||||||
|
Respond ONLY with a JSON object. No explanation, no markdown, no preamble. Like this:
|
||||||
|
{
|
||||||
|
"name": "Stripe",
|
||||||
|
"description": "Online payment processing platform that enables businesses to accept and manage digital payments, supporting various payment methods and currencies with integrated fraud protection and compliance features",
|
||||||
|
"headquarter_address": "San Francisco, CA",
|
||||||
|
"legal_name": "Stripe, Inc.",
|
||||||
|
"privacy_policy_url": "https://stripe.com/privacy",
|
||||||
|
"service_level_agreement_url": "https://stripe.com/sla",
|
||||||
|
"data_processing_agreement_url": "https://stripe.com/dpa",
|
||||||
|
"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"]
|
||||||
|
}
|
||||||
|
|
||||||
|
### Company url:
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewVendorAssessment(l *log.Logger, cfg Config) *VendorAssessment {
|
||||||
|
client := openai.NewClient(option.WithAPIKey(cfg.OpenAIAPIKey))
|
||||||
|
|
||||||
|
return &VendorAssessment{l: l, cfg: cfg, client: &client}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (va *VendorAssessment) Fetch(ctx context.Context, websiteURL string) (*vendorInfo, error) {
|
||||||
|
model := openai.ChatModel(va.cfg.ModelName)
|
||||||
|
chatCompletion, err := va.client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
|
||||||
|
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||||
|
openai.SystemMessage(systemPrompt),
|
||||||
|
openai.UserMessage(websiteURL),
|
||||||
|
},
|
||||||
|
Model: model,
|
||||||
|
Temperature: param.NewOpt(va.cfg.Temperature),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse vendor info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(chatCompletion.Choices) == 0 {
|
||||||
|
return nil, fmt.Errorf("no completion choices returned from API")
|
||||||
|
}
|
||||||
|
|
||||||
|
var vendorInfo vendorInfo
|
||||||
|
err = json.Unmarshal([]byte(chatCompletion.Choices[0].Message.Content), &vendorInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse vendor info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &vendorInfo, nil
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
|
"github.com/getprobo/probo/pkg/agents"
|
||||||
"github.com/getprobo/probo/pkg/coredata"
|
"github.com/getprobo/probo/pkg/coredata"
|
||||||
"github.com/getprobo/probo/pkg/crypto/cipher"
|
"github.com/getprobo/probo/pkg/crypto/cipher"
|
||||||
"github.com/getprobo/probo/pkg/filevalidation"
|
"github.com/getprobo/probo/pkg/filevalidation"
|
||||||
@@ -34,6 +35,7 @@ type (
|
|||||||
encryptionKey cipher.EncryptionKey
|
encryptionKey cipher.EncryptionKey
|
||||||
hostname string
|
hostname string
|
||||||
tokenSecret string
|
tokenSecret string
|
||||||
|
vendorAssessment agents.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
TenantService struct {
|
TenantService struct {
|
||||||
@@ -44,6 +46,7 @@ type (
|
|||||||
scope coredata.Scoper
|
scope coredata.Scoper
|
||||||
hostname string
|
hostname string
|
||||||
tokenSecret string
|
tokenSecret string
|
||||||
|
vendorAssessment *agents.VendorAssessment
|
||||||
Frameworks *FrameworkService
|
Frameworks *FrameworkService
|
||||||
Measures *MeasureService
|
Measures *MeasureService
|
||||||
Tasks *TaskService
|
Tasks *TaskService
|
||||||
@@ -67,6 +70,7 @@ func NewService(
|
|||||||
bucket string,
|
bucket string,
|
||||||
hostname string,
|
hostname string,
|
||||||
tokenSecret string,
|
tokenSecret string,
|
||||||
|
vendorAssessment agents.Config,
|
||||||
) (*Service, error) {
|
) (*Service, error) {
|
||||||
if bucket == "" {
|
if bucket == "" {
|
||||||
return nil, fmt.Errorf("bucket is required")
|
return nil, fmt.Errorf("bucket is required")
|
||||||
@@ -79,6 +83,7 @@ func NewService(
|
|||||||
encryptionKey: encryptionKey,
|
encryptionKey: encryptionKey,
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
tokenSecret: tokenSecret,
|
tokenSecret: tokenSecret,
|
||||||
|
vendorAssessment: vendorAssessment,
|
||||||
}
|
}
|
||||||
|
|
||||||
return svc, nil
|
return svc, nil
|
||||||
@@ -93,6 +98,7 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
|||||||
hostname: s.hostname,
|
hostname: s.hostname,
|
||||||
scope: coredata.NewScope(tenantID),
|
scope: coredata.NewScope(tenantID),
|
||||||
tokenSecret: s.tokenSecret,
|
tokenSecret: s.tokenSecret,
|
||||||
|
vendorAssessment: agents.NewVendorAssessment(nil, s.vendorAssessment),
|
||||||
}
|
}
|
||||||
|
|
||||||
tenantService.Frameworks = &FrameworkService{svc: tenantService}
|
tenantService.Frameworks = &FrameworkService{svc: tenantService}
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ type (
|
|||||||
SecurityOwnerID *gid.GID
|
SecurityOwnerID *gid.GID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AssessVendorRequest struct {
|
||||||
|
ID gid.GID
|
||||||
|
WebsiteURL string
|
||||||
|
}
|
||||||
|
|
||||||
CreateVendorRiskAssessmentRequest struct {
|
CreateVendorRiskAssessmentRequest struct {
|
||||||
VendorID gid.GID
|
VendorID gid.GID
|
||||||
AssessedByID gid.GID
|
AssessedByID gid.GID
|
||||||
@@ -421,3 +426,34 @@ func (s VendorService) GetRiskAssessment(
|
|||||||
|
|
||||||
return vendorRiskAssessment, nil
|
return vendorRiskAssessment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s VendorService) Assess(
|
||||||
|
ctx context.Context,
|
||||||
|
req AssessVendorRequest,
|
||||||
|
) (*coredata.Vendor, error) {
|
||||||
|
vendorInfo, err := s.svc.vendorAssessment.Fetch(ctx, req.WebsiteURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to assess vendor info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vendor := &coredata.Vendor{
|
||||||
|
ID: req.ID,
|
||||||
|
Name: vendorInfo.Name,
|
||||||
|
WebsiteURL: &req.WebsiteURL,
|
||||||
|
Description: &vendorInfo.Description,
|
||||||
|
Category: 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(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return vendor, nil
|
||||||
|
}
|
||||||
|
|||||||
21
pkg/probod/openai_config.go
Normal file
21
pkg/probod/openai_config.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
// PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
package probod
|
||||||
|
|
||||||
|
type openaiConfig struct {
|
||||||
|
APIKey string `json:"api-key"`
|
||||||
|
Temperature float64 `json:"temperature"`
|
||||||
|
ModelName string `json:"model-name"`
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
|
"github.com/getprobo/probo/pkg/agents"
|
||||||
"github.com/getprobo/probo/pkg/awsconfig"
|
"github.com/getprobo/probo/pkg/awsconfig"
|
||||||
"github.com/getprobo/probo/pkg/connector"
|
"github.com/getprobo/probo/pkg/connector"
|
||||||
"github.com/getprobo/probo/pkg/coredata"
|
"github.com/getprobo/probo/pkg/coredata"
|
||||||
@@ -59,6 +60,7 @@ type (
|
|||||||
AWS awsConfig `json:"aws"`
|
AWS awsConfig `json:"aws"`
|
||||||
Mailer mailerConfig `json:"mailer"`
|
Mailer mailerConfig `json:"mailer"`
|
||||||
Connectors []connectorConfig `json:"connectors"`
|
Connectors []connectorConfig `json:"connectors"`
|
||||||
|
OpenAI openaiConfig `json:"openai"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -185,6 +187,14 @@ func (impl *Implm) Run(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vendorAssessmentConfig := agents.Config{
|
||||||
|
OpenAIAPIKey: impl.cfg.OpenAI.APIKey,
|
||||||
|
Temperature: impl.cfg.OpenAI.Temperature,
|
||||||
|
ModelName: impl.cfg.OpenAI.ModelName,
|
||||||
|
}
|
||||||
|
|
||||||
|
vendorAssessment := agents.NewVendorAssessment(l.Named("vendor-assessment"), vendorAssessmentConfig)
|
||||||
|
|
||||||
usrmgrService, err := usrmgr.NewService(
|
usrmgrService, err := usrmgr.NewService(
|
||||||
ctx,
|
ctx,
|
||||||
pgClient,
|
pgClient,
|
||||||
@@ -205,6 +215,7 @@ func (impl *Implm) Run(
|
|||||||
impl.cfg.AWS.Bucket,
|
impl.cfg.AWS.Bucket,
|
||||||
impl.cfg.Hostname,
|
impl.cfg.Hostname,
|
||||||
impl.cfg.Auth.Cookie.Secret,
|
impl.cfg.Auth.Cookie.Secret,
|
||||||
|
vendorAssessmentConfig,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot create probo service: %w", err)
|
return fmt.Errorf("cannot create probo service: %w", err)
|
||||||
@@ -216,6 +227,7 @@ func (impl *Implm) Run(
|
|||||||
Probo: proboService,
|
Probo: proboService,
|
||||||
Usrmgr: usrmgrService,
|
Usrmgr: usrmgrService,
|
||||||
ConnectorRegistry: defaultConnectorRegistry,
|
ConnectorRegistry: defaultConnectorRegistry,
|
||||||
|
VendorAssessment: vendorAssessment,
|
||||||
SafeRedirect: &saferedirect.SafeRedirect{AllowedHost: impl.cfg.Hostname},
|
SafeRedirect: &saferedirect.SafeRedirect{AllowedHost: impl.cfg.Hostname},
|
||||||
Logger: l.Named("http.server"),
|
Logger: l.Named("http.server"),
|
||||||
Auth: console_v1.AuthConfig{
|
Auth: console_v1.AuthConfig{
|
||||||
|
|||||||
@@ -1088,6 +1088,8 @@ type Mutation {
|
|||||||
): CreateVendorRiskAssessmentPayload!
|
): CreateVendorRiskAssessmentPayload!
|
||||||
|
|
||||||
exportAudit(input: ExportAuditInput!): ExportAuditPayload!
|
exportAudit(input: ExportAuditInput!): ExportAuditPayload!
|
||||||
|
|
||||||
|
assessVendor(input: AssessVendorInput!): AssessVendorPayload!
|
||||||
}
|
}
|
||||||
|
|
||||||
# Input Types
|
# Input Types
|
||||||
@@ -1779,3 +1781,12 @@ input ExportAuditInput {
|
|||||||
type ExportAuditPayload {
|
type ExportAuditPayload {
|
||||||
url: String!
|
url: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input AssessVendorInput {
|
||||||
|
id: ID!
|
||||||
|
websiteUrl: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssessVendorPayload {
|
||||||
|
vendor: Vendor!
|
||||||
|
}
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ type DirectiveRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ComplexityRoot struct {
|
type ComplexityRoot struct {
|
||||||
|
AssessVendorPayload struct {
|
||||||
|
Vendor func(childComplexity int) int
|
||||||
|
}
|
||||||
|
|
||||||
AssignTaskPayload struct {
|
AssignTaskPayload struct {
|
||||||
Task func(childComplexity int) int
|
Task func(childComplexity int) int
|
||||||
}
|
}
|
||||||
@@ -329,6 +333,7 @@ type ComplexityRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mutation struct {
|
Mutation struct {
|
||||||
|
AssessVendor func(childComplexity int, input types.AssessVendorInput) int
|
||||||
AssignTask func(childComplexity int, input types.AssignTaskInput) int
|
AssignTask func(childComplexity int, input types.AssignTaskInput) int
|
||||||
ConfirmEmail func(childComplexity int, input types.ConfirmEmailInput) int
|
ConfirmEmail func(childComplexity int, input types.ConfirmEmailInput) int
|
||||||
CreateControlMeasureMapping func(childComplexity int, input types.CreateControlMeasureMappingInput) int
|
CreateControlMeasureMapping func(childComplexity int, input types.CreateControlMeasureMappingInput) int
|
||||||
@@ -827,6 +832,7 @@ type MutationResolver interface {
|
|||||||
SendSigningNotifications(ctx context.Context, input types.SendSigningNotificationsInput) (*types.SendSigningNotificationsPayload, error)
|
SendSigningNotifications(ctx context.Context, input types.SendSigningNotificationsInput) (*types.SendSigningNotificationsPayload, error)
|
||||||
CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error)
|
CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error)
|
||||||
ExportAudit(ctx context.Context, input types.ExportAuditInput) (*types.ExportAuditPayload, error)
|
ExportAudit(ctx context.Context, input types.ExportAuditInput) (*types.ExportAuditPayload, error)
|
||||||
|
AssessVendor(ctx context.Context, input types.AssessVendorInput) (*types.AssessVendorPayload, error)
|
||||||
}
|
}
|
||||||
type OrganizationResolver interface {
|
type OrganizationResolver interface {
|
||||||
LogoURL(ctx context.Context, obj *types.Organization) (*string, error)
|
LogoURL(ctx context.Context, obj *types.Organization) (*string, error)
|
||||||
@@ -919,6 +925,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
_ = ec
|
_ = ec
|
||||||
switch typeName + "." + field {
|
switch typeName + "." + field {
|
||||||
|
|
||||||
|
case "AssessVendorPayload.vendor":
|
||||||
|
if e.complexity.AssessVendorPayload.Vendor == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.AssessVendorPayload.Vendor(childComplexity), true
|
||||||
|
|
||||||
case "AssignTaskPayload.task":
|
case "AssignTaskPayload.task":
|
||||||
if e.complexity.AssignTaskPayload.Task == nil {
|
if e.complexity.AssignTaskPayload.Task == nil {
|
||||||
break
|
break
|
||||||
@@ -1724,6 +1737,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.MeasureEdge.Node(childComplexity), true
|
return e.complexity.MeasureEdge.Node(childComplexity), true
|
||||||
|
|
||||||
|
case "Mutation.assessVendor":
|
||||||
|
if e.complexity.Mutation.AssessVendor == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
args, err := ec.field_Mutation_assessVendor_args(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Mutation.AssessVendor(childComplexity, args["input"].(types.AssessVendorInput)), true
|
||||||
|
|
||||||
case "Mutation.assignTask":
|
case "Mutation.assignTask":
|
||||||
if e.complexity.Mutation.AssignTask == nil {
|
if e.complexity.Mutation.AssignTask == nil {
|
||||||
break
|
break
|
||||||
@@ -3889,6 +3914,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
|||||||
opCtx := graphql.GetOperationContext(ctx)
|
opCtx := graphql.GetOperationContext(ctx)
|
||||||
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
|
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
|
||||||
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
|
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
|
||||||
|
ec.unmarshalInputAssessVendorInput,
|
||||||
ec.unmarshalInputAssignTaskInput,
|
ec.unmarshalInputAssignTaskInput,
|
||||||
ec.unmarshalInputConfirmEmailInput,
|
ec.unmarshalInputConfirmEmailInput,
|
||||||
ec.unmarshalInputConnectorOrder,
|
ec.unmarshalInputConnectorOrder,
|
||||||
@@ -5147,6 +5173,8 @@ type Mutation {
|
|||||||
): CreateVendorRiskAssessmentPayload!
|
): CreateVendorRiskAssessmentPayload!
|
||||||
|
|
||||||
exportAudit(input: ExportAuditInput!): ExportAuditPayload!
|
exportAudit(input: ExportAuditInput!): ExportAuditPayload!
|
||||||
|
|
||||||
|
assessVendor(input: AssessVendorInput!): AssessVendorPayload!
|
||||||
}
|
}
|
||||||
|
|
||||||
# Input Types
|
# Input Types
|
||||||
@@ -5838,6 +5866,15 @@ input ExportAuditInput {
|
|||||||
type ExportAuditPayload {
|
type ExportAuditPayload {
|
||||||
url: String!
|
url: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input AssessVendorInput {
|
||||||
|
id: ID!
|
||||||
|
websiteUrl: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssessVendorPayload {
|
||||||
|
vendor: Vendor!
|
||||||
|
}
|
||||||
`, BuiltIn: false},
|
`, BuiltIn: false},
|
||||||
}
|
}
|
||||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||||
@@ -6511,6 +6548,29 @@ func (ec *executionContext) field_Measure_tasks_argsOrderBy(
|
|||||||
return zeroVal, nil
|
return zeroVal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) field_Mutation_assessVendor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||||
|
var err error
|
||||||
|
args := map[string]any{}
|
||||||
|
arg0, err := ec.field_Mutation_assessVendor_argsInput(ctx, rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
args["input"] = arg0
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
func (ec *executionContext) field_Mutation_assessVendor_argsInput(
|
||||||
|
ctx context.Context,
|
||||||
|
rawArgs map[string]any,
|
||||||
|
) (types.AssessVendorInput, error) {
|
||||||
|
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
|
||||||
|
if tmp, ok := rawArgs["input"]; ok {
|
||||||
|
return ec.unmarshalNAssessVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssessVendorInput(ctx, tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
var zeroVal types.AssessVendorInput
|
||||||
|
return zeroVal, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_assignTask_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
func (ec *executionContext) field_Mutation_assignTask_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]any{}
|
args := map[string]any{}
|
||||||
@@ -9699,6 +9759,94 @@ func (ec *executionContext) field___Type_fields_argsIncludeDeprecated(
|
|||||||
|
|
||||||
// region **************************** field.gotpl *****************************
|
// region **************************** field.gotpl *****************************
|
||||||
|
|
||||||
|
func (ec *executionContext) _AssessVendorPayload_vendor(ctx context.Context, field graphql.CollectedField, obj *types.AssessVendorPayload) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_AssessVendorPayload_vendor(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.Vendor, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*types.Vendor)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNVendor2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendor(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_AssessVendorPayload_vendor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "AssessVendorPayload",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
switch field.Name {
|
||||||
|
case "id":
|
||||||
|
return ec.fieldContext_Vendor_id(ctx, field)
|
||||||
|
case "name":
|
||||||
|
return ec.fieldContext_Vendor_name(ctx, field)
|
||||||
|
case "description":
|
||||||
|
return ec.fieldContext_Vendor_description(ctx, field)
|
||||||
|
case "organization":
|
||||||
|
return ec.fieldContext_Vendor_organization(ctx, field)
|
||||||
|
case "complianceReports":
|
||||||
|
return ec.fieldContext_Vendor_complianceReports(ctx, field)
|
||||||
|
case "riskAssessments":
|
||||||
|
return ec.fieldContext_Vendor_riskAssessments(ctx, field)
|
||||||
|
case "businessOwner":
|
||||||
|
return ec.fieldContext_Vendor_businessOwner(ctx, field)
|
||||||
|
case "securityOwner":
|
||||||
|
return ec.fieldContext_Vendor_securityOwner(ctx, field)
|
||||||
|
case "statusPageUrl":
|
||||||
|
return ec.fieldContext_Vendor_statusPageUrl(ctx, field)
|
||||||
|
case "termsOfServiceUrl":
|
||||||
|
return ec.fieldContext_Vendor_termsOfServiceUrl(ctx, field)
|
||||||
|
case "privacyPolicyUrl":
|
||||||
|
return ec.fieldContext_Vendor_privacyPolicyUrl(ctx, field)
|
||||||
|
case "serviceLevelAgreementUrl":
|
||||||
|
return ec.fieldContext_Vendor_serviceLevelAgreementUrl(ctx, field)
|
||||||
|
case "dataProcessingAgreementUrl":
|
||||||
|
return ec.fieldContext_Vendor_dataProcessingAgreementUrl(ctx, field)
|
||||||
|
case "certifications":
|
||||||
|
return ec.fieldContext_Vendor_certifications(ctx, field)
|
||||||
|
case "securityPageUrl":
|
||||||
|
return ec.fieldContext_Vendor_securityPageUrl(ctx, field)
|
||||||
|
case "trustPageUrl":
|
||||||
|
return ec.fieldContext_Vendor_trustPageUrl(ctx, field)
|
||||||
|
case "headquarterAddress":
|
||||||
|
return ec.fieldContext_Vendor_headquarterAddress(ctx, field)
|
||||||
|
case "legalName":
|
||||||
|
return ec.fieldContext_Vendor_legalName(ctx, field)
|
||||||
|
case "websiteUrl":
|
||||||
|
return ec.fieldContext_Vendor_websiteUrl(ctx, field)
|
||||||
|
case "createdAt":
|
||||||
|
return ec.fieldContext_Vendor_createdAt(ctx, field)
|
||||||
|
case "updatedAt":
|
||||||
|
return ec.fieldContext_Vendor_updatedAt(ctx, field)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no field named %q was found under type Vendor", field.Name)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _AssignTaskPayload_task(ctx context.Context, field graphql.CollectedField, obj *types.AssignTaskPayload) (ret graphql.Marshaler) {
|
func (ec *executionContext) _AssignTaskPayload_task(ctx context.Context, field graphql.CollectedField, obj *types.AssignTaskPayload) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_AssignTaskPayload_task(ctx, field)
|
fc, err := ec.fieldContext_AssignTaskPayload_task(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -18173,6 +18321,65 @@ func (ec *executionContext) fieldContext_Mutation_exportAudit(ctx context.Contex
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Mutation_assessVendor(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Mutation_assessVendor(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 ec.resolvers.Mutation().AssessVendor(rctx, fc.Args["input"].(types.AssessVendorInput))
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(*types.AssessVendorPayload)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNAssessVendorPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssessVendorPayload(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Mutation_assessVendor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Mutation",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: true,
|
||||||
|
IsResolver: true,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
switch field.Name {
|
||||||
|
case "vendor":
|
||||||
|
return ec.fieldContext_AssessVendorPayload_vendor(ctx, field)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no field named %q was found under type AssessVendorPayload", field.Name)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
err = ec.Recover(ctx, r)
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
if fc.Args, err = ec.field_Mutation_assessVendor_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return fc, err
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Organization_id(ctx context.Context, field graphql.CollectedField, obj *types.Organization) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Organization_id(ctx context.Context, field graphql.CollectedField, obj *types.Organization) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Organization_id(ctx, field)
|
fc, err := ec.fieldContext_Organization_id(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -30810,6 +31017,40 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field
|
|||||||
|
|
||||||
// region **************************** input.gotpl *****************************
|
// region **************************** input.gotpl *****************************
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalInputAssessVendorInput(ctx context.Context, obj any) (types.AssessVendorInput, error) {
|
||||||
|
var it types.AssessVendorInput
|
||||||
|
asMap := map[string]any{}
|
||||||
|
for k, v := range obj.(map[string]any) {
|
||||||
|
asMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsInOrder := [...]string{"id", "websiteUrl"}
|
||||||
|
for _, k := range fieldsInOrder {
|
||||||
|
v, ok := asMap[k]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
case "id":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id"))
|
||||||
|
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.ID = data
|
||||||
|
case "websiteUrl":
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("websiteUrl"))
|
||||||
|
data, err := ec.unmarshalNString2string(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.WebsiteURL = data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputAssignTaskInput(ctx context.Context, obj any) (types.AssignTaskInput, error) {
|
func (ec *executionContext) unmarshalInputAssignTaskInput(ctx context.Context, obj any) (types.AssignTaskInput, error) {
|
||||||
var it types.AssignTaskInput
|
var it types.AssignTaskInput
|
||||||
asMap := map[string]any{}
|
asMap := map[string]any{}
|
||||||
@@ -33899,6 +34140,45 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj
|
|||||||
|
|
||||||
// region **************************** object.gotpl ****************************
|
// region **************************** object.gotpl ****************************
|
||||||
|
|
||||||
|
var assessVendorPayloadImplementors = []string{"AssessVendorPayload"}
|
||||||
|
|
||||||
|
func (ec *executionContext) _AssessVendorPayload(ctx context.Context, sel ast.SelectionSet, obj *types.AssessVendorPayload) graphql.Marshaler {
|
||||||
|
fields := graphql.CollectFields(ec.OperationContext, sel, assessVendorPayloadImplementors)
|
||||||
|
|
||||||
|
out := graphql.NewFieldSet(fields)
|
||||||
|
deferred := make(map[string]*graphql.FieldSet)
|
||||||
|
for i, field := range fields {
|
||||||
|
switch field.Name {
|
||||||
|
case "__typename":
|
||||||
|
out.Values[i] = graphql.MarshalString("AssessVendorPayload")
|
||||||
|
case "vendor":
|
||||||
|
out.Values[i] = ec._AssessVendorPayload_vendor(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Dispatch(ctx)
|
||||||
|
if out.Invalids > 0 {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
||||||
|
|
||||||
|
for label, dfs := range deferred {
|
||||||
|
ec.processDeferredGroup(graphql.DeferredGroup{
|
||||||
|
Label: label,
|
||||||
|
Path: graphql.GetPath(ctx),
|
||||||
|
FieldSet: dfs,
|
||||||
|
Context: ctx,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
var assignTaskPayloadImplementors = []string{"AssignTaskPayload"}
|
var assignTaskPayloadImplementors = []string{"AssignTaskPayload"}
|
||||||
|
|
||||||
func (ec *executionContext) _AssignTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *types.AssignTaskPayload) graphql.Marshaler {
|
func (ec *executionContext) _AssignTaskPayload(ctx context.Context, sel ast.SelectionSet, obj *types.AssignTaskPayload) graphql.Marshaler {
|
||||||
@@ -36929,6 +37209,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
out.Invalids++
|
out.Invalids++
|
||||||
}
|
}
|
||||||
|
case "assessVendor":
|
||||||
|
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||||
|
return ec._Mutation_assessVendor(ctx, field)
|
||||||
|
})
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
panic("unknown field " + strconv.Quote(field.Name))
|
||||||
}
|
}
|
||||||
@@ -41377,6 +41664,25 @@ func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, o
|
|||||||
|
|
||||||
// region ***************************** type.gotpl *****************************
|
// region ***************************** type.gotpl *****************************
|
||||||
|
|
||||||
|
func (ec *executionContext) unmarshalNAssessVendorInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssessVendorInput(ctx context.Context, v any) (types.AssessVendorInput, error) {
|
||||||
|
res, err := ec.unmarshalInputAssessVendorInput(ctx, v)
|
||||||
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNAssessVendorPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssessVendorPayload(ctx context.Context, sel ast.SelectionSet, v types.AssessVendorPayload) graphql.Marshaler {
|
||||||
|
return ec._AssessVendorPayload(ctx, sel, &v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) marshalNAssessVendorPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssessVendorPayload(ctx context.Context, sel ast.SelectionSet, v *types.AssessVendorPayload) graphql.Marshaler {
|
||||||
|
if v == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
return ec._AssessVendorPayload(ctx, sel, v)
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNAssignTaskInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskInput(ctx context.Context, v any) (types.AssignTaskInput, error) {
|
func (ec *executionContext) unmarshalNAssignTaskInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐAssignTaskInput(ctx context.Context, v any) (types.AssignTaskInput, error) {
|
||||||
res, err := ec.unmarshalInputAssignTaskInput(ctx, v)
|
res, err := ec.unmarshalInputAssignTaskInput(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
|
|||||||
@@ -20,6 +20,15 @@ type Node interface {
|
|||||||
GetID() gid.GID
|
GetID() gid.GID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AssessVendorInput struct {
|
||||||
|
ID gid.GID `json:"id"`
|
||||||
|
WebsiteURL string `json:"websiteUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssessVendorPayload struct {
|
||||||
|
Vendor *Vendor `json:"vendor"`
|
||||||
|
}
|
||||||
|
|
||||||
type AssignTaskInput struct {
|
type AssignTaskInput struct {
|
||||||
TaskID gid.GID `json:"taskId"`
|
TaskID gid.GID `json:"taskId"`
|
||||||
AssignedToID gid.GID `json:"assignedToId"`
|
AssignedToID gid.GID `json:"assignedToId"`
|
||||||
|
|||||||
@@ -1316,6 +1316,23 @@ func (r *mutationResolver) ExportAudit(ctx context.Context, input types.ExportAu
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssessVendor is the resolver for the assessVendor field.
|
||||||
|
func (r *mutationResolver) AssessVendor(ctx context.Context, input types.AssessVendorInput) (*types.AssessVendorPayload, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, input.ID.TenantID())
|
||||||
|
|
||||||
|
vendor, err := svc.Vendors.Assess(ctx, probo.AssessVendorRequest{
|
||||||
|
ID: input.ID,
|
||||||
|
WebsiteURL: input.WebsiteURL,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot assess vendor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.AssessVendorPayload{
|
||||||
|
Vendor: types.NewVendor(vendor),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// LogoURL is the resolver for the logoUrl field.
|
// LogoURL is the resolver for the logoUrl field.
|
||||||
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/getprobo/probo/pkg/agents"
|
||||||
"github.com/getprobo/probo/pkg/connector"
|
"github.com/getprobo/probo/pkg/connector"
|
||||||
"github.com/getprobo/probo/pkg/probo"
|
"github.com/getprobo/probo/pkg/probo"
|
||||||
"github.com/getprobo/probo/pkg/saferedirect"
|
"github.com/getprobo/probo/pkg/saferedirect"
|
||||||
@@ -37,6 +38,7 @@ type Config struct {
|
|||||||
Usrmgr *usrmgr.Service
|
Usrmgr *usrmgr.Service
|
||||||
Auth console_v1.AuthConfig
|
Auth console_v1.AuthConfig
|
||||||
ConnectorRegistry *connector.ConnectorRegistry
|
ConnectorRegistry *connector.ConnectorRegistry
|
||||||
|
VendorAssessment *agents.VendorAssessment
|
||||||
SafeRedirect *saferedirect.SafeRedirect
|
SafeRedirect *saferedirect.SafeRedirect
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user