Fetch vendor data with openai
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
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"
|
||||
|
||||
"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/crypto/cipher"
|
||||
"github.com/getprobo/probo/pkg/filevalidation"
|
||||
@@ -28,12 +29,13 @@ import (
|
||||
|
||||
type (
|
||||
Service struct {
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
hostname string
|
||||
tokenSecret string
|
||||
pg *pg.Client
|
||||
s3 *s3.Client
|
||||
bucket string
|
||||
encryptionKey cipher.EncryptionKey
|
||||
hostname string
|
||||
tokenSecret string
|
||||
vendorAssessment agents.Config
|
||||
}
|
||||
|
||||
TenantService struct {
|
||||
@@ -44,6 +46,7 @@ type (
|
||||
scope coredata.Scoper
|
||||
hostname string
|
||||
tokenSecret string
|
||||
vendorAssessment *agents.VendorAssessment
|
||||
Frameworks *FrameworkService
|
||||
Measures *MeasureService
|
||||
Tasks *TaskService
|
||||
@@ -67,18 +70,20 @@ func NewService(
|
||||
bucket string,
|
||||
hostname string,
|
||||
tokenSecret string,
|
||||
vendorAssessment agents.Config,
|
||||
) (*Service, error) {
|
||||
if bucket == "" {
|
||||
return nil, fmt.Errorf("bucket is required")
|
||||
}
|
||||
|
||||
svc := &Service{
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
hostname: hostname,
|
||||
tokenSecret: tokenSecret,
|
||||
pg: pgClient,
|
||||
s3: s3Client,
|
||||
bucket: bucket,
|
||||
encryptionKey: encryptionKey,
|
||||
hostname: hostname,
|
||||
tokenSecret: tokenSecret,
|
||||
vendorAssessment: vendorAssessment,
|
||||
}
|
||||
|
||||
return svc, nil
|
||||
@@ -86,13 +91,14 @@ func NewService(
|
||||
|
||||
func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService {
|
||||
tenantService := &TenantService{
|
||||
pg: s.pg,
|
||||
s3: s.s3,
|
||||
bucket: s.bucket,
|
||||
encryptionKey: s.encryptionKey,
|
||||
hostname: s.hostname,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
tokenSecret: s.tokenSecret,
|
||||
pg: s.pg,
|
||||
s3: s.s3,
|
||||
bucket: s.bucket,
|
||||
encryptionKey: s.encryptionKey,
|
||||
hostname: s.hostname,
|
||||
scope: coredata.NewScope(tenantID),
|
||||
tokenSecret: s.tokenSecret,
|
||||
vendorAssessment: agents.NewVendorAssessment(nil, s.vendorAssessment),
|
||||
}
|
||||
|
||||
tenantService.Frameworks = &FrameworkService{svc: tenantService}
|
||||
|
||||
@@ -70,6 +70,11 @@ type (
|
||||
SecurityOwnerID *gid.GID
|
||||
}
|
||||
|
||||
AssessVendorRequest struct {
|
||||
ID gid.GID
|
||||
WebsiteURL string
|
||||
}
|
||||
|
||||
CreateVendorRiskAssessmentRequest struct {
|
||||
VendorID gid.GID
|
||||
AssessedByID gid.GID
|
||||
@@ -421,3 +426,34 @@ func (s VendorService) GetRiskAssessment(
|
||||
|
||||
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"
|
||||
|
||||
"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/connector"
|
||||
"github.com/getprobo/probo/pkg/coredata"
|
||||
@@ -59,6 +60,7 @@ type (
|
||||
AWS awsConfig `json:"aws"`
|
||||
Mailer mailerConfig `json:"mailer"`
|
||||
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(
|
||||
ctx,
|
||||
pgClient,
|
||||
@@ -205,6 +215,7 @@ func (impl *Implm) Run(
|
||||
impl.cfg.AWS.Bucket,
|
||||
impl.cfg.Hostname,
|
||||
impl.cfg.Auth.Cookie.Secret,
|
||||
vendorAssessmentConfig,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create probo service: %w", err)
|
||||
@@ -216,6 +227,7 @@ func (impl *Implm) Run(
|
||||
Probo: proboService,
|
||||
Usrmgr: usrmgrService,
|
||||
ConnectorRegistry: defaultConnectorRegistry,
|
||||
VendorAssessment: vendorAssessment,
|
||||
SafeRedirect: &saferedirect.SafeRedirect{AllowedHost: impl.cfg.Hostname},
|
||||
Logger: l.Named("http.server"),
|
||||
Auth: console_v1.AuthConfig{
|
||||
|
||||
@@ -1088,6 +1088,8 @@ type Mutation {
|
||||
): CreateVendorRiskAssessmentPayload!
|
||||
|
||||
exportAudit(input: ExportAuditInput!): ExportAuditPayload!
|
||||
|
||||
assessVendor(input: AssessVendorInput!): AssessVendorPayload!
|
||||
}
|
||||
|
||||
# Input Types
|
||||
@@ -1779,3 +1781,12 @@ input ExportAuditInput {
|
||||
type ExportAuditPayload {
|
||||
url: String!
|
||||
}
|
||||
|
||||
input AssessVendorInput {
|
||||
id: ID!
|
||||
websiteUrl: String!
|
||||
}
|
||||
|
||||
type AssessVendorPayload {
|
||||
vendor: Vendor!
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ type DirectiveRoot struct {
|
||||
}
|
||||
|
||||
type ComplexityRoot struct {
|
||||
AssessVendorPayload struct {
|
||||
Vendor func(childComplexity int) int
|
||||
}
|
||||
|
||||
AssignTaskPayload struct {
|
||||
Task func(childComplexity int) int
|
||||
}
|
||||
@@ -329,6 +333,7 @@ type ComplexityRoot struct {
|
||||
}
|
||||
|
||||
Mutation struct {
|
||||
AssessVendor func(childComplexity int, input types.AssessVendorInput) int
|
||||
AssignTask func(childComplexity int, input types.AssignTaskInput) int
|
||||
ConfirmEmail func(childComplexity int, input types.ConfirmEmailInput) 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)
|
||||
CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error)
|
||||
ExportAudit(ctx context.Context, input types.ExportAuditInput) (*types.ExportAuditPayload, error)
|
||||
AssessVendor(ctx context.Context, input types.AssessVendorInput) (*types.AssessVendorPayload, error)
|
||||
}
|
||||
type OrganizationResolver interface {
|
||||
LogoURL(ctx context.Context, obj *types.Organization) (*string, error)
|
||||
@@ -919,6 +925,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
_ = ec
|
||||
switch typeName + "." + field {
|
||||
|
||||
case "AssessVendorPayload.vendor":
|
||||
if e.complexity.AssessVendorPayload.Vendor == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.AssessVendorPayload.Vendor(childComplexity), true
|
||||
|
||||
case "AssignTaskPayload.task":
|
||||
if e.complexity.AssignTaskPayload.Task == nil {
|
||||
break
|
||||
@@ -1724,6 +1737,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
||||
|
||||
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":
|
||||
if e.complexity.Mutation.AssignTask == nil {
|
||||
break
|
||||
@@ -3889,6 +3914,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
opCtx := graphql.GetOperationContext(ctx)
|
||||
ec := executionContext{opCtx, e, 0, 0, make(chan graphql.DeferredResult)}
|
||||
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
|
||||
ec.unmarshalInputAssessVendorInput,
|
||||
ec.unmarshalInputAssignTaskInput,
|
||||
ec.unmarshalInputConfirmEmailInput,
|
||||
ec.unmarshalInputConnectorOrder,
|
||||
@@ -5147,6 +5173,8 @@ type Mutation {
|
||||
): CreateVendorRiskAssessmentPayload!
|
||||
|
||||
exportAudit(input: ExportAuditInput!): ExportAuditPayload!
|
||||
|
||||
assessVendor(input: AssessVendorInput!): AssessVendorPayload!
|
||||
}
|
||||
|
||||
# Input Types
|
||||
@@ -5838,6 +5866,15 @@ input ExportAuditInput {
|
||||
type ExportAuditPayload {
|
||||
url: String!
|
||||
}
|
||||
|
||||
input AssessVendorInput {
|
||||
id: ID!
|
||||
websiteUrl: String!
|
||||
}
|
||||
|
||||
type AssessVendorPayload {
|
||||
vendor: Vendor!
|
||||
}
|
||||
`, BuiltIn: false},
|
||||
}
|
||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
@@ -6511,6 +6548,29 @@ func (ec *executionContext) field_Measure_tasks_argsOrderBy(
|
||||
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) {
|
||||
var err error
|
||||
args := map[string]any{}
|
||||
@@ -9699,6 +9759,94 @@ func (ec *executionContext) field___Type_fields_argsIncludeDeprecated(
|
||||
|
||||
// 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) {
|
||||
fc, err := ec.fieldContext_AssignTaskPayload_task(ctx, field)
|
||||
if err != nil {
|
||||
@@ -18173,6 +18321,65 @@ func (ec *executionContext) fieldContext_Mutation_exportAudit(ctx context.Contex
|
||||
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) {
|
||||
fc, err := ec.fieldContext_Organization_id(ctx, field)
|
||||
if err != nil {
|
||||
@@ -30810,6 +31017,40 @@ func (ec *executionContext) fieldContext___Type_isOneOf(_ context.Context, field
|
||||
|
||||
// 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) {
|
||||
var it types.AssignTaskInput
|
||||
asMap := map[string]any{}
|
||||
@@ -33899,6 +34140,45 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj
|
||||
|
||||
// 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"}
|
||||
|
||||
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 {
|
||||
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:
|
||||
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 *****************************
|
||||
|
||||
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) {
|
||||
res, err := ec.unmarshalInputAssignTaskInput(ctx, v)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
|
||||
@@ -20,6 +20,15 @@ type Node interface {
|
||||
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 {
|
||||
TaskID gid.GID `json:"taskId"`
|
||||
AssignedToID gid.GID `json:"assignedToId"`
|
||||
|
||||
@@ -1316,6 +1316,23 @@ func (r *mutationResolver) ExportAudit(ctx context.Context, input types.ExportAu
|
||||
}, 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.
|
||||
func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) {
|
||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/getprobo/probo/pkg/agents"
|
||||
"github.com/getprobo/probo/pkg/connector"
|
||||
"github.com/getprobo/probo/pkg/probo"
|
||||
"github.com/getprobo/probo/pkg/saferedirect"
|
||||
@@ -37,6 +38,7 @@ type Config struct {
|
||||
Usrmgr *usrmgr.Service
|
||||
Auth console_v1.AuthConfig
|
||||
ConnectorRegistry *connector.ConnectorRegistry
|
||||
VendorAssessment *agents.VendorAssessment
|
||||
SafeRedirect *saferedirect.SafeRedirect
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user