From f580ad554c9efe024ba3648046a41572e84cd37b Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 3 Jul 2025 23:19:12 +0200 Subject: [PATCH 01/16] chore; fix Signed-off-by: Miguel Martinez --- app/controlplane/pkg/biz/workflowcontract.go | 18 ++++++++++++++++++ .../pkg/data/ent/schema/workflowcontract.go | 6 +++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index 96f3f7ad8..c835a4fa6 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -594,3 +594,21 @@ func SchemaToRawContract(contract *schemav1.CraftingSchema) (*Contract, error) { return &Contract{Raw: r, Format: unmarshal.RawFormatJSON, Schema: contract}, nil } + +// ContractScope represents a polymorphic relationship between a contract and a project or organization +type ContractScope string + +const ( + ContractScopeProject ContractScope = "project" + ContractScopeOrg ContractScope = "org" +) + +// Values implement https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues +func (ContractScope) Values() (values []string) { + values = append(values, + string(ContractScopeProject), + string(ContractScopeOrg), + ) + + return +} diff --git a/app/controlplane/pkg/data/ent/schema/workflowcontract.go b/app/controlplane/pkg/data/ent/schema/workflowcontract.go index 885c7495f..69fc1265a 100644 --- a/app/controlplane/pkg/data/ent/schema/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/schema/workflowcontract.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import ( "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/google/uuid" ) @@ -44,6 +45,9 @@ func (WorkflowContract) Fields() []ent.Field { }), field.Time("deleted_at").Optional(), field.String("description").Optional(), + // If this value is set, the contract is scoped to a project or organization + field.Enum("scoped_resource_type").GoType(biz.ContractScope("")).Optional(), + field.UUID("scoped_resource_id", uuid.UUID{}).Optional(), } } From 85c7f2a160bde6972ff786c97b2ef30e46da1815 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 3 Jul 2025 23:29:09 +0200 Subject: [PATCH 02/16] feat: add columns Signed-off-by: Miguel Martinez --- .../frontend/google/protobuf/descriptor.ts | 16 +- .../api/gen/temp-openapi/apidocs.swagger.json | 236 ++++++++++++++++++ app/controlplane/pkg/biz/workflowcontract.go | 18 -- app/controlplane/pkg/data/ent/client.go | 16 ++ .../ent/migrate/migrations/20250703212753.sql | 8 + .../pkg/data/ent/migrate/migrations/atlas.sum | 8 + .../pkg/data/ent/migrate/schema.go | 18 +- app/controlplane/pkg/data/ent/mutation.go | 127 +++++++++- app/controlplane/pkg/data/ent/schema-viz.html | 4 + .../pkg/data/ent/schema/workflowcontract.go | 14 +- .../pkg/data/ent/workflowcontract.go | 34 ++- .../pkg/data/ent/workflowcontract/where.go | 58 +++++ .../ent/workflowcontract/workflowcontract.go | 31 +++ .../pkg/data/ent/workflowcontract_create.go | 97 +++++++ .../pkg/data/ent/workflowcontract_query.go | 77 +++++- .../pkg/data/ent/workflowcontract_update.go | 121 +++++++++ 16 files changed, 846 insertions(+), 37 deletions(-) create mode 100644 app/controlplane/api/gen/temp-openapi/apidocs.swagger.json create mode 100644 app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql diff --git a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts index d59b21da4..0d2d2fb32 100644 --- a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts +++ b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts @@ -30,7 +30,7 @@ export enum Edition { EDITION_2024 = 1001, /** * EDITION_1_TEST_ONLY - Placeholder editions for testing feature resolution. These should not be - * used or relied on outside of tests. + * used or relyed on outside of tests. */ EDITION_1_TEST_ONLY = 1, EDITION_2_TEST_ONLY = 2, @@ -875,13 +875,12 @@ export interface MessageOptions { export interface FieldOptions { /** - * NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. * The ctype option instructs the C++ code generator to use a different * representation of the field than it normally would. See the specific * options below. This option is only implemented to support use of * [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - * type "bytes" in the open source release. - * TODO: make ctype actually deprecated. + * type "bytes" in the open source release -- sorry, we'll try to include + * other types in a future version! */ ctype: FieldOptions_CType; /** @@ -1053,7 +1052,11 @@ export function fieldOptions_JSTypeToJSON(object: FieldOptions_JSType): string { } } -/** If set to RETENTION_SOURCE, the option will be omitted from the binary. */ +/** + * If set to RETENTION_SOURCE, the option will be omitted from the binary. + * Note: as of January 2023, support for this is in progress and does not yet + * have an effect (b/264593489). + */ export enum FieldOptions_OptionRetention { RETENTION_UNKNOWN = 0, RETENTION_RUNTIME = 1, @@ -1096,7 +1099,8 @@ export function fieldOptions_OptionRetentionToJSON(object: FieldOptions_OptionRe /** * This indicates the types of entities that the field may apply to when used * as an option. If it is unset, then the field may be freely used as an - * option on any kind of entity. + * option on any kind of entity. Note: as of January 2023, support for this is + * in progress and does not yet have an effect (b/264593489). */ export enum FieldOptions_OptionTargetType { TARGET_TYPE_UNKNOWN = 0, diff --git a/app/controlplane/api/gen/temp-openapi/apidocs.swagger.json b/app/controlplane/api/gen/temp-openapi/apidocs.swagger.json new file mode 100644 index 000000000..876e2ba97 --- /dev/null +++ b/app/controlplane/api/gen/temp-openapi/apidocs.swagger.json @@ -0,0 +1,236 @@ +{ + "swagger": "2.0", + "info": { + "title": "Chainloop Controlplane API", + "termsOfService": "https://chainloop.dev/terms", + "version": "1.0", + "contact": { + "name": "Chainloop Support", + "url": "https://chainloop.dev", + "email": "support@chainloop.dev" + } + }, + "tags": [ + { + "name": "ReferrerService", + "description": "Referrer service for discovering referred content by digest" + } + ], + "host": "cp.chainloop.dev", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/discover/shared/{digest}": { + "get": { + "summary": "Discover public shared referrer", + "description": "Returns the referrer item for a given digest in the public shared index", + "operationId": "ReferrerService_DiscoverPublicShared", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1DiscoverPublicSharedResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "digest", + "description": "Digest is the unique identifier of the referrer to discover", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "kind", + "description": "Kind is the optional type of referrer, i.e CONTAINER_IMAGE, GIT_HEAD, ...\nUsed to filter and resolve ambiguities", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ReferrerService" + ], + "produces": [ + "application/json" + ] + } + }, + "/discover/{digest}": { + "get": { + "summary": "Discover private referrer", + "description": "Returns the referrer item for a given digest in the organizations of the logged-in user", + "operationId": "ReferrerService_DiscoverPrivate", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1ReferrerServiceDiscoverPrivateResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/rpcStatus" + } + } + }, + "parameters": [ + { + "name": "digest", + "description": "Digest is the unique identifier of the referrer to discover", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "kind", + "description": "Kind is the optional type of referrer, i.e CONTAINER_IMAGE, GIT_HEAD, ...\nUsed to filter and resolve ambiguities", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "ReferrerService" + ], + "produces": [ + "application/json" + ] + } + } + }, + "definitions": { + "protobufAny": { + "type": "object", + "properties": { + "@type": { + "type": "string" + } + }, + "additionalProperties": {} + }, + "rpcStatus": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + }, + "details": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/protobufAny" + } + } + } + }, + "v1DiscoverPublicSharedResponse": { + "type": "object", + "properties": { + "result": { + "$ref": "#/definitions/v1ReferrerItem", + "title": "Result is the discovered referrer item" + } + }, + "description": "Response for the DiscoverPublicShared method", + "title": "DiscoverPublicSharedResponse" + }, + "v1ReferrerItem": { + "type": "object", + "properties": { + "digest": { + "type": "string", + "title": "Digest of the referrer, i.e sha256:deadbeef or sha1:beefdead" + }, + "kind": { + "type": "string", + "description": "Kind of referrer, i.e CONTAINER_IMAGE, GIT_HEAD, ..." + }, + "downloadable": { + "type": "boolean", + "title": "Downloadable indicates whether the referrer is downloadable or not from CAS" + }, + "public": { + "type": "boolean", + "title": "Public indicates whether the referrer is public since it belongs to a public workflow" + }, + "references": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1ReferrerItem" + }, + "title": "References contains the list of related referrer items" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "CreatedAt is the timestamp when the referrer was created" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "title": "Metadata contains additional descriptive information about the referrer" + }, + "annotations": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "title": "Annotations are key-value pairs associated with the referrer" + } + }, + "description": "It represents a referrer object in the system", + "title": "ReferrerItem" + }, + "v1ReferrerServiceDiscoverPrivateResponse": { + "type": "object", + "properties": { + "result": { + "$ref": "#/definitions/v1ReferrerItem", + "title": "Result is the discovered referrer item" + } + }, + "description": "Response for the DiscoverPrivate method", + "title": "ReferrerServiceDiscoverPrivateResponse" + } + }, + "securityDefinitions": { + "bearerToken": { + "type": "apiKey", + "description": "Bearer token for authentication", + "name": "Authorization", + "in": "header" + } + }, + "security": [ + { + "bearerToken": [] + } + ], + "externalDocs": { + "description": "Chainloop Official Documentation", + "url": "https://docs.chainloop.dev" + } +} diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index c835a4fa6..96f3f7ad8 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -594,21 +594,3 @@ func SchemaToRawContract(contract *schemav1.CraftingSchema) (*Contract, error) { return &Contract{Raw: r, Format: unmarshal.RawFormatJSON, Schema: contract}, nil } - -// ContractScope represents a polymorphic relationship between a contract and a project or organization -type ContractScope string - -const ( - ContractScopeProject ContractScope = "project" - ContractScopeOrg ContractScope = "org" -) - -// Values implement https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues -func (ContractScope) Values() (values []string) { - values = append(values, - string(ContractScopeProject), - string(ContractScopeOrg), - ) - - return -} diff --git a/app/controlplane/pkg/data/ent/client.go b/app/controlplane/pkg/data/ent/client.go index e1ed0c1c7..a529e22d8 100644 --- a/app/controlplane/pkg/data/ent/client.go +++ b/app/controlplane/pkg/data/ent/client.go @@ -3567,6 +3567,22 @@ func (c *WorkflowContractClient) QueryWorkflows(wc *WorkflowContract) *WorkflowQ return query } +// QueryProject queries the project edge of a WorkflowContract. +func (c *WorkflowContractClient) QueryProject(wc *WorkflowContract) *ProjectQuery { + query := (&ProjectClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := wc.ID + step := sqlgraph.NewStep( + sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, id), + sqlgraph.To(project.Table, project.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, workflowcontract.ProjectTable, workflowcontract.ProjectColumn), + ) + fromV = sqlgraph.Neighbors(wc.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *WorkflowContractClient) Hooks() []Hook { return c.hooks.WorkflowContract diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql b/app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql new file mode 100644 index 000000000..95c413acd --- /dev/null +++ b/app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql @@ -0,0 +1,8 @@ +-- Drop index "workflowcontract_name_organization_workflow_contracts" from table: "workflow_contracts" +DROP INDEX "workflowcontract_name_organization_workflow_contracts"; +-- Modify "workflow_contracts" table +ALTER TABLE "workflow_contracts" ADD COLUMN "project_id" uuid NULL; +-- Create index "workflowcontract_name_organization_workflow_contracts" to table: "workflow_contracts" +CREATE UNIQUE INDEX "workflowcontract_name_organization_workflow_contracts" ON "workflow_contracts" ("name", "organization_workflow_contracts") WHERE ((deleted_at IS NULL) AND (project_id IS NULL)); +-- Create index "workflowcontract_name_project_id" to table: "workflow_contracts" +CREATE UNIQUE INDEX "workflowcontract_name_project_id" ON "workflow_contracts" ("name", "project_id") WHERE ((deleted_at IS NULL) AND (project_id IS NOT NULL)); diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum index c485b7ad1..fa71a0d66 100644 --- a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum @@ -1,4 +1,8 @@ +<<<<<<< HEAD h1:pewT4SIwZxo6E95TRjOvYvsO2AvVZDBRPljhvi6yN3c= +======= +h1:Nqn7kGmL5Hba+3tAbxdDjH6+KvSmunyHZuDIthoGQiU= +>>>>>>> 9b3f353d (feat: add columns) 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -93,5 +97,9 @@ h1:pewT4SIwZxo6E95TRjOvYvsO2AvVZDBRPljhvi6yN3c= 20250626100818.sql h1:MMCQid88eEs4uyCVBgkf5b0VYjyBd1EYRqRISco0rOI= 20250627143634.sql h1:9UdcOm4HdWyJ8bvU/vYkzCslXIpKSn7pM0l/MJHl8n4= 20250702111701.sql h1:Ni7fuL1qU5RGjBzV0XgJi9NkZINGijF8BumPuQ9conM= +<<<<<<< HEAD 20250702112642.sql h1:wrjVS+5h2hs7KNwPRBece5LgAsoEzxN/zNfvCnjoIUw= 20250704090359.sql h1:a0ksfjy2dtzviJL16HbC4eT1xBxy2qFH5mNFOpYlUrA= +======= +20250703212753.sql h1:Hr4sKsM+tlPRp0I9qRLnnkVUNpZ4xTH/XOQJ5nDdbek= +>>>>>>> 9b3f353d (feat: add columns) diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index 497ed716e..5c84720c7 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -642,6 +642,7 @@ var ( {Name: "deleted_at", Type: field.TypeTime, Nullable: true}, {Name: "description", Type: field.TypeString, Nullable: true}, {Name: "organization_workflow_contracts", Type: field.TypeUUID, Nullable: true}, + {Name: "project_id", Type: field.TypeUUID, Nullable: true}, } // WorkflowContractsTable holds the schema information for the "workflow_contracts" table. WorkflowContractsTable = &schema.Table{ @@ -655,6 +656,12 @@ var ( RefColumns: []*schema.Column{OrganizationsColumns[0]}, OnDelete: schema.Cascade, }, + { + Symbol: "workflow_contracts_projects_project", + Columns: []*schema.Column{WorkflowContractsColumns[6]}, + RefColumns: []*schema.Column{ProjectsColumns[0]}, + OnDelete: schema.SetNull, + }, }, Indexes: []*schema.Index{ { @@ -662,7 +669,15 @@ var ( Unique: true, Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[5]}, Annotation: &entsql.IndexAnnotation{ - Where: "deleted_at IS NULL", + Where: "deleted_at IS NULL AND project_id IS NULL", + }, + }, + { + Name: "workflowcontract_name_project_id", + Unique: true, + Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[6]}, + Annotation: &entsql.IndexAnnotation{ + Where: "deleted_at IS NULL AND project_id IS NOT NULL", }, }, }, @@ -933,6 +948,7 @@ func init() { WorkflowsTable.ForeignKeys[2].RefTable = WorkflowContractsTable WorkflowsTable.ForeignKeys[3].RefTable = WorkflowRunsTable WorkflowContractsTable.ForeignKeys[0].RefTable = OrganizationsTable + WorkflowContractsTable.ForeignKeys[1].RefTable = ProjectsTable WorkflowContractVersionsTable.ForeignKeys[0].RefTable = WorkflowContractsTable WorkflowRunsTable.ForeignKeys[0].RefTable = ProjectVersionsTable WorkflowRunsTable.ForeignKeys[1].RefTable = WorkflowsTable diff --git a/app/controlplane/pkg/data/ent/mutation.go b/app/controlplane/pkg/data/ent/mutation.go index 736bfa536..bc1febe77 100644 --- a/app/controlplane/pkg/data/ent/mutation.go +++ b/app/controlplane/pkg/data/ent/mutation.go @@ -15262,6 +15262,8 @@ type WorkflowContractMutation struct { workflows map[uuid.UUID]struct{} removedworkflows map[uuid.UUID]struct{} clearedworkflows bool + project *uuid.UUID + clearedproject bool done bool oldValue func(context.Context) (*WorkflowContract, error) predicates []predicate.WorkflowContract @@ -15541,6 +15543,55 @@ func (m *WorkflowContractMutation) ResetDescription() { delete(m.clearedFields, workflowcontract.FieldDescription) } +// SetProjectID sets the "project_id" field. +func (m *WorkflowContractMutation) SetProjectID(u uuid.UUID) { + m.project = &u +} + +// ProjectID returns the value of the "project_id" field in the mutation. +func (m *WorkflowContractMutation) ProjectID() (r uuid.UUID, exists bool) { + v := m.project + if v == nil { + return + } + return *v, true +} + +// OldProjectID returns the old "project_id" field's value of the WorkflowContract entity. +// If the WorkflowContract object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *WorkflowContractMutation) OldProjectID(ctx context.Context) (v uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProjectID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProjectID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProjectID: %w", err) + } + return oldValue.ProjectID, nil +} + +// ClearProjectID clears the value of the "project_id" field. +func (m *WorkflowContractMutation) ClearProjectID() { + m.project = nil + m.clearedFields[workflowcontract.FieldProjectID] = struct{}{} +} + +// ProjectIDCleared returns if the "project_id" field was cleared in this mutation. +func (m *WorkflowContractMutation) ProjectIDCleared() bool { + _, ok := m.clearedFields[workflowcontract.FieldProjectID] + return ok +} + +// ResetProjectID resets all changes to the "project_id" field. +func (m *WorkflowContractMutation) ResetProjectID() { + m.project = nil + delete(m.clearedFields, workflowcontract.FieldProjectID) +} + // AddVersionIDs adds the "versions" edge to the WorkflowContractVersion entity by ids. func (m *WorkflowContractMutation) AddVersionIDs(ids ...uuid.UUID) { if m.versions == nil { @@ -15688,6 +15739,33 @@ func (m *WorkflowContractMutation) ResetWorkflows() { m.removedworkflows = nil } +// ClearProject clears the "project" edge to the Project entity. +func (m *WorkflowContractMutation) ClearProject() { + m.clearedproject = true + m.clearedFields[workflowcontract.FieldProjectID] = struct{}{} +} + +// ProjectCleared reports if the "project" edge to the Project entity was cleared. +func (m *WorkflowContractMutation) ProjectCleared() bool { + return m.ProjectIDCleared() || m.clearedproject +} + +// ProjectIDs returns the "project" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// ProjectID instead. It exists only for internal usage by the builders. +func (m *WorkflowContractMutation) ProjectIDs() (ids []uuid.UUID) { + if id := m.project; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetProject resets all changes to the "project" edge. +func (m *WorkflowContractMutation) ResetProject() { + m.project = nil + m.clearedproject = false +} + // Where appends a list predicates to the WorkflowContractMutation builder. func (m *WorkflowContractMutation) Where(ps ...predicate.WorkflowContract) { m.predicates = append(m.predicates, ps...) @@ -15722,7 +15800,7 @@ func (m *WorkflowContractMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *WorkflowContractMutation) Fields() []string { - fields := make([]string, 0, 4) + fields := make([]string, 0, 5) if m.name != nil { fields = append(fields, workflowcontract.FieldName) } @@ -15735,6 +15813,9 @@ func (m *WorkflowContractMutation) Fields() []string { if m.description != nil { fields = append(fields, workflowcontract.FieldDescription) } + if m.project != nil { + fields = append(fields, workflowcontract.FieldProjectID) + } return fields } @@ -15751,6 +15832,8 @@ func (m *WorkflowContractMutation) Field(name string) (ent.Value, bool) { return m.DeletedAt() case workflowcontract.FieldDescription: return m.Description() + case workflowcontract.FieldProjectID: + return m.ProjectID() } return nil, false } @@ -15768,6 +15851,8 @@ func (m *WorkflowContractMutation) OldField(ctx context.Context, name string) (e return m.OldDeletedAt(ctx) case workflowcontract.FieldDescription: return m.OldDescription(ctx) + case workflowcontract.FieldProjectID: + return m.OldProjectID(ctx) } return nil, fmt.Errorf("unknown WorkflowContract field %s", name) } @@ -15805,6 +15890,13 @@ func (m *WorkflowContractMutation) SetField(name string, value ent.Value) error } m.SetDescription(v) return nil + case workflowcontract.FieldProjectID: + v, ok := value.(uuid.UUID) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProjectID(v) + return nil } return fmt.Errorf("unknown WorkflowContract field %s", name) } @@ -15841,6 +15933,9 @@ func (m *WorkflowContractMutation) ClearedFields() []string { if m.FieldCleared(workflowcontract.FieldDescription) { fields = append(fields, workflowcontract.FieldDescription) } + if m.FieldCleared(workflowcontract.FieldProjectID) { + fields = append(fields, workflowcontract.FieldProjectID) + } return fields } @@ -15861,6 +15956,9 @@ func (m *WorkflowContractMutation) ClearField(name string) error { case workflowcontract.FieldDescription: m.ClearDescription() return nil + case workflowcontract.FieldProjectID: + m.ClearProjectID() + return nil } return fmt.Errorf("unknown WorkflowContract nullable field %s", name) } @@ -15881,13 +15979,16 @@ func (m *WorkflowContractMutation) ResetField(name string) error { case workflowcontract.FieldDescription: m.ResetDescription() return nil + case workflowcontract.FieldProjectID: + m.ResetProjectID() + return nil } return fmt.Errorf("unknown WorkflowContract field %s", name) } // AddedEdges returns all edge names that were set/added in this mutation. func (m *WorkflowContractMutation) AddedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m.versions != nil { edges = append(edges, workflowcontract.EdgeVersions) } @@ -15897,6 +15998,9 @@ func (m *WorkflowContractMutation) AddedEdges() []string { if m.workflows != nil { edges = append(edges, workflowcontract.EdgeWorkflows) } + if m.project != nil { + edges = append(edges, workflowcontract.EdgeProject) + } return edges } @@ -15920,13 +16024,17 @@ func (m *WorkflowContractMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case workflowcontract.EdgeProject: + if id := m.project; id != nil { + return []ent.Value{*id} + } } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *WorkflowContractMutation) RemovedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m.removedversions != nil { edges = append(edges, workflowcontract.EdgeVersions) } @@ -15958,7 +16066,7 @@ func (m *WorkflowContractMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *WorkflowContractMutation) ClearedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m.clearedversions { edges = append(edges, workflowcontract.EdgeVersions) } @@ -15968,6 +16076,9 @@ func (m *WorkflowContractMutation) ClearedEdges() []string { if m.clearedworkflows { edges = append(edges, workflowcontract.EdgeWorkflows) } + if m.clearedproject { + edges = append(edges, workflowcontract.EdgeProject) + } return edges } @@ -15981,6 +16092,8 @@ func (m *WorkflowContractMutation) EdgeCleared(name string) bool { return m.clearedorganization case workflowcontract.EdgeWorkflows: return m.clearedworkflows + case workflowcontract.EdgeProject: + return m.clearedproject } return false } @@ -15992,6 +16105,9 @@ func (m *WorkflowContractMutation) ClearEdge(name string) error { case workflowcontract.EdgeOrganization: m.ClearOrganization() return nil + case workflowcontract.EdgeProject: + m.ClearProject() + return nil } return fmt.Errorf("unknown WorkflowContract unique edge %s", name) } @@ -16009,6 +16125,9 @@ func (m *WorkflowContractMutation) ResetEdge(name string) error { case workflowcontract.EdgeWorkflows: m.ResetWorkflows() return nil + case workflowcontract.EdgeProject: + m.ResetProject() + return nil } return fmt.Errorf("unknown WorkflowContract edge %s", name) } diff --git a/app/controlplane/pkg/data/ent/schema-viz.html b/app/controlplane/pkg/data/ent/schema-viz.html index 560c592f4..d0fa73e62 100644 --- a/app/controlplane/pkg/data/ent/schema-viz.html +++ b/app/controlplane/pkg/data/ent/schema-viz.html @@ -70,7 +70,11 @@ } +<<<<<<< HEAD const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"last_used_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"context\",\"type\":\"biz.OrgInvitationContext\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); +======= + const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowContract\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); +>>>>>>> 9b3f353d (feat: add columns) const nodes = new vis.DataSet((entGraph.nodes || []).map(n => ({ id: n.id, diff --git a/app/controlplane/pkg/data/ent/schema/workflowcontract.go b/app/controlplane/pkg/data/ent/schema/workflowcontract.go index 69fc1265a..ad400f107 100644 --- a/app/controlplane/pkg/data/ent/schema/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/schema/workflowcontract.go @@ -23,7 +23,6 @@ import ( "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/google/uuid" ) @@ -45,9 +44,8 @@ func (WorkflowContract) Fields() []ent.Field { }), field.Time("deleted_at").Optional(), field.String("description").Optional(), - // If this value is set, the contract is scoped to a project or organization - field.Enum("scoped_resource_type").GoType(biz.ContractScope("")).Optional(), - field.UUID("scoped_resource_id", uuid.UUID{}).Optional(), + // if this value is not set, the contract is an organization level contract + field.UUID("project_id", uuid.UUID{}).Optional(), } } @@ -60,6 +58,7 @@ func (WorkflowContract) Edges() []ent.Edge { Unique(), // A contract can be associated to multiple workflows edge.From("workflows", Workflow.Type).Ref("contract"), + edge.To("project", Project.Type).Field("project_id").Unique(), } } @@ -67,7 +66,12 @@ func (WorkflowContract) Indexes() []ent.Index { return []ent.Index{ // names are unique within a organization and affects only to non-deleted items index.Fields("name").Edges("organization").Unique().Annotations( - entsql.IndexWhere("deleted_at IS NULL"), + entsql.IndexWhere("deleted_at IS NULL AND project_id IS NULL"), + ), + + // for project level contracts, we scope the uniqueness to the project + index.Fields("name").Edges("project").Unique().Annotations( + entsql.IndexWhere("deleted_at IS NULL AND project_id IS NOT NULL"), ), } } diff --git a/app/controlplane/pkg/data/ent/workflowcontract.go b/app/controlplane/pkg/data/ent/workflowcontract.go index f14036398..777421d58 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/workflowcontract.go @@ -10,6 +10,7 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/google/uuid" ) @@ -27,6 +28,8 @@ type WorkflowContract struct { DeletedAt time.Time `json:"deleted_at,omitempty"` // Description holds the value of the "description" field. Description string `json:"description,omitempty"` + // ProjectID holds the value of the "project_id" field. + ProjectID uuid.UUID `json:"project_id,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the WorkflowContractQuery when eager-loading is set. Edges WorkflowContractEdges `json:"edges"` @@ -42,9 +45,11 @@ type WorkflowContractEdges struct { Organization *Organization `json:"organization,omitempty"` // Workflows holds the value of the workflows edge. Workflows []*Workflow `json:"workflows,omitempty"` + // Project holds the value of the project edge. + Project *Project `json:"project,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [3]bool + loadedTypes [4]bool } // VersionsOrErr returns the Versions value or an error if the edge @@ -76,6 +81,17 @@ func (e WorkflowContractEdges) WorkflowsOrErr() ([]*Workflow, error) { return nil, &NotLoadedError{edge: "workflows"} } +// ProjectOrErr returns the Project value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e WorkflowContractEdges) ProjectOrErr() (*Project, error) { + if e.Project != nil { + return e.Project, nil + } else if e.loadedTypes[3] { + return nil, &NotFoundError{label: project.Label} + } + return nil, &NotLoadedError{edge: "project"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*WorkflowContract) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) @@ -85,7 +101,7 @@ func (*WorkflowContract) scanValues(columns []string) ([]any, error) { values[i] = new(sql.NullString) case workflowcontract.FieldCreatedAt, workflowcontract.FieldDeletedAt: values[i] = new(sql.NullTime) - case workflowcontract.FieldID: + case workflowcontract.FieldID, workflowcontract.FieldProjectID: values[i] = new(uuid.UUID) case workflowcontract.ForeignKeys[0]: // organization_workflow_contracts values[i] = &sql.NullScanner{S: new(uuid.UUID)} @@ -134,6 +150,12 @@ func (wc *WorkflowContract) assignValues(columns []string, values []any) error { } else if value.Valid { wc.Description = value.String } + case workflowcontract.FieldProjectID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field project_id", values[i]) + } else if value != nil { + wc.ProjectID = *value + } case workflowcontract.ForeignKeys[0]: if value, ok := values[i].(*sql.NullScanner); !ok { return fmt.Errorf("unexpected type %T for field organization_workflow_contracts", values[i]) @@ -169,6 +191,11 @@ func (wc *WorkflowContract) QueryWorkflows() *WorkflowQuery { return NewWorkflowContractClient(wc.config).QueryWorkflows(wc) } +// QueryProject queries the "project" edge of the WorkflowContract entity. +func (wc *WorkflowContract) QueryProject() *ProjectQuery { + return NewWorkflowContractClient(wc.config).QueryProject(wc) +} + // Update returns a builder for updating this WorkflowContract. // Note that you need to call WorkflowContract.Unwrap() before calling this method if this WorkflowContract // was returned from a transaction, and the transaction was committed or rolled back. @@ -203,6 +230,9 @@ func (wc *WorkflowContract) String() string { builder.WriteString(", ") builder.WriteString("description=") builder.WriteString(wc.Description) + builder.WriteString(", ") + builder.WriteString("project_id=") + builder.WriteString(fmt.Sprintf("%v", wc.ProjectID)) builder.WriteByte(')') return builder.String() } diff --git a/app/controlplane/pkg/data/ent/workflowcontract/where.go b/app/controlplane/pkg/data/ent/workflowcontract/where.go index ad978a7b4..8f83a3076 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract/where.go +++ b/app/controlplane/pkg/data/ent/workflowcontract/where.go @@ -76,6 +76,11 @@ func Description(v string) predicate.WorkflowContract { return predicate.WorkflowContract(sql.FieldEQ(FieldDescription, v)) } +// ProjectID applies equality check predicate on the "project_id" field. It's identical to ProjectIDEQ. +func ProjectID(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldEQ(FieldProjectID, v)) +} + // NameEQ applies the EQ predicate on the "name" field. func NameEQ(v string) predicate.WorkflowContract { return predicate.WorkflowContract(sql.FieldEQ(FieldName, v)) @@ -306,6 +311,36 @@ func DescriptionContainsFold(v string) predicate.WorkflowContract { return predicate.WorkflowContract(sql.FieldContainsFold(FieldDescription, v)) } +// ProjectIDEQ applies the EQ predicate on the "project_id" field. +func ProjectIDEQ(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldEQ(FieldProjectID, v)) +} + +// ProjectIDNEQ applies the NEQ predicate on the "project_id" field. +func ProjectIDNEQ(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldNEQ(FieldProjectID, v)) +} + +// ProjectIDIn applies the In predicate on the "project_id" field. +func ProjectIDIn(vs ...uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldIn(FieldProjectID, vs...)) +} + +// ProjectIDNotIn applies the NotIn predicate on the "project_id" field. +func ProjectIDNotIn(vs ...uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldNotIn(FieldProjectID, vs...)) +} + +// ProjectIDIsNil applies the IsNil predicate on the "project_id" field. +func ProjectIDIsNil() predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldIsNull(FieldProjectID)) +} + +// ProjectIDNotNil applies the NotNil predicate on the "project_id" field. +func ProjectIDNotNil() predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldNotNull(FieldProjectID)) +} + // HasVersions applies the HasEdge predicate on the "versions" edge. func HasVersions() predicate.WorkflowContract { return predicate.WorkflowContract(func(s *sql.Selector) { @@ -375,6 +410,29 @@ func HasWorkflowsWith(preds ...predicate.Workflow) predicate.WorkflowContract { }) } +// HasProject applies the HasEdge predicate on the "project" edge. +func HasProject() predicate.WorkflowContract { + return predicate.WorkflowContract(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, ProjectTable, ProjectColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasProjectWith applies the HasEdge predicate on the "project" edge with a given conditions (other predicates). +func HasProjectWith(preds ...predicate.Project) predicate.WorkflowContract { + return predicate.WorkflowContract(func(s *sql.Selector) { + step := newProjectStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.WorkflowContract) predicate.WorkflowContract { return predicate.WorkflowContract(sql.AndPredicates(predicates...)) diff --git a/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go b/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go index 834bb2a81..9cb71a60f 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go @@ -23,12 +23,16 @@ const ( FieldDeletedAt = "deleted_at" // FieldDescription holds the string denoting the description field in the database. FieldDescription = "description" + // FieldProjectID holds the string denoting the project_id field in the database. + FieldProjectID = "project_id" // EdgeVersions holds the string denoting the versions edge name in mutations. EdgeVersions = "versions" // EdgeOrganization holds the string denoting the organization edge name in mutations. EdgeOrganization = "organization" // EdgeWorkflows holds the string denoting the workflows edge name in mutations. EdgeWorkflows = "workflows" + // EdgeProject holds the string denoting the project edge name in mutations. + EdgeProject = "project" // Table holds the table name of the workflowcontract in the database. Table = "workflow_contracts" // VersionsTable is the table that holds the versions relation/edge. @@ -52,6 +56,13 @@ const ( WorkflowsInverseTable = "workflows" // WorkflowsColumn is the table column denoting the workflows relation/edge. WorkflowsColumn = "workflow_contract" + // ProjectTable is the table that holds the project relation/edge. + ProjectTable = "workflow_contracts" + // ProjectInverseTable is the table name for the Project entity. + // It exists in this package in order to avoid circular dependency with the "project" package. + ProjectInverseTable = "projects" + // ProjectColumn is the table column denoting the project relation/edge. + ProjectColumn = "project_id" ) // Columns holds all SQL columns for workflowcontract fields. @@ -61,6 +72,7 @@ var Columns = []string{ FieldCreatedAt, FieldDeletedAt, FieldDescription, + FieldProjectID, } // ForeignKeys holds the SQL foreign-keys that are owned by the "workflow_contracts" @@ -119,6 +131,11 @@ func ByDescription(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldDescription, opts...).ToFunc() } +// ByProjectID orders the results by the project_id field. +func ByProjectID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldProjectID, opts...).ToFunc() +} + // ByVersionsCount orders the results by versions count. func ByVersionsCount(opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { @@ -153,6 +170,13 @@ func ByWorkflows(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { sqlgraph.OrderByNeighborTerms(s, newWorkflowsStep(), append([]sql.OrderTerm{term}, terms...)...) } } + +// ByProjectField orders the results by project field. +func ByProjectField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newProjectStep(), sql.OrderByField(field, opts...)) + } +} func newVersionsStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), @@ -174,3 +198,10 @@ func newWorkflowsStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, true, WorkflowsTable, WorkflowsColumn), ) } +func newProjectStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(ProjectInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, ProjectTable, ProjectColumn), + ) +} diff --git a/app/controlplane/pkg/data/ent/workflowcontract_create.go b/app/controlplane/pkg/data/ent/workflowcontract_create.go index 9d73e37d8..811d19456 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_create.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_create.go @@ -13,6 +13,7 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontractversion" @@ -75,6 +76,20 @@ func (wcc *WorkflowContractCreate) SetNillableDescription(s *string) *WorkflowCo return wcc } +// SetProjectID sets the "project_id" field. +func (wcc *WorkflowContractCreate) SetProjectID(u uuid.UUID) *WorkflowContractCreate { + wcc.mutation.SetProjectID(u) + return wcc +} + +// SetNillableProjectID sets the "project_id" field if the given value is not nil. +func (wcc *WorkflowContractCreate) SetNillableProjectID(u *uuid.UUID) *WorkflowContractCreate { + if u != nil { + wcc.SetProjectID(*u) + } + return wcc +} + // SetID sets the "id" field. func (wcc *WorkflowContractCreate) SetID(u uuid.UUID) *WorkflowContractCreate { wcc.mutation.SetID(u) @@ -138,6 +153,11 @@ func (wcc *WorkflowContractCreate) AddWorkflows(w ...*Workflow) *WorkflowContrac return wcc.AddWorkflowIDs(ids...) } +// SetProject sets the "project" edge to the Project entity. +func (wcc *WorkflowContractCreate) SetProject(p *Project) *WorkflowContractCreate { + return wcc.SetProjectID(p.ID) +} + // Mutation returns the WorkflowContractMutation object of the builder. func (wcc *WorkflowContractCreate) Mutation() *WorkflowContractMutation { return wcc.mutation @@ -292,6 +312,23 @@ func (wcc *WorkflowContractCreate) createSpec() (*WorkflowContract, *sqlgraph.Cr } _spec.Edges = append(_spec.Edges, edge) } + if nodes := wcc.mutation.ProjectIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: workflowcontract.ProjectTable, + Columns: []string{workflowcontract.ProjectColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.ProjectID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec } @@ -380,6 +417,24 @@ func (u *WorkflowContractUpsert) ClearDescription() *WorkflowContractUpsert { return u } +// SetProjectID sets the "project_id" field. +func (u *WorkflowContractUpsert) SetProjectID(v uuid.UUID) *WorkflowContractUpsert { + u.Set(workflowcontract.FieldProjectID, v) + return u +} + +// UpdateProjectID sets the "project_id" field to the value that was provided on create. +func (u *WorkflowContractUpsert) UpdateProjectID() *WorkflowContractUpsert { + u.SetExcluded(workflowcontract.FieldProjectID) + return u +} + +// ClearProjectID clears the value of the "project_id" field. +func (u *WorkflowContractUpsert) ClearProjectID() *WorkflowContractUpsert { + u.SetNull(workflowcontract.FieldProjectID) + return u +} + // UpdateNewValues updates the mutable fields using the new values that were set on create except the ID field. // Using this option is equivalent to using: // @@ -476,6 +531,27 @@ func (u *WorkflowContractUpsertOne) ClearDescription() *WorkflowContractUpsertOn }) } +// SetProjectID sets the "project_id" field. +func (u *WorkflowContractUpsertOne) SetProjectID(v uuid.UUID) *WorkflowContractUpsertOne { + return u.Update(func(s *WorkflowContractUpsert) { + s.SetProjectID(v) + }) +} + +// UpdateProjectID sets the "project_id" field to the value that was provided on create. +func (u *WorkflowContractUpsertOne) UpdateProjectID() *WorkflowContractUpsertOne { + return u.Update(func(s *WorkflowContractUpsert) { + s.UpdateProjectID() + }) +} + +// ClearProjectID clears the value of the "project_id" field. +func (u *WorkflowContractUpsertOne) ClearProjectID() *WorkflowContractUpsertOne { + return u.Update(func(s *WorkflowContractUpsert) { + s.ClearProjectID() + }) +} + // Exec executes the query. func (u *WorkflowContractUpsertOne) Exec(ctx context.Context) error { if len(u.create.conflict) == 0 { @@ -739,6 +815,27 @@ func (u *WorkflowContractUpsertBulk) ClearDescription() *WorkflowContractUpsertB }) } +// SetProjectID sets the "project_id" field. +func (u *WorkflowContractUpsertBulk) SetProjectID(v uuid.UUID) *WorkflowContractUpsertBulk { + return u.Update(func(s *WorkflowContractUpsert) { + s.SetProjectID(v) + }) +} + +// UpdateProjectID sets the "project_id" field to the value that was provided on create. +func (u *WorkflowContractUpsertBulk) UpdateProjectID() *WorkflowContractUpsertBulk { + return u.Update(func(s *WorkflowContractUpsert) { + s.UpdateProjectID() + }) +} + +// ClearProjectID clears the value of the "project_id" field. +func (u *WorkflowContractUpsertBulk) ClearProjectID() *WorkflowContractUpsertBulk { + return u.Update(func(s *WorkflowContractUpsert) { + s.ClearProjectID() + }) +} + // Exec executes the query. func (u *WorkflowContractUpsertBulk) Exec(ctx context.Context) error { if u.create.err != nil { diff --git a/app/controlplane/pkg/data/ent/workflowcontract_query.go b/app/controlplane/pkg/data/ent/workflowcontract_query.go index 1d2e2652c..6056b7dde 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_query.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_query.go @@ -15,6 +15,7 @@ import ( "entgo.io/ent/schema/field" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/predicate" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontractversion" @@ -31,6 +32,7 @@ type WorkflowContractQuery struct { withVersions *WorkflowContractVersionQuery withOrganization *OrganizationQuery withWorkflows *WorkflowQuery + withProject *ProjectQuery withFKs bool modifiers []func(*sql.Selector) // intermediate query (i.e. traversal path). @@ -135,6 +137,28 @@ func (wcq *WorkflowContractQuery) QueryWorkflows() *WorkflowQuery { return query } +// QueryProject chains the current query on the "project" edge. +func (wcq *WorkflowContractQuery) QueryProject() *ProjectQuery { + query := (&ProjectClient{config: wcq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := wcq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := wcq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, selector), + sqlgraph.To(project.Table, project.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, workflowcontract.ProjectTable, workflowcontract.ProjectColumn), + ) + fromU = sqlgraph.SetNeighbors(wcq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first WorkflowContract entity from the query. // Returns a *NotFoundError when no WorkflowContract was found. func (wcq *WorkflowContractQuery) First(ctx context.Context) (*WorkflowContract, error) { @@ -330,6 +354,7 @@ func (wcq *WorkflowContractQuery) Clone() *WorkflowContractQuery { withVersions: wcq.withVersions.Clone(), withOrganization: wcq.withOrganization.Clone(), withWorkflows: wcq.withWorkflows.Clone(), + withProject: wcq.withProject.Clone(), // clone intermediate query. sql: wcq.sql.Clone(), path: wcq.path, @@ -370,6 +395,17 @@ func (wcq *WorkflowContractQuery) WithWorkflows(opts ...func(*WorkflowQuery)) *W return wcq } +// WithProject tells the query-builder to eager-load the nodes that are connected to +// the "project" edge. The optional arguments are used to configure the query builder of the edge. +func (wcq *WorkflowContractQuery) WithProject(opts ...func(*ProjectQuery)) *WorkflowContractQuery { + query := (&ProjectClient{config: wcq.config}).Query() + for _, opt := range opts { + opt(query) + } + wcq.withProject = query + return wcq +} + // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -449,10 +485,11 @@ func (wcq *WorkflowContractQuery) sqlAll(ctx context.Context, hooks ...queryHook nodes = []*WorkflowContract{} withFKs = wcq.withFKs _spec = wcq.querySpec() - loadedTypes = [3]bool{ + loadedTypes = [4]bool{ wcq.withVersions != nil, wcq.withOrganization != nil, wcq.withWorkflows != nil, + wcq.withProject != nil, } ) if wcq.withOrganization != nil { @@ -502,6 +539,12 @@ func (wcq *WorkflowContractQuery) sqlAll(ctx context.Context, hooks ...queryHook return nil, err } } + if query := wcq.withProject; query != nil { + if err := wcq.loadProject(ctx, query, nodes, nil, + func(n *WorkflowContract, e *Project) { n.Edges.Project = e }); err != nil { + return nil, err + } + } return nodes, nil } @@ -599,6 +642,35 @@ func (wcq *WorkflowContractQuery) loadWorkflows(ctx context.Context, query *Work } return nil } +func (wcq *WorkflowContractQuery) loadProject(ctx context.Context, query *ProjectQuery, nodes []*WorkflowContract, init func(*WorkflowContract), assign func(*WorkflowContract, *Project)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*WorkflowContract) + for i := range nodes { + fk := nodes[i].ProjectID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(project.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "project_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} func (wcq *WorkflowContractQuery) sqlCount(ctx context.Context) (int, error) { _spec := wcq.querySpec() @@ -628,6 +700,9 @@ func (wcq *WorkflowContractQuery) querySpec() *sqlgraph.QuerySpec { _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) } } + if wcq.withProject != nil { + _spec.Node.AddColumnOnce(workflowcontract.FieldProjectID) + } } if ps := wcq.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { diff --git a/app/controlplane/pkg/data/ent/workflowcontract_update.go b/app/controlplane/pkg/data/ent/workflowcontract_update.go index d83e6f222..3b4059802 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_update.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_update.go @@ -13,6 +13,7 @@ import ( "entgo.io/ent/schema/field" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/predicate" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontractversion" @@ -73,6 +74,26 @@ func (wcu *WorkflowContractUpdate) ClearDescription() *WorkflowContractUpdate { return wcu } +// SetProjectID sets the "project_id" field. +func (wcu *WorkflowContractUpdate) SetProjectID(u uuid.UUID) *WorkflowContractUpdate { + wcu.mutation.SetProjectID(u) + return wcu +} + +// SetNillableProjectID sets the "project_id" field if the given value is not nil. +func (wcu *WorkflowContractUpdate) SetNillableProjectID(u *uuid.UUID) *WorkflowContractUpdate { + if u != nil { + wcu.SetProjectID(*u) + } + return wcu +} + +// ClearProjectID clears the value of the "project_id" field. +func (wcu *WorkflowContractUpdate) ClearProjectID() *WorkflowContractUpdate { + wcu.mutation.ClearProjectID() + return wcu +} + // AddVersionIDs adds the "versions" edge to the WorkflowContractVersion entity by IDs. func (wcu *WorkflowContractUpdate) AddVersionIDs(ids ...uuid.UUID) *WorkflowContractUpdate { wcu.mutation.AddVersionIDs(ids...) @@ -122,6 +143,11 @@ func (wcu *WorkflowContractUpdate) AddWorkflows(w ...*Workflow) *WorkflowContrac return wcu.AddWorkflowIDs(ids...) } +// SetProject sets the "project" edge to the Project entity. +func (wcu *WorkflowContractUpdate) SetProject(p *Project) *WorkflowContractUpdate { + return wcu.SetProjectID(p.ID) +} + // Mutation returns the WorkflowContractMutation object of the builder. func (wcu *WorkflowContractUpdate) Mutation() *WorkflowContractMutation { return wcu.mutation @@ -175,6 +201,12 @@ func (wcu *WorkflowContractUpdate) RemoveWorkflows(w ...*Workflow) *WorkflowCont return wcu.RemoveWorkflowIDs(ids...) } +// ClearProject clears the "project" edge to the Project entity. +func (wcu *WorkflowContractUpdate) ClearProject() *WorkflowContractUpdate { + wcu.mutation.ClearProject() + return wcu +} + // Save executes the query and returns the number of nodes affected by the update operation. func (wcu *WorkflowContractUpdate) Save(ctx context.Context) (int, error) { return withHooks(ctx, wcu.sqlSave, wcu.mutation, wcu.hooks) @@ -348,6 +380,35 @@ func (wcu *WorkflowContractUpdate) sqlSave(ctx context.Context) (n int, err erro } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if wcu.mutation.ProjectCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: workflowcontract.ProjectTable, + Columns: []string{workflowcontract.ProjectColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := wcu.mutation.ProjectIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: workflowcontract.ProjectTable, + Columns: []string{workflowcontract.ProjectColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _spec.AddModifiers(wcu.modifiers...) if n, err = sqlgraph.UpdateNodes(ctx, wcu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { @@ -410,6 +471,26 @@ func (wcuo *WorkflowContractUpdateOne) ClearDescription() *WorkflowContractUpdat return wcuo } +// SetProjectID sets the "project_id" field. +func (wcuo *WorkflowContractUpdateOne) SetProjectID(u uuid.UUID) *WorkflowContractUpdateOne { + wcuo.mutation.SetProjectID(u) + return wcuo +} + +// SetNillableProjectID sets the "project_id" field if the given value is not nil. +func (wcuo *WorkflowContractUpdateOne) SetNillableProjectID(u *uuid.UUID) *WorkflowContractUpdateOne { + if u != nil { + wcuo.SetProjectID(*u) + } + return wcuo +} + +// ClearProjectID clears the value of the "project_id" field. +func (wcuo *WorkflowContractUpdateOne) ClearProjectID() *WorkflowContractUpdateOne { + wcuo.mutation.ClearProjectID() + return wcuo +} + // AddVersionIDs adds the "versions" edge to the WorkflowContractVersion entity by IDs. func (wcuo *WorkflowContractUpdateOne) AddVersionIDs(ids ...uuid.UUID) *WorkflowContractUpdateOne { wcuo.mutation.AddVersionIDs(ids...) @@ -459,6 +540,11 @@ func (wcuo *WorkflowContractUpdateOne) AddWorkflows(w ...*Workflow) *WorkflowCon return wcuo.AddWorkflowIDs(ids...) } +// SetProject sets the "project" edge to the Project entity. +func (wcuo *WorkflowContractUpdateOne) SetProject(p *Project) *WorkflowContractUpdateOne { + return wcuo.SetProjectID(p.ID) +} + // Mutation returns the WorkflowContractMutation object of the builder. func (wcuo *WorkflowContractUpdateOne) Mutation() *WorkflowContractMutation { return wcuo.mutation @@ -512,6 +598,12 @@ func (wcuo *WorkflowContractUpdateOne) RemoveWorkflows(w ...*Workflow) *Workflow return wcuo.RemoveWorkflowIDs(ids...) } +// ClearProject clears the "project" edge to the Project entity. +func (wcuo *WorkflowContractUpdateOne) ClearProject() *WorkflowContractUpdateOne { + wcuo.mutation.ClearProject() + return wcuo +} + // Where appends a list predicates to the WorkflowContractUpdate builder. func (wcuo *WorkflowContractUpdateOne) Where(ps ...predicate.WorkflowContract) *WorkflowContractUpdateOne { wcuo.mutation.Where(ps...) @@ -715,6 +807,35 @@ func (wcuo *WorkflowContractUpdateOne) sqlSave(ctx context.Context) (_node *Work } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if wcuo.mutation.ProjectCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: workflowcontract.ProjectTable, + Columns: []string{workflowcontract.ProjectColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := wcuo.mutation.ProjectIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: workflowcontract.ProjectTable, + Columns: []string{workflowcontract.ProjectColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _spec.AddModifiers(wcuo.modifiers...) _node = &WorkflowContract{config: wcuo.config} _spec.Assign = _node.assignValues From 5dc5b15b0511a6ecdaa3cfaf3034145b52c85000 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 4 Jul 2025 11:06:27 +0200 Subject: [PATCH 03/16] fix tests Signed-off-by: Miguel Martinez --- app/controlplane/pkg/biz/workflowcontract.go | 18 + app/controlplane/pkg/data/ent/client.go | 32 -- .../ent/migrate/migrations/20250703212753.sql | 8 - .../pkg/data/ent/migrate/migrations/atlas.sum | 8 + .../pkg/data/ent/migrate/schema.go | 26 +- app/controlplane/pkg/data/ent/mutation.go | 296 ++++++++-------- app/controlplane/pkg/data/ent/schema-viz.html | 4 + .../pkg/data/ent/schema/workflowcontract.go | 19 +- .../pkg/data/ent/workflowcontract.go | 72 ++-- .../pkg/data/ent/workflowcontract/where.go | 149 ++++---- .../ent/workflowcontract/workflowcontract.go | 78 ++--- .../pkg/data/ent/workflowcontract_create.go | 214 +++++++----- .../pkg/data/ent/workflowcontract_query.go | 185 +--------- .../pkg/data/ent/workflowcontract_update.go | 317 ++++++------------ go.sum | 1 + 15 files changed, 552 insertions(+), 875 deletions(-) delete mode 100644 app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index 96f3f7ad8..c835a4fa6 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -594,3 +594,21 @@ func SchemaToRawContract(contract *schemav1.CraftingSchema) (*Contract, error) { return &Contract{Raw: r, Format: unmarshal.RawFormatJSON, Schema: contract}, nil } + +// ContractScope represents a polymorphic relationship between a contract and a project or organization +type ContractScope string + +const ( + ContractScopeProject ContractScope = "project" + ContractScopeOrg ContractScope = "org" +) + +// Values implement https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues +func (ContractScope) Values() (values []string) { + values = append(values, + string(ContractScopeProject), + string(ContractScopeOrg), + ) + + return +} diff --git a/app/controlplane/pkg/data/ent/client.go b/app/controlplane/pkg/data/ent/client.go index a529e22d8..5d44cdfa1 100644 --- a/app/controlplane/pkg/data/ent/client.go +++ b/app/controlplane/pkg/data/ent/client.go @@ -3535,22 +3535,6 @@ func (c *WorkflowContractClient) QueryVersions(wc *WorkflowContract) *WorkflowCo return query } -// QueryOrganization queries the organization edge of a WorkflowContract. -func (c *WorkflowContractClient) QueryOrganization(wc *WorkflowContract) *OrganizationQuery { - query := (&OrganizationClient{config: c.config}).Query() - query.path = func(context.Context) (fromV *sql.Selector, _ error) { - id := wc.ID - step := sqlgraph.NewStep( - sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, id), - sqlgraph.To(organization.Table, organization.FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, workflowcontract.OrganizationTable, workflowcontract.OrganizationColumn), - ) - fromV = sqlgraph.Neighbors(wc.driver.Dialect(), step) - return fromV, nil - } - return query -} - // QueryWorkflows queries the workflows edge of a WorkflowContract. func (c *WorkflowContractClient) QueryWorkflows(wc *WorkflowContract) *WorkflowQuery { query := (&WorkflowClient{config: c.config}).Query() @@ -3567,22 +3551,6 @@ func (c *WorkflowContractClient) QueryWorkflows(wc *WorkflowContract) *WorkflowQ return query } -// QueryProject queries the project edge of a WorkflowContract. -func (c *WorkflowContractClient) QueryProject(wc *WorkflowContract) *ProjectQuery { - query := (&ProjectClient{config: c.config}).Query() - query.path = func(context.Context) (fromV *sql.Selector, _ error) { - id := wc.ID - step := sqlgraph.NewStep( - sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, id), - sqlgraph.To(project.Table, project.FieldID), - sqlgraph.Edge(sqlgraph.M2O, false, workflowcontract.ProjectTable, workflowcontract.ProjectColumn), - ) - fromV = sqlgraph.Neighbors(wc.driver.Dialect(), step) - return fromV, nil - } - return query -} - // Hooks returns the client hooks. func (c *WorkflowContractClient) Hooks() []Hook { return c.hooks.WorkflowContract diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql b/app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql deleted file mode 100644 index 95c413acd..000000000 --- a/app/controlplane/pkg/data/ent/migrate/migrations/20250703212753.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Drop index "workflowcontract_name_organization_workflow_contracts" from table: "workflow_contracts" -DROP INDEX "workflowcontract_name_organization_workflow_contracts"; --- Modify "workflow_contracts" table -ALTER TABLE "workflow_contracts" ADD COLUMN "project_id" uuid NULL; --- Create index "workflowcontract_name_organization_workflow_contracts" to table: "workflow_contracts" -CREATE UNIQUE INDEX "workflowcontract_name_organization_workflow_contracts" ON "workflow_contracts" ("name", "organization_workflow_contracts") WHERE ((deleted_at IS NULL) AND (project_id IS NULL)); --- Create index "workflowcontract_name_project_id" to table: "workflow_contracts" -CREATE UNIQUE INDEX "workflowcontract_name_project_id" ON "workflow_contracts" ("name", "project_id") WHERE ((deleted_at IS NULL) AND (project_id IS NOT NULL)); diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum index fa71a0d66..a74777b78 100644 --- a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum @@ -1,8 +1,12 @@ <<<<<<< HEAD +<<<<<<< HEAD h1:pewT4SIwZxo6E95TRjOvYvsO2AvVZDBRPljhvi6yN3c= ======= h1:Nqn7kGmL5Hba+3tAbxdDjH6+KvSmunyHZuDIthoGQiU= >>>>>>> 9b3f353d (feat: add columns) +======= +h1:oR9RWah9qFLH+GgYn2+C1UpTH2Z82Zj36QLGWRG5X+4= +>>>>>>> 7a8275ef (fix tests) 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -102,4 +106,8 @@ h1:Nqn7kGmL5Hba+3tAbxdDjH6+KvSmunyHZuDIthoGQiU= 20250704090359.sql h1:a0ksfjy2dtzviJL16HbC4eT1xBxy2qFH5mNFOpYlUrA= ======= 20250703212753.sql h1:Hr4sKsM+tlPRp0I9qRLnnkVUNpZ4xTH/XOQJ5nDdbek= +<<<<<<< HEAD >>>>>>> 9b3f353d (feat: add columns) +======= +20250704090525.sql h1:VO/Kf+I0GJDfL2FaHk36YZ7f6uY9VrHjrP3EuQAidHM= +>>>>>>> 7a8275ef (fix tests) diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index 5c84720c7..205dcce76 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -641,8 +641,9 @@ var ( {Name: "created_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, {Name: "deleted_at", Type: field.TypeTime, Nullable: true}, {Name: "description", Type: field.TypeString, Nullable: true}, + {Name: "scoped_resource_type", Type: field.TypeEnum, Nullable: true, Enums: []string{"project", "org"}}, + {Name: "scoped_resource_id", Type: field.TypeUUID, Nullable: true}, {Name: "organization_workflow_contracts", Type: field.TypeUUID, Nullable: true}, - {Name: "project_id", Type: field.TypeUUID, Nullable: true}, } // WorkflowContractsTable holds the schema information for the "workflow_contracts" table. WorkflowContractsTable = &schema.Table{ @@ -652,32 +653,18 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "workflow_contracts_organizations_workflow_contracts", - Columns: []*schema.Column{WorkflowContractsColumns[5]}, + Columns: []*schema.Column{WorkflowContractsColumns[7]}, RefColumns: []*schema.Column{OrganizationsColumns[0]}, OnDelete: schema.Cascade, }, - { - Symbol: "workflow_contracts_projects_project", - Columns: []*schema.Column{WorkflowContractsColumns[6]}, - RefColumns: []*schema.Column{ProjectsColumns[0]}, - OnDelete: schema.SetNull, - }, }, Indexes: []*schema.Index{ { - Name: "workflowcontract_name_organization_workflow_contracts", + Name: "workflowcontract_name_scoped_resource_type_scoped_resource_id", Unique: true, - Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[5]}, + Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[5], WorkflowContractsColumns[6]}, Annotation: &entsql.IndexAnnotation{ - Where: "deleted_at IS NULL AND project_id IS NULL", - }, - }, - { - Name: "workflowcontract_name_project_id", - Unique: true, - Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[6]}, - Annotation: &entsql.IndexAnnotation{ - Where: "deleted_at IS NULL AND project_id IS NOT NULL", + Where: "deleted_at IS NULL", }, }, }, @@ -948,7 +935,6 @@ func init() { WorkflowsTable.ForeignKeys[2].RefTable = WorkflowContractsTable WorkflowsTable.ForeignKeys[3].RefTable = WorkflowRunsTable WorkflowContractsTable.ForeignKeys[0].RefTable = OrganizationsTable - WorkflowContractsTable.ForeignKeys[1].RefTable = ProjectsTable WorkflowContractVersionsTable.ForeignKeys[0].RefTable = WorkflowContractsTable WorkflowRunsTable.ForeignKeys[0].RefTable = ProjectVersionsTable WorkflowRunsTable.ForeignKeys[1].RefTable = WorkflowsTable diff --git a/app/controlplane/pkg/data/ent/mutation.go b/app/controlplane/pkg/data/ent/mutation.go index bc1febe77..376a8d024 100644 --- a/app/controlplane/pkg/data/ent/mutation.go +++ b/app/controlplane/pkg/data/ent/mutation.go @@ -15246,27 +15246,25 @@ func (m *WorkflowMutation) ResetEdge(name string) error { // WorkflowContractMutation represents an operation that mutates the WorkflowContract nodes in the graph. type WorkflowContractMutation struct { config - op Op - typ string - id *uuid.UUID - name *string - created_at *time.Time - deleted_at *time.Time - description *string - clearedFields map[string]struct{} - versions map[uuid.UUID]struct{} - removedversions map[uuid.UUID]struct{} - clearedversions bool - organization *uuid.UUID - clearedorganization bool - workflows map[uuid.UUID]struct{} - removedworkflows map[uuid.UUID]struct{} - clearedworkflows bool - project *uuid.UUID - clearedproject bool - done bool - oldValue func(context.Context) (*WorkflowContract, error) - predicates []predicate.WorkflowContract + op Op + typ string + id *uuid.UUID + name *string + created_at *time.Time + deleted_at *time.Time + description *string + scoped_resource_type *biz.ContractScope + scoped_resource_id *uuid.UUID + clearedFields map[string]struct{} + versions map[uuid.UUID]struct{} + removedversions map[uuid.UUID]struct{} + clearedversions bool + workflows map[uuid.UUID]struct{} + removedworkflows map[uuid.UUID]struct{} + clearedworkflows bool + done bool + oldValue func(context.Context) (*WorkflowContract, error) + predicates []predicate.WorkflowContract } var _ ent.Mutation = (*WorkflowContractMutation)(nil) @@ -15543,53 +15541,102 @@ func (m *WorkflowContractMutation) ResetDescription() { delete(m.clearedFields, workflowcontract.FieldDescription) } -// SetProjectID sets the "project_id" field. -func (m *WorkflowContractMutation) SetProjectID(u uuid.UUID) { - m.project = &u +// SetScopedResourceType sets the "scoped_resource_type" field. +func (m *WorkflowContractMutation) SetScopedResourceType(bs biz.ContractScope) { + m.scoped_resource_type = &bs } -// ProjectID returns the value of the "project_id" field in the mutation. -func (m *WorkflowContractMutation) ProjectID() (r uuid.UUID, exists bool) { - v := m.project +// ScopedResourceType returns the value of the "scoped_resource_type" field in the mutation. +func (m *WorkflowContractMutation) ScopedResourceType() (r biz.ContractScope, exists bool) { + v := m.scoped_resource_type if v == nil { return } return *v, true } -// OldProjectID returns the old "project_id" field's value of the WorkflowContract entity. +// OldScopedResourceType returns the old "scoped_resource_type" field's value of the WorkflowContract entity. // If the WorkflowContract object wasn't provided to the builder, the object is fetched from the database. // An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *WorkflowContractMutation) OldProjectID(ctx context.Context) (v uuid.UUID, err error) { +func (m *WorkflowContractMutation) OldScopedResourceType(ctx context.Context) (v biz.ContractScope, err error) { if !m.op.Is(OpUpdateOne) { - return v, errors.New("OldProjectID is only allowed on UpdateOne operations") + return v, errors.New("OldScopedResourceType is only allowed on UpdateOne operations") } if m.id == nil || m.oldValue == nil { - return v, errors.New("OldProjectID requires an ID field in the mutation") + return v, errors.New("OldScopedResourceType requires an ID field in the mutation") } oldValue, err := m.oldValue(ctx) if err != nil { - return v, fmt.Errorf("querying old value for OldProjectID: %w", err) + return v, fmt.Errorf("querying old value for OldScopedResourceType: %w", err) } - return oldValue.ProjectID, nil + return oldValue.ScopedResourceType, nil } -// ClearProjectID clears the value of the "project_id" field. -func (m *WorkflowContractMutation) ClearProjectID() { - m.project = nil - m.clearedFields[workflowcontract.FieldProjectID] = struct{}{} +// ClearScopedResourceType clears the value of the "scoped_resource_type" field. +func (m *WorkflowContractMutation) ClearScopedResourceType() { + m.scoped_resource_type = nil + m.clearedFields[workflowcontract.FieldScopedResourceType] = struct{}{} } -// ProjectIDCleared returns if the "project_id" field was cleared in this mutation. -func (m *WorkflowContractMutation) ProjectIDCleared() bool { - _, ok := m.clearedFields[workflowcontract.FieldProjectID] +// ScopedResourceTypeCleared returns if the "scoped_resource_type" field was cleared in this mutation. +func (m *WorkflowContractMutation) ScopedResourceTypeCleared() bool { + _, ok := m.clearedFields[workflowcontract.FieldScopedResourceType] return ok } -// ResetProjectID resets all changes to the "project_id" field. -func (m *WorkflowContractMutation) ResetProjectID() { - m.project = nil - delete(m.clearedFields, workflowcontract.FieldProjectID) +// ResetScopedResourceType resets all changes to the "scoped_resource_type" field. +func (m *WorkflowContractMutation) ResetScopedResourceType() { + m.scoped_resource_type = nil + delete(m.clearedFields, workflowcontract.FieldScopedResourceType) +} + +// SetScopedResourceID sets the "scoped_resource_id" field. +func (m *WorkflowContractMutation) SetScopedResourceID(u uuid.UUID) { + m.scoped_resource_id = &u +} + +// ScopedResourceID returns the value of the "scoped_resource_id" field in the mutation. +func (m *WorkflowContractMutation) ScopedResourceID() (r uuid.UUID, exists bool) { + v := m.scoped_resource_id + if v == nil { + return + } + return *v, true +} + +// OldScopedResourceID returns the old "scoped_resource_id" field's value of the WorkflowContract entity. +// If the WorkflowContract object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *WorkflowContractMutation) OldScopedResourceID(ctx context.Context) (v uuid.UUID, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldScopedResourceID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldScopedResourceID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldScopedResourceID: %w", err) + } + return oldValue.ScopedResourceID, nil +} + +// ClearScopedResourceID clears the value of the "scoped_resource_id" field. +func (m *WorkflowContractMutation) ClearScopedResourceID() { + m.scoped_resource_id = nil + m.clearedFields[workflowcontract.FieldScopedResourceID] = struct{}{} +} + +// ScopedResourceIDCleared returns if the "scoped_resource_id" field was cleared in this mutation. +func (m *WorkflowContractMutation) ScopedResourceIDCleared() bool { + _, ok := m.clearedFields[workflowcontract.FieldScopedResourceID] + return ok +} + +// ResetScopedResourceID resets all changes to the "scoped_resource_id" field. +func (m *WorkflowContractMutation) ResetScopedResourceID() { + m.scoped_resource_id = nil + delete(m.clearedFields, workflowcontract.FieldScopedResourceID) } // AddVersionIDs adds the "versions" edge to the WorkflowContractVersion entity by ids. @@ -15646,45 +15693,6 @@ func (m *WorkflowContractMutation) ResetVersions() { m.removedversions = nil } -// SetOrganizationID sets the "organization" edge to the Organization entity by id. -func (m *WorkflowContractMutation) SetOrganizationID(id uuid.UUID) { - m.organization = &id -} - -// ClearOrganization clears the "organization" edge to the Organization entity. -func (m *WorkflowContractMutation) ClearOrganization() { - m.clearedorganization = true -} - -// OrganizationCleared reports if the "organization" edge to the Organization entity was cleared. -func (m *WorkflowContractMutation) OrganizationCleared() bool { - return m.clearedorganization -} - -// OrganizationID returns the "organization" edge ID in the mutation. -func (m *WorkflowContractMutation) OrganizationID() (id uuid.UUID, exists bool) { - if m.organization != nil { - return *m.organization, true - } - return -} - -// OrganizationIDs returns the "organization" edge IDs in the mutation. -// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use -// OrganizationID instead. It exists only for internal usage by the builders. -func (m *WorkflowContractMutation) OrganizationIDs() (ids []uuid.UUID) { - if id := m.organization; id != nil { - ids = append(ids, *id) - } - return -} - -// ResetOrganization resets all changes to the "organization" edge. -func (m *WorkflowContractMutation) ResetOrganization() { - m.organization = nil - m.clearedorganization = false -} - // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by ids. func (m *WorkflowContractMutation) AddWorkflowIDs(ids ...uuid.UUID) { if m.workflows == nil { @@ -15739,33 +15747,6 @@ func (m *WorkflowContractMutation) ResetWorkflows() { m.removedworkflows = nil } -// ClearProject clears the "project" edge to the Project entity. -func (m *WorkflowContractMutation) ClearProject() { - m.clearedproject = true - m.clearedFields[workflowcontract.FieldProjectID] = struct{}{} -} - -// ProjectCleared reports if the "project" edge to the Project entity was cleared. -func (m *WorkflowContractMutation) ProjectCleared() bool { - return m.ProjectIDCleared() || m.clearedproject -} - -// ProjectIDs returns the "project" edge IDs in the mutation. -// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use -// ProjectID instead. It exists only for internal usage by the builders. -func (m *WorkflowContractMutation) ProjectIDs() (ids []uuid.UUID) { - if id := m.project; id != nil { - ids = append(ids, *id) - } - return -} - -// ResetProject resets all changes to the "project" edge. -func (m *WorkflowContractMutation) ResetProject() { - m.project = nil - m.clearedproject = false -} - // Where appends a list predicates to the WorkflowContractMutation builder. func (m *WorkflowContractMutation) Where(ps ...predicate.WorkflowContract) { m.predicates = append(m.predicates, ps...) @@ -15800,7 +15781,7 @@ func (m *WorkflowContractMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *WorkflowContractMutation) Fields() []string { - fields := make([]string, 0, 5) + fields := make([]string, 0, 6) if m.name != nil { fields = append(fields, workflowcontract.FieldName) } @@ -15813,8 +15794,11 @@ func (m *WorkflowContractMutation) Fields() []string { if m.description != nil { fields = append(fields, workflowcontract.FieldDescription) } - if m.project != nil { - fields = append(fields, workflowcontract.FieldProjectID) + if m.scoped_resource_type != nil { + fields = append(fields, workflowcontract.FieldScopedResourceType) + } + if m.scoped_resource_id != nil { + fields = append(fields, workflowcontract.FieldScopedResourceID) } return fields } @@ -15832,8 +15816,10 @@ func (m *WorkflowContractMutation) Field(name string) (ent.Value, bool) { return m.DeletedAt() case workflowcontract.FieldDescription: return m.Description() - case workflowcontract.FieldProjectID: - return m.ProjectID() + case workflowcontract.FieldScopedResourceType: + return m.ScopedResourceType() + case workflowcontract.FieldScopedResourceID: + return m.ScopedResourceID() } return nil, false } @@ -15851,8 +15837,10 @@ func (m *WorkflowContractMutation) OldField(ctx context.Context, name string) (e return m.OldDeletedAt(ctx) case workflowcontract.FieldDescription: return m.OldDescription(ctx) - case workflowcontract.FieldProjectID: - return m.OldProjectID(ctx) + case workflowcontract.FieldScopedResourceType: + return m.OldScopedResourceType(ctx) + case workflowcontract.FieldScopedResourceID: + return m.OldScopedResourceID(ctx) } return nil, fmt.Errorf("unknown WorkflowContract field %s", name) } @@ -15890,12 +15878,19 @@ func (m *WorkflowContractMutation) SetField(name string, value ent.Value) error } m.SetDescription(v) return nil - case workflowcontract.FieldProjectID: + case workflowcontract.FieldScopedResourceType: + v, ok := value.(biz.ContractScope) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetScopedResourceType(v) + return nil + case workflowcontract.FieldScopedResourceID: v, ok := value.(uuid.UUID) if !ok { return fmt.Errorf("unexpected type %T for field %s", value, name) } - m.SetProjectID(v) + m.SetScopedResourceID(v) return nil } return fmt.Errorf("unknown WorkflowContract field %s", name) @@ -15933,8 +15928,11 @@ func (m *WorkflowContractMutation) ClearedFields() []string { if m.FieldCleared(workflowcontract.FieldDescription) { fields = append(fields, workflowcontract.FieldDescription) } - if m.FieldCleared(workflowcontract.FieldProjectID) { - fields = append(fields, workflowcontract.FieldProjectID) + if m.FieldCleared(workflowcontract.FieldScopedResourceType) { + fields = append(fields, workflowcontract.FieldScopedResourceType) + } + if m.FieldCleared(workflowcontract.FieldScopedResourceID) { + fields = append(fields, workflowcontract.FieldScopedResourceID) } return fields } @@ -15956,8 +15954,11 @@ func (m *WorkflowContractMutation) ClearField(name string) error { case workflowcontract.FieldDescription: m.ClearDescription() return nil - case workflowcontract.FieldProjectID: - m.ClearProjectID() + case workflowcontract.FieldScopedResourceType: + m.ClearScopedResourceType() + return nil + case workflowcontract.FieldScopedResourceID: + m.ClearScopedResourceID() return nil } return fmt.Errorf("unknown WorkflowContract nullable field %s", name) @@ -15979,8 +15980,11 @@ func (m *WorkflowContractMutation) ResetField(name string) error { case workflowcontract.FieldDescription: m.ResetDescription() return nil - case workflowcontract.FieldProjectID: - m.ResetProjectID() + case workflowcontract.FieldScopedResourceType: + m.ResetScopedResourceType() + return nil + case workflowcontract.FieldScopedResourceID: + m.ResetScopedResourceID() return nil } return fmt.Errorf("unknown WorkflowContract field %s", name) @@ -15988,19 +15992,13 @@ func (m *WorkflowContractMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *WorkflowContractMutation) AddedEdges() []string { - edges := make([]string, 0, 4) + edges := make([]string, 0, 2) if m.versions != nil { edges = append(edges, workflowcontract.EdgeVersions) } - if m.organization != nil { - edges = append(edges, workflowcontract.EdgeOrganization) - } if m.workflows != nil { edges = append(edges, workflowcontract.EdgeWorkflows) } - if m.project != nil { - edges = append(edges, workflowcontract.EdgeProject) - } return edges } @@ -16014,27 +16012,19 @@ func (m *WorkflowContractMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids - case workflowcontract.EdgeOrganization: - if id := m.organization; id != nil { - return []ent.Value{*id} - } case workflowcontract.EdgeWorkflows: ids := make([]ent.Value, 0, len(m.workflows)) for id := range m.workflows { ids = append(ids, id) } return ids - case workflowcontract.EdgeProject: - if id := m.project; id != nil { - return []ent.Value{*id} - } } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *WorkflowContractMutation) RemovedEdges() []string { - edges := make([]string, 0, 4) + edges := make([]string, 0, 2) if m.removedversions != nil { edges = append(edges, workflowcontract.EdgeVersions) } @@ -16066,19 +16056,13 @@ func (m *WorkflowContractMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *WorkflowContractMutation) ClearedEdges() []string { - edges := make([]string, 0, 4) + edges := make([]string, 0, 2) if m.clearedversions { edges = append(edges, workflowcontract.EdgeVersions) } - if m.clearedorganization { - edges = append(edges, workflowcontract.EdgeOrganization) - } if m.clearedworkflows { edges = append(edges, workflowcontract.EdgeWorkflows) } - if m.clearedproject { - edges = append(edges, workflowcontract.EdgeProject) - } return edges } @@ -16088,12 +16072,8 @@ func (m *WorkflowContractMutation) EdgeCleared(name string) bool { switch name { case workflowcontract.EdgeVersions: return m.clearedversions - case workflowcontract.EdgeOrganization: - return m.clearedorganization case workflowcontract.EdgeWorkflows: return m.clearedworkflows - case workflowcontract.EdgeProject: - return m.clearedproject } return false } @@ -16102,12 +16082,6 @@ func (m *WorkflowContractMutation) EdgeCleared(name string) bool { // if that edge is not defined in the schema. func (m *WorkflowContractMutation) ClearEdge(name string) error { switch name { - case workflowcontract.EdgeOrganization: - m.ClearOrganization() - return nil - case workflowcontract.EdgeProject: - m.ClearProject() - return nil } return fmt.Errorf("unknown WorkflowContract unique edge %s", name) } @@ -16119,15 +16093,9 @@ func (m *WorkflowContractMutation) ResetEdge(name string) error { case workflowcontract.EdgeVersions: m.ResetVersions() return nil - case workflowcontract.EdgeOrganization: - m.ResetOrganization() - return nil case workflowcontract.EdgeWorkflows: m.ResetWorkflows() return nil - case workflowcontract.EdgeProject: - m.ResetProject() - return nil } return fmt.Errorf("unknown WorkflowContract edge %s", name) } diff --git a/app/controlplane/pkg/data/ent/schema-viz.html b/app/controlplane/pkg/data/ent/schema-viz.html index d0fa73e62..c54c7412c 100644 --- a/app/controlplane/pkg/data/ent/schema-viz.html +++ b/app/controlplane/pkg/data/ent/schema-viz.html @@ -70,11 +70,15 @@ } +<<<<<<< HEAD <<<<<<< HEAD const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"last_used_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"context\",\"type\":\"biz.OrgInvitationContext\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); ======= const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowContract\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); >>>>>>> 9b3f353d (feat: add columns) +======= + const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"scoped_resource_type\",\"type\":\"biz.ContractScope\"},{\"name\":\"scoped_resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); +>>>>>>> 7a8275ef (fix tests) const nodes = new vis.DataSet((entGraph.nodes || []).map(n => ({ id: n.id, diff --git a/app/controlplane/pkg/data/ent/schema/workflowcontract.go b/app/controlplane/pkg/data/ent/schema/workflowcontract.go index ad400f107..455ea638f 100644 --- a/app/controlplane/pkg/data/ent/schema/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/schema/workflowcontract.go @@ -23,6 +23,7 @@ import ( "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/google/uuid" ) @@ -44,8 +45,9 @@ func (WorkflowContract) Fields() []ent.Field { }), field.Time("deleted_at").Optional(), field.String("description").Optional(), - // if this value is not set, the contract is an organization level contract - field.UUID("project_id", uuid.UUID{}).Optional(), + // If this value is set, the contract is scoped to a project or organization + field.Enum("scoped_resource_type").GoType(biz.ContractScope("")).Optional(), + field.UUID("scoped_resource_id", uuid.UUID{}).Optional(), } } @@ -53,25 +55,16 @@ func (WorkflowContract) Fields() []ent.Field { func (WorkflowContract) Edges() []ent.Edge { return []ent.Edge{ edge.To("versions", WorkflowContractVersion.Type), - edge.From("organization", Organization.Type). - Ref("workflow_contracts"). - Unique(), // A contract can be associated to multiple workflows edge.From("workflows", Workflow.Type).Ref("contract"), - edge.To("project", Project.Type).Field("project_id").Unique(), } } func (WorkflowContract) Indexes() []ent.Index { return []ent.Index{ // names are unique within a organization and affects only to non-deleted items - index.Fields("name").Edges("organization").Unique().Annotations( - entsql.IndexWhere("deleted_at IS NULL AND project_id IS NULL"), - ), - - // for project level contracts, we scope the uniqueness to the project - index.Fields("name").Edges("project").Unique().Annotations( - entsql.IndexWhere("deleted_at IS NULL AND project_id IS NOT NULL"), + index.Fields("name", "scoped_resource_type", "scoped_resource_id").Unique().Annotations( + entsql.IndexWhere("deleted_at IS NULL"), ), } } diff --git a/app/controlplane/pkg/data/ent/workflowcontract.go b/app/controlplane/pkg/data/ent/workflowcontract.go index 777421d58..2a67948fd 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/workflowcontract.go @@ -9,8 +9,7 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/google/uuid" ) @@ -28,8 +27,10 @@ type WorkflowContract struct { DeletedAt time.Time `json:"deleted_at,omitempty"` // Description holds the value of the "description" field. Description string `json:"description,omitempty"` - // ProjectID holds the value of the "project_id" field. - ProjectID uuid.UUID `json:"project_id,omitempty"` + // ScopedResourceType holds the value of the "scoped_resource_type" field. + ScopedResourceType biz.ContractScope `json:"scoped_resource_type,omitempty"` + // ScopedResourceID holds the value of the "scoped_resource_id" field. + ScopedResourceID uuid.UUID `json:"scoped_resource_id,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the WorkflowContractQuery when eager-loading is set. Edges WorkflowContractEdges `json:"edges"` @@ -41,15 +42,11 @@ type WorkflowContract struct { type WorkflowContractEdges struct { // Versions holds the value of the versions edge. Versions []*WorkflowContractVersion `json:"versions,omitempty"` - // Organization holds the value of the organization edge. - Organization *Organization `json:"organization,omitempty"` // Workflows holds the value of the workflows edge. Workflows []*Workflow `json:"workflows,omitempty"` - // Project holds the value of the project edge. - Project *Project `json:"project,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [4]bool + loadedTypes [2]bool } // VersionsOrErr returns the Versions value or an error if the edge @@ -61,47 +58,25 @@ func (e WorkflowContractEdges) VersionsOrErr() ([]*WorkflowContractVersion, erro return nil, &NotLoadedError{edge: "versions"} } -// OrganizationOrErr returns the Organization value or an error if the edge -// was not loaded in eager-loading, or loaded but was not found. -func (e WorkflowContractEdges) OrganizationOrErr() (*Organization, error) { - if e.Organization != nil { - return e.Organization, nil - } else if e.loadedTypes[1] { - return nil, &NotFoundError{label: organization.Label} - } - return nil, &NotLoadedError{edge: "organization"} -} - // WorkflowsOrErr returns the Workflows value or an error if the edge // was not loaded in eager-loading. func (e WorkflowContractEdges) WorkflowsOrErr() ([]*Workflow, error) { - if e.loadedTypes[2] { + if e.loadedTypes[1] { return e.Workflows, nil } return nil, &NotLoadedError{edge: "workflows"} } -// ProjectOrErr returns the Project value or an error if the edge -// was not loaded in eager-loading, or loaded but was not found. -func (e WorkflowContractEdges) ProjectOrErr() (*Project, error) { - if e.Project != nil { - return e.Project, nil - } else if e.loadedTypes[3] { - return nil, &NotFoundError{label: project.Label} - } - return nil, &NotLoadedError{edge: "project"} -} - // scanValues returns the types for scanning values from sql.Rows. func (*WorkflowContract) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { - case workflowcontract.FieldName, workflowcontract.FieldDescription: + case workflowcontract.FieldName, workflowcontract.FieldDescription, workflowcontract.FieldScopedResourceType: values[i] = new(sql.NullString) case workflowcontract.FieldCreatedAt, workflowcontract.FieldDeletedAt: values[i] = new(sql.NullTime) - case workflowcontract.FieldID, workflowcontract.FieldProjectID: + case workflowcontract.FieldID, workflowcontract.FieldScopedResourceID: values[i] = new(uuid.UUID) case workflowcontract.ForeignKeys[0]: // organization_workflow_contracts values[i] = &sql.NullScanner{S: new(uuid.UUID)} @@ -150,11 +125,17 @@ func (wc *WorkflowContract) assignValues(columns []string, values []any) error { } else if value.Valid { wc.Description = value.String } - case workflowcontract.FieldProjectID: + case workflowcontract.FieldScopedResourceType: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field scoped_resource_type", values[i]) + } else if value.Valid { + wc.ScopedResourceType = biz.ContractScope(value.String) + } + case workflowcontract.FieldScopedResourceID: if value, ok := values[i].(*uuid.UUID); !ok { - return fmt.Errorf("unexpected type %T for field project_id", values[i]) + return fmt.Errorf("unexpected type %T for field scoped_resource_id", values[i]) } else if value != nil { - wc.ProjectID = *value + wc.ScopedResourceID = *value } case workflowcontract.ForeignKeys[0]: if value, ok := values[i].(*sql.NullScanner); !ok { @@ -181,21 +162,11 @@ func (wc *WorkflowContract) QueryVersions() *WorkflowContractVersionQuery { return NewWorkflowContractClient(wc.config).QueryVersions(wc) } -// QueryOrganization queries the "organization" edge of the WorkflowContract entity. -func (wc *WorkflowContract) QueryOrganization() *OrganizationQuery { - return NewWorkflowContractClient(wc.config).QueryOrganization(wc) -} - // QueryWorkflows queries the "workflows" edge of the WorkflowContract entity. func (wc *WorkflowContract) QueryWorkflows() *WorkflowQuery { return NewWorkflowContractClient(wc.config).QueryWorkflows(wc) } -// QueryProject queries the "project" edge of the WorkflowContract entity. -func (wc *WorkflowContract) QueryProject() *ProjectQuery { - return NewWorkflowContractClient(wc.config).QueryProject(wc) -} - // Update returns a builder for updating this WorkflowContract. // Note that you need to call WorkflowContract.Unwrap() before calling this method if this WorkflowContract // was returned from a transaction, and the transaction was committed or rolled back. @@ -231,8 +202,11 @@ func (wc *WorkflowContract) String() string { builder.WriteString("description=") builder.WriteString(wc.Description) builder.WriteString(", ") - builder.WriteString("project_id=") - builder.WriteString(fmt.Sprintf("%v", wc.ProjectID)) + builder.WriteString("scoped_resource_type=") + builder.WriteString(fmt.Sprintf("%v", wc.ScopedResourceType)) + builder.WriteString(", ") + builder.WriteString("scoped_resource_id=") + builder.WriteString(fmt.Sprintf("%v", wc.ScopedResourceID)) builder.WriteByte(')') return builder.String() } diff --git a/app/controlplane/pkg/data/ent/workflowcontract/where.go b/app/controlplane/pkg/data/ent/workflowcontract/where.go index 8f83a3076..b7db780dd 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract/where.go +++ b/app/controlplane/pkg/data/ent/workflowcontract/where.go @@ -7,6 +7,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/predicate" "github.com/google/uuid" ) @@ -76,9 +77,9 @@ func Description(v string) predicate.WorkflowContract { return predicate.WorkflowContract(sql.FieldEQ(FieldDescription, v)) } -// ProjectID applies equality check predicate on the "project_id" field. It's identical to ProjectIDEQ. -func ProjectID(v uuid.UUID) predicate.WorkflowContract { - return predicate.WorkflowContract(sql.FieldEQ(FieldProjectID, v)) +// ScopedResourceID applies equality check predicate on the "scoped_resource_id" field. It's identical to ScopedResourceIDEQ. +func ScopedResourceID(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldEQ(FieldScopedResourceID, v)) } // NameEQ applies the EQ predicate on the "name" field. @@ -311,34 +312,94 @@ func DescriptionContainsFold(v string) predicate.WorkflowContract { return predicate.WorkflowContract(sql.FieldContainsFold(FieldDescription, v)) } -// ProjectIDEQ applies the EQ predicate on the "project_id" field. -func ProjectIDEQ(v uuid.UUID) predicate.WorkflowContract { - return predicate.WorkflowContract(sql.FieldEQ(FieldProjectID, v)) +// ScopedResourceTypeEQ applies the EQ predicate on the "scoped_resource_type" field. +func ScopedResourceTypeEQ(v biz.ContractScope) predicate.WorkflowContract { + vc := v + return predicate.WorkflowContract(sql.FieldEQ(FieldScopedResourceType, vc)) } -// ProjectIDNEQ applies the NEQ predicate on the "project_id" field. -func ProjectIDNEQ(v uuid.UUID) predicate.WorkflowContract { - return predicate.WorkflowContract(sql.FieldNEQ(FieldProjectID, v)) +// ScopedResourceTypeNEQ applies the NEQ predicate on the "scoped_resource_type" field. +func ScopedResourceTypeNEQ(v biz.ContractScope) predicate.WorkflowContract { + vc := v + return predicate.WorkflowContract(sql.FieldNEQ(FieldScopedResourceType, vc)) } -// ProjectIDIn applies the In predicate on the "project_id" field. -func ProjectIDIn(vs ...uuid.UUID) predicate.WorkflowContract { - return predicate.WorkflowContract(sql.FieldIn(FieldProjectID, vs...)) +// ScopedResourceTypeIn applies the In predicate on the "scoped_resource_type" field. +func ScopedResourceTypeIn(vs ...biz.ContractScope) predicate.WorkflowContract { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.WorkflowContract(sql.FieldIn(FieldScopedResourceType, v...)) } -// ProjectIDNotIn applies the NotIn predicate on the "project_id" field. -func ProjectIDNotIn(vs ...uuid.UUID) predicate.WorkflowContract { - return predicate.WorkflowContract(sql.FieldNotIn(FieldProjectID, vs...)) +// ScopedResourceTypeNotIn applies the NotIn predicate on the "scoped_resource_type" field. +func ScopedResourceTypeNotIn(vs ...biz.ContractScope) predicate.WorkflowContract { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.WorkflowContract(sql.FieldNotIn(FieldScopedResourceType, v...)) } -// ProjectIDIsNil applies the IsNil predicate on the "project_id" field. -func ProjectIDIsNil() predicate.WorkflowContract { - return predicate.WorkflowContract(sql.FieldIsNull(FieldProjectID)) +// ScopedResourceTypeIsNil applies the IsNil predicate on the "scoped_resource_type" field. +func ScopedResourceTypeIsNil() predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldIsNull(FieldScopedResourceType)) } -// ProjectIDNotNil applies the NotNil predicate on the "project_id" field. -func ProjectIDNotNil() predicate.WorkflowContract { - return predicate.WorkflowContract(sql.FieldNotNull(FieldProjectID)) +// ScopedResourceTypeNotNil applies the NotNil predicate on the "scoped_resource_type" field. +func ScopedResourceTypeNotNil() predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldNotNull(FieldScopedResourceType)) +} + +// ScopedResourceIDEQ applies the EQ predicate on the "scoped_resource_id" field. +func ScopedResourceIDEQ(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldEQ(FieldScopedResourceID, v)) +} + +// ScopedResourceIDNEQ applies the NEQ predicate on the "scoped_resource_id" field. +func ScopedResourceIDNEQ(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldNEQ(FieldScopedResourceID, v)) +} + +// ScopedResourceIDIn applies the In predicate on the "scoped_resource_id" field. +func ScopedResourceIDIn(vs ...uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldIn(FieldScopedResourceID, vs...)) +} + +// ScopedResourceIDNotIn applies the NotIn predicate on the "scoped_resource_id" field. +func ScopedResourceIDNotIn(vs ...uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldNotIn(FieldScopedResourceID, vs...)) +} + +// ScopedResourceIDGT applies the GT predicate on the "scoped_resource_id" field. +func ScopedResourceIDGT(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldGT(FieldScopedResourceID, v)) +} + +// ScopedResourceIDGTE applies the GTE predicate on the "scoped_resource_id" field. +func ScopedResourceIDGTE(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldGTE(FieldScopedResourceID, v)) +} + +// ScopedResourceIDLT applies the LT predicate on the "scoped_resource_id" field. +func ScopedResourceIDLT(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldLT(FieldScopedResourceID, v)) +} + +// ScopedResourceIDLTE applies the LTE predicate on the "scoped_resource_id" field. +func ScopedResourceIDLTE(v uuid.UUID) predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldLTE(FieldScopedResourceID, v)) +} + +// ScopedResourceIDIsNil applies the IsNil predicate on the "scoped_resource_id" field. +func ScopedResourceIDIsNil() predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldIsNull(FieldScopedResourceID)) +} + +// ScopedResourceIDNotNil applies the NotNil predicate on the "scoped_resource_id" field. +func ScopedResourceIDNotNil() predicate.WorkflowContract { + return predicate.WorkflowContract(sql.FieldNotNull(FieldScopedResourceID)) } // HasVersions applies the HasEdge predicate on the "versions" edge. @@ -364,29 +425,6 @@ func HasVersionsWith(preds ...predicate.WorkflowContractVersion) predicate.Workf }) } -// HasOrganization applies the HasEdge predicate on the "organization" edge. -func HasOrganization() predicate.WorkflowContract { - return predicate.WorkflowContract(func(s *sql.Selector) { - step := sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, OrganizationTable, OrganizationColumn), - ) - sqlgraph.HasNeighbors(s, step) - }) -} - -// HasOrganizationWith applies the HasEdge predicate on the "organization" edge with a given conditions (other predicates). -func HasOrganizationWith(preds ...predicate.Organization) predicate.WorkflowContract { - return predicate.WorkflowContract(func(s *sql.Selector) { - step := newOrganizationStep() - sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { - for _, p := range preds { - p(s) - } - }) - }) -} - // HasWorkflows applies the HasEdge predicate on the "workflows" edge. func HasWorkflows() predicate.WorkflowContract { return predicate.WorkflowContract(func(s *sql.Selector) { @@ -410,29 +448,6 @@ func HasWorkflowsWith(preds ...predicate.Workflow) predicate.WorkflowContract { }) } -// HasProject applies the HasEdge predicate on the "project" edge. -func HasProject() predicate.WorkflowContract { - return predicate.WorkflowContract(func(s *sql.Selector) { - step := sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.Edge(sqlgraph.M2O, false, ProjectTable, ProjectColumn), - ) - sqlgraph.HasNeighbors(s, step) - }) -} - -// HasProjectWith applies the HasEdge predicate on the "project" edge with a given conditions (other predicates). -func HasProjectWith(preds ...predicate.Project) predicate.WorkflowContract { - return predicate.WorkflowContract(func(s *sql.Selector) { - step := newProjectStep() - sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { - for _, p := range preds { - p(s) - } - }) - }) -} - // And groups predicates with the AND operator between them. func And(predicates ...predicate.WorkflowContract) predicate.WorkflowContract { return predicate.WorkflowContract(sql.AndPredicates(predicates...)) diff --git a/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go b/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go index 9cb71a60f..e8ee814e2 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go @@ -3,10 +3,12 @@ package workflowcontract import ( + "fmt" "time" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/google/uuid" ) @@ -23,16 +25,14 @@ const ( FieldDeletedAt = "deleted_at" // FieldDescription holds the string denoting the description field in the database. FieldDescription = "description" - // FieldProjectID holds the string denoting the project_id field in the database. - FieldProjectID = "project_id" + // FieldScopedResourceType holds the string denoting the scoped_resource_type field in the database. + FieldScopedResourceType = "scoped_resource_type" + // FieldScopedResourceID holds the string denoting the scoped_resource_id field in the database. + FieldScopedResourceID = "scoped_resource_id" // EdgeVersions holds the string denoting the versions edge name in mutations. EdgeVersions = "versions" - // EdgeOrganization holds the string denoting the organization edge name in mutations. - EdgeOrganization = "organization" // EdgeWorkflows holds the string denoting the workflows edge name in mutations. EdgeWorkflows = "workflows" - // EdgeProject holds the string denoting the project edge name in mutations. - EdgeProject = "project" // Table holds the table name of the workflowcontract in the database. Table = "workflow_contracts" // VersionsTable is the table that holds the versions relation/edge. @@ -42,13 +42,6 @@ const ( VersionsInverseTable = "workflow_contract_versions" // VersionsColumn is the table column denoting the versions relation/edge. VersionsColumn = "workflow_contract_versions" - // OrganizationTable is the table that holds the organization relation/edge. - OrganizationTable = "workflow_contracts" - // OrganizationInverseTable is the table name for the Organization entity. - // It exists in this package in order to avoid circular dependency with the "organization" package. - OrganizationInverseTable = "organizations" - // OrganizationColumn is the table column denoting the organization relation/edge. - OrganizationColumn = "organization_workflow_contracts" // WorkflowsTable is the table that holds the workflows relation/edge. WorkflowsTable = "workflows" // WorkflowsInverseTable is the table name for the Workflow entity. @@ -56,13 +49,6 @@ const ( WorkflowsInverseTable = "workflows" // WorkflowsColumn is the table column denoting the workflows relation/edge. WorkflowsColumn = "workflow_contract" - // ProjectTable is the table that holds the project relation/edge. - ProjectTable = "workflow_contracts" - // ProjectInverseTable is the table name for the Project entity. - // It exists in this package in order to avoid circular dependency with the "project" package. - ProjectInverseTable = "projects" - // ProjectColumn is the table column denoting the project relation/edge. - ProjectColumn = "project_id" ) // Columns holds all SQL columns for workflowcontract fields. @@ -72,7 +58,8 @@ var Columns = []string{ FieldCreatedAt, FieldDeletedAt, FieldDescription, - FieldProjectID, + FieldScopedResourceType, + FieldScopedResourceID, } // ForeignKeys holds the SQL foreign-keys that are owned by the "workflow_contracts" @@ -103,6 +90,16 @@ var ( DefaultID func() uuid.UUID ) +// ScopedResourceTypeValidator is a validator for the "scoped_resource_type" field enum values. It is called by the builders before save. +func ScopedResourceTypeValidator(srt biz.ContractScope) error { + switch srt { + case "project", "org": + return nil + default: + return fmt.Errorf("workflowcontract: invalid enum value for scoped_resource_type field: %q", srt) + } +} + // OrderOption defines the ordering options for the WorkflowContract queries. type OrderOption func(*sql.Selector) @@ -131,9 +128,14 @@ func ByDescription(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldDescription, opts...).ToFunc() } -// ByProjectID orders the results by the project_id field. -func ByProjectID(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldProjectID, opts...).ToFunc() +// ByScopedResourceType orders the results by the scoped_resource_type field. +func ByScopedResourceType(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldScopedResourceType, opts...).ToFunc() +} + +// ByScopedResourceID orders the results by the scoped_resource_id field. +func ByScopedResourceID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldScopedResourceID, opts...).ToFunc() } // ByVersionsCount orders the results by versions count. @@ -150,13 +152,6 @@ func ByVersions(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { } } -// ByOrganizationField orders the results by organization field. -func ByOrganizationField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newOrganizationStep(), sql.OrderByField(field, opts...)) - } -} - // ByWorkflowsCount orders the results by workflows count. func ByWorkflowsCount(opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { @@ -170,13 +165,6 @@ func ByWorkflows(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { sqlgraph.OrderByNeighborTerms(s, newWorkflowsStep(), append([]sql.OrderTerm{term}, terms...)...) } } - -// ByProjectField orders the results by project field. -func ByProjectField(field string, opts ...sql.OrderTermOption) OrderOption { - return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newProjectStep(), sql.OrderByField(field, opts...)) - } -} func newVersionsStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), @@ -184,13 +172,6 @@ func newVersionsStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, false, VersionsTable, VersionsColumn), ) } -func newOrganizationStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(OrganizationInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, OrganizationTable, OrganizationColumn), - ) -} func newWorkflowsStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), @@ -198,10 +179,3 @@ func newWorkflowsStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, true, WorkflowsTable, WorkflowsColumn), ) } -func newProjectStep() *sqlgraph.Step { - return sqlgraph.NewStep( - sqlgraph.From(Table, FieldID), - sqlgraph.To(ProjectInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, false, ProjectTable, ProjectColumn), - ) -} diff --git a/app/controlplane/pkg/data/ent/workflowcontract_create.go b/app/controlplane/pkg/data/ent/workflowcontract_create.go index 811d19456..065783ccd 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_create.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_create.go @@ -12,8 +12,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontractversion" @@ -76,16 +75,30 @@ func (wcc *WorkflowContractCreate) SetNillableDescription(s *string) *WorkflowCo return wcc } -// SetProjectID sets the "project_id" field. -func (wcc *WorkflowContractCreate) SetProjectID(u uuid.UUID) *WorkflowContractCreate { - wcc.mutation.SetProjectID(u) +// SetScopedResourceType sets the "scoped_resource_type" field. +func (wcc *WorkflowContractCreate) SetScopedResourceType(bs biz.ContractScope) *WorkflowContractCreate { + wcc.mutation.SetScopedResourceType(bs) return wcc } -// SetNillableProjectID sets the "project_id" field if the given value is not nil. -func (wcc *WorkflowContractCreate) SetNillableProjectID(u *uuid.UUID) *WorkflowContractCreate { +// SetNillableScopedResourceType sets the "scoped_resource_type" field if the given value is not nil. +func (wcc *WorkflowContractCreate) SetNillableScopedResourceType(bs *biz.ContractScope) *WorkflowContractCreate { + if bs != nil { + wcc.SetScopedResourceType(*bs) + } + return wcc +} + +// SetScopedResourceID sets the "scoped_resource_id" field. +func (wcc *WorkflowContractCreate) SetScopedResourceID(u uuid.UUID) *WorkflowContractCreate { + wcc.mutation.SetScopedResourceID(u) + return wcc +} + +// SetNillableScopedResourceID sets the "scoped_resource_id" field if the given value is not nil. +func (wcc *WorkflowContractCreate) SetNillableScopedResourceID(u *uuid.UUID) *WorkflowContractCreate { if u != nil { - wcc.SetProjectID(*u) + wcc.SetScopedResourceID(*u) } return wcc } @@ -119,25 +132,6 @@ func (wcc *WorkflowContractCreate) AddVersions(w ...*WorkflowContractVersion) *W return wcc.AddVersionIDs(ids...) } -// SetOrganizationID sets the "organization" edge to the Organization entity by ID. -func (wcc *WorkflowContractCreate) SetOrganizationID(id uuid.UUID) *WorkflowContractCreate { - wcc.mutation.SetOrganizationID(id) - return wcc -} - -// SetNillableOrganizationID sets the "organization" edge to the Organization entity by ID if the given value is not nil. -func (wcc *WorkflowContractCreate) SetNillableOrganizationID(id *uuid.UUID) *WorkflowContractCreate { - if id != nil { - wcc = wcc.SetOrganizationID(*id) - } - return wcc -} - -// SetOrganization sets the "organization" edge to the Organization entity. -func (wcc *WorkflowContractCreate) SetOrganization(o *Organization) *WorkflowContractCreate { - return wcc.SetOrganizationID(o.ID) -} - // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by IDs. func (wcc *WorkflowContractCreate) AddWorkflowIDs(ids ...uuid.UUID) *WorkflowContractCreate { wcc.mutation.AddWorkflowIDs(ids...) @@ -153,11 +147,6 @@ func (wcc *WorkflowContractCreate) AddWorkflows(w ...*Workflow) *WorkflowContrac return wcc.AddWorkflowIDs(ids...) } -// SetProject sets the "project" edge to the Project entity. -func (wcc *WorkflowContractCreate) SetProject(p *Project) *WorkflowContractCreate { - return wcc.SetProjectID(p.ID) -} - // Mutation returns the WorkflowContractMutation object of the builder. func (wcc *WorkflowContractCreate) Mutation() *WorkflowContractMutation { return wcc.mutation @@ -211,6 +200,11 @@ func (wcc *WorkflowContractCreate) check() error { if _, ok := wcc.mutation.CreatedAt(); !ok { return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "WorkflowContract.created_at"`)} } + if v, ok := wcc.mutation.ScopedResourceType(); ok { + if err := workflowcontract.ScopedResourceTypeValidator(v); err != nil { + return &ValidationError{Name: "scoped_resource_type", err: fmt.Errorf(`ent: validator failed for field "WorkflowContract.scoped_resource_type": %w`, err)} + } + } return nil } @@ -263,6 +257,14 @@ func (wcc *WorkflowContractCreate) createSpec() (*WorkflowContract, *sqlgraph.Cr _spec.SetField(workflowcontract.FieldDescription, field.TypeString, value) _node.Description = value } + if value, ok := wcc.mutation.ScopedResourceType(); ok { + _spec.SetField(workflowcontract.FieldScopedResourceType, field.TypeEnum, value) + _node.ScopedResourceType = value + } + if value, ok := wcc.mutation.ScopedResourceID(); ok { + _spec.SetField(workflowcontract.FieldScopedResourceID, field.TypeUUID, value) + _node.ScopedResourceID = value + } if nodes := wcc.mutation.VersionsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -279,23 +281,6 @@ func (wcc *WorkflowContractCreate) createSpec() (*WorkflowContract, *sqlgraph.Cr } _spec.Edges = append(_spec.Edges, edge) } - if nodes := wcc.mutation.OrganizationIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: true, - Table: workflowcontract.OrganizationTable, - Columns: []string{workflowcontract.OrganizationColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _node.organization_workflow_contracts = &nodes[0] - _spec.Edges = append(_spec.Edges, edge) - } if nodes := wcc.mutation.WorkflowsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -312,23 +297,6 @@ func (wcc *WorkflowContractCreate) createSpec() (*WorkflowContract, *sqlgraph.Cr } _spec.Edges = append(_spec.Edges, edge) } - if nodes := wcc.mutation.ProjectIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: workflowcontract.ProjectTable, - Columns: []string{workflowcontract.ProjectColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _node.ProjectID = nodes[0] - _spec.Edges = append(_spec.Edges, edge) - } return _node, _spec } @@ -417,21 +385,39 @@ func (u *WorkflowContractUpsert) ClearDescription() *WorkflowContractUpsert { return u } -// SetProjectID sets the "project_id" field. -func (u *WorkflowContractUpsert) SetProjectID(v uuid.UUID) *WorkflowContractUpsert { - u.Set(workflowcontract.FieldProjectID, v) +// SetScopedResourceType sets the "scoped_resource_type" field. +func (u *WorkflowContractUpsert) SetScopedResourceType(v biz.ContractScope) *WorkflowContractUpsert { + u.Set(workflowcontract.FieldScopedResourceType, v) return u } -// UpdateProjectID sets the "project_id" field to the value that was provided on create. -func (u *WorkflowContractUpsert) UpdateProjectID() *WorkflowContractUpsert { - u.SetExcluded(workflowcontract.FieldProjectID) +// UpdateScopedResourceType sets the "scoped_resource_type" field to the value that was provided on create. +func (u *WorkflowContractUpsert) UpdateScopedResourceType() *WorkflowContractUpsert { + u.SetExcluded(workflowcontract.FieldScopedResourceType) return u } -// ClearProjectID clears the value of the "project_id" field. -func (u *WorkflowContractUpsert) ClearProjectID() *WorkflowContractUpsert { - u.SetNull(workflowcontract.FieldProjectID) +// ClearScopedResourceType clears the value of the "scoped_resource_type" field. +func (u *WorkflowContractUpsert) ClearScopedResourceType() *WorkflowContractUpsert { + u.SetNull(workflowcontract.FieldScopedResourceType) + return u +} + +// SetScopedResourceID sets the "scoped_resource_id" field. +func (u *WorkflowContractUpsert) SetScopedResourceID(v uuid.UUID) *WorkflowContractUpsert { + u.Set(workflowcontract.FieldScopedResourceID, v) + return u +} + +// UpdateScopedResourceID sets the "scoped_resource_id" field to the value that was provided on create. +func (u *WorkflowContractUpsert) UpdateScopedResourceID() *WorkflowContractUpsert { + u.SetExcluded(workflowcontract.FieldScopedResourceID) + return u +} + +// ClearScopedResourceID clears the value of the "scoped_resource_id" field. +func (u *WorkflowContractUpsert) ClearScopedResourceID() *WorkflowContractUpsert { + u.SetNull(workflowcontract.FieldScopedResourceID) return u } @@ -531,24 +517,45 @@ func (u *WorkflowContractUpsertOne) ClearDescription() *WorkflowContractUpsertOn }) } -// SetProjectID sets the "project_id" field. -func (u *WorkflowContractUpsertOne) SetProjectID(v uuid.UUID) *WorkflowContractUpsertOne { +// SetScopedResourceType sets the "scoped_resource_type" field. +func (u *WorkflowContractUpsertOne) SetScopedResourceType(v biz.ContractScope) *WorkflowContractUpsertOne { + return u.Update(func(s *WorkflowContractUpsert) { + s.SetScopedResourceType(v) + }) +} + +// UpdateScopedResourceType sets the "scoped_resource_type" field to the value that was provided on create. +func (u *WorkflowContractUpsertOne) UpdateScopedResourceType() *WorkflowContractUpsertOne { + return u.Update(func(s *WorkflowContractUpsert) { + s.UpdateScopedResourceType() + }) +} + +// ClearScopedResourceType clears the value of the "scoped_resource_type" field. +func (u *WorkflowContractUpsertOne) ClearScopedResourceType() *WorkflowContractUpsertOne { + return u.Update(func(s *WorkflowContractUpsert) { + s.ClearScopedResourceType() + }) +} + +// SetScopedResourceID sets the "scoped_resource_id" field. +func (u *WorkflowContractUpsertOne) SetScopedResourceID(v uuid.UUID) *WorkflowContractUpsertOne { return u.Update(func(s *WorkflowContractUpsert) { - s.SetProjectID(v) + s.SetScopedResourceID(v) }) } -// UpdateProjectID sets the "project_id" field to the value that was provided on create. -func (u *WorkflowContractUpsertOne) UpdateProjectID() *WorkflowContractUpsertOne { +// UpdateScopedResourceID sets the "scoped_resource_id" field to the value that was provided on create. +func (u *WorkflowContractUpsertOne) UpdateScopedResourceID() *WorkflowContractUpsertOne { return u.Update(func(s *WorkflowContractUpsert) { - s.UpdateProjectID() + s.UpdateScopedResourceID() }) } -// ClearProjectID clears the value of the "project_id" field. -func (u *WorkflowContractUpsertOne) ClearProjectID() *WorkflowContractUpsertOne { +// ClearScopedResourceID clears the value of the "scoped_resource_id" field. +func (u *WorkflowContractUpsertOne) ClearScopedResourceID() *WorkflowContractUpsertOne { return u.Update(func(s *WorkflowContractUpsert) { - s.ClearProjectID() + s.ClearScopedResourceID() }) } @@ -815,24 +822,45 @@ func (u *WorkflowContractUpsertBulk) ClearDescription() *WorkflowContractUpsertB }) } -// SetProjectID sets the "project_id" field. -func (u *WorkflowContractUpsertBulk) SetProjectID(v uuid.UUID) *WorkflowContractUpsertBulk { +// SetScopedResourceType sets the "scoped_resource_type" field. +func (u *WorkflowContractUpsertBulk) SetScopedResourceType(v biz.ContractScope) *WorkflowContractUpsertBulk { + return u.Update(func(s *WorkflowContractUpsert) { + s.SetScopedResourceType(v) + }) +} + +// UpdateScopedResourceType sets the "scoped_resource_type" field to the value that was provided on create. +func (u *WorkflowContractUpsertBulk) UpdateScopedResourceType() *WorkflowContractUpsertBulk { + return u.Update(func(s *WorkflowContractUpsert) { + s.UpdateScopedResourceType() + }) +} + +// ClearScopedResourceType clears the value of the "scoped_resource_type" field. +func (u *WorkflowContractUpsertBulk) ClearScopedResourceType() *WorkflowContractUpsertBulk { + return u.Update(func(s *WorkflowContractUpsert) { + s.ClearScopedResourceType() + }) +} + +// SetScopedResourceID sets the "scoped_resource_id" field. +func (u *WorkflowContractUpsertBulk) SetScopedResourceID(v uuid.UUID) *WorkflowContractUpsertBulk { return u.Update(func(s *WorkflowContractUpsert) { - s.SetProjectID(v) + s.SetScopedResourceID(v) }) } -// UpdateProjectID sets the "project_id" field to the value that was provided on create. -func (u *WorkflowContractUpsertBulk) UpdateProjectID() *WorkflowContractUpsertBulk { +// UpdateScopedResourceID sets the "scoped_resource_id" field to the value that was provided on create. +func (u *WorkflowContractUpsertBulk) UpdateScopedResourceID() *WorkflowContractUpsertBulk { return u.Update(func(s *WorkflowContractUpsert) { - s.UpdateProjectID() + s.UpdateScopedResourceID() }) } -// ClearProjectID clears the value of the "project_id" field. -func (u *WorkflowContractUpsertBulk) ClearProjectID() *WorkflowContractUpsertBulk { +// ClearScopedResourceID clears the value of the "scoped_resource_id" field. +func (u *WorkflowContractUpsertBulk) ClearScopedResourceID() *WorkflowContractUpsertBulk { return u.Update(func(s *WorkflowContractUpsert) { - s.ClearProjectID() + s.ClearScopedResourceID() }) } diff --git a/app/controlplane/pkg/data/ent/workflowcontract_query.go b/app/controlplane/pkg/data/ent/workflowcontract_query.go index 6056b7dde..9009f4f0e 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_query.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_query.go @@ -13,9 +13,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/predicate" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontractversion" @@ -25,16 +23,14 @@ import ( // WorkflowContractQuery is the builder for querying WorkflowContract entities. type WorkflowContractQuery struct { config - ctx *QueryContext - order []workflowcontract.OrderOption - inters []Interceptor - predicates []predicate.WorkflowContract - withVersions *WorkflowContractVersionQuery - withOrganization *OrganizationQuery - withWorkflows *WorkflowQuery - withProject *ProjectQuery - withFKs bool - modifiers []func(*sql.Selector) + ctx *QueryContext + order []workflowcontract.OrderOption + inters []Interceptor + predicates []predicate.WorkflowContract + withVersions *WorkflowContractVersionQuery + withWorkflows *WorkflowQuery + withFKs bool + modifiers []func(*sql.Selector) // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -93,28 +89,6 @@ func (wcq *WorkflowContractQuery) QueryVersions() *WorkflowContractVersionQuery return query } -// QueryOrganization chains the current query on the "organization" edge. -func (wcq *WorkflowContractQuery) QueryOrganization() *OrganizationQuery { - query := (&OrganizationClient{config: wcq.config}).Query() - query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { - if err := wcq.prepareQuery(ctx); err != nil { - return nil, err - } - selector := wcq.sqlQuery(ctx) - if err := selector.Err(); err != nil { - return nil, err - } - step := sqlgraph.NewStep( - sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, selector), - sqlgraph.To(organization.Table, organization.FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, workflowcontract.OrganizationTable, workflowcontract.OrganizationColumn), - ) - fromU = sqlgraph.SetNeighbors(wcq.driver.Dialect(), step) - return fromU, nil - } - return query -} - // QueryWorkflows chains the current query on the "workflows" edge. func (wcq *WorkflowContractQuery) QueryWorkflows() *WorkflowQuery { query := (&WorkflowClient{config: wcq.config}).Query() @@ -137,28 +111,6 @@ func (wcq *WorkflowContractQuery) QueryWorkflows() *WorkflowQuery { return query } -// QueryProject chains the current query on the "project" edge. -func (wcq *WorkflowContractQuery) QueryProject() *ProjectQuery { - query := (&ProjectClient{config: wcq.config}).Query() - query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { - if err := wcq.prepareQuery(ctx); err != nil { - return nil, err - } - selector := wcq.sqlQuery(ctx) - if err := selector.Err(); err != nil { - return nil, err - } - step := sqlgraph.NewStep( - sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, selector), - sqlgraph.To(project.Table, project.FieldID), - sqlgraph.Edge(sqlgraph.M2O, false, workflowcontract.ProjectTable, workflowcontract.ProjectColumn), - ) - fromU = sqlgraph.SetNeighbors(wcq.driver.Dialect(), step) - return fromU, nil - } - return query -} - // First returns the first WorkflowContract entity from the query. // Returns a *NotFoundError when no WorkflowContract was found. func (wcq *WorkflowContractQuery) First(ctx context.Context) (*WorkflowContract, error) { @@ -346,15 +298,13 @@ func (wcq *WorkflowContractQuery) Clone() *WorkflowContractQuery { return nil } return &WorkflowContractQuery{ - config: wcq.config, - ctx: wcq.ctx.Clone(), - order: append([]workflowcontract.OrderOption{}, wcq.order...), - inters: append([]Interceptor{}, wcq.inters...), - predicates: append([]predicate.WorkflowContract{}, wcq.predicates...), - withVersions: wcq.withVersions.Clone(), - withOrganization: wcq.withOrganization.Clone(), - withWorkflows: wcq.withWorkflows.Clone(), - withProject: wcq.withProject.Clone(), + config: wcq.config, + ctx: wcq.ctx.Clone(), + order: append([]workflowcontract.OrderOption{}, wcq.order...), + inters: append([]Interceptor{}, wcq.inters...), + predicates: append([]predicate.WorkflowContract{}, wcq.predicates...), + withVersions: wcq.withVersions.Clone(), + withWorkflows: wcq.withWorkflows.Clone(), // clone intermediate query. sql: wcq.sql.Clone(), path: wcq.path, @@ -373,17 +323,6 @@ func (wcq *WorkflowContractQuery) WithVersions(opts ...func(*WorkflowContractVer return wcq } -// WithOrganization tells the query-builder to eager-load the nodes that are connected to -// the "organization" edge. The optional arguments are used to configure the query builder of the edge. -func (wcq *WorkflowContractQuery) WithOrganization(opts ...func(*OrganizationQuery)) *WorkflowContractQuery { - query := (&OrganizationClient{config: wcq.config}).Query() - for _, opt := range opts { - opt(query) - } - wcq.withOrganization = query - return wcq -} - // WithWorkflows tells the query-builder to eager-load the nodes that are connected to // the "workflows" edge. The optional arguments are used to configure the query builder of the edge. func (wcq *WorkflowContractQuery) WithWorkflows(opts ...func(*WorkflowQuery)) *WorkflowContractQuery { @@ -395,17 +334,6 @@ func (wcq *WorkflowContractQuery) WithWorkflows(opts ...func(*WorkflowQuery)) *W return wcq } -// WithProject tells the query-builder to eager-load the nodes that are connected to -// the "project" edge. The optional arguments are used to configure the query builder of the edge. -func (wcq *WorkflowContractQuery) WithProject(opts ...func(*ProjectQuery)) *WorkflowContractQuery { - query := (&ProjectClient{config: wcq.config}).Query() - for _, opt := range opts { - opt(query) - } - wcq.withProject = query - return wcq -} - // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -485,16 +413,11 @@ func (wcq *WorkflowContractQuery) sqlAll(ctx context.Context, hooks ...queryHook nodes = []*WorkflowContract{} withFKs = wcq.withFKs _spec = wcq.querySpec() - loadedTypes = [4]bool{ + loadedTypes = [2]bool{ wcq.withVersions != nil, - wcq.withOrganization != nil, wcq.withWorkflows != nil, - wcq.withProject != nil, } ) - if wcq.withOrganization != nil { - withFKs = true - } if withFKs { _spec.Node.Columns = append(_spec.Node.Columns, workflowcontract.ForeignKeys...) } @@ -526,12 +449,6 @@ func (wcq *WorkflowContractQuery) sqlAll(ctx context.Context, hooks ...queryHook return nil, err } } - if query := wcq.withOrganization; query != nil { - if err := wcq.loadOrganization(ctx, query, nodes, nil, - func(n *WorkflowContract, e *Organization) { n.Edges.Organization = e }); err != nil { - return nil, err - } - } if query := wcq.withWorkflows; query != nil { if err := wcq.loadWorkflows(ctx, query, nodes, func(n *WorkflowContract) { n.Edges.Workflows = []*Workflow{} }, @@ -539,12 +456,6 @@ func (wcq *WorkflowContractQuery) sqlAll(ctx context.Context, hooks ...queryHook return nil, err } } - if query := wcq.withProject; query != nil { - if err := wcq.loadProject(ctx, query, nodes, nil, - func(n *WorkflowContract, e *Project) { n.Edges.Project = e }); err != nil { - return nil, err - } - } return nodes, nil } @@ -579,38 +490,6 @@ func (wcq *WorkflowContractQuery) loadVersions(ctx context.Context, query *Workf } return nil } -func (wcq *WorkflowContractQuery) loadOrganization(ctx context.Context, query *OrganizationQuery, nodes []*WorkflowContract, init func(*WorkflowContract), assign func(*WorkflowContract, *Organization)) error { - ids := make([]uuid.UUID, 0, len(nodes)) - nodeids := make(map[uuid.UUID][]*WorkflowContract) - for i := range nodes { - if nodes[i].organization_workflow_contracts == nil { - continue - } - fk := *nodes[i].organization_workflow_contracts - if _, ok := nodeids[fk]; !ok { - ids = append(ids, fk) - } - nodeids[fk] = append(nodeids[fk], nodes[i]) - } - if len(ids) == 0 { - return nil - } - query.Where(organization.IDIn(ids...)) - neighbors, err := query.All(ctx) - if err != nil { - return err - } - for _, n := range neighbors { - nodes, ok := nodeids[n.ID] - if !ok { - return fmt.Errorf(`unexpected foreign-key "organization_workflow_contracts" returned %v`, n.ID) - } - for i := range nodes { - assign(nodes[i], n) - } - } - return nil -} func (wcq *WorkflowContractQuery) loadWorkflows(ctx context.Context, query *WorkflowQuery, nodes []*WorkflowContract, init func(*WorkflowContract), assign func(*WorkflowContract, *Workflow)) error { fks := make([]driver.Value, 0, len(nodes)) nodeids := make(map[uuid.UUID]*WorkflowContract) @@ -642,35 +521,6 @@ func (wcq *WorkflowContractQuery) loadWorkflows(ctx context.Context, query *Work } return nil } -func (wcq *WorkflowContractQuery) loadProject(ctx context.Context, query *ProjectQuery, nodes []*WorkflowContract, init func(*WorkflowContract), assign func(*WorkflowContract, *Project)) error { - ids := make([]uuid.UUID, 0, len(nodes)) - nodeids := make(map[uuid.UUID][]*WorkflowContract) - for i := range nodes { - fk := nodes[i].ProjectID - if _, ok := nodeids[fk]; !ok { - ids = append(ids, fk) - } - nodeids[fk] = append(nodeids[fk], nodes[i]) - } - if len(ids) == 0 { - return nil - } - query.Where(project.IDIn(ids...)) - neighbors, err := query.All(ctx) - if err != nil { - return err - } - for _, n := range neighbors { - nodes, ok := nodeids[n.ID] - if !ok { - return fmt.Errorf(`unexpected foreign-key "project_id" returned %v`, n.ID) - } - for i := range nodes { - assign(nodes[i], n) - } - } - return nil -} func (wcq *WorkflowContractQuery) sqlCount(ctx context.Context) (int, error) { _spec := wcq.querySpec() @@ -700,9 +550,6 @@ func (wcq *WorkflowContractQuery) querySpec() *sqlgraph.QuerySpec { _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) } } - if wcq.withProject != nil { - _spec.Node.AddColumnOnce(workflowcontract.FieldProjectID) - } } if ps := wcq.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { diff --git a/app/controlplane/pkg/data/ent/workflowcontract_update.go b/app/controlplane/pkg/data/ent/workflowcontract_update.go index 3b4059802..c7cc64646 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_update.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_update.go @@ -11,9 +11,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/predicate" - "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/project" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontractversion" @@ -74,23 +73,43 @@ func (wcu *WorkflowContractUpdate) ClearDescription() *WorkflowContractUpdate { return wcu } -// SetProjectID sets the "project_id" field. -func (wcu *WorkflowContractUpdate) SetProjectID(u uuid.UUID) *WorkflowContractUpdate { - wcu.mutation.SetProjectID(u) +// SetScopedResourceType sets the "scoped_resource_type" field. +func (wcu *WorkflowContractUpdate) SetScopedResourceType(bs biz.ContractScope) *WorkflowContractUpdate { + wcu.mutation.SetScopedResourceType(bs) return wcu } -// SetNillableProjectID sets the "project_id" field if the given value is not nil. -func (wcu *WorkflowContractUpdate) SetNillableProjectID(u *uuid.UUID) *WorkflowContractUpdate { +// SetNillableScopedResourceType sets the "scoped_resource_type" field if the given value is not nil. +func (wcu *WorkflowContractUpdate) SetNillableScopedResourceType(bs *biz.ContractScope) *WorkflowContractUpdate { + if bs != nil { + wcu.SetScopedResourceType(*bs) + } + return wcu +} + +// ClearScopedResourceType clears the value of the "scoped_resource_type" field. +func (wcu *WorkflowContractUpdate) ClearScopedResourceType() *WorkflowContractUpdate { + wcu.mutation.ClearScopedResourceType() + return wcu +} + +// SetScopedResourceID sets the "scoped_resource_id" field. +func (wcu *WorkflowContractUpdate) SetScopedResourceID(u uuid.UUID) *WorkflowContractUpdate { + wcu.mutation.SetScopedResourceID(u) + return wcu +} + +// SetNillableScopedResourceID sets the "scoped_resource_id" field if the given value is not nil. +func (wcu *WorkflowContractUpdate) SetNillableScopedResourceID(u *uuid.UUID) *WorkflowContractUpdate { if u != nil { - wcu.SetProjectID(*u) + wcu.SetScopedResourceID(*u) } return wcu } -// ClearProjectID clears the value of the "project_id" field. -func (wcu *WorkflowContractUpdate) ClearProjectID() *WorkflowContractUpdate { - wcu.mutation.ClearProjectID() +// ClearScopedResourceID clears the value of the "scoped_resource_id" field. +func (wcu *WorkflowContractUpdate) ClearScopedResourceID() *WorkflowContractUpdate { + wcu.mutation.ClearScopedResourceID() return wcu } @@ -109,25 +128,6 @@ func (wcu *WorkflowContractUpdate) AddVersions(w ...*WorkflowContractVersion) *W return wcu.AddVersionIDs(ids...) } -// SetOrganizationID sets the "organization" edge to the Organization entity by ID. -func (wcu *WorkflowContractUpdate) SetOrganizationID(id uuid.UUID) *WorkflowContractUpdate { - wcu.mutation.SetOrganizationID(id) - return wcu -} - -// SetNillableOrganizationID sets the "organization" edge to the Organization entity by ID if the given value is not nil. -func (wcu *WorkflowContractUpdate) SetNillableOrganizationID(id *uuid.UUID) *WorkflowContractUpdate { - if id != nil { - wcu = wcu.SetOrganizationID(*id) - } - return wcu -} - -// SetOrganization sets the "organization" edge to the Organization entity. -func (wcu *WorkflowContractUpdate) SetOrganization(o *Organization) *WorkflowContractUpdate { - return wcu.SetOrganizationID(o.ID) -} - // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by IDs. func (wcu *WorkflowContractUpdate) AddWorkflowIDs(ids ...uuid.UUID) *WorkflowContractUpdate { wcu.mutation.AddWorkflowIDs(ids...) @@ -143,11 +143,6 @@ func (wcu *WorkflowContractUpdate) AddWorkflows(w ...*Workflow) *WorkflowContrac return wcu.AddWorkflowIDs(ids...) } -// SetProject sets the "project" edge to the Project entity. -func (wcu *WorkflowContractUpdate) SetProject(p *Project) *WorkflowContractUpdate { - return wcu.SetProjectID(p.ID) -} - // Mutation returns the WorkflowContractMutation object of the builder. func (wcu *WorkflowContractUpdate) Mutation() *WorkflowContractMutation { return wcu.mutation @@ -174,12 +169,6 @@ func (wcu *WorkflowContractUpdate) RemoveVersions(w ...*WorkflowContractVersion) return wcu.RemoveVersionIDs(ids...) } -// ClearOrganization clears the "organization" edge to the Organization entity. -func (wcu *WorkflowContractUpdate) ClearOrganization() *WorkflowContractUpdate { - wcu.mutation.ClearOrganization() - return wcu -} - // ClearWorkflows clears all "workflows" edges to the Workflow entity. func (wcu *WorkflowContractUpdate) ClearWorkflows() *WorkflowContractUpdate { wcu.mutation.ClearWorkflows() @@ -201,12 +190,6 @@ func (wcu *WorkflowContractUpdate) RemoveWorkflows(w ...*Workflow) *WorkflowCont return wcu.RemoveWorkflowIDs(ids...) } -// ClearProject clears the "project" edge to the Project entity. -func (wcu *WorkflowContractUpdate) ClearProject() *WorkflowContractUpdate { - wcu.mutation.ClearProject() - return wcu -} - // Save executes the query and returns the number of nodes affected by the update operation. func (wcu *WorkflowContractUpdate) Save(ctx context.Context) (int, error) { return withHooks(ctx, wcu.sqlSave, wcu.mutation, wcu.hooks) @@ -234,6 +217,16 @@ func (wcu *WorkflowContractUpdate) ExecX(ctx context.Context) { } } +// check runs all checks and user-defined validators on the builder. +func (wcu *WorkflowContractUpdate) check() error { + if v, ok := wcu.mutation.ScopedResourceType(); ok { + if err := workflowcontract.ScopedResourceTypeValidator(v); err != nil { + return &ValidationError{Name: "scoped_resource_type", err: fmt.Errorf(`ent: validator failed for field "WorkflowContract.scoped_resource_type": %w`, err)} + } + } + return nil +} + // Modify adds a statement modifier for attaching custom logic to the UPDATE statement. func (wcu *WorkflowContractUpdate) Modify(modifiers ...func(u *sql.UpdateBuilder)) *WorkflowContractUpdate { wcu.modifiers = append(wcu.modifiers, modifiers...) @@ -241,6 +234,9 @@ func (wcu *WorkflowContractUpdate) Modify(modifiers ...func(u *sql.UpdateBuilder } func (wcu *WorkflowContractUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := wcu.check(); err != nil { + return n, err + } _spec := sqlgraph.NewUpdateSpec(workflowcontract.Table, workflowcontract.Columns, sqlgraph.NewFieldSpec(workflowcontract.FieldID, field.TypeUUID)) if ps := wcu.mutation.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { @@ -261,6 +257,18 @@ func (wcu *WorkflowContractUpdate) sqlSave(ctx context.Context) (n int, err erro if wcu.mutation.DescriptionCleared() { _spec.ClearField(workflowcontract.FieldDescription, field.TypeString) } + if value, ok := wcu.mutation.ScopedResourceType(); ok { + _spec.SetField(workflowcontract.FieldScopedResourceType, field.TypeEnum, value) + } + if wcu.mutation.ScopedResourceTypeCleared() { + _spec.ClearField(workflowcontract.FieldScopedResourceType, field.TypeEnum) + } + if value, ok := wcu.mutation.ScopedResourceID(); ok { + _spec.SetField(workflowcontract.FieldScopedResourceID, field.TypeUUID, value) + } + if wcu.mutation.ScopedResourceIDCleared() { + _spec.ClearField(workflowcontract.FieldScopedResourceID, field.TypeUUID) + } if wcu.mutation.VersionsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -306,35 +314,6 @@ func (wcu *WorkflowContractUpdate) sqlSave(ctx context.Context) (n int, err erro } _spec.Edges.Add = append(_spec.Edges.Add, edge) } - if wcu.mutation.OrganizationCleared() { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: true, - Table: workflowcontract.OrganizationTable, - Columns: []string{workflowcontract.OrganizationColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), - }, - } - _spec.Edges.Clear = append(_spec.Edges.Clear, edge) - } - if nodes := wcu.mutation.OrganizationIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: true, - Table: workflowcontract.OrganizationTable, - Columns: []string{workflowcontract.OrganizationColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _spec.Edges.Add = append(_spec.Edges.Add, edge) - } if wcu.mutation.WorkflowsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -380,35 +359,6 @@ func (wcu *WorkflowContractUpdate) sqlSave(ctx context.Context) (n int, err erro } _spec.Edges.Add = append(_spec.Edges.Add, edge) } - if wcu.mutation.ProjectCleared() { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: workflowcontract.ProjectTable, - Columns: []string{workflowcontract.ProjectColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), - }, - } - _spec.Edges.Clear = append(_spec.Edges.Clear, edge) - } - if nodes := wcu.mutation.ProjectIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: workflowcontract.ProjectTable, - Columns: []string{workflowcontract.ProjectColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _spec.Edges.Add = append(_spec.Edges.Add, edge) - } _spec.AddModifiers(wcu.modifiers...) if n, err = sqlgraph.UpdateNodes(ctx, wcu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { @@ -471,23 +421,43 @@ func (wcuo *WorkflowContractUpdateOne) ClearDescription() *WorkflowContractUpdat return wcuo } -// SetProjectID sets the "project_id" field. -func (wcuo *WorkflowContractUpdateOne) SetProjectID(u uuid.UUID) *WorkflowContractUpdateOne { - wcuo.mutation.SetProjectID(u) +// SetScopedResourceType sets the "scoped_resource_type" field. +func (wcuo *WorkflowContractUpdateOne) SetScopedResourceType(bs biz.ContractScope) *WorkflowContractUpdateOne { + wcuo.mutation.SetScopedResourceType(bs) return wcuo } -// SetNillableProjectID sets the "project_id" field if the given value is not nil. -func (wcuo *WorkflowContractUpdateOne) SetNillableProjectID(u *uuid.UUID) *WorkflowContractUpdateOne { +// SetNillableScopedResourceType sets the "scoped_resource_type" field if the given value is not nil. +func (wcuo *WorkflowContractUpdateOne) SetNillableScopedResourceType(bs *biz.ContractScope) *WorkflowContractUpdateOne { + if bs != nil { + wcuo.SetScopedResourceType(*bs) + } + return wcuo +} + +// ClearScopedResourceType clears the value of the "scoped_resource_type" field. +func (wcuo *WorkflowContractUpdateOne) ClearScopedResourceType() *WorkflowContractUpdateOne { + wcuo.mutation.ClearScopedResourceType() + return wcuo +} + +// SetScopedResourceID sets the "scoped_resource_id" field. +func (wcuo *WorkflowContractUpdateOne) SetScopedResourceID(u uuid.UUID) *WorkflowContractUpdateOne { + wcuo.mutation.SetScopedResourceID(u) + return wcuo +} + +// SetNillableScopedResourceID sets the "scoped_resource_id" field if the given value is not nil. +func (wcuo *WorkflowContractUpdateOne) SetNillableScopedResourceID(u *uuid.UUID) *WorkflowContractUpdateOne { if u != nil { - wcuo.SetProjectID(*u) + wcuo.SetScopedResourceID(*u) } return wcuo } -// ClearProjectID clears the value of the "project_id" field. -func (wcuo *WorkflowContractUpdateOne) ClearProjectID() *WorkflowContractUpdateOne { - wcuo.mutation.ClearProjectID() +// ClearScopedResourceID clears the value of the "scoped_resource_id" field. +func (wcuo *WorkflowContractUpdateOne) ClearScopedResourceID() *WorkflowContractUpdateOne { + wcuo.mutation.ClearScopedResourceID() return wcuo } @@ -506,25 +476,6 @@ func (wcuo *WorkflowContractUpdateOne) AddVersions(w ...*WorkflowContractVersion return wcuo.AddVersionIDs(ids...) } -// SetOrganizationID sets the "organization" edge to the Organization entity by ID. -func (wcuo *WorkflowContractUpdateOne) SetOrganizationID(id uuid.UUID) *WorkflowContractUpdateOne { - wcuo.mutation.SetOrganizationID(id) - return wcuo -} - -// SetNillableOrganizationID sets the "organization" edge to the Organization entity by ID if the given value is not nil. -func (wcuo *WorkflowContractUpdateOne) SetNillableOrganizationID(id *uuid.UUID) *WorkflowContractUpdateOne { - if id != nil { - wcuo = wcuo.SetOrganizationID(*id) - } - return wcuo -} - -// SetOrganization sets the "organization" edge to the Organization entity. -func (wcuo *WorkflowContractUpdateOne) SetOrganization(o *Organization) *WorkflowContractUpdateOne { - return wcuo.SetOrganizationID(o.ID) -} - // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by IDs. func (wcuo *WorkflowContractUpdateOne) AddWorkflowIDs(ids ...uuid.UUID) *WorkflowContractUpdateOne { wcuo.mutation.AddWorkflowIDs(ids...) @@ -540,11 +491,6 @@ func (wcuo *WorkflowContractUpdateOne) AddWorkflows(w ...*Workflow) *WorkflowCon return wcuo.AddWorkflowIDs(ids...) } -// SetProject sets the "project" edge to the Project entity. -func (wcuo *WorkflowContractUpdateOne) SetProject(p *Project) *WorkflowContractUpdateOne { - return wcuo.SetProjectID(p.ID) -} - // Mutation returns the WorkflowContractMutation object of the builder. func (wcuo *WorkflowContractUpdateOne) Mutation() *WorkflowContractMutation { return wcuo.mutation @@ -571,12 +517,6 @@ func (wcuo *WorkflowContractUpdateOne) RemoveVersions(w ...*WorkflowContractVers return wcuo.RemoveVersionIDs(ids...) } -// ClearOrganization clears the "organization" edge to the Organization entity. -func (wcuo *WorkflowContractUpdateOne) ClearOrganization() *WorkflowContractUpdateOne { - wcuo.mutation.ClearOrganization() - return wcuo -} - // ClearWorkflows clears all "workflows" edges to the Workflow entity. func (wcuo *WorkflowContractUpdateOne) ClearWorkflows() *WorkflowContractUpdateOne { wcuo.mutation.ClearWorkflows() @@ -598,12 +538,6 @@ func (wcuo *WorkflowContractUpdateOne) RemoveWorkflows(w ...*Workflow) *Workflow return wcuo.RemoveWorkflowIDs(ids...) } -// ClearProject clears the "project" edge to the Project entity. -func (wcuo *WorkflowContractUpdateOne) ClearProject() *WorkflowContractUpdateOne { - wcuo.mutation.ClearProject() - return wcuo -} - // Where appends a list predicates to the WorkflowContractUpdate builder. func (wcuo *WorkflowContractUpdateOne) Where(ps ...predicate.WorkflowContract) *WorkflowContractUpdateOne { wcuo.mutation.Where(ps...) @@ -644,6 +578,16 @@ func (wcuo *WorkflowContractUpdateOne) ExecX(ctx context.Context) { } } +// check runs all checks and user-defined validators on the builder. +func (wcuo *WorkflowContractUpdateOne) check() error { + if v, ok := wcuo.mutation.ScopedResourceType(); ok { + if err := workflowcontract.ScopedResourceTypeValidator(v); err != nil { + return &ValidationError{Name: "scoped_resource_type", err: fmt.Errorf(`ent: validator failed for field "WorkflowContract.scoped_resource_type": %w`, err)} + } + } + return nil +} + // Modify adds a statement modifier for attaching custom logic to the UPDATE statement. func (wcuo *WorkflowContractUpdateOne) Modify(modifiers ...func(u *sql.UpdateBuilder)) *WorkflowContractUpdateOne { wcuo.modifiers = append(wcuo.modifiers, modifiers...) @@ -651,6 +595,9 @@ func (wcuo *WorkflowContractUpdateOne) Modify(modifiers ...func(u *sql.UpdateBui } func (wcuo *WorkflowContractUpdateOne) sqlSave(ctx context.Context) (_node *WorkflowContract, err error) { + if err := wcuo.check(); err != nil { + return _node, err + } _spec := sqlgraph.NewUpdateSpec(workflowcontract.Table, workflowcontract.Columns, sqlgraph.NewFieldSpec(workflowcontract.FieldID, field.TypeUUID)) id, ok := wcuo.mutation.ID() if !ok { @@ -688,6 +635,18 @@ func (wcuo *WorkflowContractUpdateOne) sqlSave(ctx context.Context) (_node *Work if wcuo.mutation.DescriptionCleared() { _spec.ClearField(workflowcontract.FieldDescription, field.TypeString) } + if value, ok := wcuo.mutation.ScopedResourceType(); ok { + _spec.SetField(workflowcontract.FieldScopedResourceType, field.TypeEnum, value) + } + if wcuo.mutation.ScopedResourceTypeCleared() { + _spec.ClearField(workflowcontract.FieldScopedResourceType, field.TypeEnum) + } + if value, ok := wcuo.mutation.ScopedResourceID(); ok { + _spec.SetField(workflowcontract.FieldScopedResourceID, field.TypeUUID, value) + } + if wcuo.mutation.ScopedResourceIDCleared() { + _spec.ClearField(workflowcontract.FieldScopedResourceID, field.TypeUUID) + } if wcuo.mutation.VersionsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -733,35 +692,6 @@ func (wcuo *WorkflowContractUpdateOne) sqlSave(ctx context.Context) (_node *Work } _spec.Edges.Add = append(_spec.Edges.Add, edge) } - if wcuo.mutation.OrganizationCleared() { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: true, - Table: workflowcontract.OrganizationTable, - Columns: []string{workflowcontract.OrganizationColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), - }, - } - _spec.Edges.Clear = append(_spec.Edges.Clear, edge) - } - if nodes := wcuo.mutation.OrganizationIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: true, - Table: workflowcontract.OrganizationTable, - Columns: []string{workflowcontract.OrganizationColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _spec.Edges.Add = append(_spec.Edges.Add, edge) - } if wcuo.mutation.WorkflowsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -807,35 +737,6 @@ func (wcuo *WorkflowContractUpdateOne) sqlSave(ctx context.Context) (_node *Work } _spec.Edges.Add = append(_spec.Edges.Add, edge) } - if wcuo.mutation.ProjectCleared() { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: workflowcontract.ProjectTable, - Columns: []string{workflowcontract.ProjectColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), - }, - } - _spec.Edges.Clear = append(_spec.Edges.Clear, edge) - } - if nodes := wcuo.mutation.ProjectIDs(); len(nodes) > 0 { - edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, - Inverse: false, - Table: workflowcontract.ProjectTable, - Columns: []string{workflowcontract.ProjectColumn}, - Bidi: false, - Target: &sqlgraph.EdgeTarget{ - IDSpec: sqlgraph.NewFieldSpec(project.FieldID, field.TypeUUID), - }, - } - for _, k := range nodes { - edge.Target.Nodes = append(edge.Target.Nodes, k) - } - _spec.Edges.Add = append(_spec.Edges.Add, edge) - } _spec.AddModifiers(wcuo.modifiers...) _node = &WorkflowContract{config: wcuo.config} _spec.Assign = _node.assignValues diff --git a/go.sum b/go.sum index 10e45e5c7..e16b77962 100644 --- a/go.sum +++ b/go.sum @@ -1079,6 +1079,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/oleiade/reflections v1.1.0 h1:D+I/UsXQB4esMathlt0kkZRJZdUDmhv5zGi/HOwYTWo= github.com/oleiade/reflections v1.1.0/go.mod h1:mCxx0QseeVCHs5Um5HhJeCKVC7AwS8kO67tky4rdisA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= From ccf9c0749782d4b6b83c3f16b826a1551ca4e9e4 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 4 Jul 2025 13:04:01 +0200 Subject: [PATCH 04/16] fix tests Signed-off-by: Miguel Martinez --- app/controlplane/pkg/data/ent/client.go | 16 +++ .../ent/migrate/migrations/20250704092359.sql | 8 ++ .../pkg/data/ent/migrate/migrations/atlas.sum | 8 ++ .../pkg/data/ent/migrate/schema.go | 8 ++ app/controlplane/pkg/data/ent/mutation.go | 65 ++++++++++- .../pkg/data/ent/schema/workflowcontract.go | 15 ++- .../pkg/data/ent/workflowcontract.go | 23 +++- .../pkg/data/ent/workflowcontract/where.go | 23 ++++ .../ent/workflowcontract/workflowcontract.go | 23 ++++ .../pkg/data/ent/workflowcontract_create.go | 37 ++++++ .../pkg/data/ent/workflowcontract_query.go | 110 +++++++++++++++--- .../pkg/data/ent/workflowcontract_update.go | 109 +++++++++++++++++ 12 files changed, 421 insertions(+), 24 deletions(-) create mode 100644 app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql diff --git a/app/controlplane/pkg/data/ent/client.go b/app/controlplane/pkg/data/ent/client.go index 5d44cdfa1..e1ed0c1c7 100644 --- a/app/controlplane/pkg/data/ent/client.go +++ b/app/controlplane/pkg/data/ent/client.go @@ -3535,6 +3535,22 @@ func (c *WorkflowContractClient) QueryVersions(wc *WorkflowContract) *WorkflowCo return query } +// QueryOrganization queries the organization edge of a WorkflowContract. +func (c *WorkflowContractClient) QueryOrganization(wc *WorkflowContract) *OrganizationQuery { + query := (&OrganizationClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := wc.ID + step := sqlgraph.NewStep( + sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, id), + sqlgraph.To(organization.Table, organization.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, workflowcontract.OrganizationTable, workflowcontract.OrganizationColumn), + ) + fromV = sqlgraph.Neighbors(wc.driver.Dialect(), step) + return fromV, nil + } + return query +} + // QueryWorkflows queries the workflows edge of a WorkflowContract. func (c *WorkflowContractClient) QueryWorkflows(wc *WorkflowContract) *WorkflowQuery { query := (&WorkflowClient{config: c.config}).Query() diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql b/app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql new file mode 100644 index 000000000..87cba251d --- /dev/null +++ b/app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql @@ -0,0 +1,8 @@ +-- Drop index "workflowcontract_name_organization_workflow_contracts" from table: "workflow_contracts" +DROP INDEX "workflowcontract_name_organization_workflow_contracts"; +-- Modify "workflow_contracts" table +ALTER TABLE "workflow_contracts" ADD COLUMN "scoped_resource_type" character varying NULL, ADD COLUMN "scoped_resource_id" uuid NULL; +-- Create index "workflowcontract_name_organization_workflow_contracts" to table: "workflow_contracts" +CREATE UNIQUE INDEX "workflowcontract_name_organization_workflow_contracts" ON "workflow_contracts" ("name", "organization_workflow_contracts") WHERE ((deleted_at IS NULL) AND (scoped_resource_type IS NULL)); +-- Create index "workflowcontract_name_scoped_resource_type_scoped_resource_id" to table: "workflow_contracts" +CREATE UNIQUE INDEX "workflowcontract_name_scoped_resource_type_scoped_resource_id" ON "workflow_contracts" ("name", "scoped_resource_type", "scoped_resource_id") WHERE (deleted_at IS NULL); diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum index a74777b78..42ac9c09a 100644 --- a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum @@ -1,5 +1,6 @@ <<<<<<< HEAD <<<<<<< HEAD +<<<<<<< HEAD h1:pewT4SIwZxo6E95TRjOvYvsO2AvVZDBRPljhvi6yN3c= ======= h1:Nqn7kGmL5Hba+3tAbxdDjH6+KvSmunyHZuDIthoGQiU= @@ -7,6 +8,9 @@ h1:Nqn7kGmL5Hba+3tAbxdDjH6+KvSmunyHZuDIthoGQiU= ======= h1:oR9RWah9qFLH+GgYn2+C1UpTH2Z82Zj36QLGWRG5X+4= >>>>>>> 7a8275ef (fix tests) +======= +h1:TVyZPOeAizQac42YgtwcW2RP0MefJCyThmt5yVkE/+8= +>>>>>>> a17a71d0 (fix tests) 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -102,6 +106,7 @@ h1:oR9RWah9qFLH+GgYn2+C1UpTH2Z82Zj36QLGWRG5X+4= 20250627143634.sql h1:9UdcOm4HdWyJ8bvU/vYkzCslXIpKSn7pM0l/MJHl8n4= 20250702111701.sql h1:Ni7fuL1qU5RGjBzV0XgJi9NkZINGijF8BumPuQ9conM= <<<<<<< HEAD +<<<<<<< HEAD 20250702112642.sql h1:wrjVS+5h2hs7KNwPRBece5LgAsoEzxN/zNfvCnjoIUw= 20250704090359.sql h1:a0ksfjy2dtzviJL16HbC4eT1xBxy2qFH5mNFOpYlUrA= ======= @@ -111,3 +116,6 @@ h1:oR9RWah9qFLH+GgYn2+C1UpTH2Z82Zj36QLGWRG5X+4= ======= 20250704090525.sql h1:VO/Kf+I0GJDfL2FaHk36YZ7f6uY9VrHjrP3EuQAidHM= >>>>>>> 7a8275ef (fix tests) +======= +20250704092359.sql h1:4WDmb0R+obpATOgDONCxoYPxVLTl9jjpkzzOEfIUPIU= +>>>>>>> a17a71d0 (fix tests) diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index 205dcce76..9a2f43be5 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -659,6 +659,14 @@ var ( }, }, Indexes: []*schema.Index{ + { + Name: "workflowcontract_name_organization_workflow_contracts", + Unique: true, + Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[7]}, + Annotation: &entsql.IndexAnnotation{ + Where: "deleted_at IS NULL AND scoped_resource_type IS NULL", + }, + }, { Name: "workflowcontract_name_scoped_resource_type_scoped_resource_id", Unique: true, diff --git a/app/controlplane/pkg/data/ent/mutation.go b/app/controlplane/pkg/data/ent/mutation.go index 376a8d024..4230c0b82 100644 --- a/app/controlplane/pkg/data/ent/mutation.go +++ b/app/controlplane/pkg/data/ent/mutation.go @@ -15259,6 +15259,8 @@ type WorkflowContractMutation struct { versions map[uuid.UUID]struct{} removedversions map[uuid.UUID]struct{} clearedversions bool + organization *uuid.UUID + clearedorganization bool workflows map[uuid.UUID]struct{} removedworkflows map[uuid.UUID]struct{} clearedworkflows bool @@ -15693,6 +15695,45 @@ func (m *WorkflowContractMutation) ResetVersions() { m.removedversions = nil } +// SetOrganizationID sets the "organization" edge to the Organization entity by id. +func (m *WorkflowContractMutation) SetOrganizationID(id uuid.UUID) { + m.organization = &id +} + +// ClearOrganization clears the "organization" edge to the Organization entity. +func (m *WorkflowContractMutation) ClearOrganization() { + m.clearedorganization = true +} + +// OrganizationCleared reports if the "organization" edge to the Organization entity was cleared. +func (m *WorkflowContractMutation) OrganizationCleared() bool { + return m.clearedorganization +} + +// OrganizationID returns the "organization" edge ID in the mutation. +func (m *WorkflowContractMutation) OrganizationID() (id uuid.UUID, exists bool) { + if m.organization != nil { + return *m.organization, true + } + return +} + +// OrganizationIDs returns the "organization" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// OrganizationID instead. It exists only for internal usage by the builders. +func (m *WorkflowContractMutation) OrganizationIDs() (ids []uuid.UUID) { + if id := m.organization; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetOrganization resets all changes to the "organization" edge. +func (m *WorkflowContractMutation) ResetOrganization() { + m.organization = nil + m.clearedorganization = false +} + // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by ids. func (m *WorkflowContractMutation) AddWorkflowIDs(ids ...uuid.UUID) { if m.workflows == nil { @@ -15992,10 +16033,13 @@ func (m *WorkflowContractMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *WorkflowContractMutation) AddedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 3) if m.versions != nil { edges = append(edges, workflowcontract.EdgeVersions) } + if m.organization != nil { + edges = append(edges, workflowcontract.EdgeOrganization) + } if m.workflows != nil { edges = append(edges, workflowcontract.EdgeWorkflows) } @@ -16012,6 +16056,10 @@ func (m *WorkflowContractMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case workflowcontract.EdgeOrganization: + if id := m.organization; id != nil { + return []ent.Value{*id} + } case workflowcontract.EdgeWorkflows: ids := make([]ent.Value, 0, len(m.workflows)) for id := range m.workflows { @@ -16024,7 +16072,7 @@ func (m *WorkflowContractMutation) AddedIDs(name string) []ent.Value { // RemovedEdges returns all edge names that were removed in this mutation. func (m *WorkflowContractMutation) RemovedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 3) if m.removedversions != nil { edges = append(edges, workflowcontract.EdgeVersions) } @@ -16056,10 +16104,13 @@ func (m *WorkflowContractMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *WorkflowContractMutation) ClearedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 3) if m.clearedversions { edges = append(edges, workflowcontract.EdgeVersions) } + if m.clearedorganization { + edges = append(edges, workflowcontract.EdgeOrganization) + } if m.clearedworkflows { edges = append(edges, workflowcontract.EdgeWorkflows) } @@ -16072,6 +16123,8 @@ func (m *WorkflowContractMutation) EdgeCleared(name string) bool { switch name { case workflowcontract.EdgeVersions: return m.clearedversions + case workflowcontract.EdgeOrganization: + return m.clearedorganization case workflowcontract.EdgeWorkflows: return m.clearedworkflows } @@ -16082,6 +16135,9 @@ func (m *WorkflowContractMutation) EdgeCleared(name string) bool { // if that edge is not defined in the schema. func (m *WorkflowContractMutation) ClearEdge(name string) error { switch name { + case workflowcontract.EdgeOrganization: + m.ClearOrganization() + return nil } return fmt.Errorf("unknown WorkflowContract unique edge %s", name) } @@ -16093,6 +16149,9 @@ func (m *WorkflowContractMutation) ResetEdge(name string) error { case workflowcontract.EdgeVersions: m.ResetVersions() return nil + case workflowcontract.EdgeOrganization: + m.ResetOrganization() + return nil case workflowcontract.EdgeWorkflows: m.ResetWorkflows() return nil diff --git a/app/controlplane/pkg/data/ent/schema/workflowcontract.go b/app/controlplane/pkg/data/ent/schema/workflowcontract.go index 455ea638f..94d0d84f7 100644 --- a/app/controlplane/pkg/data/ent/schema/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/schema/workflowcontract.go @@ -1,5 +1,5 @@ // -// Copyright 2024-2025 The Chainloop Authors. +// Copyright 2024 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ func (WorkflowContract) Fields() []ent.Field { }), field.Time("deleted_at").Optional(), field.String("description").Optional(), - // If this value is set, the contract is scoped to a project or organization + // If this value is set, the contract is scoped to a resource field.Enum("scoped_resource_type").GoType(biz.ContractScope("")).Optional(), field.UUID("scoped_resource_id", uuid.UUID{}).Optional(), } @@ -55,6 +55,11 @@ func (WorkflowContract) Fields() []ent.Field { func (WorkflowContract) Edges() []ent.Edge { return []ent.Edge{ edge.To("versions", WorkflowContractVersion.Type), + // We keep the organization edge to be able to easily list all the contracts + // regardless of the scope + edge.From("organization", Organization.Type). + Ref("workflow_contracts"). + Unique(), // A contract can be associated to multiple workflows edge.From("workflows", Workflow.Type).Ref("contract"), } @@ -62,7 +67,11 @@ func (WorkflowContract) Edges() []ent.Edge { func (WorkflowContract) Indexes() []ent.Index { return []ent.Index{ - // names are unique within a organization and affects only to non-deleted items + // names are unique within a organization and affects only to non-scoped and non-deleted items + index.Fields("name").Edges("organization").Unique().Annotations( + entsql.IndexWhere("deleted_at IS NULL AND scoped_resource_type IS NULL"), + ), + // names are unique within a resource and affects only to non-deleted items index.Fields("name", "scoped_resource_type", "scoped_resource_id").Unique().Annotations( entsql.IndexWhere("deleted_at IS NULL"), ), diff --git a/app/controlplane/pkg/data/ent/workflowcontract.go b/app/controlplane/pkg/data/ent/workflowcontract.go index 2a67948fd..b4ba03c94 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/workflowcontract.go @@ -10,6 +10,7 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/google/uuid" ) @@ -42,11 +43,13 @@ type WorkflowContract struct { type WorkflowContractEdges struct { // Versions holds the value of the versions edge. Versions []*WorkflowContractVersion `json:"versions,omitempty"` + // Organization holds the value of the organization edge. + Organization *Organization `json:"organization,omitempty"` // Workflows holds the value of the workflows edge. Workflows []*Workflow `json:"workflows,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [2]bool + loadedTypes [3]bool } // VersionsOrErr returns the Versions value or an error if the edge @@ -58,10 +61,21 @@ func (e WorkflowContractEdges) VersionsOrErr() ([]*WorkflowContractVersion, erro return nil, &NotLoadedError{edge: "versions"} } +// OrganizationOrErr returns the Organization value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e WorkflowContractEdges) OrganizationOrErr() (*Organization, error) { + if e.Organization != nil { + return e.Organization, nil + } else if e.loadedTypes[1] { + return nil, &NotFoundError{label: organization.Label} + } + return nil, &NotLoadedError{edge: "organization"} +} + // WorkflowsOrErr returns the Workflows value or an error if the edge // was not loaded in eager-loading. func (e WorkflowContractEdges) WorkflowsOrErr() ([]*Workflow, error) { - if e.loadedTypes[1] { + if e.loadedTypes[2] { return e.Workflows, nil } return nil, &NotLoadedError{edge: "workflows"} @@ -162,6 +176,11 @@ func (wc *WorkflowContract) QueryVersions() *WorkflowContractVersionQuery { return NewWorkflowContractClient(wc.config).QueryVersions(wc) } +// QueryOrganization queries the "organization" edge of the WorkflowContract entity. +func (wc *WorkflowContract) QueryOrganization() *OrganizationQuery { + return NewWorkflowContractClient(wc.config).QueryOrganization(wc) +} + // QueryWorkflows queries the "workflows" edge of the WorkflowContract entity. func (wc *WorkflowContract) QueryWorkflows() *WorkflowQuery { return NewWorkflowContractClient(wc.config).QueryWorkflows(wc) diff --git a/app/controlplane/pkg/data/ent/workflowcontract/where.go b/app/controlplane/pkg/data/ent/workflowcontract/where.go index b7db780dd..ade940dec 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract/where.go +++ b/app/controlplane/pkg/data/ent/workflowcontract/where.go @@ -425,6 +425,29 @@ func HasVersionsWith(preds ...predicate.WorkflowContractVersion) predicate.Workf }) } +// HasOrganization applies the HasEdge predicate on the "organization" edge. +func HasOrganization() predicate.WorkflowContract { + return predicate.WorkflowContract(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, OrganizationTable, OrganizationColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasOrganizationWith applies the HasEdge predicate on the "organization" edge with a given conditions (other predicates). +func HasOrganizationWith(preds ...predicate.Organization) predicate.WorkflowContract { + return predicate.WorkflowContract(func(s *sql.Selector) { + step := newOrganizationStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // HasWorkflows applies the HasEdge predicate on the "workflows" edge. func HasWorkflows() predicate.WorkflowContract { return predicate.WorkflowContract(func(s *sql.Selector) { diff --git a/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go b/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go index e8ee814e2..c3b1fa48c 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/workflowcontract/workflowcontract.go @@ -31,6 +31,8 @@ const ( FieldScopedResourceID = "scoped_resource_id" // EdgeVersions holds the string denoting the versions edge name in mutations. EdgeVersions = "versions" + // EdgeOrganization holds the string denoting the organization edge name in mutations. + EdgeOrganization = "organization" // EdgeWorkflows holds the string denoting the workflows edge name in mutations. EdgeWorkflows = "workflows" // Table holds the table name of the workflowcontract in the database. @@ -42,6 +44,13 @@ const ( VersionsInverseTable = "workflow_contract_versions" // VersionsColumn is the table column denoting the versions relation/edge. VersionsColumn = "workflow_contract_versions" + // OrganizationTable is the table that holds the organization relation/edge. + OrganizationTable = "workflow_contracts" + // OrganizationInverseTable is the table name for the Organization entity. + // It exists in this package in order to avoid circular dependency with the "organization" package. + OrganizationInverseTable = "organizations" + // OrganizationColumn is the table column denoting the organization relation/edge. + OrganizationColumn = "organization_workflow_contracts" // WorkflowsTable is the table that holds the workflows relation/edge. WorkflowsTable = "workflows" // WorkflowsInverseTable is the table name for the Workflow entity. @@ -152,6 +161,13 @@ func ByVersions(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { } } +// ByOrganizationField orders the results by organization field. +func ByOrganizationField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newOrganizationStep(), sql.OrderByField(field, opts...)) + } +} + // ByWorkflowsCount orders the results by workflows count. func ByWorkflowsCount(opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { @@ -172,6 +188,13 @@ func newVersionsStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, false, VersionsTable, VersionsColumn), ) } +func newOrganizationStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(OrganizationInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, OrganizationTable, OrganizationColumn), + ) +} func newWorkflowsStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), diff --git a/app/controlplane/pkg/data/ent/workflowcontract_create.go b/app/controlplane/pkg/data/ent/workflowcontract_create.go index 065783ccd..766cd59bb 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_create.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_create.go @@ -13,6 +13,7 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontractversion" @@ -132,6 +133,25 @@ func (wcc *WorkflowContractCreate) AddVersions(w ...*WorkflowContractVersion) *W return wcc.AddVersionIDs(ids...) } +// SetOrganizationID sets the "organization" edge to the Organization entity by ID. +func (wcc *WorkflowContractCreate) SetOrganizationID(id uuid.UUID) *WorkflowContractCreate { + wcc.mutation.SetOrganizationID(id) + return wcc +} + +// SetNillableOrganizationID sets the "organization" edge to the Organization entity by ID if the given value is not nil. +func (wcc *WorkflowContractCreate) SetNillableOrganizationID(id *uuid.UUID) *WorkflowContractCreate { + if id != nil { + wcc = wcc.SetOrganizationID(*id) + } + return wcc +} + +// SetOrganization sets the "organization" edge to the Organization entity. +func (wcc *WorkflowContractCreate) SetOrganization(o *Organization) *WorkflowContractCreate { + return wcc.SetOrganizationID(o.ID) +} + // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by IDs. func (wcc *WorkflowContractCreate) AddWorkflowIDs(ids ...uuid.UUID) *WorkflowContractCreate { wcc.mutation.AddWorkflowIDs(ids...) @@ -281,6 +301,23 @@ func (wcc *WorkflowContractCreate) createSpec() (*WorkflowContract, *sqlgraph.Cr } _spec.Edges = append(_spec.Edges, edge) } + if nodes := wcc.mutation.OrganizationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: workflowcontract.OrganizationTable, + Columns: []string{workflowcontract.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.organization_workflow_contracts = &nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } if nodes := wcc.mutation.WorkflowsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/app/controlplane/pkg/data/ent/workflowcontract_query.go b/app/controlplane/pkg/data/ent/workflowcontract_query.go index 9009f4f0e..1d2e2652c 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_query.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_query.go @@ -13,6 +13,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/predicate" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" @@ -23,14 +24,15 @@ import ( // WorkflowContractQuery is the builder for querying WorkflowContract entities. type WorkflowContractQuery struct { config - ctx *QueryContext - order []workflowcontract.OrderOption - inters []Interceptor - predicates []predicate.WorkflowContract - withVersions *WorkflowContractVersionQuery - withWorkflows *WorkflowQuery - withFKs bool - modifiers []func(*sql.Selector) + ctx *QueryContext + order []workflowcontract.OrderOption + inters []Interceptor + predicates []predicate.WorkflowContract + withVersions *WorkflowContractVersionQuery + withOrganization *OrganizationQuery + withWorkflows *WorkflowQuery + withFKs bool + modifiers []func(*sql.Selector) // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -89,6 +91,28 @@ func (wcq *WorkflowContractQuery) QueryVersions() *WorkflowContractVersionQuery return query } +// QueryOrganization chains the current query on the "organization" edge. +func (wcq *WorkflowContractQuery) QueryOrganization() *OrganizationQuery { + query := (&OrganizationClient{config: wcq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := wcq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := wcq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(workflowcontract.Table, workflowcontract.FieldID, selector), + sqlgraph.To(organization.Table, organization.FieldID), + sqlgraph.Edge(sqlgraph.M2O, true, workflowcontract.OrganizationTable, workflowcontract.OrganizationColumn), + ) + fromU = sqlgraph.SetNeighbors(wcq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // QueryWorkflows chains the current query on the "workflows" edge. func (wcq *WorkflowContractQuery) QueryWorkflows() *WorkflowQuery { query := (&WorkflowClient{config: wcq.config}).Query() @@ -298,13 +322,14 @@ func (wcq *WorkflowContractQuery) Clone() *WorkflowContractQuery { return nil } return &WorkflowContractQuery{ - config: wcq.config, - ctx: wcq.ctx.Clone(), - order: append([]workflowcontract.OrderOption{}, wcq.order...), - inters: append([]Interceptor{}, wcq.inters...), - predicates: append([]predicate.WorkflowContract{}, wcq.predicates...), - withVersions: wcq.withVersions.Clone(), - withWorkflows: wcq.withWorkflows.Clone(), + config: wcq.config, + ctx: wcq.ctx.Clone(), + order: append([]workflowcontract.OrderOption{}, wcq.order...), + inters: append([]Interceptor{}, wcq.inters...), + predicates: append([]predicate.WorkflowContract{}, wcq.predicates...), + withVersions: wcq.withVersions.Clone(), + withOrganization: wcq.withOrganization.Clone(), + withWorkflows: wcq.withWorkflows.Clone(), // clone intermediate query. sql: wcq.sql.Clone(), path: wcq.path, @@ -323,6 +348,17 @@ func (wcq *WorkflowContractQuery) WithVersions(opts ...func(*WorkflowContractVer return wcq } +// WithOrganization tells the query-builder to eager-load the nodes that are connected to +// the "organization" edge. The optional arguments are used to configure the query builder of the edge. +func (wcq *WorkflowContractQuery) WithOrganization(opts ...func(*OrganizationQuery)) *WorkflowContractQuery { + query := (&OrganizationClient{config: wcq.config}).Query() + for _, opt := range opts { + opt(query) + } + wcq.withOrganization = query + return wcq +} + // WithWorkflows tells the query-builder to eager-load the nodes that are connected to // the "workflows" edge. The optional arguments are used to configure the query builder of the edge. func (wcq *WorkflowContractQuery) WithWorkflows(opts ...func(*WorkflowQuery)) *WorkflowContractQuery { @@ -413,11 +449,15 @@ func (wcq *WorkflowContractQuery) sqlAll(ctx context.Context, hooks ...queryHook nodes = []*WorkflowContract{} withFKs = wcq.withFKs _spec = wcq.querySpec() - loadedTypes = [2]bool{ + loadedTypes = [3]bool{ wcq.withVersions != nil, + wcq.withOrganization != nil, wcq.withWorkflows != nil, } ) + if wcq.withOrganization != nil { + withFKs = true + } if withFKs { _spec.Node.Columns = append(_spec.Node.Columns, workflowcontract.ForeignKeys...) } @@ -449,6 +489,12 @@ func (wcq *WorkflowContractQuery) sqlAll(ctx context.Context, hooks ...queryHook return nil, err } } + if query := wcq.withOrganization; query != nil { + if err := wcq.loadOrganization(ctx, query, nodes, nil, + func(n *WorkflowContract, e *Organization) { n.Edges.Organization = e }); err != nil { + return nil, err + } + } if query := wcq.withWorkflows; query != nil { if err := wcq.loadWorkflows(ctx, query, nodes, func(n *WorkflowContract) { n.Edges.Workflows = []*Workflow{} }, @@ -490,6 +536,38 @@ func (wcq *WorkflowContractQuery) loadVersions(ctx context.Context, query *Workf } return nil } +func (wcq *WorkflowContractQuery) loadOrganization(ctx context.Context, query *OrganizationQuery, nodes []*WorkflowContract, init func(*WorkflowContract), assign func(*WorkflowContract, *Organization)) error { + ids := make([]uuid.UUID, 0, len(nodes)) + nodeids := make(map[uuid.UUID][]*WorkflowContract) + for i := range nodes { + if nodes[i].organization_workflow_contracts == nil { + continue + } + fk := *nodes[i].organization_workflow_contracts + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(organization.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "organization_workflow_contracts" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} func (wcq *WorkflowContractQuery) loadWorkflows(ctx context.Context, query *WorkflowQuery, nodes []*WorkflowContract, init func(*WorkflowContract), assign func(*WorkflowContract, *Workflow)) error { fks := make([]driver.Value, 0, len(nodes)) nodeids := make(map[uuid.UUID]*WorkflowContract) diff --git a/app/controlplane/pkg/data/ent/workflowcontract_update.go b/app/controlplane/pkg/data/ent/workflowcontract_update.go index c7cc64646..5ea09f64b 100644 --- a/app/controlplane/pkg/data/ent/workflowcontract_update.go +++ b/app/controlplane/pkg/data/ent/workflowcontract_update.go @@ -12,6 +12,7 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/organization" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/predicate" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflow" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/data/ent/workflowcontract" @@ -128,6 +129,25 @@ func (wcu *WorkflowContractUpdate) AddVersions(w ...*WorkflowContractVersion) *W return wcu.AddVersionIDs(ids...) } +// SetOrganizationID sets the "organization" edge to the Organization entity by ID. +func (wcu *WorkflowContractUpdate) SetOrganizationID(id uuid.UUID) *WorkflowContractUpdate { + wcu.mutation.SetOrganizationID(id) + return wcu +} + +// SetNillableOrganizationID sets the "organization" edge to the Organization entity by ID if the given value is not nil. +func (wcu *WorkflowContractUpdate) SetNillableOrganizationID(id *uuid.UUID) *WorkflowContractUpdate { + if id != nil { + wcu = wcu.SetOrganizationID(*id) + } + return wcu +} + +// SetOrganization sets the "organization" edge to the Organization entity. +func (wcu *WorkflowContractUpdate) SetOrganization(o *Organization) *WorkflowContractUpdate { + return wcu.SetOrganizationID(o.ID) +} + // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by IDs. func (wcu *WorkflowContractUpdate) AddWorkflowIDs(ids ...uuid.UUID) *WorkflowContractUpdate { wcu.mutation.AddWorkflowIDs(ids...) @@ -169,6 +189,12 @@ func (wcu *WorkflowContractUpdate) RemoveVersions(w ...*WorkflowContractVersion) return wcu.RemoveVersionIDs(ids...) } +// ClearOrganization clears the "organization" edge to the Organization entity. +func (wcu *WorkflowContractUpdate) ClearOrganization() *WorkflowContractUpdate { + wcu.mutation.ClearOrganization() + return wcu +} + // ClearWorkflows clears all "workflows" edges to the Workflow entity. func (wcu *WorkflowContractUpdate) ClearWorkflows() *WorkflowContractUpdate { wcu.mutation.ClearWorkflows() @@ -314,6 +340,35 @@ func (wcu *WorkflowContractUpdate) sqlSave(ctx context.Context) (n int, err erro } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if wcu.mutation.OrganizationCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: workflowcontract.OrganizationTable, + Columns: []string{workflowcontract.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := wcu.mutation.OrganizationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: workflowcontract.OrganizationTable, + Columns: []string{workflowcontract.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if wcu.mutation.WorkflowsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -476,6 +531,25 @@ func (wcuo *WorkflowContractUpdateOne) AddVersions(w ...*WorkflowContractVersion return wcuo.AddVersionIDs(ids...) } +// SetOrganizationID sets the "organization" edge to the Organization entity by ID. +func (wcuo *WorkflowContractUpdateOne) SetOrganizationID(id uuid.UUID) *WorkflowContractUpdateOne { + wcuo.mutation.SetOrganizationID(id) + return wcuo +} + +// SetNillableOrganizationID sets the "organization" edge to the Organization entity by ID if the given value is not nil. +func (wcuo *WorkflowContractUpdateOne) SetNillableOrganizationID(id *uuid.UUID) *WorkflowContractUpdateOne { + if id != nil { + wcuo = wcuo.SetOrganizationID(*id) + } + return wcuo +} + +// SetOrganization sets the "organization" edge to the Organization entity. +func (wcuo *WorkflowContractUpdateOne) SetOrganization(o *Organization) *WorkflowContractUpdateOne { + return wcuo.SetOrganizationID(o.ID) +} + // AddWorkflowIDs adds the "workflows" edge to the Workflow entity by IDs. func (wcuo *WorkflowContractUpdateOne) AddWorkflowIDs(ids ...uuid.UUID) *WorkflowContractUpdateOne { wcuo.mutation.AddWorkflowIDs(ids...) @@ -517,6 +591,12 @@ func (wcuo *WorkflowContractUpdateOne) RemoveVersions(w ...*WorkflowContractVers return wcuo.RemoveVersionIDs(ids...) } +// ClearOrganization clears the "organization" edge to the Organization entity. +func (wcuo *WorkflowContractUpdateOne) ClearOrganization() *WorkflowContractUpdateOne { + wcuo.mutation.ClearOrganization() + return wcuo +} + // ClearWorkflows clears all "workflows" edges to the Workflow entity. func (wcuo *WorkflowContractUpdateOne) ClearWorkflows() *WorkflowContractUpdateOne { wcuo.mutation.ClearWorkflows() @@ -692,6 +772,35 @@ func (wcuo *WorkflowContractUpdateOne) sqlSave(ctx context.Context) (_node *Work } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if wcuo.mutation.OrganizationCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: workflowcontract.OrganizationTable, + Columns: []string{workflowcontract.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := wcuo.mutation.OrganizationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: true, + Table: workflowcontract.OrganizationTable, + Columns: []string{workflowcontract.OrganizationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(organization.FieldID, field.TypeUUID), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if wcuo.mutation.WorkflowsCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, From fd07cac302f14da22c8ff622458bbf14540fa3b9 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 4 Jul 2025 16:37:57 +0200 Subject: [PATCH 05/16] validate contract Signed-off-by: Miguel Martinez --- .../api/gen/temp-openapi/apidocs.swagger.json | 236 ------------------ .../pkg/data/ent/migrate/migrations/atlas.sum | 27 +- app/controlplane/pkg/data/ent/schema-viz.html | 10 +- 3 files changed, 3 insertions(+), 270 deletions(-) delete mode 100644 app/controlplane/api/gen/temp-openapi/apidocs.swagger.json diff --git a/app/controlplane/api/gen/temp-openapi/apidocs.swagger.json b/app/controlplane/api/gen/temp-openapi/apidocs.swagger.json deleted file mode 100644 index 876e2ba97..000000000 --- a/app/controlplane/api/gen/temp-openapi/apidocs.swagger.json +++ /dev/null @@ -1,236 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "title": "Chainloop Controlplane API", - "termsOfService": "https://chainloop.dev/terms", - "version": "1.0", - "contact": { - "name": "Chainloop Support", - "url": "https://chainloop.dev", - "email": "support@chainloop.dev" - } - }, - "tags": [ - { - "name": "ReferrerService", - "description": "Referrer service for discovering referred content by digest" - } - ], - "host": "cp.chainloop.dev", - "schemes": [ - "https" - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "paths": { - "/discover/shared/{digest}": { - "get": { - "summary": "Discover public shared referrer", - "description": "Returns the referrer item for a given digest in the public shared index", - "operationId": "ReferrerService_DiscoverPublicShared", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1DiscoverPublicSharedResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "digest", - "description": "Digest is the unique identifier of the referrer to discover", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "kind", - "description": "Kind is the optional type of referrer, i.e CONTAINER_IMAGE, GIT_HEAD, ...\nUsed to filter and resolve ambiguities", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "ReferrerService" - ], - "produces": [ - "application/json" - ] - } - }, - "/discover/{digest}": { - "get": { - "summary": "Discover private referrer", - "description": "Returns the referrer item for a given digest in the organizations of the logged-in user", - "operationId": "ReferrerService_DiscoverPrivate", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1ReferrerServiceDiscoverPrivateResponse" - } - }, - "default": { - "description": "An unexpected error response.", - "schema": { - "$ref": "#/definitions/rpcStatus" - } - } - }, - "parameters": [ - { - "name": "digest", - "description": "Digest is the unique identifier of the referrer to discover", - "in": "path", - "required": true, - "type": "string" - }, - { - "name": "kind", - "description": "Kind is the optional type of referrer, i.e CONTAINER_IMAGE, GIT_HEAD, ...\nUsed to filter and resolve ambiguities", - "in": "query", - "required": false, - "type": "string" - } - ], - "tags": [ - "ReferrerService" - ], - "produces": [ - "application/json" - ] - } - } - }, - "definitions": { - "protobufAny": { - "type": "object", - "properties": { - "@type": { - "type": "string" - } - }, - "additionalProperties": {} - }, - "rpcStatus": { - "type": "object", - "properties": { - "code": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - }, - "details": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/protobufAny" - } - } - } - }, - "v1DiscoverPublicSharedResponse": { - "type": "object", - "properties": { - "result": { - "$ref": "#/definitions/v1ReferrerItem", - "title": "Result is the discovered referrer item" - } - }, - "description": "Response for the DiscoverPublicShared method", - "title": "DiscoverPublicSharedResponse" - }, - "v1ReferrerItem": { - "type": "object", - "properties": { - "digest": { - "type": "string", - "title": "Digest of the referrer, i.e sha256:deadbeef or sha1:beefdead" - }, - "kind": { - "type": "string", - "description": "Kind of referrer, i.e CONTAINER_IMAGE, GIT_HEAD, ..." - }, - "downloadable": { - "type": "boolean", - "title": "Downloadable indicates whether the referrer is downloadable or not from CAS" - }, - "public": { - "type": "boolean", - "title": "Public indicates whether the referrer is public since it belongs to a public workflow" - }, - "references": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1ReferrerItem" - }, - "title": "References contains the list of related referrer items" - }, - "created_at": { - "type": "string", - "format": "date-time", - "title": "CreatedAt is the timestamp when the referrer was created" - }, - "metadata": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "title": "Metadata contains additional descriptive information about the referrer" - }, - "annotations": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "title": "Annotations are key-value pairs associated with the referrer" - } - }, - "description": "It represents a referrer object in the system", - "title": "ReferrerItem" - }, - "v1ReferrerServiceDiscoverPrivateResponse": { - "type": "object", - "properties": { - "result": { - "$ref": "#/definitions/v1ReferrerItem", - "title": "Result is the discovered referrer item" - } - }, - "description": "Response for the DiscoverPrivate method", - "title": "ReferrerServiceDiscoverPrivateResponse" - } - }, - "securityDefinitions": { - "bearerToken": { - "type": "apiKey", - "description": "Bearer token for authentication", - "name": "Authorization", - "in": "header" - } - }, - "security": [ - { - "bearerToken": [] - } - ], - "externalDocs": { - "description": "Chainloop Official Documentation", - "url": "https://docs.chainloop.dev" - } -} diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum index 42ac9c09a..40ff393af 100644 --- a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum @@ -1,16 +1,4 @@ -<<<<<<< HEAD -<<<<<<< HEAD -<<<<<<< HEAD -h1:pewT4SIwZxo6E95TRjOvYvsO2AvVZDBRPljhvi6yN3c= -======= -h1:Nqn7kGmL5Hba+3tAbxdDjH6+KvSmunyHZuDIthoGQiU= ->>>>>>> 9b3f353d (feat: add columns) -======= -h1:oR9RWah9qFLH+GgYn2+C1UpTH2Z82Zj36QLGWRG5X+4= ->>>>>>> 7a8275ef (fix tests) -======= -h1:TVyZPOeAizQac42YgtwcW2RP0MefJCyThmt5yVkE/+8= ->>>>>>> a17a71d0 (fix tests) +h1:+yGkCvepb0rQgYUfTpHC+xRBgJeIOYo6DlhZMe2p76o= 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -105,17 +93,6 @@ h1:TVyZPOeAizQac42YgtwcW2RP0MefJCyThmt5yVkE/+8= 20250626100818.sql h1:MMCQid88eEs4uyCVBgkf5b0VYjyBd1EYRqRISco0rOI= 20250627143634.sql h1:9UdcOm4HdWyJ8bvU/vYkzCslXIpKSn7pM0l/MJHl8n4= 20250702111701.sql h1:Ni7fuL1qU5RGjBzV0XgJi9NkZINGijF8BumPuQ9conM= -<<<<<<< HEAD -<<<<<<< HEAD 20250702112642.sql h1:wrjVS+5h2hs7KNwPRBece5LgAsoEzxN/zNfvCnjoIUw= 20250704090359.sql h1:a0ksfjy2dtzviJL16HbC4eT1xBxy2qFH5mNFOpYlUrA= -======= -20250703212753.sql h1:Hr4sKsM+tlPRp0I9qRLnnkVUNpZ4xTH/XOQJ5nDdbek= -<<<<<<< HEAD ->>>>>>> 9b3f353d (feat: add columns) -======= -20250704090525.sql h1:VO/Kf+I0GJDfL2FaHk36YZ7f6uY9VrHjrP3EuQAidHM= ->>>>>>> 7a8275ef (fix tests) -======= -20250704092359.sql h1:4WDmb0R+obpATOgDONCxoYPxVLTl9jjpkzzOEfIUPIU= ->>>>>>> a17a71d0 (fix tests) +20250704092359.sql h1:LWwcBsaZtqp0AqIVqIirYR+X7ukcXc7fyLUjtv0e8OY= diff --git a/app/controlplane/pkg/data/ent/schema-viz.html b/app/controlplane/pkg/data/ent/schema-viz.html index c54c7412c..bbfda2835 100644 --- a/app/controlplane/pkg/data/ent/schema-viz.html +++ b/app/controlplane/pkg/data/ent/schema-viz.html @@ -70,15 +70,7 @@ } -<<<<<<< HEAD -<<<<<<< HEAD - const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"last_used_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"context\",\"type\":\"biz.OrgInvitationContext\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); -======= - const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowContract\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); ->>>>>>> 9b3f353d (feat: add columns) -======= - const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"scoped_resource_type\",\"type\":\"biz.ContractScope\"},{\"name\":\"scoped_resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); ->>>>>>> 7a8275ef (fix tests) + const entGraph = JSON.parse("{\"nodes\":[{\"id\":\"APIToken\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"expires_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"},{\"name\":\"last_used_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Attestation\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"bundle\",\"type\":\"[]byte\"},{\"name\":\"workflowrun_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"CASBackend\",\"fields\":[{\"name\":\"location\",\"type\":\"string\"},{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"provider\",\"type\":\"biz.CASBackendProvider\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"validation_status\",\"type\":\"biz.CASBackendValidationStatus\"},{\"name\":\"validated_at\",\"type\":\"time.Time\"},{\"name\":\"default\",\"type\":\"bool\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"fallback\",\"type\":\"bool\"},{\"name\":\"max_blob_size_bytes\",\"type\":\"int64\"}]},{\"id\":\"CASMapping\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_run_id\",\"type\":\"uuid.UUID\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Group\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"member_count\",\"type\":\"int\"}]},{\"id\":\"GroupMembership\",\"fields\":[{\"name\":\"group_id\",\"type\":\"uuid.UUID\"},{\"name\":\"user_id\",\"type\":\"uuid.UUID\"},{\"name\":\"maintainer\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"Integration\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"secret_name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"}]},{\"id\":\"IntegrationAttachment\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"configuration\",\"type\":\"[]byte\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"Membership\",\"fields\":[{\"name\":\"current\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"membership_type\",\"type\":\"authz.MembershipType\"},{\"name\":\"member_id\",\"type\":\"uuid.UUID\"},{\"name\":\"resource_type\",\"type\":\"authz.ResourceType\"},{\"name\":\"resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"OrgInvitation\",\"fields\":[{\"name\":\"receiver_email\",\"type\":\"string\"},{\"name\":\"status\",\"type\":\"biz.OrgInvitationStatus\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"sender_id\",\"type\":\"uuid.UUID\"},{\"name\":\"role\",\"type\":\"authz.Role\"},{\"name\":\"context\",\"type\":\"biz.OrgInvitationContext\"}]},{\"id\":\"Organization\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"block_on_policy_violation\",\"type\":\"bool\"}]},{\"id\":\"Project\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"ProjectVersion\",\"fields\":[{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"prerelease\",\"type\":\"bool\"},{\"name\":\"workflow_run_count\",\"type\":\"int\"},{\"name\":\"released_at\",\"type\":\"time.Time\"},{\"name\":\"latest\",\"type\":\"bool\"}]},{\"id\":\"Referrer\",\"fields\":[{\"name\":\"digest\",\"type\":\"string\"},{\"name\":\"kind\",\"type\":\"string\"},{\"name\":\"downloadable\",\"type\":\"bool\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"metadata\",\"type\":\"map[string]string\"},{\"name\":\"annotations\",\"type\":\"map[string]string\"}]},{\"id\":\"RobotAccount\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"revoked_at\",\"type\":\"time.Time\"}]},{\"id\":\"User\",\"fields\":[{\"name\":\"email\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"has_restricted_access\",\"type\":\"bool\"},{\"name\":\"first_name\",\"type\":\"string\"},{\"name\":\"last_name\",\"type\":\"string\"}]},{\"id\":\"Workflow\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"project_old\",\"type\":\"string\"},{\"name\":\"team\",\"type\":\"string\"},{\"name\":\"runs_count\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"updated_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"public\",\"type\":\"bool\"},{\"name\":\"organization_id\",\"type\":\"uuid.UUID\"},{\"name\":\"project_id\",\"type\":\"uuid.UUID\"},{\"name\":\"latest_run\",\"type\":\"uuid.UUID\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"metadata\",\"type\":\"map[string]interface {}\"}]},{\"id\":\"WorkflowContract\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"deleted_at\",\"type\":\"time.Time\"},{\"name\":\"description\",\"type\":\"string\"},{\"name\":\"scoped_resource_type\",\"type\":\"biz.ContractScope\"},{\"name\":\"scoped_resource_id\",\"type\":\"uuid.UUID\"}]},{\"id\":\"WorkflowContractVersion\",\"fields\":[{\"name\":\"body\",\"type\":\"[]byte\"},{\"name\":\"raw_body\",\"type\":\"[]byte\"},{\"name\":\"raw_body_format\",\"type\":\"unmarshal.RawFormat\"},{\"name\":\"revision\",\"type\":\"int\"},{\"name\":\"created_at\",\"type\":\"time.Time\"}]},{\"id\":\"WorkflowRun\",\"fields\":[{\"name\":\"created_at\",\"type\":\"time.Time\"},{\"name\":\"finished_at\",\"type\":\"time.Time\"},{\"name\":\"state\",\"type\":\"biz.WorkflowRunStatus\"},{\"name\":\"reason\",\"type\":\"string\"},{\"name\":\"run_url\",\"type\":\"string\"},{\"name\":\"runner_type\",\"type\":\"string\"},{\"name\":\"attestation\",\"type\":\"*dsse.Envelope\"},{\"name\":\"attestation_digest\",\"type\":\"string\"},{\"name\":\"attestation_state\",\"type\":\"[]byte\"},{\"name\":\"contract_revision_used\",\"type\":\"int\"},{\"name\":\"contract_revision_latest\",\"type\":\"int\"},{\"name\":\"version_id\",\"type\":\"uuid.UUID\"},{\"name\":\"workflow_id\",\"type\":\"uuid.UUID\"}]}],\"edges\":[{\"from\":\"APIToken\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"CASMapping\",\"to\":\"CASBackend\",\"label\":\"cas_backend\"},{\"from\":\"CASMapping\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"CASMapping\",\"to\":\"Project\",\"label\":\"project\"},{\"from\":\"Group\",\"to\":\"User\",\"label\":\"members\"},{\"from\":\"GroupMembership\",\"to\":\"Group\",\"label\":\"group\"},{\"from\":\"GroupMembership\",\"to\":\"User\",\"label\":\"user\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Integration\",\"label\":\"integration\"},{\"from\":\"IntegrationAttachment\",\"to\":\"Workflow\",\"label\":\"workflow\"},{\"from\":\"OrgInvitation\",\"to\":\"Organization\",\"label\":\"organization\"},{\"from\":\"OrgInvitation\",\"to\":\"User\",\"label\":\"sender\"},{\"from\":\"Organization\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Organization\",\"to\":\"WorkflowContract\",\"label\":\"workflow_contracts\"},{\"from\":\"Organization\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Organization\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"Organization\",\"to\":\"Integration\",\"label\":\"integrations\"},{\"from\":\"Organization\",\"to\":\"APIToken\",\"label\":\"api_tokens\"},{\"from\":\"Organization\",\"to\":\"Project\",\"label\":\"projects\"},{\"from\":\"Organization\",\"to\":\"Group\",\"label\":\"groups\"},{\"from\":\"Project\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"Project\",\"to\":\"ProjectVersion\",\"label\":\"versions\"},{\"from\":\"ProjectVersion\",\"to\":\"WorkflowRun\",\"label\":\"runs\"},{\"from\":\"Referrer\",\"to\":\"Referrer\",\"label\":\"references\"},{\"from\":\"Referrer\",\"to\":\"Workflow\",\"label\":\"workflows\"},{\"from\":\"User\",\"to\":\"Membership\",\"label\":\"memberships\"},{\"from\":\"Workflow\",\"to\":\"RobotAccount\",\"label\":\"robotaccounts\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"workflowruns\"},{\"from\":\"Workflow\",\"to\":\"WorkflowContract\",\"label\":\"contract\"},{\"from\":\"Workflow\",\"to\":\"WorkflowRun\",\"label\":\"latest_workflow_run\"},{\"from\":\"WorkflowContract\",\"to\":\"WorkflowContractVersion\",\"label\":\"versions\"},{\"from\":\"WorkflowRun\",\"to\":\"WorkflowContractVersion\",\"label\":\"contract_version\"},{\"from\":\"WorkflowRun\",\"to\":\"CASBackend\",\"label\":\"cas_backends\"},{\"from\":\"WorkflowRun\",\"to\":\"Attestation\",\"label\":\"attestation_bundle\"}]}"); const nodes = new vis.DataSet((entGraph.nodes || []).map(n => ({ id: n.id, From b2689c3b2b8d073905cfd10144f57c739ed34e20 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Fri, 4 Jul 2025 16:48:59 +0200 Subject: [PATCH 06/16] feat: add contract Signed-off-by: Miguel Martinez --- app/controlplane/pkg/biz/workflowcontract.go | 2 ++ app/controlplane/pkg/data/workflow.go | 8 ++++---- app/controlplane/pkg/data/workflowcontract.go | 10 +++++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index c835a4fa6..f53137577 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -96,6 +96,8 @@ type ContractCreateOpts struct { Description *string // raw representation of the contract in whatever original format it was (json, yaml, ...) Contract *Contract + // ProjectID indicates the project to be scoped to + ProjectID *uuid.UUID } type ContractUpdateOpts struct { diff --git a/app/controlplane/pkg/data/workflow.go b/app/controlplane/pkg/data/workflow.go index c0bf0b9c2..660239f91 100644 --- a/app/controlplane/pkg/data/workflow.go +++ b/app/controlplane/pkg/data/workflow.go @@ -118,11 +118,11 @@ func (r *WorkflowRepo) Create(ctx context.Context, opts *biz.WorkflowCreateOpts) if err != nil { if ent.IsNotFound(err) { // Create a new contract associated with the workflow - // TODO: associate it with the project soon contract, _, err = r.contractRepo.addCreateToTx(ctx, tx, &biz.ContractCreateOpts{ - OrgID: orgUUID, - Name: defaultContractName, - Contract: opts.DetectedContract, + OrgID: orgUUID, + Name: defaultContractName, + Contract: opts.DetectedContract, + ProjectID: &projectID, }) if err != nil { return fmt.Errorf("creating contract: %w", err) diff --git a/app/controlplane/pkg/data/workflowcontract.go b/app/controlplane/pkg/data/workflowcontract.go index a90b05e42..b25ed071d 100644 --- a/app/controlplane/pkg/data/workflowcontract.go +++ b/app/controlplane/pkg/data/workflowcontract.go @@ -102,11 +102,15 @@ func (r *WorkflowContractRepo) Create(ctx context.Context, opts *biz.ContractCre } func (r *WorkflowContractRepo) addCreateToTx(ctx context.Context, tx *ent.Tx, opts *biz.ContractCreateOpts) (*ent.WorkflowContract, *ent.WorkflowContractVersion, error) { - contract, err := tx.WorkflowContract.Create(). + contractQuery := tx.WorkflowContract.Create(). SetName(opts.Name).SetOrganizationID(opts.OrgID). - SetNillableDescription(opts.Description). - Save(ctx) + SetNillableDescription(opts.Description) + if opts.ProjectID != nil { + contractQuery = contractQuery.SetScopedResourceID(*opts.ProjectID).SetScopedResourceType(biz.ContractScopeProject) + } + + contract, err := contractQuery.Save(ctx) if err != nil { return nil, nil, handleError(err) } From 5c5b9d97b305bcd26628ea19bf38e1dd63020ef7 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Tue, 8 Jul 2025 23:59:01 +0200 Subject: [PATCH 07/16] contracts Signed-off-by: Miguel Martinez --- app/cli/cmd/workflow_contract_create.go | 7 +- app/cli/cmd/workflow_contract_list.go | 10 +- .../action/workflow_contract_create.go | 8 +- .../internal/action/workflow_contract_list.go | 19 +- .../controlplane/v1/response_messages.pb.go | 790 ++++++++++-------- .../controlplane/v1/response_messages.proto | 11 + .../api/controlplane/v1/shared_message.go | 8 + .../controlplane/v1/workflow_contract.pb.go | 340 ++++---- .../controlplane/v1/workflow_contract.proto | 9 +- .../v1/workflow_contract_grpc.pb.go | 2 +- .../controlplane/v1/response_messages.ts | 112 +++ .../controlplane/v1/workflow_contract.ts | 29 +- ...ntrolplane.v1.ScopedEntity.jsonschema.json | 21 + .../controlplane.v1.ScopedEntity.schema.json | 21 + ...ne.v1.WorkflowContractItem.jsonschema.json | 8 + ...lplane.v1.WorkflowContractItem.schema.json | 8 + ...ntractServiceCreateRequest.jsonschema.json | 8 + ...owContractServiceCreateRequest.schema.json | 8 + .../internal/service/workflowcontract.go | 42 +- app/controlplane/pkg/authz/authz.go | 12 +- app/controlplane/pkg/biz/workflowcontract.go | 21 +- app/controlplane/pkg/data/workflowcontract.go | 33 +- 22 files changed, 992 insertions(+), 535 deletions(-) create mode 100644 app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.jsonschema.json create mode 100644 app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.schema.json diff --git a/app/cli/cmd/workflow_contract_create.go b/app/cli/cmd/workflow_contract_create.go index 94265c588..68f5f361b 100644 --- a/app/cli/cmd/workflow_contract_create.go +++ b/app/cli/cmd/workflow_contract_create.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import ( ) func newWorkflowContractCreateCmd() *cobra.Command { - var name, description, contractPath string + var name, description, contractPath, projectName string cmd := &cobra.Command{ Use: "create", @@ -31,7 +31,7 @@ func newWorkflowContractCreateCmd() *cobra.Command { if cmd.Flags().Changed("description") { desc = &description } - res, err := action.NewWorkflowContractCreate(actionOpts).Run(name, desc, contractPath) + res, err := action.NewWorkflowContractCreate(actionOpts).Run(name, desc, contractPath, projectName) if err != nil { return err } @@ -47,6 +47,7 @@ func newWorkflowContractCreateCmd() *cobra.Command { cmd.Flags().StringVarP(&contractPath, "contract", "f", "", "path or URL to the contract schema") cmd.Flags().StringVar(&description, "description", "", "description of the contract") + cmd.Flags().StringVar(&projectName, "project", "", "project name used to scope the contract, if not set the contract will be created in the organization") return cmd } diff --git a/app/cli/cmd/workflow_contract_list.go b/app/cli/cmd/workflow_contract_list.go index b7df5e228..39bb40d6c 100644 --- a/app/cli/cmd/workflow_contract_list.go +++ b/app/cli/cmd/workflow_contract_list.go @@ -16,6 +16,7 @@ package cmd import ( + "fmt" "time" "github.com/chainloop-dev/chainloop/app/cli/internal/action" @@ -48,9 +49,14 @@ func contractItemTableOutput(contract *action.WorkflowContractItem) error { func contractListTableOutput(contracts []*action.WorkflowContractItem) error { t := newTableWriter() - t.AppendHeader(table.Row{"Name", "Latest Revision", "Created At", "Updated At", "# Workflows"}) + t.AppendHeader(table.Row{"Name", "Latest Revision", "Created At", "Updated At", "# Workflows", "Scope"}) for _, p := range contracts { - t.AppendRow(table.Row{p.Name, p.LatestRevision, p.CreatedAt.Format(time.RFC822), p.LatestRevisionCreatedAt.Format(time.RFC822), len(p.WorkflowRefs)}) + scope := "org" + if p.ScopedEntity != nil { + scope = fmt.Sprintf("%s/%s", p.ScopedEntity.Type, p.ScopedEntity.Name) + } + + t.AppendRow(table.Row{p.Name, p.LatestRevision, p.CreatedAt.Format(time.RFC822), p.LatestRevisionCreatedAt.Format(time.RFC822), len(p.WorkflowRefs), scope}) } t.Render() diff --git a/app/cli/internal/action/workflow_contract_create.go b/app/cli/internal/action/workflow_contract_create.go index ce4d96092..d0de3933e 100644 --- a/app/cli/internal/action/workflow_contract_create.go +++ b/app/cli/internal/action/workflow_contract_create.go @@ -29,13 +29,19 @@ func NewWorkflowContractCreate(cfg *ActionsOpts) *WorkflowContractCreate { return &WorkflowContractCreate{cfg} } -func (action *WorkflowContractCreate) Run(name string, description *string, contractPath string) (*WorkflowContractItem, error) { +func (action *WorkflowContractCreate) Run(name string, description *string, contractPath string, projectName string) (*WorkflowContractItem, error) { client := pb.NewWorkflowContractServiceClient(action.cfg.CPConnection) request := &pb.WorkflowContractServiceCreateRequest{ Name: name, Description: description, } + if projectName != "" { + request.ProjectReference = &pb.IdentityReference{ + Name: &projectName, + } + } + if contractPath != "" { rawContract, err := LoadFileOrURL(contractPath) if err != nil { diff --git a/app/cli/internal/action/workflow_contract_list.go b/app/cli/internal/action/workflow_contract_list.go index 159930ba2..fae0d7946 100644 --- a/app/cli/internal/action/workflow_contract_list.go +++ b/app/cli/internal/action/workflow_contract_list.go @@ -36,6 +36,13 @@ type WorkflowContractItem struct { CreatedAt *time.Time `json:"createdAt"` Workflows []string `json:"workflows,omitempty"` // TODO: remove this field after all clients are updated WorkflowRefs []*WorkflowRef `json:"workflowRefs,omitempty"` + ScopedEntity *ScopedEntity `json:"scopedEntity,omitempty"` +} + +type ScopedEntity struct { + Type string `json:"type"` + ID string `json:"id"` + Name string `json:"name"` } type WorkflowRef struct { @@ -82,7 +89,7 @@ func pbWorkflowContractItemToAction(in *pb.WorkflowContractItem) *WorkflowContra for _, w := range in.WorkflowRefs { workflowRefs = append(workflowRefs, pbWorkflowRefToAction(w)) } - return &WorkflowContractItem{ + item := &WorkflowContractItem{ Name: in.GetName(), ID: in.GetId(), LatestRevision: int(in.GetLatestRevision()), @@ -92,6 +99,16 @@ func pbWorkflowContractItemToAction(in *pb.WorkflowContractItem) *WorkflowContra Description: in.GetDescription(), LatestRevisionCreatedAt: toTimePtr(in.GetLatestRevisionCreatedAt().AsTime()), } + + if in.ScopedEntity != nil { + item.ScopedEntity = &ScopedEntity{ + Type: in.ScopedEntity.Type, + ID: in.ScopedEntity.Id, + Name: in.ScopedEntity.Name, + } + } + + return item } func pbWorkflowContractVersionItemToAction(in *pb.WorkflowContractVersionItem) *WorkflowContractVersionItem { diff --git a/app/controlplane/api/controlplane/v1/response_messages.pb.go b/app/controlplane/api/controlplane/v1/response_messages.pb.go index 1bbb89a9a..e4349b10a 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.pb.go +++ b/app/controlplane/api/controlplane/v1/response_messages.pb.go @@ -385,7 +385,7 @@ func (x WorkflowContractVersionItem_RawBody_Format) Number() protoreflect.EnumNu // Deprecated: Use WorkflowContractVersionItem_RawBody_Format.Descriptor instead. func (WorkflowContractVersionItem_RawBody_Format) EnumDescriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{10, 0, 0} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{11, 0, 0} } type OrgItem_PolicyViolationBlockingStrategy int32 @@ -434,7 +434,7 @@ func (x OrgItem_PolicyViolationBlockingStrategy) Number() protoreflect.EnumNumbe // Deprecated: Use OrgItem_PolicyViolationBlockingStrategy.Descriptor instead. func (OrgItem_PolicyViolationBlockingStrategy) EnumDescriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{13, 0} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{14, 0} } type CASBackendItem_ValidationStatus int32 @@ -483,7 +483,7 @@ func (x CASBackendItem_ValidationStatus) Number() protoreflect.EnumNumber { // Deprecated: Use CASBackendItem_ValidationStatus.Descriptor instead. func (CASBackendItem_ValidationStatus) EnumDescriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{14, 0} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{15, 0} } type WorkflowItem struct { @@ -1310,6 +1310,8 @@ type WorkflowContractItem struct { // Deprecated: Marked as deprecated in controlplane/v1/response_messages.proto. WorkflowNames []string `protobuf:"bytes,5,rep,name=workflow_names,json=workflowNames,proto3" json:"workflow_names,omitempty"` WorkflowRefs []*WorkflowRef `protobuf:"bytes,7,rep,name=workflow_refs,json=workflowRefs,proto3" json:"workflow_refs,omitempty"` + // wether the contract is scoped to an entity in the organization + ScopedEntity *ScopedEntity `protobuf:"bytes,9,opt,name=scoped_entity,json=scopedEntity,proto3" json:"scoped_entity,omitempty"` } func (x *WorkflowContractItem) Reset() { @@ -1401,6 +1403,79 @@ func (x *WorkflowContractItem) GetWorkflowRefs() []*WorkflowRef { return nil } +func (x *WorkflowContractItem) GetScopedEntity() *ScopedEntity { + if x != nil { + return x.ScopedEntity + } + return nil +} + +type ScopedEntity struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Type is the type of the scoped entity i.e project or org + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + // ID is the id of the scoped entity + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // Name is the name of the scoped entity + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *ScopedEntity) Reset() { + *x = ScopedEntity{} + if protoimpl.UnsafeEnabled { + mi := &file_controlplane_v1_response_messages_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScopedEntity) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScopedEntity) ProtoMessage() {} + +func (x *ScopedEntity) ProtoReflect() protoreflect.Message { + mi := &file_controlplane_v1_response_messages_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScopedEntity.ProtoReflect.Descriptor instead. +func (*ScopedEntity) Descriptor() ([]byte, []int) { + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{9} +} + +func (x *ScopedEntity) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *ScopedEntity) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ScopedEntity) GetName() string { + if x != nil { + return x.Name + } + return "" +} + type WorkflowRef struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1414,7 +1489,7 @@ type WorkflowRef struct { func (x *WorkflowRef) Reset() { *x = WorkflowRef{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[9] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1427,7 +1502,7 @@ func (x *WorkflowRef) String() string { func (*WorkflowRef) ProtoMessage() {} func (x *WorkflowRef) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[9] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1440,7 +1515,7 @@ func (x *WorkflowRef) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkflowRef.ProtoReflect.Descriptor instead. func (*WorkflowRef) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{9} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{10} } func (x *WorkflowRef) GetId() string { @@ -1484,7 +1559,7 @@ type WorkflowContractVersionItem struct { func (x *WorkflowContractVersionItem) Reset() { *x = WorkflowContractVersionItem{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[10] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1497,7 +1572,7 @@ func (x *WorkflowContractVersionItem) String() string { func (*WorkflowContractVersionItem) ProtoMessage() {} func (x *WorkflowContractVersionItem) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[10] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1510,7 +1585,7 @@ func (x *WorkflowContractVersionItem) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkflowContractVersionItem.ProtoReflect.Descriptor instead. func (*WorkflowContractVersionItem) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{10} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{11} } func (x *WorkflowContractVersionItem) GetId() string { @@ -1591,7 +1666,7 @@ type User struct { func (x *User) Reset() { *x = User{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[11] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1604,7 +1679,7 @@ func (x *User) String() string { func (*User) ProtoMessage() {} func (x *User) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[11] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1617,7 +1692,7 @@ func (x *User) ProtoReflect() protoreflect.Message { // Deprecated: Use User.ProtoReflect.Descriptor instead. func (*User) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{11} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{12} } func (x *User) GetId() string { @@ -1672,7 +1747,7 @@ type OrgMembershipItem struct { func (x *OrgMembershipItem) Reset() { *x = OrgMembershipItem{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[12] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1685,7 +1760,7 @@ func (x *OrgMembershipItem) String() string { func (*OrgMembershipItem) ProtoMessage() {} func (x *OrgMembershipItem) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[12] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1698,7 +1773,7 @@ func (x *OrgMembershipItem) ProtoReflect() protoreflect.Message { // Deprecated: Use OrgMembershipItem.ProtoReflect.Descriptor instead. func (*OrgMembershipItem) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{12} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{13} } func (x *OrgMembershipItem) GetId() string { @@ -1764,7 +1839,7 @@ type OrgItem struct { func (x *OrgItem) Reset() { *x = OrgItem{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[13] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1777,7 +1852,7 @@ func (x *OrgItem) String() string { func (*OrgItem) ProtoMessage() {} func (x *OrgItem) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[13] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1790,7 +1865,7 @@ func (x *OrgItem) ProtoReflect() protoreflect.Message { // Deprecated: Use OrgItem.ProtoReflect.Descriptor instead. func (*OrgItem) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{13} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{14} } func (x *OrgItem) GetId() string { @@ -1848,7 +1923,7 @@ type CASBackendItem struct { func (x *CASBackendItem) Reset() { *x = CASBackendItem{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[14] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1861,7 +1936,7 @@ func (x *CASBackendItem) String() string { func (*CASBackendItem) ProtoMessage() {} func (x *CASBackendItem) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[14] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1874,7 +1949,7 @@ func (x *CASBackendItem) ProtoReflect() protoreflect.Message { // Deprecated: Use CASBackendItem.ProtoReflect.Descriptor instead. func (*CASBackendItem) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{14} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{15} } func (x *CASBackendItem) GetId() string { @@ -1975,7 +2050,7 @@ type APITokenItem struct { func (x *APITokenItem) Reset() { *x = APITokenItem{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[15] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1988,7 +2063,7 @@ func (x *APITokenItem) String() string { func (*APITokenItem) ProtoMessage() {} func (x *APITokenItem) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[15] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2001,7 +2076,7 @@ func (x *APITokenItem) ProtoReflect() protoreflect.Message { // Deprecated: Use APITokenItem.ProtoReflect.Descriptor instead. func (*APITokenItem) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{15} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{16} } func (x *APITokenItem) GetId() string { @@ -2095,7 +2170,7 @@ type AttestationItem_PolicyEvaluationStatus struct { func (x *AttestationItem_PolicyEvaluationStatus) Reset() { *x = AttestationItem_PolicyEvaluationStatus{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[18] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2108,7 +2183,7 @@ func (x *AttestationItem_PolicyEvaluationStatus) String() string { func (*AttestationItem_PolicyEvaluationStatus) ProtoMessage() {} func (x *AttestationItem_PolicyEvaluationStatus) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[18] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2164,7 +2239,7 @@ type AttestationItem_EnvVariable struct { func (x *AttestationItem_EnvVariable) Reset() { *x = AttestationItem_EnvVariable{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[19] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2177,7 +2252,7 @@ func (x *AttestationItem_EnvVariable) String() string { func (*AttestationItem_EnvVariable) ProtoMessage() {} func (x *AttestationItem_EnvVariable) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[19] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2232,7 +2307,7 @@ type AttestationItem_Material struct { func (x *AttestationItem_Material) Reset() { *x = AttestationItem_Material{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[20] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2245,7 +2320,7 @@ func (x *AttestationItem_Material) String() string { func (*AttestationItem_Material) ProtoMessage() {} func (x *AttestationItem_Material) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[20] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2336,7 +2411,7 @@ type WorkflowContractVersionItem_RawBody struct { func (x *WorkflowContractVersionItem_RawBody) Reset() { *x = WorkflowContractVersionItem_RawBody{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[25] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2349,7 +2424,7 @@ func (x *WorkflowContractVersionItem_RawBody) String() string { func (*WorkflowContractVersionItem_RawBody) ProtoMessage() {} func (x *WorkflowContractVersionItem_RawBody) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[25] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2362,7 +2437,7 @@ func (x *WorkflowContractVersionItem_RawBody) ProtoReflect() protoreflect.Messag // Deprecated: Use WorkflowContractVersionItem_RawBody.ProtoReflect.Descriptor instead. func (*WorkflowContractVersionItem_RawBody) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{10, 0} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{11, 0} } func (x *WorkflowContractVersionItem_RawBody) GetBody() []byte { @@ -2391,7 +2466,7 @@ type CASBackendItem_Limits struct { func (x *CASBackendItem_Limits) Reset() { *x = CASBackendItem_Limits{} if protoimpl.UnsafeEnabled { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[26] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2404,7 +2479,7 @@ func (x *CASBackendItem_Limits) String() string { func (*CASBackendItem_Limits) ProtoMessage() {} func (x *CASBackendItem_Limits) ProtoReflect() protoreflect.Message { - mi := &file_controlplane_v1_response_messages_proto_msgTypes[26] + mi := &file_controlplane_v1_response_messages_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2417,7 +2492,7 @@ func (x *CASBackendItem_Limits) ProtoReflect() protoreflect.Message { // Deprecated: Use CASBackendItem_Limits.ProtoReflect.Descriptor instead. func (*CASBackendItem_Limits) Descriptor() ([]byte, []int) { - return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{14, 0} + return file_controlplane_v1_response_messages_proto_rawDescGZIP(), []int{15, 0} } func (x *CASBackendItem_Limits) GetMaxBytes() int64 { @@ -2681,7 +2756,7 @@ var file_controlplane_v1_response_messages_proto_rawDesc = []byte{ 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x87, 0x03, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, + 0x22, 0xcb, 0x03, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, @@ -2705,239 +2780,248 @@ var file_controlplane_v1_response_messages_proto_rawDesc = []byte{ 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x66, 0x52, 0x0c, 0x77, 0x6f, - 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x66, 0x73, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x66, 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, - 0x6d, 0x65, 0x2d, 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, - 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, - 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, - 0x2c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, - 0x79, 0x70, 0x68, 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, - 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, - 0x28, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, - 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9d, 0x04, 0x0a, 0x1b, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x12, 0x39, 0x0a, 0x02, 0x76, 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x61, 0x66, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x42, 0x02, 0x18, 0x01, 0x48, 0x00, 0x52, 0x02, 0x76, 0x31, 0x12, 0x57, 0x0a, 0x0c, - 0x72, 0x61, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, - 0x2e, 0x52, 0x61, 0x77, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0xd1, 0x01, 0x0a, 0x07, 0x52, - 0x61, 0x77, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x5e, 0x0a, 0x06, 0x66, 0x6f, - 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x52, 0x61, 0x77, 0x42, 0x6f, 0x64, 0x79, - 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x42, 0x09, 0xba, 0x48, 0x06, 0x82, 0x01, 0x03, 0x22, - 0x01, 0x00, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x52, 0x0a, 0x06, 0x46, 0x6f, - 0x72, 0x6d, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, - 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0f, 0x0a, - 0x0b, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x59, 0x41, 0x4d, 0x4c, 0x10, 0x02, 0x12, 0x0e, - 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x43, 0x55, 0x45, 0x10, 0x03, 0x42, 0x0a, - 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x22, 0xa3, 0x01, 0x0a, 0x04, 0x55, - 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x41, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, - 0x22, 0xbf, 0x02, 0x0a, 0x11, 0x4f, 0x72, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, - 0x69, 0x70, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x03, 0x6f, 0x72, 0x67, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x03, 0x6f, - 0x72, 0x67, 0x12, 0x29, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, - 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, - 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x33, 0x0a, - 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, - 0x6c, 0x65, 0x22, 0xa5, 0x03, 0x0a, 0x07, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x66, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x52, 0x0c, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x46, + 0x0a, 0x0c, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x66, 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2d, 0x64, + 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, + 0x63, 0x61, 0x73, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, 0x68, 0x65, + 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, 0x61, + 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, + 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0c, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9d, 0x04, 0x0a, 0x1b, 0x57, 0x6f, 0x72, 0x6b, 0x66, + 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x83, 0x01, - 0x0a, 0x21, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x5f, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, - 0x74, 0x65, 0x6d, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, + 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, + 0x02, 0x76, 0x31, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x77, 0x6f, 0x72, 0x6b, + 0x66, 0x6c, 0x6f, 0x77, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x72, 0x61, 0x66, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x42, 0x02, + 0x18, 0x01, 0x48, 0x00, 0x52, 0x02, 0x76, 0x31, 0x12, 0x57, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x52, 0x61, 0x77, + 0x42, 0x6f, 0x64, 0x79, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, + 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x1a, 0xd1, 0x01, 0x0a, 0x07, 0x52, 0x61, 0x77, 0x42, 0x6f, + 0x64, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x5e, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, + 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x52, 0x61, 0x77, 0x42, 0x6f, 0x64, 0x79, 0x2e, 0x46, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x42, 0x09, 0xba, 0x48, 0x06, 0x82, 0x01, 0x03, 0x22, 0x01, 0x00, 0x52, 0x06, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x52, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x12, 0x16, 0x0a, 0x12, 0x46, 0x4f, 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, + 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x4f, 0x52, 0x4d, + 0x41, 0x54, 0x5f, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x4f, 0x52, + 0x4d, 0x41, 0x54, 0x5f, 0x59, 0x41, 0x4d, 0x4c, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, + 0x52, 0x4d, 0x41, 0x54, 0x5f, 0x43, 0x55, 0x45, 0x10, 0x03, 0x42, 0x0a, 0x0a, 0x08, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x22, 0xa3, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xbf, 0x02, 0x0a, + 0x11, 0x4f, 0x72, 0x67, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x49, 0x74, + 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x2a, 0x0a, 0x03, 0x6f, 0x72, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x03, 0x6f, 0x72, 0x67, 0x12, 0x29, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, + 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x33, 0x0a, 0x04, 0x72, 0x6f, 0x6c, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0xa5, + 0x03, 0x0a, 0x07, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x83, 0x01, 0x0a, 0x21, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x76, 0x69, 0x6f, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x49, 0x74, 0x65, 0x6d, 0x2e, + 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, + 0x1e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, + 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, + 0xb4, 0x01, 0x0a, 0x1f, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x52, 0x1e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x72, 0x61, 0x74, - 0x65, 0x67, 0x79, 0x22, 0xb4, 0x01, 0x0a, 0x1f, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x56, 0x69, - 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x53, - 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x32, 0x0a, 0x2e, 0x50, 0x4f, 0x4c, 0x49, 0x43, + 0x65, 0x67, 0x79, 0x12, 0x32, 0x0a, 0x2e, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, + 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x49, 0x4e, 0x47, + 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2c, 0x0a, 0x28, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, - 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2c, 0x0a, 0x28, 0x50, - 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, - 0x59, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x2f, 0x0a, 0x2b, 0x50, 0x4f, 0x4c, - 0x49, 0x43, 0x59, 0x5f, 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, - 0x4f, 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, - 0x41, 0x44, 0x56, 0x49, 0x53, 0x4f, 0x52, 0x59, 0x10, 0x02, 0x22, 0xf5, 0x04, 0x0a, 0x0e, 0x43, - 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x5d, 0x0a, 0x11, 0x76, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, - 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, - 0x64, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, - 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x2e, - 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x1b, - 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x08, 0x69, 0x73, 0x49, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0x25, 0x0a, 0x06, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x42, 0x79, 0x74, - 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x41, 0x4c, - 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, - 0x4b, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, - 0x10, 0x02, 0x22, 0xdb, 0x03, 0x0a, 0x0c, 0x41, 0x50, 0x49, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, - 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x72, 0x67, - 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x21, - 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, - 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, - 0x65, 0x73, 0x5f, 0x61, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, - 0x41, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x73, 0x65, 0x64, 0x41, 0x74, - 0x2a, 0xa6, 0x01, 0x0a, 0x09, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, - 0x0a, 0x16, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x55, - 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, - 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x02, - 0x12, 0x15, 0x0a, 0x11, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, - 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x55, 0x4e, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x12, - 0x18, 0x0a, 0x14, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, - 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x2a, 0xaf, 0x01, 0x0a, 0x0e, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x1b, - 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, - 0x1a, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, - 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x56, 0x49, 0x45, 0x57, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1d, 0x0a, - 0x19, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, - 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, - 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, - 0x4f, 0x52, 0x47, 0x5f, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x03, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, - 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, - 0x52, 0x47, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x04, 0x2a, 0x60, 0x0a, 0x0e, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, 0x0a, - 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x26, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, - 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, - 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x6d, 0x0a, - 0x12, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x24, 0x0a, 0x20, 0x46, 0x45, 0x44, 0x45, 0x52, 0x41, 0x54, 0x45, 0x44, - 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x21, 0x46, 0x45, 0x44, - 0x45, 0x52, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, - 0x52, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, - 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x84, 0x01, 0x0a, - 0x19, 0x55, 0x73, 0x65, 0x72, 0x57, 0x69, 0x74, 0x68, 0x4e, 0x6f, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x29, 0x55, 0x53, - 0x45, 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, - 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x32, 0x0a, 0x28, 0x55, 0x53, 0x45, - 0x52, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, - 0x53, 0x48, 0x49, 0x50, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, - 0x4e, 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, - 0x45, 0xf4, 0x03, 0x2a, 0x80, 0x01, 0x0a, 0x17, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4f, 0x66, 0x4f, 0x72, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, - 0x2c, 0x0a, 0x28, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x4d, 0x45, 0x4d, 0x42, - 0x45, 0x52, 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x31, 0x0a, - 0x27, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, - 0x5f, 0x4f, 0x46, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, - 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, - 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, - 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, - 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, - 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4b, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x42, 0x4c, + 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x2f, 0x0a, 0x2b, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x5f, + 0x56, 0x49, 0x4f, 0x4c, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x49, + 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x41, 0x44, 0x56, 0x49, + 0x53, 0x4f, 0x52, 0x59, 0x10, 0x02, 0x22, 0xf5, 0x04, 0x0a, 0x0e, 0x43, 0x41, 0x53, 0x42, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x5d, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x43, 0x41, 0x53, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, + 0x6d, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x3e, 0x0a, 0x06, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x41, 0x53, + 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x2e, 0x4c, 0x69, 0x6d, 0x69, + 0x74, 0x73, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, + 0x5f, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, + 0x73, 0x49, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x1a, 0x25, 0x0a, 0x06, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x6e, + 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x21, 0x0a, 0x1d, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, + 0x1d, 0x0a, 0x19, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x22, 0xdb, + 0x03, 0x0a, 0x0c, 0x41, 0x50, 0x49, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, + 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2b, + 0x0a, 0x11, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x72, 0x67, 0x61, 0x6e, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x72, 0x65, 0x76, 0x6f, + 0x6b, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, 0x74, 0x12, 0x3c, + 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x73, 0x65, 0x64, 0x41, 0x74, 0x2a, 0xa6, 0x01, 0x0a, + 0x09, 0x52, 0x75, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x55, + 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x49, 0x5a, 0x45, 0x44, + 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x45, 0x44, 0x45, 0x44, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, + 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, + 0x44, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x52, + 0x55, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, + 0x4c, 0x45, 0x44, 0x10, 0x05, 0x2a, 0xaf, 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, + 0x73, 0x68, 0x69, 0x70, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x45, 0x4d, 0x42, + 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x4d, + 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, + 0x5f, 0x56, 0x49, 0x45, 0x57, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x4d, + 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, + 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x45, 0x4d, 0x42, + 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, + 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x03, 0x12, 0x1e, 0x0a, 0x1a, 0x4d, 0x45, 0x4d, 0x42, 0x45, + 0x52, 0x53, 0x48, 0x49, 0x50, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x4d, + 0x45, 0x4d, 0x42, 0x45, 0x52, 0x10, 0x04, 0x2a, 0x60, 0x0a, 0x0e, 0x41, 0x6c, 0x6c, 0x6f, 0x77, + 0x4c, 0x69, 0x73, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x1c, 0x41, 0x4c, 0x4c, + 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x26, 0x0a, 0x1c, 0x41, + 0x4c, 0x4c, 0x4f, 0x57, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, + 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x1a, 0x04, 0xa8, + 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x6d, 0x0a, 0x12, 0x46, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x41, 0x75, 0x74, 0x68, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, + 0x24, 0x0a, 0x20, 0x46, 0x45, 0x44, 0x45, 0x52, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x41, 0x55, 0x54, + 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2b, 0x0a, 0x21, 0x46, 0x45, 0x44, 0x45, 0x52, 0x41, 0x54, + 0x45, 0x44, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, + 0x41, 0x55, 0x54, 0x48, 0x4f, 0x52, 0x49, 0x5a, 0x45, 0x44, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, + 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, 0x84, 0x01, 0x0a, 0x19, 0x55, 0x73, 0x65, + 0x72, 0x57, 0x69, 0x74, 0x68, 0x4e, 0x6f, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x29, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x57, + 0x49, 0x54, 0x48, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, + 0x50, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, + 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x32, 0x0a, 0x28, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x57, 0x49, + 0x54, 0x48, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x48, 0x49, 0x50, + 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x5f, 0x4f, 0x52, + 0x47, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, 0xf4, 0x03, 0x2a, + 0x80, 0x01, 0x0a, 0x17, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x4f, 0x66, 0x4f, 0x72, 0x67, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x28, 0x55, + 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x4f, + 0x46, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x31, 0x0a, 0x27, 0x55, 0x53, 0x45, + 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x4d, 0x45, 0x4d, 0x42, 0x45, 0x52, 0x5f, 0x4f, 0x46, 0x5f, + 0x4f, 0x52, 0x47, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x49, 0x4e, + 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x01, 0x1a, 0x04, 0xa8, 0x45, 0x93, 0x03, 0x1a, 0x04, 0xa0, 0x45, + 0xf4, 0x03, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2953,7 +3037,7 @@ func file_controlplane_v1_response_messages_proto_rawDescGZIP() []byte { } var file_controlplane_v1_response_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 9) -var file_controlplane_v1_response_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 27) +var file_controlplane_v1_response_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 28) var file_controlplane_v1_response_messages_proto_goTypes = []interface{}{ (RunStatus)(0), // 0: controlplane.v1.RunStatus (MembershipRole)(0), // 1: controlplane.v1.MembershipRole @@ -2973,82 +3057,84 @@ var file_controlplane_v1_response_messages_proto_goTypes = []interface{}{ (*PolicyViolation)(nil), // 15: controlplane.v1.PolicyViolation (*PolicyReference)(nil), // 16: controlplane.v1.PolicyReference (*WorkflowContractItem)(nil), // 17: controlplane.v1.WorkflowContractItem - (*WorkflowRef)(nil), // 18: controlplane.v1.WorkflowRef - (*WorkflowContractVersionItem)(nil), // 19: controlplane.v1.WorkflowContractVersionItem - (*User)(nil), // 20: controlplane.v1.User - (*OrgMembershipItem)(nil), // 21: controlplane.v1.OrgMembershipItem - (*OrgItem)(nil), // 22: controlplane.v1.OrgItem - (*CASBackendItem)(nil), // 23: controlplane.v1.CASBackendItem - (*APITokenItem)(nil), // 24: controlplane.v1.APITokenItem - nil, // 25: controlplane.v1.AttestationItem.AnnotationsEntry - nil, // 26: controlplane.v1.AttestationItem.PolicyEvaluationsEntry - (*AttestationItem_PolicyEvaluationStatus)(nil), // 27: controlplane.v1.AttestationItem.PolicyEvaluationStatus - (*AttestationItem_EnvVariable)(nil), // 28: controlplane.v1.AttestationItem.EnvVariable - (*AttestationItem_Material)(nil), // 29: controlplane.v1.AttestationItem.Material - nil, // 30: controlplane.v1.AttestationItem.Material.AnnotationsEntry - nil, // 31: controlplane.v1.PolicyEvaluation.AnnotationsEntry - nil, // 32: controlplane.v1.PolicyEvaluation.WithEntry - nil, // 33: controlplane.v1.PolicyReference.DigestEntry - (*WorkflowContractVersionItem_RawBody)(nil), // 34: controlplane.v1.WorkflowContractVersionItem.RawBody - (*CASBackendItem_Limits)(nil), // 35: controlplane.v1.CASBackendItem.Limits - (*timestamppb.Timestamp)(nil), // 36: google.protobuf.Timestamp - (v1.CraftingSchema_Runner_RunnerType)(0), // 37: workflowcontract.v1.CraftingSchema.Runner.RunnerType - (*v1.CraftingSchema)(nil), // 38: workflowcontract.v1.CraftingSchema + (*ScopedEntity)(nil), // 18: controlplane.v1.ScopedEntity + (*WorkflowRef)(nil), // 19: controlplane.v1.WorkflowRef + (*WorkflowContractVersionItem)(nil), // 20: controlplane.v1.WorkflowContractVersionItem + (*User)(nil), // 21: controlplane.v1.User + (*OrgMembershipItem)(nil), // 22: controlplane.v1.OrgMembershipItem + (*OrgItem)(nil), // 23: controlplane.v1.OrgItem + (*CASBackendItem)(nil), // 24: controlplane.v1.CASBackendItem + (*APITokenItem)(nil), // 25: controlplane.v1.APITokenItem + nil, // 26: controlplane.v1.AttestationItem.AnnotationsEntry + nil, // 27: controlplane.v1.AttestationItem.PolicyEvaluationsEntry + (*AttestationItem_PolicyEvaluationStatus)(nil), // 28: controlplane.v1.AttestationItem.PolicyEvaluationStatus + (*AttestationItem_EnvVariable)(nil), // 29: controlplane.v1.AttestationItem.EnvVariable + (*AttestationItem_Material)(nil), // 30: controlplane.v1.AttestationItem.Material + nil, // 31: controlplane.v1.AttestationItem.Material.AnnotationsEntry + nil, // 32: controlplane.v1.PolicyEvaluation.AnnotationsEntry + nil, // 33: controlplane.v1.PolicyEvaluation.WithEntry + nil, // 34: controlplane.v1.PolicyReference.DigestEntry + (*WorkflowContractVersionItem_RawBody)(nil), // 35: controlplane.v1.WorkflowContractVersionItem.RawBody + (*CASBackendItem_Limits)(nil), // 36: controlplane.v1.CASBackendItem.Limits + (*timestamppb.Timestamp)(nil), // 37: google.protobuf.Timestamp + (v1.CraftingSchema_Runner_RunnerType)(0), // 38: workflowcontract.v1.CraftingSchema.Runner.RunnerType + (*v1.CraftingSchema)(nil), // 39: workflowcontract.v1.CraftingSchema } var file_controlplane_v1_response_messages_proto_depIdxs = []int32{ - 36, // 0: controlplane.v1.WorkflowItem.created_at:type_name -> google.protobuf.Timestamp + 37, // 0: controlplane.v1.WorkflowItem.created_at:type_name -> google.protobuf.Timestamp 10, // 1: controlplane.v1.WorkflowItem.last_run:type_name -> controlplane.v1.WorkflowRunItem - 36, // 2: controlplane.v1.WorkflowRunItem.created_at:type_name -> google.protobuf.Timestamp - 36, // 3: controlplane.v1.WorkflowRunItem.finished_at:type_name -> google.protobuf.Timestamp + 37, // 2: controlplane.v1.WorkflowRunItem.created_at:type_name -> google.protobuf.Timestamp + 37, // 3: controlplane.v1.WorkflowRunItem.finished_at:type_name -> google.protobuf.Timestamp 0, // 4: controlplane.v1.WorkflowRunItem.status:type_name -> controlplane.v1.RunStatus 9, // 5: controlplane.v1.WorkflowRunItem.workflow:type_name -> controlplane.v1.WorkflowItem - 37, // 6: controlplane.v1.WorkflowRunItem.runner_type:type_name -> workflowcontract.v1.CraftingSchema.Runner.RunnerType - 19, // 7: controlplane.v1.WorkflowRunItem.contract_version:type_name -> controlplane.v1.WorkflowContractVersionItem + 38, // 6: controlplane.v1.WorkflowRunItem.runner_type:type_name -> workflowcontract.v1.CraftingSchema.Runner.RunnerType + 20, // 7: controlplane.v1.WorkflowRunItem.contract_version:type_name -> controlplane.v1.WorkflowContractVersionItem 11, // 8: controlplane.v1.WorkflowRunItem.version:type_name -> controlplane.v1.ProjectVersion - 36, // 9: controlplane.v1.ProjectVersion.created_at:type_name -> google.protobuf.Timestamp - 36, // 10: controlplane.v1.ProjectVersion.released_at:type_name -> google.protobuf.Timestamp - 28, // 11: controlplane.v1.AttestationItem.env_vars:type_name -> controlplane.v1.AttestationItem.EnvVariable - 29, // 12: controlplane.v1.AttestationItem.materials:type_name -> controlplane.v1.AttestationItem.Material - 25, // 13: controlplane.v1.AttestationItem.annotations:type_name -> controlplane.v1.AttestationItem.AnnotationsEntry - 26, // 14: controlplane.v1.AttestationItem.policy_evaluations:type_name -> controlplane.v1.AttestationItem.PolicyEvaluationsEntry - 27, // 15: controlplane.v1.AttestationItem.policy_evaluation_status:type_name -> controlplane.v1.AttestationItem.PolicyEvaluationStatus + 37, // 9: controlplane.v1.ProjectVersion.created_at:type_name -> google.protobuf.Timestamp + 37, // 10: controlplane.v1.ProjectVersion.released_at:type_name -> google.protobuf.Timestamp + 29, // 11: controlplane.v1.AttestationItem.env_vars:type_name -> controlplane.v1.AttestationItem.EnvVariable + 30, // 12: controlplane.v1.AttestationItem.materials:type_name -> controlplane.v1.AttestationItem.Material + 26, // 13: controlplane.v1.AttestationItem.annotations:type_name -> controlplane.v1.AttestationItem.AnnotationsEntry + 27, // 14: controlplane.v1.AttestationItem.policy_evaluations:type_name -> controlplane.v1.AttestationItem.PolicyEvaluationsEntry + 28, // 15: controlplane.v1.AttestationItem.policy_evaluation_status:type_name -> controlplane.v1.AttestationItem.PolicyEvaluationStatus 14, // 16: controlplane.v1.PolicyEvaluations.evaluations:type_name -> controlplane.v1.PolicyEvaluation - 31, // 17: controlplane.v1.PolicyEvaluation.annotations:type_name -> controlplane.v1.PolicyEvaluation.AnnotationsEntry - 32, // 18: controlplane.v1.PolicyEvaluation.with:type_name -> controlplane.v1.PolicyEvaluation.WithEntry + 32, // 17: controlplane.v1.PolicyEvaluation.annotations:type_name -> controlplane.v1.PolicyEvaluation.AnnotationsEntry + 33, // 18: controlplane.v1.PolicyEvaluation.with:type_name -> controlplane.v1.PolicyEvaluation.WithEntry 15, // 19: controlplane.v1.PolicyEvaluation.violations:type_name -> controlplane.v1.PolicyViolation 16, // 20: controlplane.v1.PolicyEvaluation.policy_reference:type_name -> controlplane.v1.PolicyReference 16, // 21: controlplane.v1.PolicyEvaluation.group_reference:type_name -> controlplane.v1.PolicyReference - 33, // 22: controlplane.v1.PolicyReference.digest:type_name -> controlplane.v1.PolicyReference.DigestEntry - 36, // 23: controlplane.v1.WorkflowContractItem.created_at:type_name -> google.protobuf.Timestamp - 36, // 24: controlplane.v1.WorkflowContractItem.latest_revision_created_at:type_name -> google.protobuf.Timestamp - 18, // 25: controlplane.v1.WorkflowContractItem.workflow_refs:type_name -> controlplane.v1.WorkflowRef - 36, // 26: controlplane.v1.WorkflowContractVersionItem.created_at:type_name -> google.protobuf.Timestamp - 38, // 27: controlplane.v1.WorkflowContractVersionItem.v1:type_name -> workflowcontract.v1.CraftingSchema - 34, // 28: controlplane.v1.WorkflowContractVersionItem.raw_contract:type_name -> controlplane.v1.WorkflowContractVersionItem.RawBody - 36, // 29: controlplane.v1.User.created_at:type_name -> google.protobuf.Timestamp - 22, // 30: controlplane.v1.OrgMembershipItem.org:type_name -> controlplane.v1.OrgItem - 20, // 31: controlplane.v1.OrgMembershipItem.user:type_name -> controlplane.v1.User - 36, // 32: controlplane.v1.OrgMembershipItem.created_at:type_name -> google.protobuf.Timestamp - 36, // 33: controlplane.v1.OrgMembershipItem.updated_at:type_name -> google.protobuf.Timestamp - 1, // 34: controlplane.v1.OrgMembershipItem.role:type_name -> controlplane.v1.MembershipRole - 36, // 35: controlplane.v1.OrgItem.created_at:type_name -> google.protobuf.Timestamp - 7, // 36: controlplane.v1.OrgItem.default_policy_violation_strategy:type_name -> controlplane.v1.OrgItem.PolicyViolationBlockingStrategy - 36, // 37: controlplane.v1.CASBackendItem.created_at:type_name -> google.protobuf.Timestamp - 36, // 38: controlplane.v1.CASBackendItem.validated_at:type_name -> google.protobuf.Timestamp - 8, // 39: controlplane.v1.CASBackendItem.validation_status:type_name -> controlplane.v1.CASBackendItem.ValidationStatus - 35, // 40: controlplane.v1.CASBackendItem.limits:type_name -> controlplane.v1.CASBackendItem.Limits - 36, // 41: controlplane.v1.APITokenItem.created_at:type_name -> google.protobuf.Timestamp - 36, // 42: controlplane.v1.APITokenItem.revoked_at:type_name -> google.protobuf.Timestamp - 36, // 43: controlplane.v1.APITokenItem.expires_at:type_name -> google.protobuf.Timestamp - 36, // 44: controlplane.v1.APITokenItem.last_used_at:type_name -> google.protobuf.Timestamp - 13, // 45: controlplane.v1.AttestationItem.PolicyEvaluationsEntry.value:type_name -> controlplane.v1.PolicyEvaluations - 30, // 46: controlplane.v1.AttestationItem.Material.annotations:type_name -> controlplane.v1.AttestationItem.Material.AnnotationsEntry - 6, // 47: controlplane.v1.WorkflowContractVersionItem.RawBody.format:type_name -> controlplane.v1.WorkflowContractVersionItem.RawBody.Format - 48, // [48:48] is the sub-list for method output_type - 48, // [48:48] is the sub-list for method input_type - 48, // [48:48] is the sub-list for extension type_name - 48, // [48:48] is the sub-list for extension extendee - 0, // [0:48] is the sub-list for field type_name + 34, // 22: controlplane.v1.PolicyReference.digest:type_name -> controlplane.v1.PolicyReference.DigestEntry + 37, // 23: controlplane.v1.WorkflowContractItem.created_at:type_name -> google.protobuf.Timestamp + 37, // 24: controlplane.v1.WorkflowContractItem.latest_revision_created_at:type_name -> google.protobuf.Timestamp + 19, // 25: controlplane.v1.WorkflowContractItem.workflow_refs:type_name -> controlplane.v1.WorkflowRef + 18, // 26: controlplane.v1.WorkflowContractItem.scoped_entity:type_name -> controlplane.v1.ScopedEntity + 37, // 27: controlplane.v1.WorkflowContractVersionItem.created_at:type_name -> google.protobuf.Timestamp + 39, // 28: controlplane.v1.WorkflowContractVersionItem.v1:type_name -> workflowcontract.v1.CraftingSchema + 35, // 29: controlplane.v1.WorkflowContractVersionItem.raw_contract:type_name -> controlplane.v1.WorkflowContractVersionItem.RawBody + 37, // 30: controlplane.v1.User.created_at:type_name -> google.protobuf.Timestamp + 23, // 31: controlplane.v1.OrgMembershipItem.org:type_name -> controlplane.v1.OrgItem + 21, // 32: controlplane.v1.OrgMembershipItem.user:type_name -> controlplane.v1.User + 37, // 33: controlplane.v1.OrgMembershipItem.created_at:type_name -> google.protobuf.Timestamp + 37, // 34: controlplane.v1.OrgMembershipItem.updated_at:type_name -> google.protobuf.Timestamp + 1, // 35: controlplane.v1.OrgMembershipItem.role:type_name -> controlplane.v1.MembershipRole + 37, // 36: controlplane.v1.OrgItem.created_at:type_name -> google.protobuf.Timestamp + 7, // 37: controlplane.v1.OrgItem.default_policy_violation_strategy:type_name -> controlplane.v1.OrgItem.PolicyViolationBlockingStrategy + 37, // 38: controlplane.v1.CASBackendItem.created_at:type_name -> google.protobuf.Timestamp + 37, // 39: controlplane.v1.CASBackendItem.validated_at:type_name -> google.protobuf.Timestamp + 8, // 40: controlplane.v1.CASBackendItem.validation_status:type_name -> controlplane.v1.CASBackendItem.ValidationStatus + 36, // 41: controlplane.v1.CASBackendItem.limits:type_name -> controlplane.v1.CASBackendItem.Limits + 37, // 42: controlplane.v1.APITokenItem.created_at:type_name -> google.protobuf.Timestamp + 37, // 43: controlplane.v1.APITokenItem.revoked_at:type_name -> google.protobuf.Timestamp + 37, // 44: controlplane.v1.APITokenItem.expires_at:type_name -> google.protobuf.Timestamp + 37, // 45: controlplane.v1.APITokenItem.last_used_at:type_name -> google.protobuf.Timestamp + 13, // 46: controlplane.v1.AttestationItem.PolicyEvaluationsEntry.value:type_name -> controlplane.v1.PolicyEvaluations + 31, // 47: controlplane.v1.AttestationItem.Material.annotations:type_name -> controlplane.v1.AttestationItem.Material.AnnotationsEntry + 6, // 48: controlplane.v1.WorkflowContractVersionItem.RawBody.format:type_name -> controlplane.v1.WorkflowContractVersionItem.RawBody.Format + 49, // [49:49] is the sub-list for method output_type + 49, // [49:49] is the sub-list for method input_type + 49, // [49:49] is the sub-list for extension type_name + 49, // [49:49] is the sub-list for extension extendee + 0, // [0:49] is the sub-list for field type_name } func init() { file_controlplane_v1_response_messages_proto_init() } @@ -3166,7 +3252,7 @@ func file_controlplane_v1_response_messages_proto_init() { } } file_controlplane_v1_response_messages_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkflowRef); i { + switch v := v.(*ScopedEntity); i { case 0: return &v.state case 1: @@ -3178,7 +3264,7 @@ func file_controlplane_v1_response_messages_proto_init() { } } file_controlplane_v1_response_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WorkflowContractVersionItem); i { + switch v := v.(*WorkflowRef); i { case 0: return &v.state case 1: @@ -3190,7 +3276,7 @@ func file_controlplane_v1_response_messages_proto_init() { } } file_controlplane_v1_response_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*User); i { + switch v := v.(*WorkflowContractVersionItem); i { case 0: return &v.state case 1: @@ -3202,7 +3288,7 @@ func file_controlplane_v1_response_messages_proto_init() { } } file_controlplane_v1_response_messages_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OrgMembershipItem); i { + switch v := v.(*User); i { case 0: return &v.state case 1: @@ -3214,7 +3300,7 @@ func file_controlplane_v1_response_messages_proto_init() { } } file_controlplane_v1_response_messages_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OrgItem); i { + switch v := v.(*OrgMembershipItem); i { case 0: return &v.state case 1: @@ -3226,7 +3312,7 @@ func file_controlplane_v1_response_messages_proto_init() { } } file_controlplane_v1_response_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CASBackendItem); i { + switch v := v.(*OrgItem); i { case 0: return &v.state case 1: @@ -3238,6 +3324,18 @@ func file_controlplane_v1_response_messages_proto_init() { } } file_controlplane_v1_response_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CASBackendItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controlplane_v1_response_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*APITokenItem); i { case 0: return &v.state @@ -3249,7 +3347,7 @@ func file_controlplane_v1_response_messages_proto_init() { return nil } } - file_controlplane_v1_response_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_v1_response_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttestationItem_PolicyEvaluationStatus); i { case 0: return &v.state @@ -3261,7 +3359,7 @@ func file_controlplane_v1_response_messages_proto_init() { return nil } } - file_controlplane_v1_response_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_v1_response_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttestationItem_EnvVariable); i { case 0: return &v.state @@ -3273,7 +3371,7 @@ func file_controlplane_v1_response_messages_proto_init() { return nil } } - file_controlplane_v1_response_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_v1_response_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttestationItem_Material); i { case 0: return &v.state @@ -3285,7 +3383,7 @@ func file_controlplane_v1_response_messages_proto_init() { return nil } } - file_controlplane_v1_response_messages_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_v1_response_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WorkflowContractVersionItem_RawBody); i { case 0: return &v.state @@ -3297,7 +3395,7 @@ func file_controlplane_v1_response_messages_proto_init() { return nil } } - file_controlplane_v1_response_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_controlplane_v1_response_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CASBackendItem_Limits); i { case 0: return &v.state @@ -3310,7 +3408,7 @@ func file_controlplane_v1_response_messages_proto_init() { } } } - file_controlplane_v1_response_messages_proto_msgTypes[10].OneofWrappers = []interface{}{ + file_controlplane_v1_response_messages_proto_msgTypes[11].OneofWrappers = []interface{}{ (*WorkflowContractVersionItem_V1)(nil), } type x struct{} @@ -3319,7 +3417,7 @@ func file_controlplane_v1_response_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_controlplane_v1_response_messages_proto_rawDesc, NumEnums: 9, - NumMessages: 27, + NumMessages: 28, NumExtensions: 0, NumServices: 0, }, diff --git a/app/controlplane/api/controlplane/v1/response_messages.proto b/app/controlplane/api/controlplane/v1/response_messages.proto index 9d5600806..80cc8f1d7 100644 --- a/app/controlplane/api/controlplane/v1/response_messages.proto +++ b/app/controlplane/api/controlplane/v1/response_messages.proto @@ -176,6 +176,17 @@ message WorkflowContractItem { // Workflows associated with this contract repeated string workflow_names = 5 [deprecated = true]; repeated WorkflowRef workflow_refs = 7; + // wether the contract is scoped to an entity in the organization + ScopedEntity scoped_entity = 9; +} + +message ScopedEntity { + // Type is the type of the scoped entity i.e project or org + string type = 1; + // ID is the id of the scoped entity + string id = 2; + // Name is the name of the scoped entity + string name = 3; } message WorkflowRef { diff --git a/app/controlplane/api/controlplane/v1/shared_message.go b/app/controlplane/api/controlplane/v1/shared_message.go index 8fd0e8847..9ffd40e0c 100644 --- a/app/controlplane/api/controlplane/v1/shared_message.go +++ b/app/controlplane/api/controlplane/v1/shared_message.go @@ -40,3 +40,11 @@ func (i *IdentityReference) Parse() (*uuid.UUID, *string, error) { return nil, nil, nil } + +func (i *IdentityReference) IsSet() bool { + if i == nil { + return false + } + + return i.GetId() != "" || i.GetName() != "" +} diff --git a/app/controlplane/api/controlplane/v1/workflow_contract.pb.go b/app/controlplane/api/controlplane/v1/workflow_contract.pb.go index 8b5f24bd9..5b65e3d17 100644 --- a/app/controlplane/api/controlplane/v1/workflow_contract.pb.go +++ b/app/controlplane/api/controlplane/v1/workflow_contract.pb.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -130,6 +130,8 @@ type WorkflowContractServiceCreateRequest struct { // Raw representation of the contract in json, yaml or cue RawContract []byte `protobuf:"bytes,4,opt,name=raw_contract,json=rawContract,proto3" json:"raw_contract,omitempty"` Description *string `protobuf:"bytes,3,opt,name=description,proto3,oneof" json:"description,omitempty"` + // You might need to specify a project reference if you want/need to create a contract scoped to a project + ProjectReference *IdentityReference `protobuf:"bytes,5,opt,name=project_reference,json=projectReference,proto3" json:"project_reference,omitempty"` } func (x *WorkflowContractServiceCreateRequest) Reset() { @@ -185,6 +187,13 @@ func (x *WorkflowContractServiceCreateRequest) GetDescription() string { return "" } +func (x *WorkflowContractServiceCreateRequest) GetProjectReference() *IdentityReference { + if x != nil { + return x.ProjectReference + } + return nil +} + type WorkflowContractServiceCreateResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -651,17 +660,116 @@ var file_controlplane_v1_workflow_contract_proto_rawDesc = []byte{ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x24, 0x0a, 0x22, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x64, 0x0a, 0x23, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x1a, 0x24, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, + 0x31, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x24, 0x0a, 0x22, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, - 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x64, 0x0a, 0x23, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x9a, 0x02, 0x0a, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x22, 0xeb, 0x02, 0x0a, 0x24, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x97, 0x01, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, + 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, + 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, + 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, + 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, 0x68, 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, + 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, + 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, + 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, + 0x4f, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x10, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x66, 0x0a, 0x25, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x74, 0x65, 0x6d, + 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x9a, 0x02, 0x0a, 0x24, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2e, + 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, 0x65, + 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, 0x68, + 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, + 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, + 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, + 0x61, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x25, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x96, 0x02, 0x0a, 0x25, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x55, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x95, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x41, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x12, 0x48, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, + 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xde, + 0x01, 0x0a, 0x26, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, + 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, + 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6c, 0x65, + 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, 0x68, 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, + 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, + 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, + 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, + 0x9a, 0x02, 0x0a, 0x27, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x06, 0x72, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, + 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x95, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x41, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, + 0x63, 0x74, 0x12, 0x48, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, + 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x74, + 0x65, 0x6d, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xc0, 0x01, 0x0a, 0x24, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, @@ -671,146 +779,55 @@ var file_controlplane_v1_workflow_contract_proto_rawDesc = []byte{ 0x68, 0x79, 0x70, 0x68, 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, - 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x25, 0x57, 0x6f, 0x72, + 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x27, 0x0a, 0x25, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xf6, 0x04, 0x0a, 0x17, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0x9a, 0x02, 0x0a, 0x24, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, - 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, - 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, - 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6c, - 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2c, - 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, 0x68, 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, - 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, - 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, - 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x61, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x72, 0x61, 0x77, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0e, - 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x96, - 0x02, 0x0a, 0x25, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, - 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, + 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, - 0x95, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, - 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, - 0x74, 0x65, 0x6d, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x48, 0x0a, - 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, - 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x72, - 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xde, 0x01, 0x0a, 0x26, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x97, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x82, 0x01, 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, - 0x2e, 0x64, 0x6e, 0x73, 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, - 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, - 0x65, 0x72, 0x63, 0x61, 0x73, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, - 0x68, 0x65, 0x6e, 0x73, 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, - 0x2d, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, - 0x5d, 0x29, 0x3f, 0x24, 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, - 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x9a, 0x02, 0x0a, 0x27, 0x57, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, - 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, - 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, - 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x95, 0x01, - 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x41, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x49, 0x74, 0x65, - 0x6d, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x48, 0x0a, 0x08, 0x72, - 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x08, 0x72, 0x65, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xc0, 0x01, 0x0a, 0x24, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x97, - 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x82, 0x01, - 0xba, 0x48, 0x7f, 0xba, 0x01, 0x7c, 0x0a, 0x0d, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x64, 0x6e, 0x73, - 0x2d, 0x31, 0x31, 0x32, 0x33, 0x12, 0x3a, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x63, 0x61, - 0x73, 0x65, 0x20, 0x6c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x73, 0x2c, 0x20, 0x6e, 0x75, 0x6d, 0x62, - 0x65, 0x72, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x68, 0x79, 0x70, 0x68, 0x65, 0x6e, 0x73, - 0x2e, 0x1a, 0x2f, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, - 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x28, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, - 0x30, 0x2d, 0x39, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x3f, 0x24, - 0x27, 0x29, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x27, 0x0a, 0x25, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x32, 0xf6, 0x04, 0x0a, 0x17, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x71, 0x0a, - 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, - 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, - 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x77, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, + 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x77, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x06, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, - 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, - 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x08, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x37, + 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x08, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x37, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, + 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, - 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, - 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x77, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x35, 0x2e, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, - 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, - 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, - 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, - 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, - 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x66, 0x6c, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x4c, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x6c, 0x6f, 0x6f, 0x70, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -840,32 +857,34 @@ var file_controlplane_v1_workflow_contract_proto_goTypes = []interface{}{ (*WorkflowContractServiceUpdateResponse_Result)(nil), // 10: controlplane.v1.WorkflowContractServiceUpdateResponse.Result (*WorkflowContractServiceDescribeResponse_Result)(nil), // 11: controlplane.v1.WorkflowContractServiceDescribeResponse.Result (*WorkflowContractItem)(nil), // 12: controlplane.v1.WorkflowContractItem - (*WorkflowContractVersionItem)(nil), // 13: controlplane.v1.WorkflowContractVersionItem + (*IdentityReference)(nil), // 13: controlplane.v1.IdentityReference + (*WorkflowContractVersionItem)(nil), // 14: controlplane.v1.WorkflowContractVersionItem } var file_controlplane_v1_workflow_contract_proto_depIdxs = []int32{ 12, // 0: controlplane.v1.WorkflowContractServiceListResponse.result:type_name -> controlplane.v1.WorkflowContractItem - 12, // 1: controlplane.v1.WorkflowContractServiceCreateResponse.result:type_name -> controlplane.v1.WorkflowContractItem - 10, // 2: controlplane.v1.WorkflowContractServiceUpdateResponse.result:type_name -> controlplane.v1.WorkflowContractServiceUpdateResponse.Result - 11, // 3: controlplane.v1.WorkflowContractServiceDescribeResponse.result:type_name -> controlplane.v1.WorkflowContractServiceDescribeResponse.Result - 12, // 4: controlplane.v1.WorkflowContractServiceUpdateResponse.Result.contract:type_name -> controlplane.v1.WorkflowContractItem - 13, // 5: controlplane.v1.WorkflowContractServiceUpdateResponse.Result.revision:type_name -> controlplane.v1.WorkflowContractVersionItem - 12, // 6: controlplane.v1.WorkflowContractServiceDescribeResponse.Result.contract:type_name -> controlplane.v1.WorkflowContractItem - 13, // 7: controlplane.v1.WorkflowContractServiceDescribeResponse.Result.revision:type_name -> controlplane.v1.WorkflowContractVersionItem - 0, // 8: controlplane.v1.WorkflowContractService.List:input_type -> controlplane.v1.WorkflowContractServiceListRequest - 2, // 9: controlplane.v1.WorkflowContractService.Create:input_type -> controlplane.v1.WorkflowContractServiceCreateRequest - 4, // 10: controlplane.v1.WorkflowContractService.Update:input_type -> controlplane.v1.WorkflowContractServiceUpdateRequest - 6, // 11: controlplane.v1.WorkflowContractService.Describe:input_type -> controlplane.v1.WorkflowContractServiceDescribeRequest - 8, // 12: controlplane.v1.WorkflowContractService.Delete:input_type -> controlplane.v1.WorkflowContractServiceDeleteRequest - 1, // 13: controlplane.v1.WorkflowContractService.List:output_type -> controlplane.v1.WorkflowContractServiceListResponse - 3, // 14: controlplane.v1.WorkflowContractService.Create:output_type -> controlplane.v1.WorkflowContractServiceCreateResponse - 5, // 15: controlplane.v1.WorkflowContractService.Update:output_type -> controlplane.v1.WorkflowContractServiceUpdateResponse - 7, // 16: controlplane.v1.WorkflowContractService.Describe:output_type -> controlplane.v1.WorkflowContractServiceDescribeResponse - 9, // 17: controlplane.v1.WorkflowContractService.Delete:output_type -> controlplane.v1.WorkflowContractServiceDeleteResponse - 13, // [13:18] is the sub-list for method output_type - 8, // [8:13] is the sub-list for method input_type - 8, // [8:8] is the sub-list for extension type_name - 8, // [8:8] is the sub-list for extension extendee - 0, // [0:8] is the sub-list for field type_name + 13, // 1: controlplane.v1.WorkflowContractServiceCreateRequest.project_reference:type_name -> controlplane.v1.IdentityReference + 12, // 2: controlplane.v1.WorkflowContractServiceCreateResponse.result:type_name -> controlplane.v1.WorkflowContractItem + 10, // 3: controlplane.v1.WorkflowContractServiceUpdateResponse.result:type_name -> controlplane.v1.WorkflowContractServiceUpdateResponse.Result + 11, // 4: controlplane.v1.WorkflowContractServiceDescribeResponse.result:type_name -> controlplane.v1.WorkflowContractServiceDescribeResponse.Result + 12, // 5: controlplane.v1.WorkflowContractServiceUpdateResponse.Result.contract:type_name -> controlplane.v1.WorkflowContractItem + 14, // 6: controlplane.v1.WorkflowContractServiceUpdateResponse.Result.revision:type_name -> controlplane.v1.WorkflowContractVersionItem + 12, // 7: controlplane.v1.WorkflowContractServiceDescribeResponse.Result.contract:type_name -> controlplane.v1.WorkflowContractItem + 14, // 8: controlplane.v1.WorkflowContractServiceDescribeResponse.Result.revision:type_name -> controlplane.v1.WorkflowContractVersionItem + 0, // 9: controlplane.v1.WorkflowContractService.List:input_type -> controlplane.v1.WorkflowContractServiceListRequest + 2, // 10: controlplane.v1.WorkflowContractService.Create:input_type -> controlplane.v1.WorkflowContractServiceCreateRequest + 4, // 11: controlplane.v1.WorkflowContractService.Update:input_type -> controlplane.v1.WorkflowContractServiceUpdateRequest + 6, // 12: controlplane.v1.WorkflowContractService.Describe:input_type -> controlplane.v1.WorkflowContractServiceDescribeRequest + 8, // 13: controlplane.v1.WorkflowContractService.Delete:input_type -> controlplane.v1.WorkflowContractServiceDeleteRequest + 1, // 14: controlplane.v1.WorkflowContractService.List:output_type -> controlplane.v1.WorkflowContractServiceListResponse + 3, // 15: controlplane.v1.WorkflowContractService.Create:output_type -> controlplane.v1.WorkflowContractServiceCreateResponse + 5, // 16: controlplane.v1.WorkflowContractService.Update:output_type -> controlplane.v1.WorkflowContractServiceUpdateResponse + 7, // 17: controlplane.v1.WorkflowContractService.Describe:output_type -> controlplane.v1.WorkflowContractServiceDescribeResponse + 9, // 18: controlplane.v1.WorkflowContractService.Delete:output_type -> controlplane.v1.WorkflowContractServiceDeleteResponse + 14, // [14:19] is the sub-list for method output_type + 9, // [9:14] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name } func init() { file_controlplane_v1_workflow_contract_proto_init() } @@ -874,6 +893,7 @@ func file_controlplane_v1_workflow_contract_proto_init() { return } file_controlplane_v1_response_messages_proto_init() + file_controlplane_v1_shared_message_proto_init() if !protoimpl.UnsafeEnabled { file_controlplane_v1_workflow_contract_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*WorkflowContractServiceListRequest); i { diff --git a/app/controlplane/api/controlplane/v1/workflow_contract.proto b/app/controlplane/api/controlplane/v1/workflow_contract.proto index a56b6fe75..d96eb00dc 100644 --- a/app/controlplane/api/controlplane/v1/workflow_contract.proto +++ b/app/controlplane/api/controlplane/v1/workflow_contract.proto @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package controlplane.v1; import "buf/validate/validate.proto"; import "controlplane/v1/response_messages.proto"; +import "controlplane/v1/shared_message.proto"; option go_package = "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1;v1"; @@ -49,6 +50,9 @@ message WorkflowContractServiceCreateRequest { bytes raw_contract = 4; optional string description = 3; + + // You might need to specify a project reference if you want/need to create a contract scoped to a project + IdentityReference project_reference = 5; } message WorkflowContractServiceCreateResponse { @@ -87,6 +91,9 @@ message WorkflowContractServiceDescribeRequest { } }]; int32 revision = 2; + + // You might need to specify a project reference if you want/need to describe a contract scoped to a project + IdentityReference project_reference = 5; } message WorkflowContractServiceDescribeResponse { diff --git a/app/controlplane/api/controlplane/v1/workflow_contract_grpc.pb.go b/app/controlplane/api/controlplane/v1/workflow_contract_grpc.pb.go index 2572b676a..83ec2a572 100644 --- a/app/controlplane/api/controlplane/v1/workflow_contract_grpc.pb.go +++ b/app/controlplane/api/controlplane/v1/workflow_contract_grpc.pb.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts b/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts index cefad198a..e69eedfe2 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/response_messages.ts @@ -437,6 +437,17 @@ export interface WorkflowContractItem { */ workflowNames: string[]; workflowRefs: WorkflowRef[]; + /** wether the contract is scoped to an entity in the organization */ + scopedEntity?: ScopedEntity; +} + +export interface ScopedEntity { + /** Type is the type of the scoped entity i.e project or org */ + type: string; + /** ID is the id of the scoped entity */ + id: string; + /** Name is the name of the scoped entity */ + name: string; } export interface WorkflowRef { @@ -2806,6 +2817,7 @@ function createBaseWorkflowContractItem(): WorkflowContractItem { latestRevisionCreatedAt: undefined, workflowNames: [], workflowRefs: [], + scopedEntity: undefined, }; } @@ -2835,6 +2847,9 @@ export const WorkflowContractItem = { for (const v of message.workflowRefs) { WorkflowRef.encode(v!, writer.uint32(58).fork()).ldelim(); } + if (message.scopedEntity !== undefined) { + ScopedEntity.encode(message.scopedEntity, writer.uint32(74).fork()).ldelim(); + } return writer; }, @@ -2901,6 +2916,13 @@ export const WorkflowContractItem = { message.workflowRefs.push(WorkflowRef.decode(reader, reader.uint32())); continue; + case 9: + if (tag !== 74) { + break; + } + + message.scopedEntity = ScopedEntity.decode(reader, reader.uint32()); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -2924,6 +2946,7 @@ export const WorkflowContractItem = { workflowRefs: Array.isArray(object?.workflowRefs) ? object.workflowRefs.map((e: any) => WorkflowRef.fromJSON(e)) : [], + scopedEntity: isSet(object.scopedEntity) ? ScopedEntity.fromJSON(object.scopedEntity) : undefined, }; }, @@ -2946,6 +2969,8 @@ export const WorkflowContractItem = { } else { obj.workflowRefs = []; } + message.scopedEntity !== undefined && + (obj.scopedEntity = message.scopedEntity ? ScopedEntity.toJSON(message.scopedEntity) : undefined); return obj; }, @@ -2963,6 +2988,93 @@ export const WorkflowContractItem = { message.latestRevisionCreatedAt = object.latestRevisionCreatedAt ?? undefined; message.workflowNames = object.workflowNames?.map((e) => e) || []; message.workflowRefs = object.workflowRefs?.map((e) => WorkflowRef.fromPartial(e)) || []; + message.scopedEntity = (object.scopedEntity !== undefined && object.scopedEntity !== null) + ? ScopedEntity.fromPartial(object.scopedEntity) + : undefined; + return message; + }, +}; + +function createBaseScopedEntity(): ScopedEntity { + return { type: "", id: "", name: "" }; +} + +export const ScopedEntity = { + encode(message: ScopedEntity, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.type !== "") { + writer.uint32(10).string(message.type); + } + if (message.id !== "") { + writer.uint32(18).string(message.id); + } + if (message.name !== "") { + writer.uint32(26).string(message.name); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ScopedEntity { + const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseScopedEntity(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (tag !== 10) { + break; + } + + message.type = reader.string(); + continue; + case 2: + if (tag !== 18) { + break; + } + + message.id = reader.string(); + continue; + case 3: + if (tag !== 26) { + break; + } + + message.name = reader.string(); + continue; + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skipType(tag & 7); + } + return message; + }, + + fromJSON(object: any): ScopedEntity { + return { + type: isSet(object.type) ? String(object.type) : "", + id: isSet(object.id) ? String(object.id) : "", + name: isSet(object.name) ? String(object.name) : "", + }; + }, + + toJSON(message: ScopedEntity): unknown { + const obj: any = {}; + message.type !== undefined && (obj.type = message.type); + message.id !== undefined && (obj.id = message.id); + message.name !== undefined && (obj.name = message.name); + return obj; + }, + + create, I>>(base?: I): ScopedEntity { + return ScopedEntity.fromPartial(base ?? {}); + }, + + fromPartial, I>>(object: I): ScopedEntity { + const message = createBaseScopedEntity(); + message.type = object.type ?? ""; + message.id = object.id ?? ""; + message.name = object.name ?? ""; return message; }, }; diff --git a/app/controlplane/api/gen/frontend/controlplane/v1/workflow_contract.ts b/app/controlplane/api/gen/frontend/controlplane/v1/workflow_contract.ts index 56c63f0fd..60260f75b 100644 --- a/app/controlplane/api/gen/frontend/controlplane/v1/workflow_contract.ts +++ b/app/controlplane/api/gen/frontend/controlplane/v1/workflow_contract.ts @@ -3,6 +3,7 @@ import { grpc } from "@improbable-eng/grpc-web"; import { BrowserHeaders } from "browser-headers"; import _m0 from "protobufjs/minimal"; import { WorkflowContractItem, WorkflowContractVersionItem } from "./response_messages"; +import { IdentityReference } from "./shared_message"; export const protobufPackage = "controlplane.v1"; @@ -17,7 +18,11 @@ export interface WorkflowContractServiceCreateRequest { name: string; /** Raw representation of the contract in json, yaml or cue */ rawContract: Uint8Array; - description?: string | undefined; + description?: + | string + | undefined; + /** You might need to specify a project reference if you want/need to create a contract scoped to a project */ + projectReference?: IdentityReference; } export interface WorkflowContractServiceCreateResponse { @@ -176,7 +181,7 @@ export const WorkflowContractServiceListResponse = { }; function createBaseWorkflowContractServiceCreateRequest(): WorkflowContractServiceCreateRequest { - return { name: "", rawContract: new Uint8Array(0), description: undefined }; + return { name: "", rawContract: new Uint8Array(0), description: undefined, projectReference: undefined }; } export const WorkflowContractServiceCreateRequest = { @@ -190,6 +195,9 @@ export const WorkflowContractServiceCreateRequest = { if (message.description !== undefined) { writer.uint32(26).string(message.description); } + if (message.projectReference !== undefined) { + IdentityReference.encode(message.projectReference, writer.uint32(42).fork()).ldelim(); + } return writer; }, @@ -221,6 +229,13 @@ export const WorkflowContractServiceCreateRequest = { message.description = reader.string(); continue; + case 5: + if (tag !== 42) { + break; + } + + message.projectReference = IdentityReference.decode(reader, reader.uint32()); + continue; } if ((tag & 7) === 4 || tag === 0) { break; @@ -235,6 +250,9 @@ export const WorkflowContractServiceCreateRequest = { name: isSet(object.name) ? String(object.name) : "", rawContract: isSet(object.rawContract) ? bytesFromBase64(object.rawContract) : new Uint8Array(0), description: isSet(object.description) ? String(object.description) : undefined, + projectReference: isSet(object.projectReference) + ? IdentityReference.fromJSON(object.projectReference) + : undefined, }; }, @@ -244,6 +262,10 @@ export const WorkflowContractServiceCreateRequest = { message.rawContract !== undefined && (obj.rawContract = base64FromBytes(message.rawContract !== undefined ? message.rawContract : new Uint8Array(0))); message.description !== undefined && (obj.description = message.description); + message.projectReference !== undefined && + (obj.projectReference = message.projectReference + ? IdentityReference.toJSON(message.projectReference) + : undefined); return obj; }, @@ -260,6 +282,9 @@ export const WorkflowContractServiceCreateRequest = { message.name = object.name ?? ""; message.rawContract = object.rawContract ?? new Uint8Array(0); message.description = object.description ?? undefined; + message.projectReference = (object.projectReference !== undefined && object.projectReference !== null) + ? IdentityReference.fromPartial(object.projectReference) + : undefined; return message; }, }; diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.jsonschema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.jsonschema.json new file mode 100644 index 000000000..2925be4e1 --- /dev/null +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.jsonschema.json @@ -0,0 +1,21 @@ +{ + "$id": "controlplane.v1.ScopedEntity.jsonschema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "id": { + "description": "ID is the id of the scoped entity", + "type": "string" + }, + "name": { + "description": "Name is the name of the scoped entity", + "type": "string" + }, + "type": { + "description": "Type is the type of the scoped entity i.e project or org", + "type": "string" + } + }, + "title": "Scoped Entity", + "type": "object" +} diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.schema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.schema.json new file mode 100644 index 000000000..c4b5f2591 --- /dev/null +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.ScopedEntity.schema.json @@ -0,0 +1,21 @@ +{ + "$id": "controlplane.v1.ScopedEntity.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "id": { + "description": "ID is the id of the scoped entity", + "type": "string" + }, + "name": { + "description": "Name is the name of the scoped entity", + "type": "string" + }, + "type": { + "description": "Type is the type of the scoped entity i.e project or org", + "type": "string" + } + }, + "title": "Scoped Entity", + "type": "object" +} diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.jsonschema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.jsonschema.json index 1af502336..4b840f5ab 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.jsonschema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.jsonschema.json @@ -14,6 +14,10 @@ "^(latest_revision_created_at)$": { "$ref": "google.protobuf.Timestamp.jsonschema.json" }, + "^(scoped_entity)$": { + "$ref": "controlplane.v1.ScopedEntity.jsonschema.json", + "description": "wether the contract is scoped to an entity in the organization" + }, "^(workflow_names)$": { "description": "Workflows associated with this contract", "items": { @@ -49,6 +53,10 @@ "name": { "type": "string" }, + "scopedEntity": { + "$ref": "controlplane.v1.ScopedEntity.jsonschema.json", + "description": "wether the contract is scoped to an entity in the organization" + }, "workflowNames": { "description": "Workflows associated with this contract", "items": { diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.schema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.schema.json index 216dcf46f..675fad47e 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.schema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractItem.schema.json @@ -14,6 +14,10 @@ "^(latestRevisionCreatedAt)$": { "$ref": "google.protobuf.Timestamp.schema.json" }, + "^(scopedEntity)$": { + "$ref": "controlplane.v1.ScopedEntity.schema.json", + "description": "wether the contract is scoped to an entity in the organization" + }, "^(workflowNames)$": { "description": "Workflows associated with this contract", "items": { @@ -49,6 +53,10 @@ "name": { "type": "string" }, + "scoped_entity": { + "$ref": "controlplane.v1.ScopedEntity.schema.json", + "description": "wether the contract is scoped to an entity in the organization" + }, "workflow_names": { "description": "Workflows associated with this contract", "items": { diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.jsonschema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.jsonschema.json index db0042de6..4574d5258 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.jsonschema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.jsonschema.json @@ -3,6 +3,10 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "patternProperties": { + "^(project_reference)$": { + "$ref": "controlplane.v1.IdentityReference.jsonschema.json", + "description": "You might need to specify a project reference if you want/need to create a contract scoped to a project" + }, "^(raw_contract)$": { "description": "Raw representation of the contract in json, yaml or cue", "pattern": "^[A-Za-z0-9+/]*={0,2}$", @@ -16,6 +20,10 @@ "name": { "type": "string" }, + "projectReference": { + "$ref": "controlplane.v1.IdentityReference.jsonschema.json", + "description": "You might need to specify a project reference if you want/need to create a contract scoped to a project" + }, "rawContract": { "description": "Raw representation of the contract in json, yaml or cue", "pattern": "^[A-Za-z0-9+/]*={0,2}$", diff --git a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.schema.json b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.schema.json index 7e5437859..2e3c8ec1b 100644 --- a/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.schema.json +++ b/app/controlplane/api/gen/jsonschema/controlplane.v1.WorkflowContractServiceCreateRequest.schema.json @@ -3,6 +3,10 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "patternProperties": { + "^(projectReference)$": { + "$ref": "controlplane.v1.IdentityReference.schema.json", + "description": "You might need to specify a project reference if you want/need to create a contract scoped to a project" + }, "^(rawContract)$": { "description": "Raw representation of the contract in json, yaml or cue", "pattern": "^[A-Za-z0-9+/]*={0,2}$", @@ -16,6 +20,10 @@ "name": { "type": "string" }, + "project_reference": { + "$ref": "controlplane.v1.IdentityReference.schema.json", + "description": "You might need to specify a project reference if you want/need to create a contract scoped to a project" + }, "raw_contract": { "description": "Raw representation of the contract in json, yaml or cue", "pattern": "^[A-Za-z0-9+/]*={0,2}$", diff --git a/app/controlplane/internal/service/workflowcontract.go b/app/controlplane/internal/service/workflowcontract.go index e3659f6aa..17bc05801 100644 --- a/app/controlplane/internal/service/workflowcontract.go +++ b/app/controlplane/internal/service/workflowcontract.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,9 +20,11 @@ import ( pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1" "github.com/chainloop-dev/chainloop/app/controlplane/internal/usercontext/entities" + "github.com/chainloop-dev/chainloop/app/controlplane/pkg/authz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/unmarshal" errors "github.com/go-kratos/kratos/v2/errors" + "github.com/google/uuid" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -93,6 +95,23 @@ func (s *WorkflowContractService) Create(ctx context.Context, req *pb.WorkflowCo return nil, err } + // Force project if RBAC is enabled + if rbacEnabled(ctx) && !req.ProjectReference.IsSet() { + return nil, errors.BadRequest("invalid", "project is required") + } + + // if the project is provided we make sure it exists and the user has permission to it + var projectID *uuid.UUID + if req.ProjectReference.IsSet() { + // Make sure the provided project exists and the user has permission to create tokens in it + project, err := s.userHasPermissionOnProject(ctx, currentOrg.ID, req.GetProjectReference(), authz.PolicyWorkflowContractCreate) + if err != nil { + return nil, err + } + + projectID = &project.ID + } + // we need this token to forward it to the provider service next token, err := entities.GetRawToken(ctx) if err != nil { @@ -107,9 +126,12 @@ func (s *WorkflowContractService) Create(ctx context.Context, req *pb.WorkflowCo // Currently supporting only v1 version schema, err := s.contractUseCase.Create(ctx, &biz.WorkflowContractCreateOpts{ - OrgID: currentOrg.ID, - Name: req.Name, Description: req.Description, - RawSchema: req.RawContract}) + OrgID: currentOrg.ID, + Name: req.Name, + Description: req.Description, + RawSchema: req.RawContract, + ProjectID: projectID, + }) if err != nil { return nil, handleUseCaseErr(err, s.log) } @@ -178,7 +200,7 @@ func bizWorkFlowContractToPb(schema *biz.WorkflowContract) *pb.WorkflowContractI workflowNames = append(workflowNames, ref.Name) } - return &pb.WorkflowContractItem{ + result := &pb.WorkflowContractItem{ Id: schema.ID.String(), CreatedAt: timestamppb.New(*schema.CreatedAt), Name: schema.Name, @@ -188,6 +210,16 @@ func bizWorkFlowContractToPb(schema *biz.WorkflowContract) *pb.WorkflowContractI WorkflowRefs: workflowRefs, Description: schema.Description, } + + if schema.ScopedEntity != nil { + result.ScopedEntity = &pb.ScopedEntity{ + Type: schema.ScopedEntity.Type, + Id: schema.ScopedEntity.ID.String(), + Name: schema.ScopedEntity.Name, + } + } + + return result } func bizWorkFlowContractVersionToPb(schema *biz.WorkflowContractVersion) *pb.WorkflowContractVersionItem { diff --git a/app/controlplane/pkg/authz/authz.go b/app/controlplane/pkg/authz/authz.go index 4da273a17..1eb64343e 100644 --- a/app/controlplane/pkg/authz/authz.go +++ b/app/controlplane/pkg/authz/authz.go @@ -275,19 +275,27 @@ var RolesMap = map[Role][]*Policy{ RoleProjectViewer: { PolicyWorkflowRead, PolicyWorkflowRunRead, + // workflow contracts + PolicyWorkflowContractList, + PolicyWorkflowContractRead, }, // RoleProjectAdmin: represents a project administrator. It's the higher role in project resources, // and it's only considered when the org-level role is `RoleOrgMember` RoleProjectAdmin: { - // attestations + // workflow contracts + PolicyWorkflowContractList, + PolicyWorkflowContractRead, + PolicyWorkflowContractCreate, + PolicyWorkflowContractUpdate, + PolicyWorkflowContractDelete, + // attestations PolicyWorkflowRead, PolicyWorkflowCreate, PolicyWorkflowRunCreate, PolicyWorkflowRunUpdate, // to reset attestations // workflow operations - PolicyWorkflowUpdate, PolicyWorkflowDelete, diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index f53137577..0a36e2946 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -41,6 +41,17 @@ type WorkflowContract struct { CreatedAt *time.Time // WorkflowRefs is the list of workflows associated with this contract WorkflowRefs []*WorkflowRef + // entity the contract is scoped to, if not set it's scoped to the organization + ScopedEntity *ScopedEntity +} + +type ScopedEntity struct { + // Type is the type of the scoped entity i.e project or org + Type string + // ID is the id of the scoped entity + ID uuid.UUID + // Name is the name of the scoped entity + Name string } type WorkflowContractVersion struct { @@ -153,6 +164,7 @@ type WorkflowContractCreateOpts struct { OrgID, Name string RawSchema []byte Description *string + ProjectID *uuid.UUID // Make sure that the name is unique in the organization AddUniquePrefix bool } @@ -192,8 +204,11 @@ func (uc *WorkflowContractUseCase) Create(ctx context.Context, opts *WorkflowCon // Create a workflow with a unique name if needed args := &ContractCreateOpts{ - OrgID: orgUUID, Name: opts.Name, Description: opts.Description, - Contract: contract, + OrgID: orgUUID, + Name: opts.Name, + Description: opts.Description, + Contract: contract, + ProjectID: opts.ProjectID, } var c *WorkflowContract diff --git a/app/controlplane/pkg/data/workflowcontract.go b/app/controlplane/pkg/data/workflowcontract.go index b25ed071d..017c01818 100644 --- a/app/controlplane/pkg/data/workflowcontract.go +++ b/app/controlplane/pkg/data/workflowcontract.go @@ -72,7 +72,7 @@ func (r *WorkflowContractRepo) List(ctx context.Context, orgID uuid.UUID) ([]*bi if err != nil { return nil, err } - res := entContractToBizContract(s, latestV, workflowReferences) + res := r.entContractToBizContract(ctx, s, latestV, workflowReferences) result = append(result, res) } @@ -97,7 +97,7 @@ func (r *WorkflowContractRepo) Create(ctx context.Context, opts *biz.ContractCre return nil, err } - res := entContractToBizContract(contract, version, nil) + res := r.entContractToBizContract(ctx, contract, version, nil) return res, nil } @@ -141,7 +141,7 @@ func (r *WorkflowContractRepo) FindVersionByID(ctx context.Context, versionID uu } return &biz.WorkflowContractWithVersion{ - Contract: entContractToBizContract(version.Edges.Contract, version, nil), + Contract: r.entContractToBizContract(ctx, version.Edges.Contract, version, nil), Version: contractVersion, }, nil } @@ -188,7 +188,7 @@ func (r *WorkflowContractRepo) Describe(ctx context.Context, orgID, contractID u } } - s := entContractToBizContract(contract, latestV, workflowReferences) + s := r.entContractToBizContract(ctx, contract, latestV, workflowReferences) return &biz.WorkflowContractWithVersion{ Contract: s, Version: v, @@ -262,7 +262,7 @@ func (r *WorkflowContractRepo) Update(ctx context.Context, orgID uuid.UUID, name } return &biz.WorkflowContractWithVersion{ - Contract: entContractToBizContract(contract, lv, workflowReferences), + Contract: r.entContractToBizContract(ctx, contract, lv, workflowReferences), Version: v, }, nil } @@ -285,7 +285,7 @@ func (r *WorkflowContractRepo) FindByIDInOrg(ctx context.Context, orgID, contrac return nil, err } - return entContractToBizContract(contract, latestV, workflowReferences), nil + return r.entContractToBizContract(ctx, contract, latestV, workflowReferences), nil } func (r *WorkflowContractRepo) FindByNameInOrg(ctx context.Context, orgID uuid.UUID, name string) (*biz.WorkflowContract, error) { @@ -306,7 +306,7 @@ func (r *WorkflowContractRepo) FindByNameInOrg(ctx context.Context, orgID uuid.U return nil, fmt.Errorf("failed to get latest version: %w", err) } - return entContractToBizContract(contract, latestV, workflowReferences), nil + return r.entContractToBizContract(ctx, contract, latestV, workflowReferences), nil } func (r *WorkflowContractRepo) SoftDelete(ctx context.Context, id uuid.UUID) error { @@ -403,7 +403,7 @@ func contractInOrgQuery(ctx context.Context, q *ent.OrganizationQuery, orgID uui return query.Only(ctx) } -func entContractToBizContract(w *ent.WorkflowContract, version *ent.WorkflowContractVersion, workflowReferences []*biz.WorkflowRef) *biz.WorkflowContract { +func (r *WorkflowContractRepo) entContractToBizContract(ctx context.Context, w *ent.WorkflowContract, version *ent.WorkflowContractVersion, workflowReferences []*biz.WorkflowRef) *biz.WorkflowContract { c := &biz.WorkflowContract{ Name: w.Name, ID: w.ID, @@ -413,6 +413,23 @@ func entContractToBizContract(w *ent.WorkflowContract, version *ent.WorkflowCont Description: w.Description, } + if w.ScopedResourceID != uuid.Nil { + c.ScopedEntity = &biz.ScopedEntity{ + Type: string(w.ScopedResourceType), + ID: w.ScopedResourceID, + } + } + + // preload the project name if the contract is scoped to a project + if w.ScopedResourceType == biz.ContractScopeProject { + project, err := r.data.DB.Project.Get(ctx, w.ScopedResourceID) + if err != nil { + r.log.Errorf("failed to get project: %w", err) + return c + } + c.ScopedEntity.Name = project.Name + } + c.LatestRevision = version.Revision return c } From 270576bec251cc5818971a06287abc7a46d93589 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 13:27:08 +0200 Subject: [PATCH 08/16] RBAC contract access Signed-off-by: Miguel Martinez --- .../controlplane/v1/workflow_contract.proto | 3 -- app/controlplane/internal/service/service.go | 5 +- .../internal/service/workflowcontract.go | 51 +++++++++++++++++-- app/controlplane/pkg/biz/workflowcontract.go | 8 +++ .../ent/migrate/migrations/20250704092359.sql | 8 --- .../ent/migrate/migrations/20250710105502.sql | 2 + .../pkg/data/ent/migrate/migrations/atlas.sum | 4 +- .../pkg/data/ent/migrate/schema.go | 8 --- .../pkg/data/ent/schema/workflowcontract.go | 7 +-- 9 files changed, 65 insertions(+), 31 deletions(-) delete mode 100644 app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql create mode 100644 app/controlplane/pkg/data/ent/migrate/migrations/20250710105502.sql diff --git a/app/controlplane/api/controlplane/v1/workflow_contract.proto b/app/controlplane/api/controlplane/v1/workflow_contract.proto index d96eb00dc..b78f29796 100644 --- a/app/controlplane/api/controlplane/v1/workflow_contract.proto +++ b/app/controlplane/api/controlplane/v1/workflow_contract.proto @@ -91,9 +91,6 @@ message WorkflowContractServiceDescribeRequest { } }]; int32 revision = 2; - - // You might need to specify a project reference if you want/need to describe a contract scoped to a project - IdentityReference project_reference = 5; } message WorkflowContractServiceDescribeResponse { diff --git a/app/controlplane/internal/service/service.go b/app/controlplane/internal/service/service.go index 18fbbc28d..9329dd224 100644 --- a/app/controlplane/internal/service/service.go +++ b/app/controlplane/internal/service/service.go @@ -200,9 +200,10 @@ func (s *service) authorizeResource(ctx context.Context, op *authz.Policy, resou } } + var defaultMessage = fmt.Sprintf("you do not have permissions to access to the %s associated with this resource", resourceType) // If no matching resources were found, return forbidden error if len(matchingResources) == 0 { - return errors.Forbidden("forbidden", "operation not allowed") + return errors.Forbidden("forbidden", defaultMessage) } // Try to enforce the policy with each matching role @@ -220,7 +221,7 @@ func (s *service) authorizeResource(ctx context.Context, op *authz.Policy, resou } // If none of the roles pass, return forbidden error - return errors.Forbidden("forbidden", "operation not allowed") + return errors.Forbidden("forbidden", defaultMessage) } // userHasPermissionOnProject is a helper method that checks if a policy can be applied to a project. It looks for a project diff --git a/app/controlplane/internal/service/workflowcontract.go b/app/controlplane/internal/service/workflowcontract.go index 17bc05801..a21ecabd9 100644 --- a/app/controlplane/internal/service/workflowcontract.go +++ b/app/controlplane/internal/service/workflowcontract.go @@ -74,6 +74,13 @@ func (s *WorkflowContractService) Describe(ctx context.Context, req *pb.Workflow return nil, errors.NotFound("not found", "contract not found") } + // 1 - If the contract is scoped to a project, make sure the user has permission to read it + // otherwise everyone can read it, use it + if err := s.checkContractAccess(ctx, contract, true); err != nil { + return nil, err + } + + // 2 - Get the contract version contractWithVersion, err := s.contractUseCase.Describe(ctx, currentOrg.ID, contract.ID.String(), int(req.GetRevision())) if err != nil { return nil, handleUseCaseErr(err, s.log) @@ -95,7 +102,8 @@ func (s *WorkflowContractService) Create(ctx context.Context, req *pb.WorkflowCo return nil, err } - // Force project if RBAC is enabled + // Authorization checks + // Force setting a project scope if RBAC is enabled if rbacEnabled(ctx) && !req.ProjectReference.IsSet() { return nil, errors.BadRequest("invalid", "project is required") } @@ -145,13 +153,27 @@ func (s *WorkflowContractService) Update(ctx context.Context, req *pb.WorkflowCo return nil, err } + contract, err := s.contractUseCase.FindByNameInOrg(ctx, currentOrg.ID, req.GetName()) + if err != nil { + return nil, handleUseCaseErr(err, s.log) + } else if contract == nil { + return nil, errors.NotFound("not found", "contract not found") + } + + if err := s.checkContractAccess(ctx, contract, false); err != nil { + return nil, err + } + token, err := entities.GetRawToken(ctx) if err != nil { return nil, err } - if err = s.contractUseCase.ValidateContractPolicies(req.RawContract, token); err != nil { - return nil, handleUseCaseErr(err, s.log) + // Validate the contract policies if the raw contract is provided + if len(req.RawContract) != 0 { + if err = s.contractUseCase.ValidateContractPolicies(req.RawContract, token); err != nil { + return nil, handleUseCaseErr(err, s.log) + } } schemaWithVersion, err := s.contractUseCase.Update(ctx, currentOrg.ID, req.Name, @@ -184,6 +206,10 @@ func (s *WorkflowContractService) Delete(ctx context.Context, req *pb.WorkflowCo return nil, errors.NotFound("not found", "contract not found") } + if err := s.checkContractAccess(ctx, contract, false); err != nil { + return nil, err + } + if err := s.contractUseCase.Delete(ctx, currentOrg.ID, contract.ID.String()); err != nil { return nil, handleUseCaseErr(err, s.log) } @@ -249,3 +275,22 @@ func bizWorkFlowContractVersionToPb(schema *biz.WorkflowContractVersion) *pb.Wor }, } } + +// checkContractAccess checks if the current user can manage a contract +// if the contract is global it makes sure that the user is an admin +// if the contract is scoped to a project it makes sure that the user has permission in the project +func (s *WorkflowContractService) checkContractAccess(ctx context.Context, contract *biz.WorkflowContract, allowGlobalAccess bool) error { + // 1 - Only admins can manage global contracts unless allowGlobalAccess is true + if contract.IsGlobalScoped() && rbacEnabled(ctx) && !allowGlobalAccess { + return errors.BadRequest("invalid", "you can not manage a global contract") + } + + // 2 - If the contract is scoped to a project, make sure the user has permission to read it + if contract.IsProjectScoped() { + if err := s.authorizeResource(ctx, authz.PolicyWorkflowContractRead, authz.ResourceTypeProject, contract.ScopedEntity.ID); err != nil { + return err + } + } + + return nil +} diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index 0a36e2946..640524fe4 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -160,6 +160,14 @@ func (uc *WorkflowContractUseCase) FindByNameInOrg(ctx context.Context, orgID, n return uc.repo.FindByNameInOrg(ctx, orgUUID, name) } +func (c *WorkflowContract) IsGlobalScoped() bool { + return c.ScopedEntity == nil +} + +func (c *WorkflowContract) IsProjectScoped() bool { + return c.ScopedEntity != nil && c.ScopedEntity.Type == string(ContractScopeProject) +} + type WorkflowContractCreateOpts struct { OrgID, Name string RawSchema []byte diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql b/app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql deleted file mode 100644 index 87cba251d..000000000 --- a/app/controlplane/pkg/data/ent/migrate/migrations/20250704092359.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Drop index "workflowcontract_name_organization_workflow_contracts" from table: "workflow_contracts" -DROP INDEX "workflowcontract_name_organization_workflow_contracts"; --- Modify "workflow_contracts" table -ALTER TABLE "workflow_contracts" ADD COLUMN "scoped_resource_type" character varying NULL, ADD COLUMN "scoped_resource_id" uuid NULL; --- Create index "workflowcontract_name_organization_workflow_contracts" to table: "workflow_contracts" -CREATE UNIQUE INDEX "workflowcontract_name_organization_workflow_contracts" ON "workflow_contracts" ("name", "organization_workflow_contracts") WHERE ((deleted_at IS NULL) AND (scoped_resource_type IS NULL)); --- Create index "workflowcontract_name_scoped_resource_type_scoped_resource_id" to table: "workflow_contracts" -CREATE UNIQUE INDEX "workflowcontract_name_scoped_resource_type_scoped_resource_id" ON "workflow_contracts" ("name", "scoped_resource_type", "scoped_resource_id") WHERE (deleted_at IS NULL); diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/20250710105502.sql b/app/controlplane/pkg/data/ent/migrate/migrations/20250710105502.sql new file mode 100644 index 000000000..e2e7526b1 --- /dev/null +++ b/app/controlplane/pkg/data/ent/migrate/migrations/20250710105502.sql @@ -0,0 +1,2 @@ +-- Modify "workflow_contracts" table +ALTER TABLE "workflow_contracts" ADD COLUMN "scoped_resource_type" character varying NULL, ADD COLUMN "scoped_resource_id" uuid NULL; diff --git a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum index 40ff393af..887b83c74 100644 --- a/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum +++ b/app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:+yGkCvepb0rQgYUfTpHC+xRBgJeIOYo6DlhZMe2p76o= +h1:i8q/MAG0rdlc1GCi0fAagiO70ZEhj6wvvFp8kgM+l50= 20230706165452_init-schema.sql h1:VvqbNFEQnCvUVyj2iDYVQQxDM0+sSXqocpt/5H64k8M= 20230710111950-cas-backend.sql h1:A8iBuSzZIEbdsv9ipBtscZQuaBp3V5/VMw7eZH6GX+g= 20230712094107-cas-backends-workflow-runs.sql h1:a5rzxpVGyd56nLRSsKrmCFc9sebg65RWzLghKHh5xvI= @@ -95,4 +95,4 @@ h1:+yGkCvepb0rQgYUfTpHC+xRBgJeIOYo6DlhZMe2p76o= 20250702111701.sql h1:Ni7fuL1qU5RGjBzV0XgJi9NkZINGijF8BumPuQ9conM= 20250702112642.sql h1:wrjVS+5h2hs7KNwPRBece5LgAsoEzxN/zNfvCnjoIUw= 20250704090359.sql h1:a0ksfjy2dtzviJL16HbC4eT1xBxy2qFH5mNFOpYlUrA= -20250704092359.sql h1:LWwcBsaZtqp0AqIVqIirYR+X7ukcXc7fyLUjtv0e8OY= +20250710105502.sql h1:EA6Ta1qsZcrNoOrO5zUNgiweHDtjl0HUlobukRuruko= diff --git a/app/controlplane/pkg/data/ent/migrate/schema.go b/app/controlplane/pkg/data/ent/migrate/schema.go index 9a2f43be5..fa48502c0 100644 --- a/app/controlplane/pkg/data/ent/migrate/schema.go +++ b/app/controlplane/pkg/data/ent/migrate/schema.go @@ -663,14 +663,6 @@ var ( Name: "workflowcontract_name_organization_workflow_contracts", Unique: true, Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[7]}, - Annotation: &entsql.IndexAnnotation{ - Where: "deleted_at IS NULL AND scoped_resource_type IS NULL", - }, - }, - { - Name: "workflowcontract_name_scoped_resource_type_scoped_resource_id", - Unique: true, - Columns: []*schema.Column{WorkflowContractsColumns[1], WorkflowContractsColumns[5], WorkflowContractsColumns[6]}, Annotation: &entsql.IndexAnnotation{ Where: "deleted_at IS NULL", }, diff --git a/app/controlplane/pkg/data/ent/schema/workflowcontract.go b/app/controlplane/pkg/data/ent/schema/workflowcontract.go index 94d0d84f7..59ea1b40a 100644 --- a/app/controlplane/pkg/data/ent/schema/workflowcontract.go +++ b/app/controlplane/pkg/data/ent/schema/workflowcontract.go @@ -67,12 +67,9 @@ func (WorkflowContract) Edges() []ent.Edge { func (WorkflowContract) Indexes() []ent.Index { return []ent.Index{ - // names are unique within a organization and affects only to non-scoped and non-deleted items + // TODO: add a unique index on name and scoped_resource_type and scoped_resource_id + // for now keeping a global one for backward compatibility index.Fields("name").Edges("organization").Unique().Annotations( - entsql.IndexWhere("deleted_at IS NULL AND scoped_resource_type IS NULL"), - ), - // names are unique within a resource and affects only to non-deleted items - index.Fields("name", "scoped_resource_type", "scoped_resource_id").Unique().Annotations( entsql.IndexWhere("deleted_at IS NULL"), ), } From ec365e7a58b10fd5f098d885304f9054c5ba84f3 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 13:50:01 +0200 Subject: [PATCH 09/16] RBAC contract access Signed-off-by: Miguel Martinez --- .../internal/service/workflowcontract.go | 2 +- app/controlplane/pkg/biz/workflowcontract.go | 25 ++++++++++++++++--- .../biz/workflowcontract_integration_test.go | 2 +- app/controlplane/pkg/data/workflowcontract.go | 25 ++++++++++++++++--- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/app/controlplane/internal/service/workflowcontract.go b/app/controlplane/internal/service/workflowcontract.go index a21ecabd9..de6370264 100644 --- a/app/controlplane/internal/service/workflowcontract.go +++ b/app/controlplane/internal/service/workflowcontract.go @@ -48,7 +48,7 @@ func (s *WorkflowContractService) List(ctx context.Context, _ *pb.WorkflowContra return nil, err } - contracts, err := s.contractUseCase.List(ctx, currentOrg.ID) + contracts, err := s.contractUseCase.List(ctx, currentOrg.ID, biz.WithProjectFilter(s.visibleProjects(ctx))) if err != nil { return nil, handleUseCaseErr(err, s.log) } diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index 640524fe4..ecb2c56d4 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -78,7 +78,7 @@ type WorkflowContractWithVersion struct { type WorkflowContractRepo interface { Create(ctx context.Context, opts *ContractCreateOpts) (*WorkflowContract, error) - List(ctx context.Context, orgID uuid.UUID) ([]*WorkflowContract, error) + List(ctx context.Context, orgID uuid.UUID, filter *WorkflowContractListFilters) ([]*WorkflowContract, error) FindByIDInOrg(ctx context.Context, orgID, ID uuid.UUID) (*WorkflowContract, error) FindByNameInOrg(ctx context.Context, orgID uuid.UUID, name string) (*WorkflowContract, error) Describe(ctx context.Context, orgID, contractID uuid.UUID, revision int, opts ...ContractQueryOpt) (*WorkflowContractWithVersion, error) @@ -128,13 +128,32 @@ func NewWorkflowContractUseCase(repo WorkflowContractRepo, policyRegistry *polic return &WorkflowContractUseCase{repo: repo, policyRegistry: policyRegistry, auditorUC: auditorUC, logger: log.NewHelper(logger)} } -func (uc *WorkflowContractUseCase) List(ctx context.Context, orgID string) ([]*WorkflowContract, error) { +type WorkflowContractListFilters struct { + // FilterByProjects is used to filter the result by a project list + // If it's empty, no filter will be applied + FilterByProjects []uuid.UUID +} + +type WorkflowListOpt func(opts *WorkflowContractListFilters) + +func WithProjectFilter(projectIDs []uuid.UUID) WorkflowListOpt { + return func(opts *WorkflowContractListFilters) { + opts.FilterByProjects = projectIDs + } +} + +func (uc *WorkflowContractUseCase) List(ctx context.Context, orgID string, opts ...WorkflowListOpt) ([]*WorkflowContract, error) { orgUUID, err := uuid.Parse(orgID) if err != nil { return nil, NewErrInvalidUUID(err) } - return uc.repo.List(ctx, orgUUID) + filters := &WorkflowContractListFilters{} + for _, opt := range opts { + opt(filters) + } + + return uc.repo.List(ctx, orgUUID, filters) } func (uc *WorkflowContractUseCase) FindByIDInOrg(ctx context.Context, orgID, contractID string) (*WorkflowContract, error) { diff --git a/app/controlplane/pkg/biz/workflowcontract_integration_test.go b/app/controlplane/pkg/biz/workflowcontract_integration_test.go index d91a21fbf..d4d45729b 100644 --- a/app/controlplane/pkg/biz/workflowcontract_integration_test.go +++ b/app/controlplane/pkg/biz/workflowcontract_integration_test.go @@ -1,5 +1,5 @@ // -// Copyright 2024 The Chainloop Authors. +// Copyright 2024-2025 The Chainloop Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/app/controlplane/pkg/data/workflowcontract.go b/app/controlplane/pkg/data/workflowcontract.go index 017c01818..0f6a8234a 100644 --- a/app/controlplane/pkg/data/workflowcontract.go +++ b/app/controlplane/pkg/data/workflowcontract.go @@ -48,10 +48,29 @@ func NewWorkflowContractRepo(data *Data, logger log.Logger) biz.WorkflowContract } } -func (r *WorkflowContractRepo) List(ctx context.Context, orgID uuid.UUID) ([]*biz.WorkflowContract, error) { - contracts, err := orgScopedQuery(r.data.DB, orgID). +// List returns a list of workflow contracts for a given organization +// If no project filters are provided, we return all the contracts scoped to the organization +// otherwise we return the global contracts alongside the org scoped projects +func (r *WorkflowContractRepo) List(ctx context.Context, orgID uuid.UUID, filter *biz.WorkflowContractListFilters) ([]*biz.WorkflowContract, error) { + wcontractQuery := orgScopedQuery(r.data.DB, orgID). QueryWorkflowContracts(). - Where(workflowcontract.DeletedAtIsNil()). + Where(workflowcontract.DeletedAtIsNil()) + + // If specific projects are provided + // we return the global contracts alongside the org scoped projects + if len(filter.FilterByProjects) > 0 { + wcontractQuery = wcontractQuery.Where( + workflowcontract.Or( + workflowcontract.And( + workflowcontract.ScopedResourceTypeIn(biz.ContractScopeProject), + workflowcontract.ScopedResourceIDIn(filter.FilterByProjects...), + ), + workflowcontract.ScopedResourceIDIsNil(), + ), + ) + } + + contracts, err := wcontractQuery. WithWorkflows(func(q *ent.WorkflowQuery) { q.Where(workflow.DeletedAtIsNil()) }). From 2296ed44dc8c22e399485e3ad7fd88f23336336d Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 13:59:02 +0200 Subject: [PATCH 10/16] RBAC contract access Signed-off-by: Miguel Martinez --- .../biz/workflowcontract_integration_test.go | 36 ++++++++++++++++++- go.sum | 1 - 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/app/controlplane/pkg/biz/workflowcontract_integration_test.go b/app/controlplane/pkg/biz/workflowcontract_integration_test.go index d4d45729b..e350920ae 100644 --- a/app/controlplane/pkg/biz/workflowcontract_integration_test.go +++ b/app/controlplane/pkg/biz/workflowcontract_integration_test.go @@ -240,6 +240,26 @@ func (s *workflowContractIntegrationTestSuite) TestCreate() { } } +func (s *workflowContractIntegrationTestSuite) TestList() { + ctx := context.Background() + + s.Run("by default it returns all the contracts from the org both global and scoped", func() { + contracts, err := s.WorkflowContract.List(ctx, s.org.ID) + s.NoError(err) + s.Equal(3, len(contracts)) + }) + + s.Run("if filtered by project it returns the contracts scoped to the project alongside the global contracts", func() { + contracts, err := s.WorkflowContract.List(ctx, s.org.ID, biz.WithProjectFilter([]uuid.UUID{s.p1.ID})) + s.NoError(err) + s.Equal(2, len(contracts)) + s.Equal(s.contractScopedToProject.ID, contracts[0].ID) + s.True(contracts[0].IsProjectScoped()) + s.Equal(s.contractOrg1.ID, contracts[1].ID) + s.True(contracts[1].IsGlobalScoped()) + }) +} + func (s *workflowContractIntegrationTestSuite) TestCreateWithCustomContract() { ctx := context.Background() @@ -315,8 +335,10 @@ func TestWorkflowContractUseCase(t *testing.T) { type workflowContractIntegrationTestSuite struct { testhelpers.UseCasesEachTestSuite org, org2 *biz.Organization + p1, p2 *biz.Project - contractOrg1 *biz.WorkflowContract + contractOrg1 *biz.WorkflowContract + contractScopedToProject *biz.WorkflowContract } func (s *workflowContractIntegrationTestSuite) SetupTest() { @@ -329,6 +351,18 @@ func (s *workflowContractIntegrationTestSuite) SetupTest() { s.org2, err = s.Organization.CreateWithRandomName(ctx) s.NoError(err) + s.p1, err = s.Project.Create(ctx, s.org.ID, "a-valid-project") + s.NoError(err) + + p2, err := s.Project.Create(ctx, s.org.ID, "a-valid-project-2") + s.NoError(err) + s.contractOrg1, err = s.WorkflowContract.Create(ctx, &biz.WorkflowContractCreateOpts{OrgID: s.org.ID, Name: "a-valid-contract"}) s.NoError(err) + + s.contractScopedToProject, err = s.WorkflowContract.Create(ctx, &biz.WorkflowContractCreateOpts{OrgID: s.org.ID, Name: "a-valid-contract-scoped-to-project", ProjectID: &s.p1.ID}) + s.NoError(err) + + _, err = s.WorkflowContract.Create(ctx, &biz.WorkflowContractCreateOpts{OrgID: s.org.ID, Name: "a-valid-contract-scoped-to-project-2", ProjectID: &p2.ID}) + s.Require().NoError(err) } diff --git a/go.sum b/go.sum index e16b77962..10e45e5c7 100644 --- a/go.sum +++ b/go.sum @@ -1079,7 +1079,6 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/oleiade/reflections v1.1.0 h1:D+I/UsXQB4esMathlt0kkZRJZdUDmhv5zGi/HOwYTWo= github.com/oleiade/reflections v1.1.0/go.mod h1:mCxx0QseeVCHs5Um5HhJeCKVC7AwS8kO67tky4rdisA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= From da40bfa8878c5d3aeb7ce4c1e881ae4be2eb4633 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 14:03:15 +0200 Subject: [PATCH 11/16] RBAC contract access Signed-off-by: Miguel Martinez --- app/controlplane/internal/service/workflowcontract.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controlplane/internal/service/workflowcontract.go b/app/controlplane/internal/service/workflowcontract.go index de6370264..9438c2caa 100644 --- a/app/controlplane/internal/service/workflowcontract.go +++ b/app/controlplane/internal/service/workflowcontract.go @@ -76,7 +76,7 @@ func (s *WorkflowContractService) Describe(ctx context.Context, req *pb.Workflow // 1 - If the contract is scoped to a project, make sure the user has permission to read it // otherwise everyone can read it, use it - if err := s.checkContractAccess(ctx, contract, true); err != nil { + if err := s.checkContractAccess(ctx, contract, authz.PolicyWorkflowContractRead, true); err != nil { return nil, err } @@ -160,7 +160,7 @@ func (s *WorkflowContractService) Update(ctx context.Context, req *pb.WorkflowCo return nil, errors.NotFound("not found", "contract not found") } - if err := s.checkContractAccess(ctx, contract, false); err != nil { + if err := s.checkContractAccess(ctx, contract, authz.PolicyWorkflowContractUpdate, false); err != nil { return nil, err } @@ -206,7 +206,7 @@ func (s *WorkflowContractService) Delete(ctx context.Context, req *pb.WorkflowCo return nil, errors.NotFound("not found", "contract not found") } - if err := s.checkContractAccess(ctx, contract, false); err != nil { + if err := s.checkContractAccess(ctx, contract, authz.PolicyWorkflowContractDelete, false); err != nil { return nil, err } @@ -279,7 +279,7 @@ func bizWorkFlowContractVersionToPb(schema *biz.WorkflowContractVersion) *pb.Wor // checkContractAccess checks if the current user can manage a contract // if the contract is global it makes sure that the user is an admin // if the contract is scoped to a project it makes sure that the user has permission in the project -func (s *WorkflowContractService) checkContractAccess(ctx context.Context, contract *biz.WorkflowContract, allowGlobalAccess bool) error { +func (s *WorkflowContractService) checkContractAccess(ctx context.Context, contract *biz.WorkflowContract, policy *authz.Policy, allowGlobalAccess bool) error { // 1 - Only admins can manage global contracts unless allowGlobalAccess is true if contract.IsGlobalScoped() && rbacEnabled(ctx) && !allowGlobalAccess { return errors.BadRequest("invalid", "you can not manage a global contract") @@ -287,7 +287,7 @@ func (s *WorkflowContractService) checkContractAccess(ctx context.Context, contr // 2 - If the contract is scoped to a project, make sure the user has permission to read it if contract.IsProjectScoped() { - if err := s.authorizeResource(ctx, authz.PolicyWorkflowContractRead, authz.ResourceTypeProject, contract.ScopedEntity.ID); err != nil { + if err := s.authorizeResource(ctx, policy, authz.ResourceTypeProject, contract.ScopedEntity.ID); err != nil { return err } } From 9e597d0c1b0f0e287bdd51e8495b58b60c900883 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 14:08:36 +0200 Subject: [PATCH 12/16] RBAC contract access Signed-off-by: Miguel Martinez --- app/cli/documentation/cli-reference.mdx | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/app/cli/documentation/cli-reference.mdx b/app/cli/documentation/cli-reference.mdx index b94a21bed..7b1e13a70 100755 --- a/app/cli/documentation/cli-reference.mdx +++ b/app/cli/documentation/cli-reference.mdx @@ -1460,6 +1460,48 @@ Options inherited from parent commands -y, --yes Skip confirmation ``` +## chainloop gather-runner-context + +Gather runner context data from a given provider. + +Synopsis + +Gather runner context data from a given provider. + +Provided by plugin: platform v0.218.0-SNAPSHOT-bd8099ad + +``` +chainloop gather-runner-context [flags] +``` + +Options + +``` +-h, --help help for gather-runner-context +--output-file string Output file path for the protection data (JSON format) (default "runner-context.json") +--runner-api-url string Provider API URL +--runner-org string Provider organization name +--runner-provider string Provider name +--runner-repo string Provider repository name +--runner-token string Provider access token with read rights to the given repository. +``` + +Options inherited from parent commands + +``` +--artifact-cas string URL for the Artifacts Content Addressable Storage API ($CHAINLOOP_ARTIFACT_CAS_API) (default "api.cas.chainloop.dev:443") +--artifact-cas-ca string CUSTOM CA file for the Artifacts CAS API (optional) ($CHAINLOOP_ARTIFACT_CAS_API_CA) +-c, --config string Path to an existing config file (default is $HOME/.config/chainloop/config.toml) +--control-plane string URL for the Control Plane API ($CHAINLOOP_CONTROL_PLANE_API) (default "api.cp.chainloop.dev:443") +--control-plane-ca string CUSTOM CA file for the Control Plane API (optional) ($CHAINLOOP_CONTROL_PLANE_API_CA) +--debug Enable debug/verbose logging mode +-i, --insecure Skip TLS transport during connection to the control plane ($CHAINLOOP_API_INSECURE) +-n, --org string organization name +-o, --output string Output format, valid options are json and table (default "table") +-t, --token string API token. NOTE: Alternatively use the env variable CHAINLOOP_TOKEN +-y, --yes Skip confirmation +``` + ## chainloop integration Third party integrations @@ -2965,6 +3007,7 @@ Options --description string description of the contract -h, --help help for create --name string contract name +--project string project name used to scope the contract, if not set the contract will be created in the organization ``` Options inherited from parent commands From 64a6e931946e2d9a6636f5c99e9d1a29adae381b Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 14:19:11 +0200 Subject: [PATCH 13/16] RBAC contract access Signed-off-by: Miguel Martinez --- app/controlplane/pkg/biz/workflowcontract_integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controlplane/pkg/biz/workflowcontract_integration_test.go b/app/controlplane/pkg/biz/workflowcontract_integration_test.go index e350920ae..837690afa 100644 --- a/app/controlplane/pkg/biz/workflowcontract_integration_test.go +++ b/app/controlplane/pkg/biz/workflowcontract_integration_test.go @@ -335,7 +335,7 @@ func TestWorkflowContractUseCase(t *testing.T) { type workflowContractIntegrationTestSuite struct { testhelpers.UseCasesEachTestSuite org, org2 *biz.Organization - p1, p2 *biz.Project + p1 *biz.Project contractOrg1 *biz.WorkflowContract contractScopedToProject *biz.WorkflowContract From 8798176ea6dc465933c080d33d7757d56cadd5fe Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 14:21:21 +0200 Subject: [PATCH 14/16] RBAC contract access Signed-off-by: Miguel Martinez --- app/cli/documentation/cli-reference.mdx | 42 ------------------------- 1 file changed, 42 deletions(-) diff --git a/app/cli/documentation/cli-reference.mdx b/app/cli/documentation/cli-reference.mdx index 7b1e13a70..c9d05bb4d 100755 --- a/app/cli/documentation/cli-reference.mdx +++ b/app/cli/documentation/cli-reference.mdx @@ -1460,48 +1460,6 @@ Options inherited from parent commands -y, --yes Skip confirmation ``` -## chainloop gather-runner-context - -Gather runner context data from a given provider. - -Synopsis - -Gather runner context data from a given provider. - -Provided by plugin: platform v0.218.0-SNAPSHOT-bd8099ad - -``` -chainloop gather-runner-context [flags] -``` - -Options - -``` --h, --help help for gather-runner-context ---output-file string Output file path for the protection data (JSON format) (default "runner-context.json") ---runner-api-url string Provider API URL ---runner-org string Provider organization name ---runner-provider string Provider name ---runner-repo string Provider repository name ---runner-token string Provider access token with read rights to the given repository. -``` - -Options inherited from parent commands - -``` ---artifact-cas string URL for the Artifacts Content Addressable Storage API ($CHAINLOOP_ARTIFACT_CAS_API) (default "api.cas.chainloop.dev:443") ---artifact-cas-ca string CUSTOM CA file for the Artifacts CAS API (optional) ($CHAINLOOP_ARTIFACT_CAS_API_CA) --c, --config string Path to an existing config file (default is $HOME/.config/chainloop/config.toml) ---control-plane string URL for the Control Plane API ($CHAINLOOP_CONTROL_PLANE_API) (default "api.cp.chainloop.dev:443") ---control-plane-ca string CUSTOM CA file for the Control Plane API (optional) ($CHAINLOOP_CONTROL_PLANE_API_CA) ---debug Enable debug/verbose logging mode --i, --insecure Skip TLS transport during connection to the control plane ($CHAINLOOP_API_INSECURE) --n, --org string organization name --o, --output string Output format, valid options are json and table (default "table") --t, --token string API token. NOTE: Alternatively use the env variable CHAINLOOP_TOKEN --y, --yes Skip confirmation -``` - ## chainloop integration Third party integrations From 050a55c817df4e84731a56929369ebed65e9d798 Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 14:39:54 +0200 Subject: [PATCH 15/16] scope down attestation contract Signed-off-by: Miguel Martinez --- app/controlplane/pkg/data/workflow.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/controlplane/pkg/data/workflow.go b/app/controlplane/pkg/data/workflow.go index 660239f91..bd35652eb 100644 --- a/app/controlplane/pkg/data/workflow.go +++ b/app/controlplane/pkg/data/workflow.go @@ -62,6 +62,7 @@ func (r *WorkflowRepo) Create(ctx context.Context, opts *biz.WorkflowCreateOpts) return nil, fmt.Errorf("contract name and ID cannot be provided at the same time") } + // Load an existing contract reference if provided var contractUUID uuid.UUID if opts.ContractID != "" { contractUUID, err = uuid.Parse(opts.ContractID) @@ -133,6 +134,17 @@ func (r *WorkflowRepo) Create(ctx context.Context, opts *biz.WorkflowCreateOpts) } contractUUID = contract.ID + } else { + // We want to use an existing contract, let's make sure it's scoped to the project or org + existingContract, err := contractInOrg(ctx, r.data.DB, orgUUID, &contractUUID, nil) + if err != nil { + return err + } + + // Fail if it's scoped to a different project + if existingContract.ScopedResourceID != uuid.Nil && existingContract.ScopedResourceID != projectID && existingContract.ScopedResourceType == biz.ContractScopeProject { + return biz.NewErrUnauthorizedStr(fmt.Sprintf("contract %q is scoped to a different project", opts.ContractName)) + } } entwf, err = tx.Workflow.Create(). From 5b450a5efad05f72a21d7cc55d9d5df56e41a19d Mon Sep 17 00:00:00 2001 From: Miguel Martinez Date: Thu, 10 Jul 2025 14:55:00 +0200 Subject: [PATCH 16/16] scope down attestation contract Signed-off-by: Miguel Martinez --- .../gen/frontend/google/protobuf/descriptor.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts index 0d2d2fb32..d59b21da4 100644 --- a/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts +++ b/app/controlplane/api/gen/frontend/google/protobuf/descriptor.ts @@ -30,7 +30,7 @@ export enum Edition { EDITION_2024 = 1001, /** * EDITION_1_TEST_ONLY - Placeholder editions for testing feature resolution. These should not be - * used or relyed on outside of tests. + * used or relied on outside of tests. */ EDITION_1_TEST_ONLY = 1, EDITION_2_TEST_ONLY = 2, @@ -875,12 +875,13 @@ export interface MessageOptions { export interface FieldOptions { /** + * NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. * The ctype option instructs the C++ code generator to use a different * representation of the field than it normally would. See the specific * options below. This option is only implemented to support use of * [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - * type "bytes" in the open source release -- sorry, we'll try to include - * other types in a future version! + * type "bytes" in the open source release. + * TODO: make ctype actually deprecated. */ ctype: FieldOptions_CType; /** @@ -1052,11 +1053,7 @@ export function fieldOptions_JSTypeToJSON(object: FieldOptions_JSType): string { } } -/** - * If set to RETENTION_SOURCE, the option will be omitted from the binary. - * Note: as of January 2023, support for this is in progress and does not yet - * have an effect (b/264593489). - */ +/** If set to RETENTION_SOURCE, the option will be omitted from the binary. */ export enum FieldOptions_OptionRetention { RETENTION_UNKNOWN = 0, RETENTION_RUNTIME = 1, @@ -1099,8 +1096,7 @@ export function fieldOptions_OptionRetentionToJSON(object: FieldOptions_OptionRe /** * This indicates the types of entities that the field may apply to when used * as an option. If it is unset, then the field may be freely used as an - * option on any kind of entity. Note: as of January 2023, support for this is - * in progress and does not yet have an effect (b/264593489). + * option on any kind of entity. */ export enum FieldOptions_OptionTargetType { TARGET_TYPE_UNKNOWN = 0,