From f038642ece25d21baa223fa855461a16b25accc8 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Mon, 21 Apr 2025 12:49:58 -0700 Subject: [PATCH] Add first risk assememnt implementation Signed-off-by: Bryan Frimin --- pkg/coredata/business_impact.go | 60 + pkg/coredata/data_sensitivity.go | 62 + pkg/coredata/entity_type_reg.go | 2 +- pkg/coredata/migrations/20240421T032700Z.sql | 1 + pkg/coredata/migrations/20250420T120000Z.sql | 305 +++ pkg/coredata/migrations/20250420T120001Z.sql | 3 + pkg/coredata/migrations/20250421T032000Z.sql | 1 + pkg/coredata/people.go | 88 +- pkg/coredata/risk_tier.go | 66 - pkg/coredata/service_criticality.go | 66 - pkg/coredata/vendor.go | 75 +- pkg/coredata/vendor_risk_assessment.go | 299 +++ .../vendor_risk_assessment_order_field.go | 41 + pkg/probo/organization_service.go | 4 +- pkg/probo/people_service.go | 41 +- pkg/probo/vendor_service.go | 85 +- pkg/server/api/console/v1/schema.graphql | 123 +- pkg/server/api/console/v1/schema/schema.go | 2244 ++++++++++++++--- pkg/server/api/console/v1/types/types.go | 129 +- pkg/server/api/console/v1/types/vendor.go | 2 - .../v1/types/vendor_risk_assessment.go | 57 + pkg/server/api/console/v1/v1_resolver.go | 68 +- 22 files changed, 3168 insertions(+), 654 deletions(-) create mode 100644 pkg/coredata/business_impact.go create mode 100644 pkg/coredata/data_sensitivity.go create mode 100644 pkg/coredata/migrations/20240421T032700Z.sql create mode 100644 pkg/coredata/migrations/20250420T120000Z.sql create mode 100644 pkg/coredata/migrations/20250420T120001Z.sql create mode 100644 pkg/coredata/migrations/20250421T032000Z.sql delete mode 100644 pkg/coredata/risk_tier.go delete mode 100644 pkg/coredata/service_criticality.go create mode 100644 pkg/coredata/vendor_risk_assessment.go create mode 100644 pkg/coredata/vendor_risk_assessment_order_field.go create mode 100644 pkg/server/api/console/v1/types/vendor_risk_assessment.go diff --git a/pkg/coredata/business_impact.go b/pkg/coredata/business_impact.go new file mode 100644 index 000000000..8449dd520 --- /dev/null +++ b/pkg/coredata/business_impact.go @@ -0,0 +1,60 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 coredata + +import ( + "database/sql/driver" + "fmt" +) + +func (bi BusinessImpact) MarshalText() ([]byte, error) { + return []byte(bi.String()), nil +} + +func (bi *BusinessImpact) UnmarshalText(data []byte) error { + val := string(data) + + switch val { + case BusinessImpactLow.String(): + *bi = BusinessImpactLow + case BusinessImpactMedium.String(): + *bi = BusinessImpactMedium + case BusinessImpactHigh.String(): + *bi = BusinessImpactHigh + case BusinessImpactCritical.String(): + *bi = BusinessImpactCritical + default: + return fmt.Errorf("invalid BusinessImpact value: %q", val) + } + + return nil +} + +func (bi BusinessImpact) String() string { + return string(bi) +} + +func (bi *BusinessImpact) Scan(value any) error { + val, ok := value.(string) + if !ok { + return fmt.Errorf("invalid scan source for BusinessImpact, expected string got %T", value) + } + + return bi.UnmarshalText([]byte(val)) +} + +func (bi BusinessImpact) Value() (driver.Value, error) { + return bi.String(), nil +} diff --git a/pkg/coredata/data_sensitivity.go b/pkg/coredata/data_sensitivity.go new file mode 100644 index 000000000..731bf039b --- /dev/null +++ b/pkg/coredata/data_sensitivity.go @@ -0,0 +1,62 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 coredata + +import ( + "database/sql/driver" + "fmt" +) + +func (ds DataSensitivity) MarshalText() ([]byte, error) { + return []byte(ds.String()), nil +} + +func (ds *DataSensitivity) UnmarshalText(data []byte) error { + val := string(data) + + switch val { + case DataSensitivityNone.String(): + *ds = DataSensitivityNone + case DataSensitivityLow.String(): + *ds = DataSensitivityLow + case DataSensitivityMedium.String(): + *ds = DataSensitivityMedium + case DataSensitivityHigh.String(): + *ds = DataSensitivityHigh + case DataSensitivityCritical.String(): + *ds = DataSensitivityCritical + default: + return fmt.Errorf("invalid DataSensitivity value: %q", val) + } + + return nil +} + +func (ds DataSensitivity) String() string { + return string(ds) +} + +func (ds *DataSensitivity) Scan(value any) error { + val, ok := value.(string) + if !ok { + return fmt.Errorf("invalid scan source for DataSensitivity, expected string got %T", value) + } + + return ds.UnmarshalText([]byte(val)) +} + +func (ds DataSensitivity) Value() (driver.Value, error) { + return ds.String(), nil +} diff --git a/pkg/coredata/entity_type_reg.go b/pkg/coredata/entity_type_reg.go index 722d97b4a..efcac77ad 100644 --- a/pkg/coredata/entity_type_reg.go +++ b/pkg/coredata/entity_type_reg.go @@ -21,7 +21,7 @@ const ( TaskEntityType EvidenceEntityType ConnectorEntityType - _TaskStateTransitionEntityType // UNUSED + VendorRiskAssessmentEntityType VendorEntityType PeopleEntityType VendorComplianceReportEntityType diff --git a/pkg/coredata/migrations/20240421T032700Z.sql b/pkg/coredata/migrations/20240421T032700Z.sql new file mode 100644 index 000000000..86580951a --- /dev/null +++ b/pkg/coredata/migrations/20240421T032700Z.sql @@ -0,0 +1 @@ +ALTER TABLE peoples DROP COLUMN version; diff --git a/pkg/coredata/migrations/20250420T120000Z.sql b/pkg/coredata/migrations/20250420T120000Z.sql new file mode 100644 index 000000000..fa833fd2a --- /dev/null +++ b/pkg/coredata/migrations/20250420T120000Z.sql @@ -0,0 +1,305 @@ +CREATE EXTENSION IF NOT EXISTS pgcrypto; + +-- PostgreSQL implementation of the GID generation system + +-- 1. First, create functions for TenantID generation +CREATE OR REPLACE FUNCTION generate_machine_id() +RETURNS bytea AS $func$ +DECLARE + machine_id bytea; +BEGIN + -- Generate 3 random bytes for machine ID + machine_id := decode(encode(gen_random_bytes(3), 'hex'), 'hex'); + RETURN machine_id; +END; +$func$ LANGUAGE plpgsql STABLE; + +-- Store machine ID as a database-wide setting (run once) +DO $block$ +BEGIN + -- Check if the setting exists + IF NOT EXISTS (SELECT 1 FROM pg_settings WHERE name = 'app.machine_id') THEN + -- Create custom parameter in postgresql.conf or via ALTER SYSTEM + PERFORM set_config('app.machine_id', encode(generate_machine_id(), 'hex'), false); + END IF; +END $block$; + +-- Counter for tenant ID generation (used atomically) +CREATE SEQUENCE IF NOT EXISTS tenant_id_counter_seq; + +-- Function to generate a TenantID +CREATE OR REPLACE FUNCTION generate_tenant_id() +RETURNS bytea AS $func$ +DECLARE + id bytea; + machine_id bytea; + timestamp_bytes bytea; + counter_bytes bytea; + counter_val int; +BEGIN + -- 1. Get machine ID (3 bytes) + machine_id := decode(current_setting('app.machine_id'), 'hex'); + + -- 2. Get timestamp bytes (3 bytes - Unix time in seconds) + timestamp_bytes := substring(int8send(extract(epoch from now())::bigint) from 6 for 3); + + -- 3. Get counter (2 bytes) + counter_val := nextval('tenant_id_counter_seq') % 65536; -- 2^16 + counter_bytes := substring(int4send(counter_val) from 3 for 2); + + -- 4. Combine all parts + id := machine_id || timestamp_bytes || counter_bytes; + + RETURN id; +END; +$func$ LANGUAGE plpgsql VOLATILE; + +-- Function to convert TenantID to string +CREATE OR REPLACE FUNCTION tenant_id_to_string(tenant_id bytea) +RETURNS text AS $func$ +BEGIN + -- Make sure to handle padding properly - remove trailing '=' characters + RETURN rtrim(translate(encode(tenant_id, 'base64'), '+/', '-_'), '='); +END; +$func$ LANGUAGE plpgsql IMMUTABLE; + +-- Function to parse tenant ID from string +CREATE OR REPLACE FUNCTION parse_tenant_id(encoded text) +RETURNS bytea AS $func$ +DECLARE + decoded bytea; + padded_input text; + padding_needed int; +BEGIN + -- Add proper padding for base64 decoding + padding_needed := (4 - (length(encoded) % 4)) % 4; + padded_input := encoded || repeat('=', padding_needed); + + -- Replace URL-safe chars and decode + BEGIN + decoded := decode(translate(padded_input, '-_', '+/'), 'base64'); + EXCEPTION WHEN OTHERS THEN + RAISE EXCEPTION 'Invalid base64 encoding in tenant ID'; + END; + + -- Validate length + IF octet_length(decoded) != 8 THEN + RAISE EXCEPTION 'Invalid tenant ID length: got %, want 8', octet_length(decoded); + END IF; + + RETURN decoded; +END; +$func$ LANGUAGE plpgsql IMMUTABLE; + +-- 2. Now create functions for full GID generation + +-- Function to generate a GID +CREATE OR REPLACE FUNCTION generate_gid(tenant_id bytea, entity_type int) +RETURNS bytea AS $func$ +DECLARE + id bytea; + timestamp_ms_bytes bytea; + entity_type_bytes bytea; + random_bytes bytea; +BEGIN + -- Validate tenant_id + IF tenant_id IS NULL OR octet_length(tenant_id) != 8 THEN + RAISE EXCEPTION 'Invalid tenant ID: must be 8 bytes'; + END IF; + + -- 1. Start with tenant ID (8 bytes) + id := tenant_id; + + -- 2. Add entity type (2 bytes) + entity_type_bytes := substring(int4send(entity_type) from 3 for 2); + id := id || entity_type_bytes; + + -- 3. Add timestamp in milliseconds (8 bytes) + -- Extract milliseconds since epoch + timestamp_ms_bytes := int8send( + (extract(epoch from now()) * 1000)::bigint + ); + id := id || timestamp_ms_bytes; + + -- 4. Add random bytes for uniqueness (6 bytes) + random_bytes := gen_random_bytes(6); + id := id || random_bytes; + + RETURN id; +END; +$func$ LANGUAGE plpgsql VOLATILE; + +-- Note: removed the single-parameter overload - tenant_id must be explicitly provided + +-- Function to convert GID to string +CREATE OR REPLACE FUNCTION gid_to_string(gid bytea) +RETURNS text AS $func$ +BEGIN + -- Make sure to handle padding properly - remove trailing '=' characters + RETURN rtrim(translate(encode(gid, 'base64'), '+/', '-_'), '='); +END; +$func$ LANGUAGE plpgsql IMMUTABLE; + +-- Function to parse GID from string +CREATE OR REPLACE FUNCTION parse_gid(encoded text) +RETURNS bytea AS $func$ +DECLARE + decoded bytea; + padded_input text; + padding_needed int; +BEGIN + -- Add proper padding for base64 decoding + padding_needed := (4 - (length(encoded) % 4)) % 4; + padded_input := encoded || repeat('=', padding_needed); + + -- Replace URL-safe chars and decode + BEGIN + decoded := decode(translate(padded_input, '-_', '+/'), 'base64'); + EXCEPTION WHEN OTHERS THEN + RAISE EXCEPTION 'Invalid base64 encoding in GID'; + END; + + -- Validate length + IF octet_length(decoded) != 24 THEN + RAISE EXCEPTION 'Invalid GID length: got %, want 24', octet_length(decoded); + END IF; + + RETURN decoded; +END; +$func$ LANGUAGE plpgsql IMMUTABLE; + +-- Extract tenant ID from GID +CREATE OR REPLACE FUNCTION extract_tenant_id(gid bytea) +RETURNS bytea AS $func$ +BEGIN + RETURN substring(gid from 1 for 8); +END; +$func$ LANGUAGE plpgsql IMMUTABLE; + +-- Extract entity type from GID +CREATE OR REPLACE FUNCTION extract_entity_type(gid bytea) +RETURNS int AS $func$ +BEGIN + RETURN get_byte(gid, 8) * 256 + get_byte(gid, 9); +END; +$func$ LANGUAGE plpgsql IMMUTABLE; + +-- Extract timestamp from GID +CREATE OR REPLACE FUNCTION extract_timestamp(gid bytea) +RETURNS timestamp AS $func$ +DECLARE + ms bigint; +BEGIN + ms := (get_byte(gid, 10)::bigint << 56) | + (get_byte(gid, 11)::bigint << 48) | + (get_byte(gid, 12)::bigint << 40) | + (get_byte(gid, 13)::bigint << 32) | + (get_byte(gid, 14)::bigint << 24) | + (get_byte(gid, 15)::bigint << 16) | + (get_byte(gid, 16)::bigint << 8) | + get_byte(gid, 17)::bigint; + + RETURN to_timestamp(ms / 1000.0); +END; +$func$ LANGUAGE plpgsql IMMUTABLE; + +-- Example usage: +-- Generate a new GID for entity type 42 with a specific tenant ID +-- SELECT gid_to_string(generate_gid(generate_tenant_id(), 42)); + +-- Parse a GID from string +-- SELECT parse_gid('your-base64-encoded-gid-here'); + +-- Extract components +-- SELECT +-- gid_to_string(gid) as gid_string, +-- tenant_id_to_string(extract_tenant_id(gid)) as tenant_id, +-- extract_entity_type(gid) as entity_type, +-- extract_timestamp(gid) as created_at +-- FROM (SELECT generate_gid(generate_tenant_id(), 42) as gid) t; + +CREATE OR REPLACE FUNCTION decode_base64_unpadded(input_text text) +RETURNS bytea AS $$ +DECLARE + padded_text text; + mod_length integer; +BEGIN + -- Calculate how many padding characters we need to add + mod_length := length(input_text) % 4; + + -- Add the required padding + IF mod_length = 0 THEN + padded_text := input_text; + ELSIF mod_length = 1 THEN + -- Invalid base64 - length mod 4 can't be 1 + RAISE EXCEPTION 'Invalid base64 length'; + ELSIF mod_length = 2 THEN + padded_text := input_text || '=='; + ELSIF mod_length = 3 THEN + padded_text := input_text || '='; + END IF; + + -- Decode the padded base64 + RETURN decode(padded_text, 'base64'); +END; +$$ LANGUAGE plpgsql; + + + +CREATE TYPE data_sensitivity AS ENUM ('NONE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'); +CREATE TYPE business_impact AS ENUM ('LOW', 'MEDIUM', 'HIGH', 'CRITICAL'); + +CREATE TABLE risk_assessments ( + tenant_id TEXT NOT NULL, + id TEXT PRIMARY KEY, + vendor_id TEXT NOT NULL REFERENCES vendors(id) ON DELETE CASCADE, + accessed_at TIMESTAMP WITH TIME ZONE NOT NULL, + accessed_by TEXT NOT NULL REFERENCES peoples(id) ON DELETE SET NULL, + approved_at TIMESTAMP WITH TIME ZONE NOT NULL, + approved_by TEXT NOT NULL REFERENCES peoples(id) ON DELETE SET NULL, + expires_at TIMESTAMP WITH TIME ZONE NOT NULL, + data_sensitivity data_sensitivity NOT NULL, + business_impact business_impact NOT NULL, + notes TEXT, + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE NOT NULL +); + +ALTER TABLE peoples ADD COLUMN user_id TEXT NOT NULL REFERENCES users(id) ON DELETE SET NULL; + +UPDATE peoples p +SET user_id = u.id +FROM users u +WHERE u.email_address = p.primary_email_address; + +INSERT INTO peoples ( + tenant_id, + id, + organization_id, + full_name, + primary_email_address, + kind, + user_id, + additional_email_addresses, + created_at, + updated_at, + version +) +SELECT + o.tenant_id, + encode(generate_gid(decode_base64_unpadded(o.tenant_id), 8), 'base64'), + o.id, + u.fullname, + u.email_address, + 'CONTRACTOR', + u.id, + ARRAY[]::TEXT[], + NOW(), + NOW(), + 1 +FROM users u +JOIN users_organizations uo ON u.id = uo.user_id +JOIN organizations o ON uo.organization_id = o.id +LEFT JOIN peoples p ON u.email_address = p.primary_email_address +WHERE p.id IS NULL; + diff --git a/pkg/coredata/migrations/20250420T120001Z.sql b/pkg/coredata/migrations/20250420T120001Z.sql new file mode 100644 index 000000000..9f0b81913 --- /dev/null +++ b/pkg/coredata/migrations/20250420T120001Z.sql @@ -0,0 +1,3 @@ +ALTER TABLE vendors + DROP COLUMN service_criticality, + DROP COLUMN risk_tier; \ No newline at end of file diff --git a/pkg/coredata/migrations/20250421T032000Z.sql b/pkg/coredata/migrations/20250421T032000Z.sql new file mode 100644 index 000000000..1692b1a83 --- /dev/null +++ b/pkg/coredata/migrations/20250421T032000Z.sql @@ -0,0 +1 @@ +ALTER TABLE peoples ALTER COLUMN user_id DROP NOT NULL; \ No newline at end of file diff --git a/pkg/coredata/people.go b/pkg/coredata/people.go index fa7ed8294..9cd913e55 100644 --- a/pkg/coredata/people.go +++ b/pkg/coredata/people.go @@ -31,23 +31,15 @@ type ( ID gid.GID `db:"id"` OrganizationID gid.GID `db:"organization_id"` Kind PeopleKind `db:"kind"` + UserID *gid.GID `db:"user_id"` FullName string `db:"full_name"` PrimaryEmailAddress string `db:"primary_email_address"` AdditionalEmailAddresses []string `db:"additional_email_addresses"` CreatedAt time.Time `db:"created_at"` UpdatedAt time.Time `db:"updated_at"` - Version int `db:"version"` } Peoples []*People - - UpdatePeopleParams struct { - ExpectedVersion int - FullName *string - PrimaryEmailAddress *string - AdditionalEmailAddresses *[]string - Kind *PeopleKind - } ) func (p People) CursorKey(orderBy PeopleOrderField) page.CursorKey { @@ -72,12 +64,12 @@ SELECT id, organization_id, kind, + user_id, full_name, primary_email_address, additional_email_addresses, created_at, - updated_at, - version + updated_at FROM peoples WHERE @@ -117,25 +109,25 @@ INSERT INTO tenant_id, id, organization_id, + user_id, kind, full_name, primary_email_address, additional_email_addresses, created_at, - updated_at, - version + updated_at ) VALUES ( @tenant_id, @people_id, @organization_id, + @user_id, @kind, @full_name, @primary_email_address, @additional_email_addresses, @created_at, - @updated_at, - @version + @updated_at ) ` @@ -143,13 +135,13 @@ VALUES ( "tenant_id": scope.GetTenantID(), "people_id": p.ID, "organization_id": p.OrganizationID, + "user_id": p.UserID, "kind": p.Kind, "full_name": p.FullName, "primary_email_address": p.PrimaryEmailAddress, "additional_email_addresses": p.AdditionalEmailAddresses, "created_at": p.CreatedAt, "updated_at": p.UpdatedAt, - "version": p.Version, } _, err := conn.Exec(ctx, q, args) return err @@ -180,18 +172,17 @@ func (p *Peoples) LoadByOrganizationID( organizationID gid.GID, cursor *page.Cursor[PeopleOrderField], ) error { - // Base query q := ` SELECT id, organization_id, kind, + user_id, full_name, primary_email_address, additional_email_addresses, created_at, - updated_at, - version + updated_at FROM peoples WHERE @@ -225,64 +216,35 @@ func (p *People) Update( ctx context.Context, conn pg.Conn, scope Scoper, - params UpdatePeopleParams, ) error { q := ` UPDATE peoples SET - full_name = COALESCE(@full_name, full_name), - primary_email_address = COALESCE(@primary_email_address, primary_email_address), - additional_email_addresses = COALESCE(@additional_email_addresses, additional_email_addresses), - kind = COALESCE(@kind, kind), - updated_at = @updated_at, - version = version + 1 + user_id = @user_id, + full_name = @full_name, + primary_email_address = @primary_email_address, + additional_email_addresses = @additional_email_addresses, + kind = @kind, + updated_at = @updated_at WHERE %s AND id = @people_id - AND version = @expected_version -RETURNING - id, - organization_id, - kind, - full_name, - primary_email_address, - additional_email_addresses, - created_at, - updated_at, - version ` q = fmt.Sprintf(q, scope.SQLFragment()) args := pgx.StrictNamedArgs{ - "people_id": p.ID, - "expected_version": params.ExpectedVersion, - "updated_at": time.Now(), + "people_id": p.ID, + "user_id": p.UserID, + "full_name": p.FullName, + "primary_email_address": p.PrimaryEmailAddress, + "additional_email_addresses": p.AdditionalEmailAddresses, + "kind": p.Kind, + "updated_at": p.UpdatedAt, } - - if params.FullName != nil { - args["full_name"] = *params.FullName - } - if params.PrimaryEmailAddress != nil { - args["primary_email_address"] = *params.PrimaryEmailAddress - } - if params.AdditionalEmailAddresses != nil { - args["additional_email_addresses"] = *params.AdditionalEmailAddresses - } - if params.Kind != nil { - args["kind"] = *params.Kind - } - maps.Copy(args, scope.SQLArguments()) - rows, err := conn.Query(ctx, q, args) + _, err := conn.Exec(ctx, q, args) if err != nil { - return fmt.Errorf("cannot query people: %w", err) + return fmt.Errorf("cannot update people: %w", err) } - people, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[People]) - if err != nil { - return fmt.Errorf("cannot collect people: %w", err) - } - - *p = people - return nil } diff --git a/pkg/coredata/risk_tier.go b/pkg/coredata/risk_tier.go deleted file mode 100644 index 45c1a7b8e..000000000 --- a/pkg/coredata/risk_tier.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2025 Probo Inc . -// -// 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 coredata - -import ( - "database/sql/driver" - "fmt" -) - -type RiskTier string - -const ( - RiskTierCritical RiskTier = "CRITICAL" // Handles sensitive data, critical for platform operation - RiskTierSignificant RiskTier = "SIGNIFICANT" // No user data access, but important for platform management - RiskTierGeneral RiskTier = "GENERAL" // General vendor with minimal risk -) - -func (rt RiskTier) MarshalText() ([]byte, error) { - return []byte(rt.String()), nil -} - -func (rt *RiskTier) UnmarshalText(data []byte) error { - val := string(data) - - switch val { - case RiskTierCritical.String(): - *rt = RiskTierCritical - case RiskTierSignificant.String(): - *rt = RiskTierSignificant - case RiskTierGeneral.String(): - *rt = RiskTierGeneral - default: - return fmt.Errorf("invalid RiskTier value: %q", val) - } - - return nil -} - -func (rt RiskTier) String() string { - return string(rt) -} - -func (rt *RiskTier) Scan(value any) error { - val, ok := value.(string) - if !ok { - return fmt.Errorf("invalid scan source for RiskTier, expected string got %T", value) - } - - return rt.UnmarshalText([]byte(val)) -} - -func (rt RiskTier) Value() (driver.Value, error) { - return rt.String(), nil -} diff --git a/pkg/coredata/service_criticality.go b/pkg/coredata/service_criticality.go deleted file mode 100644 index b5b94aecb..000000000 --- a/pkg/coredata/service_criticality.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2025 Probo Inc . -// -// 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 coredata - -import ( - "database/sql/driver" - "fmt" -) - -type ServiceCriticality string - -const ( - ServiceCriticalityLow ServiceCriticality = "LOW" - ServiceCriticalityMedium ServiceCriticality = "MEDIUM" - ServiceCriticalityHigh ServiceCriticality = "HIGH" -) - -func (sc ServiceCriticality) MarshalText() ([]byte, error) { - return []byte(sc.String()), nil -} - -func (sc *ServiceCriticality) UnmarshalText(data []byte) error { - val := string(data) - - switch val { - case ServiceCriticalityLow.String(): - *sc = ServiceCriticalityLow - case ServiceCriticalityMedium.String(): - *sc = ServiceCriticalityMedium - case ServiceCriticalityHigh.String(): - *sc = ServiceCriticalityHigh - default: - return fmt.Errorf("invalid ServiceCriticality value: %q", val) - } - - return nil -} - -func (sc ServiceCriticality) String() string { - return string(sc) -} - -func (sc *ServiceCriticality) Scan(value any) error { - val, ok := value.(string) - if !ok { - return fmt.Errorf("invalid scan source for ServiceCriticality, expected string got %T", value) - } - - return sc.UnmarshalText([]byte(val)) -} - -func (sc ServiceCriticality) Value() (driver.Value, error) { - return sc.String(), nil -} diff --git a/pkg/coredata/vendor.go b/pkg/coredata/vendor.go index cf7192786..96ce189df 100644 --- a/pkg/coredata/vendor.go +++ b/pkg/coredata/vendor.go @@ -16,7 +16,6 @@ package coredata import ( "context" - "errors" "fmt" "maps" "time" @@ -27,34 +26,30 @@ import ( "go.gearno.de/kit/pg" ) -var ErrConcurrentModification = errors.New("concurrent modification") - type ( Vendor struct { - ID gid.GID `db:"id"` - OrganizationID gid.GID `db:"organization_id"` - Name string `db:"name"` - Description *string `db:"description"` - Category string `db:"category"` - ServiceStartAt time.Time `db:"service_start_at"` - ServiceTerminationAt *time.Time `db:"service_termination_at"` - HeadquarterAddress *string `db:"headquarter_address"` - LegalName *string `db:"legal_name"` - WebsiteURL *string `db:"website_url"` - PrivacyPolicyURL *string `db:"privacy_policy_url"` - ServiceLevelAgreementURL *string `db:"service_level_agreement_url"` - DataProcessingAgreementURL *string `db:"data_processing_agreement_url"` - Certifications []string `db:"certifications"` - ServiceCriticality ServiceCriticality `db:"service_criticality"` - RiskTier RiskTier `db:"risk_tier"` - BusinessOwnerID *gid.GID `db:"business_owner_id"` - SecurityOwnerID *gid.GID `db:"security_owner_id"` - StatusPageURL *string `db:"status_page_url"` - TermsOfServiceURL *string `db:"terms_of_service_url"` - SecurityPageURL *string `db:"security_page_url"` - TrustPageURL *string `db:"trust_page_url"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID gid.GID `db:"id"` + OrganizationID gid.GID `db:"organization_id"` + Name string `db:"name"` + Description *string `db:"description"` + Category string `db:"category"` + ServiceStartAt time.Time `db:"service_start_at"` + ServiceTerminationAt *time.Time `db:"service_termination_at"` + HeadquarterAddress *string `db:"headquarter_address"` + LegalName *string `db:"legal_name"` + WebsiteURL *string `db:"website_url"` + PrivacyPolicyURL *string `db:"privacy_policy_url"` + ServiceLevelAgreementURL *string `db:"service_level_agreement_url"` + DataProcessingAgreementURL *string `db:"data_processing_agreement_url"` + Certifications []string `db:"certifications"` + BusinessOwnerID *gid.GID `db:"business_owner_id"` + SecurityOwnerID *gid.GID `db:"security_owner_id"` + StatusPageURL *string `db:"status_page_url"` + TermsOfServiceURL *string `db:"terms_of_service_url"` + SecurityPageURL *string `db:"security_page_url"` + TrustPageURL *string `db:"trust_page_url"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } Vendors []*Vendor @@ -93,10 +88,8 @@ SELECT service_level_agreement_url, data_processing_agreement_url, certifications, - service_criticality, - risk_tier, - business_owner_id, - security_owner_id, + business_owner_id, + security_owner_id, status_page_url, terms_of_service_url, security_page_url, @@ -155,10 +148,8 @@ INSERT INTO certifications, service_start_at, service_termination_at, - service_criticality, - risk_tier, business_owner_id, - security_owner_id, + security_owner_id, status_page_url, terms_of_service_url, security_page_url, @@ -182,10 +173,8 @@ VALUES ( @certifications, @service_start_at, @service_termination_at, - @service_criticality, - @risk_tier, @business_owner_id, - @security_owner_id, + @security_owner_id, @status_page_url, @terms_of_service_url, @security_page_url, @@ -211,8 +200,6 @@ VALUES ( "certifications": v.Certifications, "service_start_at": v.ServiceStartAt, "service_termination_at": v.ServiceTerminationAt, - "service_criticality": v.ServiceCriticality, - "risk_tier": v.RiskTier, "business_owner_id": v.BusinessOwnerID, "security_owner_id": v.SecurityOwnerID, "status_page_url": v.StatusPageURL, @@ -267,10 +254,8 @@ SELECT certifications, service_start_at, service_termination_at, - service_criticality, - risk_tier, - business_owner_id, - security_owner_id, + business_owner_id, + security_owner_id, status_page_url, terms_of_service_url, security_page_url, @@ -317,8 +302,6 @@ SET description = @description, service_start_at = @service_start_at, service_termination_at = @service_termination_at, - service_criticality = @service_criticality, - risk_tier = @risk_tier, category = @category, headquarter_address = @headquarter_address, legal_name = @legal_name, @@ -346,8 +329,6 @@ WHERE %s "description": v.Description, "service_start_at": v.ServiceStartAt, "service_termination_at": v.ServiceTerminationAt, - "service_criticality": v.ServiceCriticality, - "risk_tier": v.RiskTier, "category": v.Category, "headquarter_address": v.HeadquarterAddress, "legal_name": v.LegalName, diff --git a/pkg/coredata/vendor_risk_assessment.go b/pkg/coredata/vendor_risk_assessment.go new file mode 100644 index 000000000..a8c6fe928 --- /dev/null +++ b/pkg/coredata/vendor_risk_assessment.go @@ -0,0 +1,299 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 coredata + +import ( + "context" + "fmt" + "maps" + "time" + + "github.com/getprobo/probo/pkg/gid" + "github.com/getprobo/probo/pkg/page" + "github.com/jackc/pgx/v5" + "go.gearno.de/kit/pg" +) + +type ( + // RiskAssessment represents a point-in-time risk assessment for a vendor + VendorRiskAssessment struct { + ID gid.GID `db:"id"` + VendorID gid.GID `db:"vendor_id"` + AssessedAt time.Time `db:"assessed_at"` + AssessedBy gid.GID `db:"assessed_by"` + AccessedAt time.Time `db:"accessed_at"` + ApprovedBy gid.GID `db:"approved_by"` + ApprovedAt time.Time `db:"approved_at"` + ExpiresAt time.Time `db:"expires_at"` + DataSensitivity DataSensitivity `db:"data_sensitivity"` + BusinessImpact BusinessImpact `db:"business_impact"` + Notes *string `db:"notes"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` + } + + // DataSensitivity represents the level of data sensitivity handled by a vendor + DataSensitivity string + + // BusinessImpact represents the impact level the vendor has on business operations + BusinessImpact string + + // RiskAssessments is a collection of RiskAssessment objects + VendorRiskAssessments []*VendorRiskAssessment +) + +// Constants for DataSensitivity +const ( + DataSensitivityNone DataSensitivity = "NONE" // No sensitive data + DataSensitivityLow DataSensitivity = "LOW" // Public or non-sensitive data + DataSensitivityMedium DataSensitivity = "MEDIUM" // Internal/restricted data + DataSensitivityHigh DataSensitivity = "HIGH" // Confidential data + DataSensitivityCritical DataSensitivity = "CRITICAL" // Regulated/PII/financial data +) + +// Constants for BusinessImpact +const ( + BusinessImpactLow BusinessImpact = "LOW" // Minimal impact on business + BusinessImpactMedium BusinessImpact = "MEDIUM" // Moderate impact on business + BusinessImpactHigh BusinessImpact = "HIGH" // Significant business impact + BusinessImpactCritical BusinessImpact = "CRITICAL" // Critical to business operations +) + +func (v VendorRiskAssessment) CursorKey(orderBy VendorRiskAssessmentOrderField) page.CursorKey { + switch orderBy { + case VendorRiskAssessmentOrderFieldCreatedAt: + return page.NewCursorKey(v.ID, v.CreatedAt) + case VendorRiskAssessmentOrderFieldExpiresAt: + return page.NewCursorKey(v.ID, v.ExpiresAt) + } + + panic(fmt.Sprintf("unsupported order by: %s", orderBy)) +} + +// Insert adds a new risk assessment to the database +func (r VendorRiskAssessment) Insert( + ctx context.Context, + conn pg.Conn, + scope Scoper, +) error { + q := ` +INSERT INTO + risk_assessments ( + tenant_id, + id, + vendor_id, + assessed_at, + assessed_by, + accessed_at, + approved_by, + approved_at, + expires_at, + data_sensitivity, + business_impact, + notes, + created_at, + updated_at + ) +VALUES ( + @tenant_id, + @id, + @vendor_id, + @assessed_at, + @assessed_by, + @expires_at, + @data_sensitivity, + @business_impact, + @notes, + @attachments, + @created_at, + @updated_at +) +` + + args := pgx.StrictNamedArgs{ + "tenant_id": scope.GetTenantID(), + "id": r.ID, + "vendor_id": r.VendorID, + "assessed_at": r.AssessedAt, + "assessed_by": r.AssessedBy, + "accessed_at": r.AccessedAt, + "approved_by": r.ApprovedBy, + "approved_at": r.ApprovedAt, + "expires_at": r.ExpiresAt, + "data_sensitivity": r.DataSensitivity, + "business_impact": r.BusinessImpact, + "notes": r.Notes, + "created_at": r.CreatedAt, + "updated_at": r.UpdatedAt, + } + _, err := conn.Exec(ctx, q, args) + return err +} + +// LoadByID loads a risk assessment by its ID +func (r *VendorRiskAssessment) LoadByID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + id gid.GID, +) error { + q := ` +SELECT + id, + vendor_id, + assessed_at, + assessed_by, + accessed_at, + approved_by, + approved_at, + expires_at, + data_sensitivity, + business_impact, + notes, + created_at, + updated_at +FROM + risk_assessments +WHERE + %s + AND id = @id +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"id": id} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query risk assessment: %w", err) + } + defer rows.Close() + + assessment, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[VendorRiskAssessment]) + if err != nil { + return fmt.Errorf("cannot collect risk assessment: %w", err) + } + + *r = assessment + + return nil +} + +// LoadLatestByVendorID loads the most recent risk assessment for a vendor +func (r *VendorRiskAssessment) LoadLatestByVendorID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + vendorID gid.GID, +) error { + q := ` +SELECT + id, + vendor_id, + assessed_at, + assessed_by, + accessed_at, + approved_by, + approved_at, + expires_at, + data_sensitivity, + business_impact, + notes, + created_at, + updated_at +FROM + risk_assessments +WHERE + %s + AND vendor_id = @vendor_id +ORDER BY + assessed_at DESC +LIMIT 1; +` + + q = fmt.Sprintf(q, scope.SQLFragment()) + + args := pgx.StrictNamedArgs{"vendor_id": vendorID} + maps.Copy(args, scope.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query risk assessment: %w", err) + } + defer rows.Close() + + assessment, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[VendorRiskAssessment]) + if err != nil { + return fmt.Errorf("cannot collect risk assessment: %w", err) + } + + *r = assessment + + return nil +} + +// LoadByVendorID loads all risk assessments for a vendor, ordered by assessment date +func (r *VendorRiskAssessments) LoadByVendorID( + ctx context.Context, + conn pg.Conn, + scope Scoper, + vendorID gid.GID, + cursor *page.Cursor[VendorRiskAssessmentOrderField], +) error { + q := ` +SELECT + id, + vendor_id, + assessed_at, + assessed_by, + accessed_at, + approved_by, + approved_at, + expires_at, + data_sensitivity, + business_impact, + notes, + created_at, + updated_at +FROM + risk_assessments +WHERE + %s + AND vendor_id = @vendor_id + AND %s +` + + q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment()) + + args := pgx.StrictNamedArgs{"vendor_id": vendorID} + maps.Copy(args, scope.SQLArguments()) + maps.Copy(args, cursor.SQLArguments()) + + rows, err := conn.Query(ctx, q, args) + if err != nil { + return fmt.Errorf("cannot query risk assessments: %w", err) + } + + assessments, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[VendorRiskAssessment]) + if err != nil { + return fmt.Errorf("cannot collect risk assessments: %w", err) + } + + *r = assessments + + return nil +} diff --git a/pkg/coredata/vendor_risk_assessment_order_field.go b/pkg/coredata/vendor_risk_assessment_order_field.go new file mode 100644 index 000000000..9b40e9af2 --- /dev/null +++ b/pkg/coredata/vendor_risk_assessment_order_field.go @@ -0,0 +1,41 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 coredata + +type ( + VendorRiskAssessmentOrderField string +) + +const ( + VendorRiskAssessmentOrderFieldCreatedAt VendorRiskAssessmentOrderField = "CREATED_AT" + VendorRiskAssessmentOrderFieldExpiresAt VendorRiskAssessmentOrderField = "EXPIRES_AT" +) + +func (p VendorRiskAssessmentOrderField) Column() string { + return string(p) +} + +func (p VendorRiskAssessmentOrderField) String() string { + return string(p) +} + +func (p VendorRiskAssessmentOrderField) MarshalText() ([]byte, error) { + return []byte(p.String()), nil +} + +func (p *VendorRiskAssessmentOrderField) UnmarshalText(text []byte) error { + *p = VendorRiskAssessmentOrderField(text) + return nil +} diff --git a/pkg/probo/organization_service.go b/pkg/probo/organization_service.go index d732f624d..3c57ce740 100644 --- a/pkg/probo/organization_service.go +++ b/pkg/probo/organization_service.go @@ -64,8 +64,8 @@ func (s OrganizationService) Create( err = s.svc.pg.WithConn( ctx, - func(conn pg.Conn) error { - if err := organization.Insert(ctx, conn); err != nil { + func(tx pg.Conn) error { + if err := organization.Insert(ctx, tx); err != nil { return fmt.Errorf("cannot insert organization: %w", err) } diff --git a/pkg/probo/people_service.go b/pkg/probo/people_service.go index d174e3c64..cafb5d767 100644 --- a/pkg/probo/people_service.go +++ b/pkg/probo/people_service.go @@ -32,7 +32,7 @@ type ( UpdatePeopleRequest struct { ID gid.GID - ExpectedVersion int + UserID *gid.GID Kind *coredata.PeopleKind FullName *string PrimaryEmailAddress *string @@ -41,6 +41,7 @@ type ( CreatePeopleRequest struct { OrganizationID gid.GID + UserID *gid.GID FullName string PrimaryEmailAddress string AdditionalEmailAddresses []string @@ -99,20 +100,38 @@ func (s PeopleService) Update( ctx context.Context, req UpdatePeopleRequest, ) (*coredata.People, error) { - params := coredata.UpdatePeopleParams{ - ExpectedVersion: req.ExpectedVersion, - Kind: req.Kind, - FullName: req.FullName, - PrimaryEmailAddress: req.PrimaryEmailAddress, - AdditionalEmailAddresses: req.AdditionalEmailAddresses, - } - - people := &coredata.People{ID: req.ID} + people := &coredata.People{} err := s.svc.pg.WithTx( ctx, func(conn pg.Conn) error { - return people.Update(ctx, conn, s.svc.scope, params) + if err := people.LoadByID(ctx, conn, s.svc.scope, req.ID); err != nil { + return fmt.Errorf("cannot load people: %w", err) + } + + if req.UserID != nil { + people.UserID = req.UserID + } + + if req.Kind != nil { + people.Kind = *req.Kind + } + + if req.FullName != nil { + people.FullName = *req.FullName + } + + if req.PrimaryEmailAddress != nil { + people.PrimaryEmailAddress = *req.PrimaryEmailAddress + } + + if req.AdditionalEmailAddresses != nil { + people.AdditionalEmailAddresses = *req.AdditionalEmailAddresses + } + + people.UpdatedAt = time.Now() + + return people.Update(ctx, conn, s.svc.scope) }) if err != nil { return nil, err diff --git a/pkg/probo/vendor_service.go b/pkg/probo/vendor_service.go index 9bddd4394..73c8f24fe 100644 --- a/pkg/probo/vendor_service.go +++ b/pkg/probo/vendor_service.go @@ -48,8 +48,6 @@ type ( StatusPageURL *string ServiceStartAt time.Time ServiceTerminationAt *time.Time - ServiceCriticality coredata.ServiceCriticality - RiskTier coredata.RiskTier BusinessOwnerID *gid.GID SecurityOwnerID *gid.GID } @@ -72,11 +70,18 @@ type ( StatusPageURL *string ServiceStartAt *time.Time ServiceTerminationAt *time.Time - ServiceCriticality *coredata.ServiceCriticality - RiskTier *coredata.RiskTier BusinessOwnerID *gid.GID SecurityOwnerID *gid.GID } + + CreateVendorRiskAssessmentRequest struct { + VendorID gid.GID + AssessedByID gid.GID + ExpiresAt time.Time + DataSensitivity coredata.DataSensitivity + BusinessImpact coredata.BusinessImpact + Notes *string + } ) func (s VendorService) ListForOrganizationID( @@ -135,14 +140,6 @@ func (s VendorService) Update( vendor.ServiceTerminationAt = req.ServiceTerminationAt } - if req.ServiceCriticality != nil { - vendor.ServiceCriticality = *req.ServiceCriticality - } - - if req.RiskTier != nil { - vendor.RiskTier = *req.RiskTier - } - if req.StatusPageURL != nil { vendor.StatusPageURL = req.StatusPageURL } @@ -296,8 +293,6 @@ func (s VendorService) Create( TrustPageURL: req.TrustPageURL, StatusPageURL: req.StatusPageURL, TermsOfServiceURL: req.TermsOfServiceURL, - ServiceCriticality: req.ServiceCriticality, - RiskTier: req.RiskTier, } if req.Category != nil { @@ -327,3 +322,65 @@ func (s VendorService) Create( return vendor, nil } + +func (s VendorService) ListRiskAssessments( + ctx context.Context, + vendorID gid.GID, + cursor *page.Cursor[coredata.VendorRiskAssessmentOrderField], +) (*page.Page[*coredata.VendorRiskAssessment, coredata.VendorRiskAssessmentOrderField], error) { + var vendorRiskAssessments coredata.VendorRiskAssessments + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + return vendorRiskAssessments.LoadByVendorID(ctx, conn, s.svc.scope, vendorID, cursor) + }, + ) + + if err != nil { + return nil, err + } + + return page.NewPage(vendorRiskAssessments, cursor), nil +} + +func (s VendorService) CreateRiskAssessment( + ctx context.Context, + req CreateVendorRiskAssessmentRequest, +) (*coredata.VendorRiskAssessment, error) { + vendorRiskAssessmentID, err := gid.NewGID(s.svc.scope.GetTenantID(), coredata.VendorRiskAssessmentEntityType) + if err != nil { + return nil, fmt.Errorf("cannot create vendor risk assessment global id: %w", err) + } + + now := time.Now() + + vendorRiskAssessment := &coredata.VendorRiskAssessment{ + ID: vendorRiskAssessmentID, + VendorID: req.VendorID, + AssessedBy: req.AssessedByID, + ExpiresAt: req.ExpiresAt, + DataSensitivity: req.DataSensitivity, + BusinessImpact: req.BusinessImpact, + Notes: req.Notes, + CreatedAt: now, + UpdatedAt: now, + } + + err = s.svc.pg.WithTx( + ctx, + func(conn pg.Conn) error { + if err := vendorRiskAssessment.Insert(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot insert vendor risk assessment: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return vendorRiskAssessment, nil +} diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index dc01cd319..d7e00c6c3 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -107,32 +107,6 @@ enum MesureImportance ) } -enum ServiceCriticality - @goModel(model: "github.com/getprobo/probo/pkg/coredata.ServiceCriticality") { - LOW - @goEnum( - value: "github.com/getprobo/probo/pkg/coredata.ServiceCriticalityLow" - ) - MEDIUM - @goEnum( - value: "github.com/getprobo/probo/pkg/coredata.ServiceCriticalityMedium" - ) - HIGH - @goEnum( - value: "github.com/getprobo/probo/pkg/coredata.ServiceCriticalityHigh" - ) -} - -enum RiskTier - @goModel(model: "github.com/getprobo/probo/pkg/coredata.RiskTier") { - CRITICAL - @goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierCritical") - SIGNIFICANT - @goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierSignificant") - GENERAL - @goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierGeneral") -} - enum PolicyStatus @goModel(model: "github.com/getprobo/probo/pkg/coredata.PolicyStatus") { DRAFT @@ -276,6 +250,32 @@ enum ConnectorOrderField ) } +enum DataSensitivity + @goModel(model: "github.com/getprobo/probo/pkg/coredata.DataSensitivity") { + NONE + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityNone") + LOW + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityLow") + MEDIUM + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityMedium") + HIGH + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityHigh") + CRITICAL + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityCritical") +} + +enum BusinessImpact + @goModel(model: "github.com/getprobo/probo/pkg/coredata.BusinessImpact") { + LOW + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactLow") + MEDIUM + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactMedium") + HIGH + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactHigh") + CRITICAL + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactCritical") +} + # Order Input Types input UserOrder @goModel( @@ -488,13 +488,19 @@ type Vendor implements Node { orderBy: VendorComplianceReportOrder ): VendorComplianceReportConnection! @goField(forceResolver: true) + riskAssessments( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: VendorRiskAssessmentOrder + ): VendorRiskAssessmentConnection! @goField(forceResolver: true) + businessOwner: People @goField(forceResolver: true) securityOwner: People @goField(forceResolver: true) serviceStartAt: Datetime! serviceTerminationAt: Datetime - serviceCriticality: ServiceCriticality! - riskTier: RiskTier! statusPageUrl: String termsOfServiceUrl: String privacyPolicyUrl: String @@ -850,6 +856,16 @@ type ConnectorEdge { node: Connector! } +type VendorRiskAssessmentConnection { + edges: [VendorRiskAssessmentEdge!]! + pageInfo: PageInfo! +} + +type VendorRiskAssessmentEdge { + cursor: CursorKey! + node: VendorRiskAssessment! +} + # Root Types type Query { node(id: ID!): Node! @@ -951,6 +967,8 @@ type Mutation { createPolicy(input: CreatePolicyInput!): CreatePolicyPayload! updatePolicy(input: UpdatePolicyInput!): UpdatePolicyPayload! deletePolicy(input: DeletePolicyInput!): DeletePolicyPayload! + + createVendorRiskAssessment(input: CreateVendorRiskAssessmentInput!): CreateVendorRiskAssessmentPayload! } # Input Types @@ -986,8 +1004,6 @@ input CreateVendorInput { termsOfServiceUrl: String serviceStartAt: Datetime! serviceTerminationAt: Datetime - serviceCriticality: ServiceCriticality! - riskTier: RiskTier! businessOwnerId: ID securityOwnerId: ID } @@ -998,8 +1014,6 @@ input UpdateVendorInput { description: String serviceStartAt: Datetime serviceTerminationAt: Datetime - serviceCriticality: ServiceCriticality - riskTier: RiskTier statusPageUrl: String termsOfServiceUrl: String privacyPolicyUrl: String @@ -1434,3 +1448,48 @@ type InviteUserPayload { type RemoveUserPayload { success: Boolean! } + +input VendorRiskAssessmentOrder { + field: VendorRiskAssessmentOrderField! + direction: OrderDirection! +} + +type VendorRiskAssessment implements Node { + id: ID! + vendor: Vendor! @goField(forceResolver: true) + assessedAt: Datetime! + assessedBy: People! @goField(forceResolver: true) + expiresAt: Datetime! + dataSensitivity: DataSensitivity! + businessImpact: BusinessImpact! + notes: String + attachments: [String!]! + createdAt: Datetime! + updatedAt: Datetime! +} + +enum VendorRiskAssessmentOrderField + @goModel(model: "github.com/getprobo/probo/pkg/coredata.VendorRiskAssessmentOrderField") { + CREATED_AT + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorRiskAssessmentOrderFieldCreatedAt" + ) + EXPIRES_AT + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorRiskAssessmentOrderFieldExpiresAt" + ) +} + +input CreateVendorRiskAssessmentInput { + vendorId: ID! + assessedBy: ID! + expiresAt: Datetime! + dataSensitivity: DataSensitivity! + businessImpact: BusinessImpact! + notes: String + attachments: [String!] +} + +type CreateVendorRiskAssessmentPayload { + vendorRiskAssessmentEdge: VendorRiskAssessmentEdge! +} diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index e18d2fc6c..7ed04375a 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -54,6 +54,7 @@ type ResolverRoot interface { Task() TaskResolver Vendor() VendorResolver VendorComplianceReport() VendorComplianceReportResolver + VendorRiskAssessment() VendorRiskAssessmentResolver Viewer() ViewerResolver } @@ -160,6 +161,10 @@ type ComplexityRoot struct { VendorEdge func(childComplexity int) int } + CreateVendorRiskAssessmentPayload struct { + VendorRiskAssessmentEdge func(childComplexity int) int + } + DeleteControlMesureMappingPayload struct { Success func(childComplexity int) int } @@ -311,6 +316,7 @@ type ComplexityRoot struct { CreateRiskPolicyMapping func(childComplexity int, input types.CreateRiskPolicyMappingInput) int CreateTask func(childComplexity int, input types.CreateTaskInput) int CreateVendor func(childComplexity int, input types.CreateVendorInput) int + CreateVendorRiskAssessment func(childComplexity int, input types.CreateVendorRiskAssessmentInput) int DeleteControlMesureMapping func(childComplexity int, input types.DeleteControlMesureMappingInput) int DeleteControlPolicyMapping func(childComplexity int, input types.DeleteControlPolicyMappingInput) int DeleteEvidence func(childComplexity int, input types.DeleteEvidenceInput) int @@ -557,10 +563,9 @@ type ComplexityRoot struct { LegalName func(childComplexity int) int Name func(childComplexity int) int PrivacyPolicyURL func(childComplexity int) int - RiskTier func(childComplexity int) int + RiskAssessments func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) int SecurityOwner func(childComplexity int) int SecurityPageURL func(childComplexity int) int - ServiceCriticality func(childComplexity int) int ServiceLevelAgreementURL func(childComplexity int) int ServiceStartAt func(childComplexity int) int ServiceTerminationAt func(childComplexity int) int @@ -603,6 +608,30 @@ type ComplexityRoot struct { Node func(childComplexity int) int } + VendorRiskAssessment struct { + AssessedAt func(childComplexity int) int + AssessedBy func(childComplexity int) int + Attachments func(childComplexity int) int + BusinessImpact func(childComplexity int) int + CreatedAt func(childComplexity int) int + DataSensitivity func(childComplexity int) int + ExpiresAt func(childComplexity int) int + ID func(childComplexity int) int + Notes func(childComplexity int) int + UpdatedAt func(childComplexity int) int + Vendor func(childComplexity int) int + } + + VendorRiskAssessmentConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + } + + VendorRiskAssessmentEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int + } + Viewer struct { ID func(childComplexity int) int Organizations func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrganizationOrder) int @@ -670,6 +699,7 @@ type MutationResolver interface { CreatePolicy(ctx context.Context, input types.CreatePolicyInput) (*types.CreatePolicyPayload, error) UpdatePolicy(ctx context.Context, input types.UpdatePolicyInput) (*types.UpdatePolicyPayload, error) DeletePolicy(ctx context.Context, input types.DeletePolicyInput) (*types.DeletePolicyPayload, error) + CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) } type OrganizationResolver interface { LogoURL(ctx context.Context, obj *types.Organization) (*string, error) @@ -702,6 +732,7 @@ type TaskResolver interface { } type VendorResolver interface { ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) + RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) BusinessOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) SecurityOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) } @@ -710,6 +741,11 @@ type VendorComplianceReportResolver interface { FileURL(ctx context.Context, obj *types.VendorComplianceReport) (string, error) } +type VendorRiskAssessmentResolver interface { + Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) + + AssessedBy(ctx context.Context, obj *types.VendorRiskAssessment) (*types.People, error) +} type ViewerResolver interface { Organizations(ctx context.Context, obj *types.Viewer, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrganizationOrder) (*types.OrganizationConnection, error) } @@ -995,6 +1031,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.CreateVendorPayload.VendorEdge(childComplexity), true + case "CreateVendorRiskAssessmentPayload.vendorRiskAssessmentEdge": + if e.complexity.CreateVendorRiskAssessmentPayload.VendorRiskAssessmentEdge == nil { + break + } + + return e.complexity.CreateVendorRiskAssessmentPayload.VendorRiskAssessmentEdge(childComplexity), true + case "DeleteControlMesureMappingPayload.success": if e.complexity.DeleteControlMesureMappingPayload.Success == nil { break @@ -1594,6 +1637,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.CreateVendor(childComplexity, args["input"].(types.CreateVendorInput)), true + case "Mutation.createVendorRiskAssessment": + if e.complexity.Mutation.CreateVendorRiskAssessment == nil { + break + } + + args, err := ec.field_Mutation_createVendorRiskAssessment_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.CreateVendorRiskAssessment(childComplexity, args["input"].(types.CreateVendorRiskAssessmentInput)), true + case "Mutation.deleteControlMesureMapping": if e.complexity.Mutation.DeleteControlMesureMapping == nil { break @@ -2822,12 +2877,17 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Vendor.PrivacyPolicyURL(childComplexity), true - case "Vendor.riskTier": - if e.complexity.Vendor.RiskTier == nil { + case "Vendor.riskAssessments": + if e.complexity.Vendor.RiskAssessments == nil { break } - return e.complexity.Vendor.RiskTier(childComplexity), true + args, err := ec.field_Vendor_riskAssessments_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Vendor.RiskAssessments(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.VendorRiskAssessmentOrder)), true case "Vendor.securityOwner": if e.complexity.Vendor.SecurityOwner == nil { @@ -2843,13 +2903,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Vendor.SecurityPageURL(childComplexity), true - case "Vendor.serviceCriticality": - if e.complexity.Vendor.ServiceCriticality == nil { - break - } - - return e.complexity.Vendor.ServiceCriticality(childComplexity), true - case "Vendor.serviceLevelAgreementUrl": if e.complexity.Vendor.ServiceLevelAgreementURL == nil { break @@ -3025,6 +3078,111 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.VendorEdge.Node(childComplexity), true + case "VendorRiskAssessment.assessedAt": + if e.complexity.VendorRiskAssessment.AssessedAt == nil { + break + } + + return e.complexity.VendorRiskAssessment.AssessedAt(childComplexity), true + + case "VendorRiskAssessment.assessedBy": + if e.complexity.VendorRiskAssessment.AssessedBy == nil { + break + } + + return e.complexity.VendorRiskAssessment.AssessedBy(childComplexity), true + + case "VendorRiskAssessment.attachments": + if e.complexity.VendorRiskAssessment.Attachments == nil { + break + } + + return e.complexity.VendorRiskAssessment.Attachments(childComplexity), true + + case "VendorRiskAssessment.businessImpact": + if e.complexity.VendorRiskAssessment.BusinessImpact == nil { + break + } + + return e.complexity.VendorRiskAssessment.BusinessImpact(childComplexity), true + + case "VendorRiskAssessment.createdAt": + if e.complexity.VendorRiskAssessment.CreatedAt == nil { + break + } + + return e.complexity.VendorRiskAssessment.CreatedAt(childComplexity), true + + case "VendorRiskAssessment.dataSensitivity": + if e.complexity.VendorRiskAssessment.DataSensitivity == nil { + break + } + + return e.complexity.VendorRiskAssessment.DataSensitivity(childComplexity), true + + case "VendorRiskAssessment.expiresAt": + if e.complexity.VendorRiskAssessment.ExpiresAt == nil { + break + } + + return e.complexity.VendorRiskAssessment.ExpiresAt(childComplexity), true + + case "VendorRiskAssessment.id": + if e.complexity.VendorRiskAssessment.ID == nil { + break + } + + return e.complexity.VendorRiskAssessment.ID(childComplexity), true + + case "VendorRiskAssessment.notes": + if e.complexity.VendorRiskAssessment.Notes == nil { + break + } + + return e.complexity.VendorRiskAssessment.Notes(childComplexity), true + + case "VendorRiskAssessment.updatedAt": + if e.complexity.VendorRiskAssessment.UpdatedAt == nil { + break + } + + return e.complexity.VendorRiskAssessment.UpdatedAt(childComplexity), true + + case "VendorRiskAssessment.vendor": + if e.complexity.VendorRiskAssessment.Vendor == nil { + break + } + + return e.complexity.VendorRiskAssessment.Vendor(childComplexity), true + + case "VendorRiskAssessmentConnection.edges": + if e.complexity.VendorRiskAssessmentConnection.Edges == nil { + break + } + + return e.complexity.VendorRiskAssessmentConnection.Edges(childComplexity), true + + case "VendorRiskAssessmentConnection.pageInfo": + if e.complexity.VendorRiskAssessmentConnection.PageInfo == nil { + break + } + + return e.complexity.VendorRiskAssessmentConnection.PageInfo(childComplexity), true + + case "VendorRiskAssessmentEdge.cursor": + if e.complexity.VendorRiskAssessmentEdge.Cursor == nil { + break + } + + return e.complexity.VendorRiskAssessmentEdge.Cursor(childComplexity), true + + case "VendorRiskAssessmentEdge.node": + if e.complexity.VendorRiskAssessmentEdge.Node == nil { + break + } + + return e.complexity.VendorRiskAssessmentEdge.Node(childComplexity), true + case "Viewer.id": if e.complexity.Viewer.ID == nil { break @@ -3076,6 +3234,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputCreateRiskPolicyMappingInput, ec.unmarshalInputCreateTaskInput, ec.unmarshalInputCreateVendorInput, + ec.unmarshalInputCreateVendorRiskAssessmentInput, ec.unmarshalInputDeleteControlMesureMappingInput, ec.unmarshalInputDeleteControlPolicyMappingInput, ec.unmarshalInputDeleteEvidenceInput, @@ -3116,6 +3275,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputUserOrder, ec.unmarshalInputVendorComplianceReportOrder, ec.unmarshalInputVendorOrder, + ec.unmarshalInputVendorRiskAssessmentOrder, ) first := true @@ -3322,32 +3482,6 @@ enum MesureImportance ) } -enum ServiceCriticality - @goModel(model: "github.com/getprobo/probo/pkg/coredata.ServiceCriticality") { - LOW - @goEnum( - value: "github.com/getprobo/probo/pkg/coredata.ServiceCriticalityLow" - ) - MEDIUM - @goEnum( - value: "github.com/getprobo/probo/pkg/coredata.ServiceCriticalityMedium" - ) - HIGH - @goEnum( - value: "github.com/getprobo/probo/pkg/coredata.ServiceCriticalityHigh" - ) -} - -enum RiskTier - @goModel(model: "github.com/getprobo/probo/pkg/coredata.RiskTier") { - CRITICAL - @goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierCritical") - SIGNIFICANT - @goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierSignificant") - GENERAL - @goEnum(value: "github.com/getprobo/probo/pkg/coredata.RiskTierGeneral") -} - enum PolicyStatus @goModel(model: "github.com/getprobo/probo/pkg/coredata.PolicyStatus") { DRAFT @@ -3491,6 +3625,32 @@ enum ConnectorOrderField ) } +enum DataSensitivity + @goModel(model: "github.com/getprobo/probo/pkg/coredata.DataSensitivity") { + NONE + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityNone") + LOW + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityLow") + MEDIUM + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityMedium") + HIGH + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityHigh") + CRITICAL + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.DataSensitivityCritical") +} + +enum BusinessImpact + @goModel(model: "github.com/getprobo/probo/pkg/coredata.BusinessImpact") { + LOW + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactLow") + MEDIUM + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactMedium") + HIGH + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactHigh") + CRITICAL + @goEnum(value: "github.com/getprobo/probo/pkg/coredata.BusinessImpactCritical") +} + # Order Input Types input UserOrder @goModel( @@ -3703,13 +3863,19 @@ type Vendor implements Node { orderBy: VendorComplianceReportOrder ): VendorComplianceReportConnection! @goField(forceResolver: true) + riskAssessments( + first: Int + after: CursorKey + last: Int + before: CursorKey + orderBy: VendorRiskAssessmentOrder + ): VendorRiskAssessmentConnection! @goField(forceResolver: true) + businessOwner: People @goField(forceResolver: true) securityOwner: People @goField(forceResolver: true) serviceStartAt: Datetime! serviceTerminationAt: Datetime - serviceCriticality: ServiceCriticality! - riskTier: RiskTier! statusPageUrl: String termsOfServiceUrl: String privacyPolicyUrl: String @@ -4065,6 +4231,16 @@ type ConnectorEdge { node: Connector! } +type VendorRiskAssessmentConnection { + edges: [VendorRiskAssessmentEdge!]! + pageInfo: PageInfo! +} + +type VendorRiskAssessmentEdge { + cursor: CursorKey! + node: VendorRiskAssessment! +} + # Root Types type Query { node(id: ID!): Node! @@ -4166,6 +4342,8 @@ type Mutation { createPolicy(input: CreatePolicyInput!): CreatePolicyPayload! updatePolicy(input: UpdatePolicyInput!): UpdatePolicyPayload! deletePolicy(input: DeletePolicyInput!): DeletePolicyPayload! + + createVendorRiskAssessment(input: CreateVendorRiskAssessmentInput!): CreateVendorRiskAssessmentPayload! } # Input Types @@ -4201,8 +4379,6 @@ input CreateVendorInput { termsOfServiceUrl: String serviceStartAt: Datetime! serviceTerminationAt: Datetime - serviceCriticality: ServiceCriticality! - riskTier: RiskTier! businessOwnerId: ID securityOwnerId: ID } @@ -4213,8 +4389,6 @@ input UpdateVendorInput { description: String serviceStartAt: Datetime serviceTerminationAt: Datetime - serviceCriticality: ServiceCriticality - riskTier: RiskTier statusPageUrl: String termsOfServiceUrl: String privacyPolicyUrl: String @@ -4649,6 +4823,51 @@ type InviteUserPayload { type RemoveUserPayload { success: Boolean! } + +input VendorRiskAssessmentOrder { + field: VendorRiskAssessmentOrderField! + direction: OrderDirection! +} + +type VendorRiskAssessment implements Node { + id: ID! + vendor: Vendor! @goField(forceResolver: true) + assessedAt: Datetime! + assessedBy: People! @goField(forceResolver: true) + expiresAt: Datetime! + dataSensitivity: DataSensitivity! + businessImpact: BusinessImpact! + notes: String + attachments: [String!]! + createdAt: Datetime! + updatedAt: Datetime! +} + +enum VendorRiskAssessmentOrderField + @goModel(model: "github.com/getprobo/probo/pkg/coredata.VendorRiskAssessmentOrderField") { + CREATED_AT + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorRiskAssessmentOrderFieldCreatedAt" + ) + EXPIRES_AT + @goEnum( + value: "github.com/getprobo/probo/pkg/coredata.VendorRiskAssessmentOrderFieldExpiresAt" + ) +} + +input CreateVendorRiskAssessmentInput { + vendorId: ID! + assessedBy: ID! + expiresAt: Datetime! + dataSensitivity: DataSensitivity! + businessImpact: BusinessImpact! + notes: String + attachments: [String!] +} + +type CreateVendorRiskAssessmentPayload { + vendorRiskAssessmentEdge: VendorRiskAssessmentEdge! +} `, BuiltIn: false}, } var parsedSchema = gqlparser.MustLoadSchema(sources...) @@ -5549,6 +5768,29 @@ func (ec *executionContext) field_Mutation_createTask_argsInput( return zeroVal, nil } +func (ec *executionContext) field_Mutation_createVendorRiskAssessment_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Mutation_createVendorRiskAssessment_argsInput(ctx, rawArgs) + if err != nil { + return nil, err + } + args["input"] = arg0 + return args, nil +} +func (ec *executionContext) field_Mutation_createVendorRiskAssessment_argsInput( + ctx context.Context, + rawArgs map[string]any, +) (types.CreateVendorRiskAssessmentInput, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNCreateVendorRiskAssessmentInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorRiskAssessmentInput(ctx, tmp) + } + + var zeroVal types.CreateVendorRiskAssessmentInput + return zeroVal, nil +} + func (ec *executionContext) field_Mutation_createVendor_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -7615,6 +7857,101 @@ func (ec *executionContext) field_Vendor_complianceReports_argsOrderBy( return zeroVal, nil } +func (ec *executionContext) field_Vendor_riskAssessments_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { + var err error + args := map[string]any{} + arg0, err := ec.field_Vendor_riskAssessments_argsFirst(ctx, rawArgs) + if err != nil { + return nil, err + } + args["first"] = arg0 + arg1, err := ec.field_Vendor_riskAssessments_argsAfter(ctx, rawArgs) + if err != nil { + return nil, err + } + args["after"] = arg1 + arg2, err := ec.field_Vendor_riskAssessments_argsLast(ctx, rawArgs) + if err != nil { + return nil, err + } + args["last"] = arg2 + arg3, err := ec.field_Vendor_riskAssessments_argsBefore(ctx, rawArgs) + if err != nil { + return nil, err + } + args["before"] = arg3 + arg4, err := ec.field_Vendor_riskAssessments_argsOrderBy(ctx, rawArgs) + if err != nil { + return nil, err + } + args["orderBy"] = arg4 + return args, nil +} +func (ec *executionContext) field_Vendor_riskAssessments_argsFirst( + ctx context.Context, + rawArgs map[string]any, +) (*int, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + if tmp, ok := rawArgs["first"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_riskAssessments_argsAfter( + ctx context.Context, + rawArgs map[string]any, +) (*page.CursorKey, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + if tmp, ok := rawArgs["after"]; ok { + return ec.unmarshalOCursorKey2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx, tmp) + } + + var zeroVal *page.CursorKey + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_riskAssessments_argsLast( + ctx context.Context, + rawArgs map[string]any, +) (*int, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("last")) + if tmp, ok := rawArgs["last"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_riskAssessments_argsBefore( + ctx context.Context, + rawArgs map[string]any, +) (*page.CursorKey, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("before")) + if tmp, ok := rawArgs["before"]; ok { + return ec.unmarshalOCursorKey2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx, tmp) + } + + var zeroVal *page.CursorKey + return zeroVal, nil +} + +func (ec *executionContext) field_Vendor_riskAssessments_argsOrderBy( + ctx context.Context, + rawArgs map[string]any, +) (*types.VendorRiskAssessmentOrder, error) { + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("orderBy")) + if tmp, ok := rawArgs["orderBy"]; ok { + return ec.unmarshalOVendorRiskAssessmentOrder2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentOrder(ctx, tmp) + } + + var zeroVal *types.VendorRiskAssessmentOrder + return zeroVal, nil +} + func (ec *executionContext) field_Viewer_organizations_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) { var err error args := map[string]any{} @@ -9564,6 +9901,56 @@ func (ec *executionContext) fieldContext_CreateVendorPayload_vendorEdge(_ contex return fc, nil } +func (ec *executionContext) _CreateVendorRiskAssessmentPayload_vendorRiskAssessmentEdge(ctx context.Context, field graphql.CollectedField, obj *types.CreateVendorRiskAssessmentPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CreateVendorRiskAssessmentPayload_vendorRiskAssessmentEdge(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.VendorRiskAssessmentEdge, 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.VendorRiskAssessmentEdge) + fc.Result = res + return ec.marshalNVendorRiskAssessmentEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentEdge(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CreateVendorRiskAssessmentPayload_vendorRiskAssessmentEdge(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CreateVendorRiskAssessmentPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "cursor": + return ec.fieldContext_VendorRiskAssessmentEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_VendorRiskAssessmentEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorRiskAssessmentEdge", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _DeleteControlMesureMappingPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.DeleteControlMesureMappingPayload) (ret graphql.Marshaler) { fc, err := ec.fieldContext_DeleteControlMesureMappingPayload_success(ctx, field) if err != nil { @@ -14858,6 +15245,65 @@ func (ec *executionContext) fieldContext_Mutation_deletePolicy(ctx context.Conte return fc, nil } +func (ec *executionContext) _Mutation_createVendorRiskAssessment(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_createVendorRiskAssessment(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().CreateVendorRiskAssessment(rctx, fc.Args["input"].(types.CreateVendorRiskAssessmentInput)) + }) + 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.CreateVendorRiskAssessmentPayload) + fc.Result = res + return ec.marshalNCreateVendorRiskAssessmentPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorRiskAssessmentPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_createVendorRiskAssessment(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 "vendorRiskAssessmentEdge": + return ec.fieldContext_CreateVendorRiskAssessmentPayload_vendorRiskAssessmentEdge(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CreateVendorRiskAssessmentPayload", 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_createVendorRiskAssessment_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 { @@ -19779,6 +20225,8 @@ func (ec *executionContext) fieldContext_UpdateVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_description(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": @@ -19787,10 +20235,6 @@ func (ec *executionContext) fieldContext_UpdateVendorPayload_vendor(_ context.Co return ec.fieldContext_Vendor_serviceStartAt(ctx, field) case "serviceTerminationAt": return ec.fieldContext_Vendor_serviceTerminationAt(ctx, field) - case "serviceCriticality": - return ec.fieldContext_Vendor_serviceCriticality(ctx, field) - case "riskTier": - return ec.fieldContext_Vendor_riskTier(ctx, field) case "statusPageUrl": return ec.fieldContext_Vendor_statusPageUrl(ctx, field) case "termsOfServiceUrl": @@ -20488,6 +20932,67 @@ func (ec *executionContext) fieldContext_Vendor_complianceReports(ctx context.Co return fc, nil } +func (ec *executionContext) _Vendor_riskAssessments(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Vendor_riskAssessments(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.Vendor().RiskAssessments(rctx, obj, fc.Args["first"].(*int), fc.Args["after"].(*page.CursorKey), fc.Args["last"].(*int), fc.Args["before"].(*page.CursorKey), fc.Args["orderBy"].(*types.VendorRiskAssessmentOrder)) + }) + 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.VendorRiskAssessmentConnection) + fc.Result = res + return ec.marshalNVendorRiskAssessmentConnection2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentConnection(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Vendor_riskAssessments(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Vendor", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "edges": + return ec.fieldContext_VendorRiskAssessmentConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_VendorRiskAssessmentConnection_pageInfo(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorRiskAssessmentConnection", 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_Vendor_riskAssessments_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Vendor_businessOwner(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Vendor_businessOwner(ctx, field) if err != nil { @@ -20687,94 +21192,6 @@ func (ec *executionContext) fieldContext_Vendor_serviceTerminationAt(_ context.C return fc, nil } -func (ec *executionContext) _Vendor_serviceCriticality(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Vendor_serviceCriticality(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.ServiceCriticality, 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.(coredata.ServiceCriticality) - fc.Result = res - return ec.marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Vendor_serviceCriticality(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Vendor", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ServiceCriticality does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Vendor_riskTier(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Vendor_riskTier(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.RiskTier, 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.(coredata.RiskTier) - fc.Result = res - return ec.marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Vendor_riskTier(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Vendor", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type RiskTier does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _Vendor_statusPageUrl(ctx context.Context, field graphql.CollectedField, obj *types.Vendor) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Vendor_statusPageUrl(ctx, field) if err != nil { @@ -21408,6 +21825,8 @@ func (ec *executionContext) fieldContext_VendorComplianceReport_vendor(_ context return ec.fieldContext_Vendor_description(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": @@ -21416,10 +21835,6 @@ func (ec *executionContext) fieldContext_VendorComplianceReport_vendor(_ context return ec.fieldContext_Vendor_serviceStartAt(ctx, field) case "serviceTerminationAt": return ec.fieldContext_Vendor_serviceTerminationAt(ctx, field) - case "serviceCriticality": - return ec.fieldContext_Vendor_serviceCriticality(ctx, field) - case "riskTier": - return ec.fieldContext_Vendor_riskTier(ctx, field) case "statusPageUrl": return ec.fieldContext_Vendor_statusPageUrl(ctx, field) case "termsOfServiceUrl": @@ -22165,6 +22580,8 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel return ec.fieldContext_Vendor_description(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": @@ -22173,10 +22590,6 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel return ec.fieldContext_Vendor_serviceStartAt(ctx, field) case "serviceTerminationAt": return ec.fieldContext_Vendor_serviceTerminationAt(ctx, field) - case "serviceCriticality": - return ec.fieldContext_Vendor_serviceCriticality(ctx, field) - case "riskTier": - return ec.fieldContext_Vendor_riskTier(ctx, field) case "statusPageUrl": return ec.fieldContext_Vendor_statusPageUrl(ctx, field) case "termsOfServiceUrl": @@ -22210,6 +22623,765 @@ func (ec *executionContext) fieldContext_VendorEdge_node(_ context.Context, fiel return fc, nil } +func (ec *executionContext) _VendorRiskAssessment_id(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_id(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.ID, 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.(gid.GID) + fc.Result = res + return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_vendor(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_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 ec.resolvers.VendorRiskAssessment().Vendor(rctx, obj) + }) + 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_VendorRiskAssessment_vendor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: true, + IsResolver: true, + 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 "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 "serviceStartAt": + return ec.fieldContext_Vendor_serviceStartAt(ctx, field) + case "serviceTerminationAt": + return ec.fieldContext_Vendor_serviceTerminationAt(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) _VendorRiskAssessment_assessedAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_assessedAt(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.AssessedAt, 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.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_assessedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_assessedBy(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_assessedBy(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.VendorRiskAssessment().AssessedBy(rctx, obj) + }) + 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.People) + fc.Result = res + return ec.marshalNPeople2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPeople(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_assessedBy(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_People_id(ctx, field) + case "fullName": + return ec.fieldContext_People_fullName(ctx, field) + case "primaryEmailAddress": + return ec.fieldContext_People_primaryEmailAddress(ctx, field) + case "additionalEmailAddresses": + return ec.fieldContext_People_additionalEmailAddresses(ctx, field) + case "kind": + return ec.fieldContext_People_kind(ctx, field) + case "createdAt": + return ec.fieldContext_People_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_People_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type People", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_expiresAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_expiresAt(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.ExpiresAt, 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.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_expiresAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_dataSensitivity(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_dataSensitivity(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.DataSensitivity, 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.(coredata.DataSensitivity) + fc.Result = res + return ec.marshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_dataSensitivity(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type DataSensitivity does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_businessImpact(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_businessImpact(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.BusinessImpact, 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.(coredata.BusinessImpact) + fc.Result = res + return ec.marshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_businessImpact(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type BusinessImpact does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_notes(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_notes(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.Notes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_notes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_attachments(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_attachments(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.Attachments, 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.([]string) + fc.Result = res + return ec.marshalNString2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_attachments(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_createdAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_createdAt(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.CreatedAt, 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.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessment_updatedAt(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessment) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessment_updatedAt(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.UpdatedAt, 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.(time.Time) + fc.Result = res + return ec.marshalNDatetime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessment_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessment", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Datetime does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessmentConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessmentConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessmentConnection_edges(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.Edges, 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.VendorRiskAssessmentEdge) + fc.Result = res + return ec.marshalNVendorRiskAssessmentEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentEdgeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessmentConnection_edges(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessmentConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "cursor": + return ec.fieldContext_VendorRiskAssessmentEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_VendorRiskAssessmentEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorRiskAssessmentEdge", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessmentConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessmentConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessmentConnection_pageInfo(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.PageInfo, 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.PageInfo) + fc.Result = res + return ec.marshalNPageInfo2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessmentConnection_pageInfo(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessmentConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + case "hasPreviousPage": + return ec.fieldContext_PageInfo_hasPreviousPage(ctx, field) + case "startCursor": + return ec.fieldContext_PageInfo_startCursor(ctx, field) + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessmentEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessmentEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessmentEdge_cursor(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.Cursor, 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.(page.CursorKey) + fc.Result = res + return ec.marshalNCursorKey2githubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessmentEdge_cursor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessmentEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type CursorKey does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _VendorRiskAssessmentEdge_node(ctx context.Context, field graphql.CollectedField, obj *types.VendorRiskAssessmentEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_VendorRiskAssessmentEdge_node(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.Node, 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.VendorRiskAssessment) + fc.Result = res + return ec.marshalNVendorRiskAssessment2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessment(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_VendorRiskAssessmentEdge_node(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "VendorRiskAssessmentEdge", + 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_VendorRiskAssessment_id(ctx, field) + case "vendor": + return ec.fieldContext_VendorRiskAssessment_vendor(ctx, field) + case "assessedAt": + return ec.fieldContext_VendorRiskAssessment_assessedAt(ctx, field) + case "assessedBy": + return ec.fieldContext_VendorRiskAssessment_assessedBy(ctx, field) + case "expiresAt": + return ec.fieldContext_VendorRiskAssessment_expiresAt(ctx, field) + case "dataSensitivity": + return ec.fieldContext_VendorRiskAssessment_dataSensitivity(ctx, field) + case "businessImpact": + return ec.fieldContext_VendorRiskAssessment_businessImpact(ctx, field) + case "notes": + return ec.fieldContext_VendorRiskAssessment_notes(ctx, field) + case "attachments": + return ec.fieldContext_VendorRiskAssessment_attachments(ctx, field) + case "createdAt": + return ec.fieldContext_VendorRiskAssessment_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_VendorRiskAssessment_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type VendorRiskAssessment", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Viewer_id(ctx context.Context, field graphql.CollectedField, obj *types.Viewer) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Viewer_id(ctx, field) if err != nil { @@ -25041,7 +26213,7 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"organizationId", "name", "description", "headquarterAddress", "legalName", "websiteUrl", "privacyPolicyUrl", "category", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "certifications", "securityPageUrl", "trustPageUrl", "statusPageUrl", "termsOfServiceUrl", "serviceStartAt", "serviceTerminationAt", "serviceCriticality", "riskTier", "businessOwnerId", "securityOwnerId"} + fieldsInOrder := [...]string{"organizationId", "name", "description", "headquarterAddress", "legalName", "websiteUrl", "privacyPolicyUrl", "category", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "certifications", "securityPageUrl", "trustPageUrl", "statusPageUrl", "termsOfServiceUrl", "serviceStartAt", "serviceTerminationAt", "businessOwnerId", "securityOwnerId"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -25167,20 +26339,6 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, return it, err } it.ServiceTerminationAt = data - case "serviceCriticality": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceCriticality")) - data, err := ec.unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx, v) - if err != nil { - return it, err - } - it.ServiceCriticality = data - case "riskTier": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("riskTier")) - data, err := ec.unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx, v) - if err != nil { - return it, err - } - it.RiskTier = data case "businessOwnerId": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("businessOwnerId")) data, err := ec.unmarshalOID2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) @@ -25201,6 +26359,75 @@ func (ec *executionContext) unmarshalInputCreateVendorInput(ctx context.Context, return it, nil } +func (ec *executionContext) unmarshalInputCreateVendorRiskAssessmentInput(ctx context.Context, obj any) (types.CreateVendorRiskAssessmentInput, error) { + var it types.CreateVendorRiskAssessmentInput + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"vendorId", "assessedBy", "expiresAt", "dataSensitivity", "businessImpact", "notes", "attachments"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "vendorId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("vendorId")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.VendorID = data + case "assessedBy": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("assessedBy")) + data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v) + if err != nil { + return it, err + } + it.AssessedBy = data + case "expiresAt": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("expiresAt")) + data, err := ec.unmarshalNDatetime2timeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.ExpiresAt = data + case "dataSensitivity": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dataSensitivity")) + data, err := ec.unmarshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity(ctx, v) + if err != nil { + return it, err + } + it.DataSensitivity = data + case "businessImpact": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("businessImpact")) + data, err := ec.unmarshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact(ctx, v) + if err != nil { + return it, err + } + it.BusinessImpact = data + case "notes": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("notes")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.Notes = data + case "attachments": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("attachments")) + data, err := ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + it.Attachments = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputDeleteControlMesureMappingInput(ctx context.Context, obj any) (types.DeleteControlMesureMappingInput, error) { var it types.DeleteControlMesureMappingInput asMap := map[string]any{} @@ -26531,7 +27758,7 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"id", "name", "description", "serviceStartAt", "serviceTerminationAt", "serviceCriticality", "riskTier", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "websiteUrl", "legalName", "headquarterAddress", "category", "certifications", "securityPageUrl", "trustPageUrl", "businessOwnerId", "securityOwnerId"} + fieldsInOrder := [...]string{"id", "name", "description", "serviceStartAt", "serviceTerminationAt", "statusPageUrl", "termsOfServiceUrl", "privacyPolicyUrl", "serviceLevelAgreementUrl", "dataProcessingAgreementUrl", "websiteUrl", "legalName", "headquarterAddress", "category", "certifications", "securityPageUrl", "trustPageUrl", "businessOwnerId", "securityOwnerId"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -26573,20 +27800,6 @@ func (ec *executionContext) unmarshalInputUpdateVendorInput(ctx context.Context, return it, err } it.ServiceTerminationAt = data - case "serviceCriticality": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("serviceCriticality")) - data, err := ec.unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx, v) - if err != nil { - return it, err - } - it.ServiceCriticality = data - case "riskTier": - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("riskTier")) - data, err := ec.unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx, v) - if err != nil { - return it, err - } - it.RiskTier = data case "statusPageUrl": ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("statusPageUrl")) data, err := ec.unmarshalOString2ᚖstring(ctx, v) @@ -26848,6 +28061,40 @@ func (ec *executionContext) unmarshalInputVendorOrder(ctx context.Context, obj a return it, nil } +func (ec *executionContext) unmarshalInputVendorRiskAssessmentOrder(ctx context.Context, obj any) (types.VendorRiskAssessmentOrder, error) { + var it types.VendorRiskAssessmentOrder + asMap := map[string]any{} + for k, v := range obj.(map[string]any) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"field", "direction"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "field": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("field")) + data, err := ec.unmarshalNVendorRiskAssessmentOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorRiskAssessmentOrderField(ctx, v) + if err != nil { + return it, err + } + it.Field = data + case "direction": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("direction")) + data, err := ec.unmarshalNOrderDirection2githubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐOrderDirection(ctx, v) + if err != nil { + return it, err + } + it.Direction = data + } + } + + return it, nil +} + // endregion **************************** input.gotpl ***************************** // region ************************** interface.gotpl *************************** @@ -26856,6 +28103,13 @@ func (ec *executionContext) _Node(ctx context.Context, sel ast.SelectionSet, obj switch obj := (obj).(type) { case nil: return graphql.Null + case types.VendorRiskAssessment: + return ec._VendorRiskAssessment(ctx, sel, &obj) + case *types.VendorRiskAssessment: + if obj == nil { + return graphql.Null + } + return ec._VendorRiskAssessment(ctx, sel, obj) case types.VendorComplianceReport: return ec._VendorComplianceReport(ctx, sel, &obj) case *types.VendorComplianceReport: @@ -27912,6 +29166,45 @@ func (ec *executionContext) _CreateVendorPayload(ctx context.Context, sel ast.Se return out } +var createVendorRiskAssessmentPayloadImplementors = []string{"CreateVendorRiskAssessmentPayload"} + +func (ec *executionContext) _CreateVendorRiskAssessmentPayload(ctx context.Context, sel ast.SelectionSet, obj *types.CreateVendorRiskAssessmentPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, createVendorRiskAssessmentPayloadImplementors) + + 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("CreateVendorRiskAssessmentPayload") + case "vendorRiskAssessmentEdge": + out.Values[i] = ec._CreateVendorRiskAssessmentPayload_vendorRiskAssessmentEdge(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 deleteControlMesureMappingPayloadImplementors = []string{"DeleteControlMesureMappingPayload"} func (ec *executionContext) _DeleteControlMesureMappingPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteControlMesureMappingPayload) graphql.Marshaler { @@ -29557,6 +30850,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { out.Invalids++ } + case "createVendorRiskAssessment": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_createVendorRiskAssessment(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -31836,6 +33136,42 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o continue } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "riskAssessments": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Vendor_riskAssessments(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "businessOwner": field := field @@ -31910,16 +33246,6 @@ func (ec *executionContext) _Vendor(ctx context.Context, sel ast.SelectionSet, o } case "serviceTerminationAt": out.Values[i] = ec._Vendor_serviceTerminationAt(ctx, field, obj) - case "serviceCriticality": - out.Values[i] = ec._Vendor_serviceCriticality(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } - case "riskTier": - out.Values[i] = ec._Vendor_riskTier(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) - } case "statusPageUrl": out.Values[i] = ec._Vendor_statusPageUrl(ctx, field, obj) case "termsOfServiceUrl": @@ -32292,6 +33618,242 @@ func (ec *executionContext) _VendorEdge(ctx context.Context, sel ast.SelectionSe return out } +var vendorRiskAssessmentImplementors = []string{"VendorRiskAssessment", "Node"} + +func (ec *executionContext) _VendorRiskAssessment(ctx context.Context, sel ast.SelectionSet, obj *types.VendorRiskAssessment) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, vendorRiskAssessmentImplementors) + + 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("VendorRiskAssessment") + case "id": + out.Values[i] = ec._VendorRiskAssessment_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "vendor": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._VendorRiskAssessment_vendor(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "assessedAt": + out.Values[i] = ec._VendorRiskAssessment_assessedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "assessedBy": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._VendorRiskAssessment_assessedBy(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + case "expiresAt": + out.Values[i] = ec._VendorRiskAssessment_expiresAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "dataSensitivity": + out.Values[i] = ec._VendorRiskAssessment_dataSensitivity(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "businessImpact": + out.Values[i] = ec._VendorRiskAssessment_businessImpact(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "notes": + out.Values[i] = ec._VendorRiskAssessment_notes(ctx, field, obj) + case "attachments": + out.Values[i] = ec._VendorRiskAssessment_attachments(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "createdAt": + out.Values[i] = ec._VendorRiskAssessment_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + case "updatedAt": + out.Values[i] = ec._VendorRiskAssessment_updatedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&out.Invalids, 1) + } + 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 vendorRiskAssessmentConnectionImplementors = []string{"VendorRiskAssessmentConnection"} + +func (ec *executionContext) _VendorRiskAssessmentConnection(ctx context.Context, sel ast.SelectionSet, obj *types.VendorRiskAssessmentConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, vendorRiskAssessmentConnectionImplementors) + + 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("VendorRiskAssessmentConnection") + case "edges": + out.Values[i] = ec._VendorRiskAssessmentConnection_edges(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "pageInfo": + out.Values[i] = ec._VendorRiskAssessmentConnection_pageInfo(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 vendorRiskAssessmentEdgeImplementors = []string{"VendorRiskAssessmentEdge"} + +func (ec *executionContext) _VendorRiskAssessmentEdge(ctx context.Context, sel ast.SelectionSet, obj *types.VendorRiskAssessmentEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, vendorRiskAssessmentEdgeImplementors) + + 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("VendorRiskAssessmentEdge") + case "cursor": + out.Values[i] = ec._VendorRiskAssessmentEdge_cursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "node": + out.Values[i] = ec._VendorRiskAssessmentEdge_node(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 viewerImplementors = []string{"Viewer"} func (ec *executionContext) _Viewer(ctx context.Context, sel ast.SelectionSet, obj *types.Viewer) graphql.Marshaler { @@ -32741,6 +34303,37 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se return res } +func (ec *executionContext) unmarshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact(ctx context.Context, v any) (coredata.BusinessImpact, error) { + tmp, err := graphql.UnmarshalString(v) + res := unmarshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact[tmp] + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact(ctx context.Context, sel ast.SelectionSet, v coredata.BusinessImpact) graphql.Marshaler { + res := graphql.MarshalString(marshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact[v]) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +var ( + unmarshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact = map[string]coredata.BusinessImpact{ + "LOW": coredata.BusinessImpactLow, + "MEDIUM": coredata.BusinessImpactMedium, + "HIGH": coredata.BusinessImpactHigh, + "CRITICAL": coredata.BusinessImpactCritical, + } + marshalNBusinessImpact2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐBusinessImpact = map[coredata.BusinessImpact]string{ + coredata.BusinessImpactLow: "LOW", + coredata.BusinessImpactMedium: "MEDIUM", + coredata.BusinessImpactHigh: "HIGH", + coredata.BusinessImpactCritical: "CRITICAL", + } +) + func (ec *executionContext) unmarshalNConfirmEmailInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐConfirmEmailInput(ctx context.Context, v any) (types.ConfirmEmailInput, error) { res, err := ec.unmarshalInputConfirmEmailInput(ctx, v) return res, graphql.ErrorOnPath(ctx, err) @@ -33215,6 +34808,25 @@ func (ec *executionContext) marshalNCreateVendorPayload2ᚖgithubᚗcomᚋgetpro return ec._CreateVendorPayload(ctx, sel, v) } +func (ec *executionContext) unmarshalNCreateVendorRiskAssessmentInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorRiskAssessmentInput(ctx context.Context, v any) (types.CreateVendorRiskAssessmentInput, error) { + res, err := ec.unmarshalInputCreateVendorRiskAssessmentInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNCreateVendorRiskAssessmentPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorRiskAssessmentPayload(ctx context.Context, sel ast.SelectionSet, v types.CreateVendorRiskAssessmentPayload) graphql.Marshaler { + return ec._CreateVendorRiskAssessmentPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNCreateVendorRiskAssessmentPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐCreateVendorRiskAssessmentPayload(ctx context.Context, sel ast.SelectionSet, v *types.CreateVendorRiskAssessmentPayload) 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._CreateVendorRiskAssessmentPayload(ctx, sel, v) +} + func (ec *executionContext) unmarshalNCursorKey2githubᚗcomᚋgetproboᚋproboᚋpkgᚋpageᚐCursorKey(ctx context.Context, v any) (page.CursorKey, error) { res, err := types.UnmarshalCursorKeyScalar(v) return res, graphql.ErrorOnPath(ctx, err) @@ -33230,6 +34842,39 @@ func (ec *executionContext) marshalNCursorKey2githubᚗcomᚋgetproboᚋproboᚋ return res } +func (ec *executionContext) unmarshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity(ctx context.Context, v any) (coredata.DataSensitivity, error) { + tmp, err := graphql.UnmarshalString(v) + res := unmarshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity[tmp] + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity(ctx context.Context, sel ast.SelectionSet, v coredata.DataSensitivity) graphql.Marshaler { + res := graphql.MarshalString(marshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity[v]) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +var ( + unmarshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity = map[string]coredata.DataSensitivity{ + "NONE": coredata.DataSensitivityNone, + "LOW": coredata.DataSensitivityLow, + "MEDIUM": coredata.DataSensitivityMedium, + "HIGH": coredata.DataSensitivityHigh, + "CRITICAL": coredata.DataSensitivityCritical, + } + marshalNDataSensitivity2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐDataSensitivity = map[coredata.DataSensitivity]string{ + coredata.DataSensitivityNone: "NONE", + coredata.DataSensitivityLow: "LOW", + coredata.DataSensitivityMedium: "MEDIUM", + coredata.DataSensitivityHigh: "HIGH", + coredata.DataSensitivityCritical: "CRITICAL", + } +) + func (ec *executionContext) unmarshalNDatetime2timeᚐTime(ctx context.Context, v any) (time.Time, error) { res, err := graphql.UnmarshalTime(v) return res, graphql.ErrorOnPath(ctx, err) @@ -34547,35 +36192,6 @@ var ( } ) -func (ec *executionContext) unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, v any) (coredata.RiskTier, error) { - tmp, err := graphql.UnmarshalString(v) - res := unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[tmp] - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v coredata.RiskTier) graphql.Marshaler { - res := graphql.MarshalString(marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[v]) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -var ( - unmarshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{ - "CRITICAL": coredata.RiskTierCritical, - "SIGNIFICANT": coredata.RiskTierSignificant, - "GENERAL": coredata.RiskTierGeneral, - } - marshalNRiskTier2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{ - coredata.RiskTierCritical: "CRITICAL", - coredata.RiskTierSignificant: "SIGNIFICANT", - coredata.RiskTierGeneral: "GENERAL", - } -) - func (ec *executionContext) unmarshalNRiskTreatment2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTreatment(ctx context.Context, v any) (coredata.RiskTreatment, error) { tmp, err := graphql.UnmarshalString(v) res := unmarshalNRiskTreatment2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTreatment[tmp] @@ -34607,35 +36223,6 @@ var ( } ) -func (ec *executionContext) unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (coredata.ServiceCriticality, error) { - tmp, err := graphql.UnmarshalString(v) - res := unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[tmp] - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v coredata.ServiceCriticality) graphql.Marshaler { - res := graphql.MarshalString(marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[v]) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -var ( - unmarshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{ - "LOW": coredata.ServiceCriticalityLow, - "MEDIUM": coredata.ServiceCriticalityMedium, - "HIGH": coredata.ServiceCriticalityHigh, - } - marshalNServiceCriticality2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{ - coredata.ServiceCriticalityLow: "LOW", - coredata.ServiceCriticalityMedium: "MEDIUM", - coredata.ServiceCriticalityHigh: "HIGH", - } -) - func (ec *executionContext) unmarshalNString2string(ctx context.Context, v any) (string, error) { res, err := graphql.UnmarshalString(v) return res, graphql.ErrorOnPath(ctx, err) @@ -35313,6 +36900,111 @@ func (ec *executionContext) marshalNVendorOrderField2githubᚗcomᚋgetproboᚋp return res } +func (ec *executionContext) marshalNVendorRiskAssessment2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessment(ctx context.Context, sel ast.SelectionSet, v *types.VendorRiskAssessment) 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._VendorRiskAssessment(ctx, sel, v) +} + +func (ec *executionContext) marshalNVendorRiskAssessmentConnection2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentConnection(ctx context.Context, sel ast.SelectionSet, v types.VendorRiskAssessmentConnection) graphql.Marshaler { + return ec._VendorRiskAssessmentConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNVendorRiskAssessmentConnection2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentConnection(ctx context.Context, sel ast.SelectionSet, v *types.VendorRiskAssessmentConnection) 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._VendorRiskAssessmentConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalNVendorRiskAssessmentEdge2ᚕᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.VendorRiskAssessmentEdge) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNVendorRiskAssessmentEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentEdge(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNVendorRiskAssessmentEdge2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentEdge(ctx context.Context, sel ast.SelectionSet, v *types.VendorRiskAssessmentEdge) 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._VendorRiskAssessmentEdge(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNVendorRiskAssessmentOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorRiskAssessmentOrderField(ctx context.Context, v any) (coredata.VendorRiskAssessmentOrderField, error) { + tmp, err := graphql.UnmarshalString(v) + res := unmarshalNVendorRiskAssessmentOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorRiskAssessmentOrderField[tmp] + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNVendorRiskAssessmentOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorRiskAssessmentOrderField(ctx context.Context, sel ast.SelectionSet, v coredata.VendorRiskAssessmentOrderField) graphql.Marshaler { + res := graphql.MarshalString(marshalNVendorRiskAssessmentOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorRiskAssessmentOrderField[v]) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +var ( + unmarshalNVendorRiskAssessmentOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorRiskAssessmentOrderField = map[string]coredata.VendorRiskAssessmentOrderField{ + "CREATED_AT": coredata.VendorRiskAssessmentOrderFieldCreatedAt, + "EXPIRES_AT": coredata.VendorRiskAssessmentOrderFieldExpiresAt, + } + marshalNVendorRiskAssessmentOrderField2githubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐVendorRiskAssessmentOrderField = map[coredata.VendorRiskAssessmentOrderField]string{ + coredata.VendorRiskAssessmentOrderFieldCreatedAt: "CREATED_AT", + coredata.VendorRiskAssessmentOrderFieldExpiresAt: "EXPIRES_AT", + } +) + func (ec *executionContext) marshalNViewer2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐViewer(ctx context.Context, sel ast.SelectionSet, v types.Viewer) graphql.Marshaler { return ec._Viewer(ctx, sel, &v) } @@ -35883,36 +37575,6 @@ func (ec *executionContext) unmarshalORiskOrder2ᚖgithubᚗcomᚋgetproboᚋpro return &res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, v any) (*coredata.RiskTier, error) { - if v == nil { - return nil, nil - } - tmp, err := graphql.UnmarshalString(v) - res := unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[tmp] - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier(ctx context.Context, sel ast.SelectionSet, v *coredata.RiskTier) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalString(marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier[*v]) - return res -} - -var ( - unmarshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[string]coredata.RiskTier{ - "CRITICAL": coredata.RiskTierCritical, - "SIGNIFICANT": coredata.RiskTierSignificant, - "GENERAL": coredata.RiskTierGeneral, - } - marshalORiskTier2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTier = map[coredata.RiskTier]string{ - coredata.RiskTierCritical: "CRITICAL", - coredata.RiskTierSignificant: "SIGNIFICANT", - coredata.RiskTierGeneral: "GENERAL", - } -) - func (ec *executionContext) unmarshalORiskTreatment2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐRiskTreatment(ctx context.Context, v any) (*coredata.RiskTreatment, error) { if v == nil { return nil, nil @@ -35945,36 +37607,6 @@ var ( } ) -func (ec *executionContext) unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, v any) (*coredata.ServiceCriticality, error) { - if v == nil { - return nil, nil - } - tmp, err := graphql.UnmarshalString(v) - res := unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[tmp] - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality(ctx context.Context, sel ast.SelectionSet, v *coredata.ServiceCriticality) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalString(marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality[*v]) - return res -} - -var ( - unmarshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[string]coredata.ServiceCriticality{ - "LOW": coredata.ServiceCriticalityLow, - "MEDIUM": coredata.ServiceCriticalityMedium, - "HIGH": coredata.ServiceCriticalityHigh, - } - marshalOServiceCriticality2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋcoredataᚐServiceCriticality = map[coredata.ServiceCriticality]string{ - coredata.ServiceCriticalityLow: "LOW", - coredata.ServiceCriticalityMedium: "MEDIUM", - coredata.ServiceCriticalityHigh: "HIGH", - } -) - func (ec *executionContext) unmarshalOString2ᚕstringᚄ(ctx context.Context, v any) ([]string, error) { if v == nil { return nil, nil @@ -36103,6 +37735,14 @@ func (ec *executionContext) unmarshalOVendorOrder2ᚖgithubᚗcomᚋgetproboᚋp return &res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalOVendorRiskAssessmentOrder2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐVendorRiskAssessmentOrder(ctx context.Context, v any) (*types.VendorRiskAssessmentOrder, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputVendorRiskAssessmentOrder(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index 6540d6556..9f93fd0d1 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -220,33 +220,45 @@ type CreateTaskPayload struct { } type CreateVendorInput struct { - OrganizationID gid.GID `json:"organizationId"` - Name string `json:"name"` - Description *string `json:"description,omitempty"` - HeadquarterAddress *string `json:"headquarterAddress,omitempty"` - LegalName *string `json:"legalName,omitempty"` - WebsiteURL *string `json:"websiteUrl,omitempty"` - PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` - Category *string `json:"category,omitempty"` - ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` - DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` - Certifications []string `json:"certifications,omitempty"` - SecurityPageURL *string `json:"securityPageUrl,omitempty"` - TrustPageURL *string `json:"trustPageUrl,omitempty"` - StatusPageURL *string `json:"statusPageUrl,omitempty"` - TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` - ServiceStartAt time.Time `json:"serviceStartAt"` - ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"` - ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"` - RiskTier coredata.RiskTier `json:"riskTier"` - BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` - SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` + OrganizationID gid.GID `json:"organizationId"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + HeadquarterAddress *string `json:"headquarterAddress,omitempty"` + LegalName *string `json:"legalName,omitempty"` + WebsiteURL *string `json:"websiteUrl,omitempty"` + PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` + Category *string `json:"category,omitempty"` + ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` + DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` + Certifications []string `json:"certifications,omitempty"` + SecurityPageURL *string `json:"securityPageUrl,omitempty"` + TrustPageURL *string `json:"trustPageUrl,omitempty"` + StatusPageURL *string `json:"statusPageUrl,omitempty"` + TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` + ServiceStartAt time.Time `json:"serviceStartAt"` + ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"` + BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` + SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` } type CreateVendorPayload struct { VendorEdge *VendorEdge `json:"vendorEdge"` } +type CreateVendorRiskAssessmentInput struct { + VendorID gid.GID `json:"vendorId"` + AssessedBy gid.GID `json:"assessedBy"` + ExpiresAt time.Time `json:"expiresAt"` + DataSensitivity coredata.DataSensitivity `json:"dataSensitivity"` + BusinessImpact coredata.BusinessImpact `json:"businessImpact"` + Notes *string `json:"notes,omitempty"` + Attachments []string `json:"attachments,omitempty"` +} + +type CreateVendorRiskAssessmentPayload struct { + VendorRiskAssessmentEdge *VendorRiskAssessmentEdge `json:"vendorRiskAssessmentEdge"` +} + type DeleteControlMesureMappingInput struct { ControlID gid.GID `json:"controlId"` MesureID gid.GID `json:"mesureId"` @@ -744,27 +756,25 @@ type UpdateTaskPayload struct { } type UpdateVendorInput struct { - ID gid.GID `json:"id"` - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - ServiceStartAt *time.Time `json:"serviceStartAt,omitempty"` - ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"` - ServiceCriticality *coredata.ServiceCriticality `json:"serviceCriticality,omitempty"` - RiskTier *coredata.RiskTier `json:"riskTier,omitempty"` - StatusPageURL *string `json:"statusPageUrl,omitempty"` - TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` - PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` - ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` - DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` - WebsiteURL *string `json:"websiteUrl,omitempty"` - LegalName *string `json:"legalName,omitempty"` - HeadquarterAddress *string `json:"headquarterAddress,omitempty"` - Category *string `json:"category,omitempty"` - Certifications []string `json:"certifications,omitempty"` - SecurityPageURL *string `json:"securityPageUrl,omitempty"` - TrustPageURL *string `json:"trustPageUrl,omitempty"` - BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` - SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` + ID gid.GID `json:"id"` + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + ServiceStartAt *time.Time `json:"serviceStartAt,omitempty"` + ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"` + StatusPageURL *string `json:"statusPageUrl,omitempty"` + TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` + PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` + ServiceLevelAgreementURL *string `json:"serviceLevelAgreementUrl,omitempty"` + DataProcessingAgreementURL *string `json:"dataProcessingAgreementUrl,omitempty"` + WebsiteURL *string `json:"websiteUrl,omitempty"` + LegalName *string `json:"legalName,omitempty"` + HeadquarterAddress *string `json:"headquarterAddress,omitempty"` + Category *string `json:"category,omitempty"` + Certifications []string `json:"certifications,omitempty"` + SecurityPageURL *string `json:"securityPageUrl,omitempty"` + TrustPageURL *string `json:"trustPageUrl,omitempty"` + BusinessOwnerID *gid.GID `json:"businessOwnerId,omitempty"` + SecurityOwnerID *gid.GID `json:"securityOwnerId,omitempty"` } type UpdateVendorPayload struct { @@ -809,12 +819,11 @@ type Vendor struct { Name string `json:"name"` Description *string `json:"description,omitempty"` ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"` + RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"` BusinessOwner *People `json:"businessOwner,omitempty"` SecurityOwner *People `json:"securityOwner,omitempty"` ServiceStartAt time.Time `json:"serviceStartAt"` ServiceTerminationAt *time.Time `json:"serviceTerminationAt,omitempty"` - ServiceCriticality coredata.ServiceCriticality `json:"serviceCriticality"` - RiskTier coredata.RiskTier `json:"riskTier"` StatusPageURL *string `json:"statusPageUrl,omitempty"` TermsOfServiceURL *string `json:"termsOfServiceUrl,omitempty"` PrivacyPolicyURL *string `json:"privacyPolicyUrl,omitempty"` @@ -868,6 +877,38 @@ type VendorEdge struct { Node *Vendor `json:"node"` } +type VendorRiskAssessment struct { + ID gid.GID `json:"id"` + Vendor *Vendor `json:"vendor"` + AssessedAt time.Time `json:"assessedAt"` + AssessedBy *People `json:"assessedBy"` + ExpiresAt time.Time `json:"expiresAt"` + DataSensitivity coredata.DataSensitivity `json:"dataSensitivity"` + BusinessImpact coredata.BusinessImpact `json:"businessImpact"` + Notes *string `json:"notes,omitempty"` + Attachments []string `json:"attachments"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +func (VendorRiskAssessment) IsNode() {} +func (this VendorRiskAssessment) GetID() gid.GID { return this.ID } + +type VendorRiskAssessmentConnection struct { + Edges []*VendorRiskAssessmentEdge `json:"edges"` + PageInfo *PageInfo `json:"pageInfo"` +} + +type VendorRiskAssessmentEdge struct { + Cursor page.CursorKey `json:"cursor"` + Node *VendorRiskAssessment `json:"node"` +} + +type VendorRiskAssessmentOrder struct { + Field coredata.VendorRiskAssessmentOrderField `json:"field"` + Direction page.OrderDirection `json:"direction"` +} + type Viewer struct { ID gid.GID `json:"id"` User *User `json:"user"` diff --git a/pkg/server/api/console/v1/types/vendor.go b/pkg/server/api/console/v1/types/vendor.go index ad8bd55c3..58d93998b 100644 --- a/pkg/server/api/console/v1/types/vendor.go +++ b/pkg/server/api/console/v1/types/vendor.go @@ -52,8 +52,6 @@ func NewVendor(v *coredata.Vendor) *Vendor { UpdatedAt: v.UpdatedAt, ServiceStartAt: v.ServiceStartAt, ServiceTerminationAt: v.ServiceTerminationAt, - ServiceCriticality: v.ServiceCriticality, - RiskTier: v.RiskTier, StatusPageURL: v.StatusPageURL, TermsOfServiceURL: v.TermsOfServiceURL, PrivacyPolicyURL: v.PrivacyPolicyURL, diff --git a/pkg/server/api/console/v1/types/vendor_risk_assessment.go b/pkg/server/api/console/v1/types/vendor_risk_assessment.go new file mode 100644 index 000000000..8406dcaf0 --- /dev/null +++ b/pkg/server/api/console/v1/types/vendor_risk_assessment.go @@ -0,0 +1,57 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 types + +import ( + "github.com/getprobo/probo/pkg/coredata" + "github.com/getprobo/probo/pkg/page" +) + +type ( + VendorRiskAssessmentOrderBy OrderBy[coredata.VendorRiskAssessmentOrderField] +) + +func NewVendorRiskAssessmentConnection(p *page.Page[*coredata.VendorRiskAssessment, coredata.VendorRiskAssessmentOrderField]) *VendorRiskAssessmentConnection { + var edges = make([]*VendorRiskAssessmentEdge, len(p.Data)) + + for i := range edges { + edges[i] = NewVendorRiskAssessmentEdge(p.Data[i], p.Cursor.OrderBy.Field) + } + + return &VendorRiskAssessmentConnection{ + Edges: edges, + PageInfo: NewPageInfo(p), + } +} + +func NewVendorRiskAssessmentEdge(c *coredata.VendorRiskAssessment, orderBy coredata.VendorRiskAssessmentOrderField) *VendorRiskAssessmentEdge { + return &VendorRiskAssessmentEdge{ + Cursor: c.CursorKey(orderBy), + Node: NewVendorRiskAssessment(c), + } +} + +func NewVendorRiskAssessment(c *coredata.VendorRiskAssessment) *VendorRiskAssessment { + return &VendorRiskAssessment{ + ID: c.ID, + AssessedAt: c.AssessedAt, + ExpiresAt: c.ExpiresAt, + DataSensitivity: c.DataSensitivity, + BusinessImpact: c.BusinessImpact, + Notes: c.Notes, + CreatedAt: c.CreatedAt, + UpdatedAt: c.UpdatedAt, + } +} diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index 560fcc376..4b4344c39 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -206,6 +206,22 @@ func (r *mutationResolver) CreateOrganization(ctx context.Context, input types.C tenantIDs, _ := ctx.Value(userTenantContextKey).(*[]gid.TenantID) *tenantIDs = append(*tenantIDs, organization.ID.TenantID()) + _, err = svc.Peoples.Create( + ctx, + probo.CreatePeopleRequest{ + OrganizationID: organization.ID, + UserID: &UserFromContext(ctx).ID, + FullName: UserFromContext(ctx).FullName, + PrimaryEmailAddress: UserFromContext(ctx).EmailAddress, + AdditionalEmailAddresses: []string{}, + Kind: coredata.PeopleKindEmployee, + }, + ) + + if err != nil { + return nil, fmt.Errorf("cannot create people: %w", err) + } + return &types.CreateOrganizationPayload{ OrganizationEdge: types.NewOrganizationEdge(organization, coredata.OrganizationOrderFieldCreatedAt), }, nil @@ -363,8 +379,6 @@ func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateV Description: input.Description, ServiceStartAt: input.ServiceStartAt, ServiceTerminationAt: input.ServiceTerminationAt, - ServiceCriticality: input.ServiceCriticality, - RiskTier: input.RiskTier, StatusPageURL: input.StatusPageURL, TermsOfServiceURL: input.TermsOfServiceURL, PrivacyPolicyURL: input.PrivacyPolicyURL, @@ -399,8 +413,6 @@ func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateV Description: input.Description, ServiceStartAt: input.ServiceStartAt, ServiceTerminationAt: input.ServiceTerminationAt, - ServiceCriticality: input.ServiceCriticality, - RiskTier: input.RiskTier, StatusPageURL: input.StatusPageURL, TermsOfServiceURL: input.TermsOfServiceURL, PrivacyPolicyURL: input.PrivacyPolicyURL, @@ -1034,6 +1046,33 @@ func (r *mutationResolver) DeletePolicy(ctx context.Context, input types.DeleteP }, nil } +// CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field. +func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) { + svc := GetTenantService(ctx, r.proboSvc, input.VendorID.TenantID()) + user := UserFromContext(ctx) + + expiresAt := time.Now().Add(time.Hour * 24 * 365) + + vendorRiskAssessment, err := svc.Vendors.CreateRiskAssessment( + ctx, + probo.CreateVendorRiskAssessmentRequest{ + VendorID: input.VendorID, + AssessedByID: user.ID, + ExpiresAt: expiresAt, + DataSensitivity: input.DataSensitivity, + BusinessImpact: input.BusinessImpact, + Notes: input.Notes, + }, + ) + if err != nil { + panic(fmt.Errorf("cannot create vendor risk assessment: %w", err)) + } + + return &types.CreateVendorRiskAssessmentPayload{ + VendorRiskAssessmentEdge: types.NewVendorRiskAssessmentEdge(vendorRiskAssessment, coredata.VendorRiskAssessmentOrderFieldCreatedAt), + }, 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()) @@ -1544,6 +1583,11 @@ func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendo return types.NewVendorComplianceReportConnection(page), nil } +// RiskAssessments is the resolver for the riskAssessments field. +func (r *vendorResolver) RiskAssessments(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorRiskAssessmentOrder) (*types.VendorRiskAssessmentConnection, error) { + panic(fmt.Errorf("not implemented: RiskAssessments - riskAssessments")) +} + // BusinessOwner is the resolver for the businessOwner field. func (r *vendorResolver) BusinessOwner(ctx context.Context, obj *types.Vendor) (*types.People, error) { svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID()) @@ -1610,6 +1654,16 @@ func (r *vendorComplianceReportResolver) FileURL(ctx context.Context, obj *types return fileURL, nil } +// Vendor is the resolver for the vendor field. +func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) { + panic(fmt.Errorf("not implemented: Vendor - vendor")) +} + +// AssessedBy is the resolver for the assessedBy field. +func (r *vendorRiskAssessmentResolver) AssessedBy(ctx context.Context, obj *types.VendorRiskAssessment) (*types.People, error) { + panic(fmt.Errorf("not implemented: AssessedBy - assessedBy")) +} + // Organizations is the resolver for the organizations field. func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrganizationOrder) (*types.OrganizationConnection, error) { user := UserFromContext(ctx) @@ -1673,6 +1727,11 @@ func (r *Resolver) VendorComplianceReport() schema.VendorComplianceReportResolve return &vendorComplianceReportResolver{r} } +// VendorRiskAssessment returns schema.VendorRiskAssessmentResolver implementation. +func (r *Resolver) VendorRiskAssessment() schema.VendorRiskAssessmentResolver { + return &vendorRiskAssessmentResolver{r} +} + // Viewer returns schema.ViewerResolver implementation. func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} } @@ -1688,4 +1747,5 @@ type riskResolver struct{ *Resolver } type taskResolver struct{ *Resolver } type vendorResolver struct{ *Resolver } type vendorComplianceReportResolver struct{ *Resolver } +type vendorRiskAssessmentResolver struct{ *Resolver } type viewerResolver struct{ *Resolver }