From 9fa7a93b552661c1a34365b04106ce89bc6c29d5 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Wed, 18 Jun 2025 12:33:17 +0200 Subject: [PATCH 01/20] chore: go.mod Signed-off-by: Danny Kopping # Conflicts: # go.sum --- go.mod | 3 +++ 1 file changed, 3 insertions(+) diff --git a/go.mod b/go.mod index ef52718460cdd..4298c0d4c59bf 100644 --- a/go.mod +++ b/go.mod @@ -535,3 +535,6 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect ) + +// TODO: replace once new version is cut. +replace github.com/coder/terraform-provider-coder/v2 v2.5.3 => github.com/coder/terraform-provider-coder/v2 v2.5.4-0.20250618103053-97e45841d2c8 From d01a050fae20b7d01c1ea2f932f1ec2a05b86813 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Wed, 18 Jun 2025 11:42:39 +0200 Subject: [PATCH 02/20] feat: proto & db changes to persist coder_ai_task state Signed-off-by: Danny Kopping --- coderd/database/dbauthz/dbauthz.go | 29 ++ coderd/database/dbgen/dbgen.go | 2 - coderd/database/dbmem/dbmem.go | 43 ++- coderd/database/dbmetrics/querymetrics.go | 14 + coderd/database/dbmock/dbmock.go | 28 ++ coderd/database/querier.go | 2 + coderd/database/queries.sql.go | 60 +++- coderd/database/queries/templateversions.sql | 14 +- coderd/database/queries/workspacebuilds.sql | 14 +- coderd/templateversions.go | 6 - coderd/wsbuilder/wsbuilder.go | 6 - provisionerd/proto/provisionerd.pb.go | 321 ++++++++++--------- provisionerd/proto/provisionerd.proto | 2 + provisionersdk/proto/provisioner.proto | 17 + 14 files changed, 378 insertions(+), 180 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index adb2007918f8d..03c42c19c6028 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -4535,6 +4535,28 @@ func (q *querier) UpdateTemplateScheduleByID(ctx context.Context, arg database.U return update(q.log, q.auth, fetch, q.db.UpdateTemplateScheduleByID)(ctx, arg) } +func (q *querier) UpdateTemplateVersionAITaskByJobID(ctx context.Context, arg database.UpdateTemplateVersionAITaskByJobIDParams) error { + // An actor is allowed to update the template version AI task flag if they are authorized to update the template. + tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID) + if err != nil { + return err + } + var obj rbac.Objecter + if !tv.TemplateID.Valid { + obj = rbac.ResourceTemplate.InOrg(tv.OrganizationID) + } else { + tpl, err := q.db.GetTemplateByID(ctx, tv.TemplateID.UUID) + if err != nil { + return err + } + obj = tpl + } + if err := q.authorizeContext(ctx, policy.ActionUpdate, obj); err != nil { + return err + } + return q.db.UpdateTemplateVersionAITaskByJobID(ctx, arg) +} + func (q *querier) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) error { // An actor is allowed to update the template version if they are authorized to update the template. tv, err := q.db.GetTemplateVersionByID(ctx, arg.ID) @@ -4891,6 +4913,13 @@ func (q *querier) UpdateWorkspaceAutostart(ctx context.Context, arg database.Upd return update(q.log, q.auth, fetch, q.db.UpdateWorkspaceAutostart)(ctx, arg) } +func (q *querier) UpdateWorkspaceBuildAITaskByID(ctx context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error { + if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil { + return err + } + return q.db.UpdateWorkspaceBuildAITaskByID(ctx, arg) +} + // UpdateWorkspaceBuildCostByID is used by the provisioning system to update the cost of a workspace build. func (q *querier) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil { diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 5b03fd0eb1396..62c27babea2bd 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -410,7 +410,6 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil UUID: uuid.UUID{}, Valid: false, }), - HasAITask: orig.HasAITask, }) if err != nil { return err @@ -985,7 +984,6 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers JobID: takeFirst(orig.JobID, uuid.New()), CreatedBy: takeFirst(orig.CreatedBy, uuid.New()), SourceExampleID: takeFirst(orig.SourceExampleID, sql.NullString{}), - HasAITask: orig.HasAITask, }) if err != nil { return err diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 25b44e2930892..1ae6531f07b9e 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -9463,7 +9463,6 @@ func (q *FakeQuerier) InsertTemplateVersion(_ context.Context, arg database.Inse JobID: arg.JobID, CreatedBy: arg.CreatedBy, SourceExampleID: arg.SourceExampleID, - HasAITask: arg.HasAITask, } q.templateVersions = append(q.templateVersions, version) return nil @@ -10143,7 +10142,6 @@ func (q *FakeQuerier) InsertWorkspaceBuild(_ context.Context, arg database.Inser MaxDeadline: arg.MaxDeadline, Reason: arg.Reason, TemplateVersionPresetID: arg.TemplateVersionPresetID, - HasAITask: arg.HasAITask, } q.workspaceBuilds = append(q.workspaceBuilds, workspaceBuild) return nil @@ -11348,6 +11346,26 @@ func (q *FakeQuerier) UpdateTemplateScheduleByID(_ context.Context, arg database return sql.ErrNoRows } +func (q *FakeQuerier) UpdateTemplateVersionAITaskByJobID(_ context.Context, arg database.UpdateTemplateVersionAITaskByJobIDParams) error { + if err := validateDatabaseType(arg); err != nil { + return err + } + + q.mutex.Lock() + defer q.mutex.Unlock() + + for index, templateVersion := range q.templateVersions { + if templateVersion.JobID != arg.JobID { + continue + } + templateVersion.HasAITask = arg.HasAITask + templateVersion.UpdatedAt = arg.UpdatedAt + q.templateVersions[index] = templateVersion + return nil + } + return sql.ErrNoRows +} + func (q *FakeQuerier) UpdateTemplateVersionByID(_ context.Context, arg database.UpdateTemplateVersionByIDParams) error { if err := validateDatabaseType(arg); err != nil { return err @@ -12043,6 +12061,27 @@ func (q *FakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.U return sql.ErrNoRows } +func (q *FakeQuerier) UpdateWorkspaceBuildAITaskByID(_ context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error { + err := validateDatabaseType(arg) + if err != nil { + return err + } + + q.mutex.Lock() + defer q.mutex.Unlock() + + for index, workspaceBuild := range q.workspaceBuilds { + if workspaceBuild.ID != arg.ID { + continue + } + workspaceBuild.HasAITask = arg.HasAITask + workspaceBuild.UpdatedAt = dbtime.Now() + q.workspaceBuilds[index] = workspaceBuild + return nil + } + return sql.ErrNoRows +} + func (q *FakeQuerier) UpdateWorkspaceBuildCostByID(_ context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { if err := validateDatabaseType(arg); err != nil { return err diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 0450776785d42..b6b94c71d61cc 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -2832,6 +2832,13 @@ func (m queryMetricsStore) UpdateTemplateScheduleByID(ctx context.Context, arg d return err } +func (m queryMetricsStore) UpdateTemplateVersionAITaskByJobID(ctx context.Context, arg database.UpdateTemplateVersionAITaskByJobIDParams) error { + start := time.Now() + r0 := m.s.UpdateTemplateVersionAITaskByJobID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateTemplateVersionAITaskByJobID").Observe(time.Since(start).Seconds()) + return r0 +} + func (m queryMetricsStore) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) error { start := time.Now() err := m.s.UpdateTemplateVersionByID(ctx, arg) @@ -3035,6 +3042,13 @@ func (m queryMetricsStore) UpdateWorkspaceAutostart(ctx context.Context, arg dat return err } +func (m queryMetricsStore) UpdateWorkspaceBuildAITaskByID(ctx context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error { + start := time.Now() + r0 := m.s.UpdateWorkspaceBuildAITaskByID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateWorkspaceBuildAITaskByID").Observe(time.Since(start).Seconds()) + return r0 +} + func (m queryMetricsStore) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { start := time.Now() err := m.s.UpdateWorkspaceBuildCostByID(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index dbd8f5ca0753c..e590b56eadc7b 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -5992,6 +5992,20 @@ func (mr *MockStoreMockRecorder) UpdateTemplateScheduleByID(ctx, arg any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateScheduleByID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateScheduleByID), ctx, arg) } +// UpdateTemplateVersionAITaskByJobID mocks base method. +func (m *MockStore) UpdateTemplateVersionAITaskByJobID(ctx context.Context, arg database.UpdateTemplateVersionAITaskByJobIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateVersionAITaskByJobID", ctx, arg) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateTemplateVersionAITaskByJobID indicates an expected call of UpdateTemplateVersionAITaskByJobID. +func (mr *MockStoreMockRecorder) UpdateTemplateVersionAITaskByJobID(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateVersionAITaskByJobID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateVersionAITaskByJobID), ctx, arg) +} + // UpdateTemplateVersionByID mocks base method. func (m *MockStore) UpdateTemplateVersionByID(ctx context.Context, arg database.UpdateTemplateVersionByIDParams) error { m.ctrl.T.Helper() @@ -6410,6 +6424,20 @@ func (mr *MockStoreMockRecorder) UpdateWorkspaceAutostart(ctx, arg any) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAutostart", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAutostart), ctx, arg) } +// UpdateWorkspaceBuildAITaskByID mocks base method. +func (m *MockStore) UpdateWorkspaceBuildAITaskByID(ctx context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceBuildAITaskByID", ctx, arg) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceBuildAITaskByID indicates an expected call of UpdateWorkspaceBuildAITaskByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceBuildAITaskByID(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceBuildAITaskByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceBuildAITaskByID), ctx, arg) +} + // UpdateWorkspaceBuildCostByID mocks base method. func (m *MockStore) UpdateWorkspaceBuildCostByID(ctx context.Context, arg database.UpdateWorkspaceBuildCostByIDParams) error { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 4cfd0d1c4da5f..5fd5093cb7e9d 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -597,6 +597,7 @@ type sqlcQuerier interface { UpdateTemplateDeletedByID(ctx context.Context, arg UpdateTemplateDeletedByIDParams) error UpdateTemplateMetaByID(ctx context.Context, arg UpdateTemplateMetaByIDParams) error UpdateTemplateScheduleByID(ctx context.Context, arg UpdateTemplateScheduleByIDParams) error + UpdateTemplateVersionAITaskByJobID(ctx context.Context, arg UpdateTemplateVersionAITaskByJobIDParams) error UpdateTemplateVersionByID(ctx context.Context, arg UpdateTemplateVersionByIDParams) error UpdateTemplateVersionDescriptionByJobID(ctx context.Context, arg UpdateTemplateVersionDescriptionByJobIDParams) error UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context.Context, arg UpdateTemplateVersionExternalAuthProvidersByJobIDParams) error @@ -626,6 +627,7 @@ type sqlcQuerier interface { UpdateWorkspaceAppHealthByID(ctx context.Context, arg UpdateWorkspaceAppHealthByIDParams) error UpdateWorkspaceAutomaticUpdates(ctx context.Context, arg UpdateWorkspaceAutomaticUpdatesParams) error UpdateWorkspaceAutostart(ctx context.Context, arg UpdateWorkspaceAutostartParams) error + UpdateWorkspaceBuildAITaskByID(ctx context.Context, arg UpdateWorkspaceBuildAITaskByIDParams) error UpdateWorkspaceBuildCostByID(ctx context.Context, arg UpdateWorkspaceBuildCostByIDParams) error UpdateWorkspaceBuildDeadlineByID(ctx context.Context, arg UpdateWorkspaceBuildDeadlineByIDParams) error UpdateWorkspaceBuildProvisionerStateByID(ctx context.Context, arg UpdateWorkspaceBuildProvisionerStateByIDParams) error diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index fe32851f0e002..fcfa06d12224b 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -11917,11 +11917,10 @@ INSERT INTO readme, job_id, created_by, - source_example_id, - has_ai_task + source_example_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) ` type InsertTemplateVersionParams struct { @@ -11936,7 +11935,6 @@ type InsertTemplateVersionParams struct { JobID uuid.UUID `db:"job_id" json:"job_id"` CreatedBy uuid.UUID `db:"created_by" json:"created_by"` SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"` - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` } func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) error { @@ -11952,7 +11950,6 @@ func (q *sqlQuerier) InsertTemplateVersion(ctx context.Context, arg InsertTempla arg.JobID, arg.CreatedBy, arg.SourceExampleID, - arg.HasAITask, ) return err } @@ -11978,6 +11975,27 @@ func (q *sqlQuerier) UnarchiveTemplateVersion(ctx context.Context, arg Unarchive return err } +const updateTemplateVersionAITaskByJobID = `-- name: UpdateTemplateVersionAITaskByJobID :exec +UPDATE + template_versions +SET + has_ai_task = $2, + updated_at = $3 +WHERE + job_id = $1 +` + +type UpdateTemplateVersionAITaskByJobIDParams struct { + JobID uuid.UUID `db:"job_id" json:"job_id"` + HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` +} + +func (q *sqlQuerier) UpdateTemplateVersionAITaskByJobID(ctx context.Context, arg UpdateTemplateVersionAITaskByJobIDParams) error { + _, err := q.db.ExecContext(ctx, updateTemplateVersionAITaskByJobID, arg.JobID, arg.HasAITask, arg.UpdatedAt) + return err +} + const updateTemplateVersionByID = `-- name: UpdateTemplateVersionByID :exec UPDATE template_versions @@ -17670,11 +17688,10 @@ INSERT INTO deadline, max_deadline, reason, - template_version_preset_id, - has_ai_task + template_version_preset_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) ` type InsertWorkspaceBuildParams struct { @@ -17692,7 +17709,6 @@ type InsertWorkspaceBuildParams struct { MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` Reason BuildReason `db:"reason" json:"reason"` TemplateVersionPresetID uuid.NullUUID `db:"template_version_preset_id" json:"template_version_preset_id"` - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` } func (q *sqlQuerier) InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspaceBuildParams) error { @@ -17711,7 +17727,33 @@ func (q *sqlQuerier) InsertWorkspaceBuild(ctx context.Context, arg InsertWorkspa arg.MaxDeadline, arg.Reason, arg.TemplateVersionPresetID, + ) + return err +} + +const updateWorkspaceBuildAITaskByID = `-- name: UpdateWorkspaceBuildAITaskByID :exec +UPDATE + workspace_builds +SET + has_ai_task = $1, + ai_tasks_sidebar_app_id = $2, + updated_at = $3::timestamptz +WHERE id = $4::uuid +` + +type UpdateWorkspaceBuildAITaskByIDParams struct { + HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` + SidebarAppID uuid.NullUUID `db:"sidebar_app_id" json:"sidebar_app_id"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + ID uuid.UUID `db:"id" json:"id"` +} + +func (q *sqlQuerier) UpdateWorkspaceBuildAITaskByID(ctx context.Context, arg UpdateWorkspaceBuildAITaskByIDParams) error { + _, err := q.db.ExecContext(ctx, updateWorkspaceBuildAITaskByID, arg.HasAITask, + arg.SidebarAppID, + arg.UpdatedAt, + arg.ID, ) return err } diff --git a/coderd/database/queries/templateversions.sql b/coderd/database/queries/templateversions.sql index ac88a8b493152..4a37413d2f439 100644 --- a/coderd/database/queries/templateversions.sql +++ b/coderd/database/queries/templateversions.sql @@ -88,11 +88,10 @@ INSERT INTO readme, job_id, created_by, - source_example_id, - has_ai_task + source_example_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12); + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11); -- name: UpdateTemplateVersionByID :exec UPDATE @@ -123,6 +122,15 @@ SET WHERE job_id = $1; +-- name: UpdateTemplateVersionAITaskByJobID :exec +UPDATE + template_versions +SET + has_ai_task = $2, + updated_at = $3 +WHERE + job_id = $1; + -- name: GetPreviousTemplateVersion :one SELECT * diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql index b380e5423c21c..0526477866e81 100644 --- a/coderd/database/queries/workspacebuilds.sql +++ b/coderd/database/queries/workspacebuilds.sql @@ -121,11 +121,10 @@ INSERT INTO deadline, max_deadline, reason, - template_version_preset_id, - has_ai_task + template_version_preset_id ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15); + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14); -- name: UpdateWorkspaceBuildCostByID :exec UPDATE @@ -152,6 +151,15 @@ SET updated_at = @updated_at::timestamptz WHERE id = @id::uuid; +-- name: UpdateWorkspaceBuildAITaskByID :exec +UPDATE + workspace_builds +SET + has_ai_task = @has_ai_task, + ai_tasks_sidebar_app_id = @sidebar_app_id, + updated_at = @updated_at::timestamptz +WHERE id = @id::uuid; + -- name: GetActiveWorkspaceBuildsByTemplateID :many SELECT wb.* FROM ( diff --git a/coderd/templateversions.go b/coderd/templateversions.go index d9f9c3db42dd6..d79f86f1f6626 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -1730,12 +1730,6 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht String: req.ExampleID, Valid: req.ExampleID != "", }, - // appease the exhaustruct linter - // TODO: set this to whether the template version defines a `coder_ai_task` tf resource - HasAITask: sql.NullBool{ - Bool: false, - Valid: false, - }, }) if err != nil { if database.IsUniqueViolation(err, database.UniqueTemplateVersionsTemplateIDNameKey) { diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index b52a20ac1e9db..0e9748da549c2 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -425,12 +425,6 @@ func (b *Builder) buildTx(authFunc func(action policy.Action, object rbac.Object UUID: b.templateVersionPresetID, Valid: b.templateVersionPresetID != uuid.Nil, }, - // appease the exhaustruct linter - // TODO: set this to whether the build included a `coder_ai_task` tf resource - HasAITask: sql.NullBool{ - Bool: false, - Valid: false, - }, }) if err != nil { code := http.StatusInternalServerError diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index b4343eafbfdac..9960105c78962 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -1309,6 +1309,7 @@ type CompletedJob_WorkspaceBuild struct { Timings []*proto.Timing `protobuf:"bytes,3,rep,name=timings,proto3" json:"timings,omitempty"` Modules []*proto.Module `protobuf:"bytes,4,rep,name=modules,proto3" json:"modules,omitempty"` ResourceReplacements []*proto.ResourceReplacement `protobuf:"bytes,5,rep,name=resource_replacements,json=resourceReplacements,proto3" json:"resource_replacements,omitempty"` + AiTasks []*proto.AITask `protobuf:"bytes,6,rep,name=ai_tasks,json=aiTasks,proto3" json:"ai_tasks,omitempty"` } func (x *CompletedJob_WorkspaceBuild) Reset() { @@ -1378,6 +1379,13 @@ func (x *CompletedJob_WorkspaceBuild) GetResourceReplacements() []*proto.Resourc return nil } +func (x *CompletedJob_WorkspaceBuild) GetAiTasks() []*proto.AITask { + if x != nil { + return x.AiTasks + } + return nil +} + type CompletedJob_TemplateImport struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1394,6 +1402,7 @@ type CompletedJob_TemplateImport struct { Plan []byte `protobuf:"bytes,9,opt,name=plan,proto3" json:"plan,omitempty"` ModuleFiles []byte `protobuf:"bytes,10,opt,name=module_files,json=moduleFiles,proto3" json:"module_files,omitempty"` ModuleFilesHash []byte `protobuf:"bytes,11,opt,name=module_files_hash,json=moduleFilesHash,proto3" json:"module_files_hash,omitempty"` + HasAiTasks bool `protobuf:"varint,12,opt,name=has_ai_tasks,json=hasAiTasks,proto3" json:"has_ai_tasks,omitempty"` } func (x *CompletedJob_TemplateImport) Reset() { @@ -1505,6 +1514,13 @@ func (x *CompletedJob_TemplateImport) GetModuleFilesHash() []byte { return nil } +func (x *CompletedJob_TemplateImport) GetHasAiTasks() bool { + if x != nil { + return x.HasAiTasks + } + return false +} + type CompletedJob_TemplateDryRun struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1694,7 +1710,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, - 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xb9, 0x0a, 0x0a, 0x0c, 0x43, 0x6f, + 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x8b, 0x0b, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, @@ -1713,7 +1729,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, - 0x79, 0x52, 0x75, 0x6e, 0x1a, 0x90, 0x02, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x79, 0x52, 0x75, 0x6e, 0x1a, 0xc0, 0x02, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, @@ -1730,7 +1746,10 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, - 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0xfd, 0x04, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, + 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x08, 0x61, 0x69, 0x5f, 0x74, 0x61, + 0x73, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x49, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x07, + 0x61, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x1a, 0x9f, 0x05, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, @@ -1770,122 +1789,124 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, - 0x6c, 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x74, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2d, - 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x06, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xb0, 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2f, 0x0a, - 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, - 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2b, - 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0xa6, 0x03, 0x0a, 0x10, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, - 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, - 0x6f, 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x4c, 0x0a, 0x12, 0x74, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, - 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a, 0x14, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, - 0x58, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x67, - 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x57, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 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, 0x4a, 0x04, 0x08, 0x03, 0x10, - 0x04, 0x22, 0x7a, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, - 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x4a, 0x0a, - 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, - 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, - 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x22, 0x68, 0x0a, 0x13, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, - 0x12, 0x29, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x73, - 0x75, 0x6d, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x64, - 0x69, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, - 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x64, - 0x67, 0x65, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x63, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, - 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0b, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, - 0x70, 0x69, 0x65, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x50, - 0x69, 0x65, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x69, 0x65, - 0x63, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, - 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, - 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, - 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, - 0x32, 0x8b, 0x04, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0a, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, - 0x64, 0x4a, 0x6f, 0x62, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x52, 0x0a, 0x14, 0x41, 0x63, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x57, 0x69, 0x74, 0x68, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x1a, 0x19, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x28, 0x01, 0x30, 0x01, 0x12, 0x52, 0x0a, - 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x12, 0x20, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, + 0x6c, 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x61, 0x73, 0x5f, 0x61, + 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x68, + 0x61, 0x73, 0x41, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x1a, 0x74, 0x0a, 0x0e, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x33, 0x0a, 0x09, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x12, 0x2d, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, + 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xb0, 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, + 0x2f, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, + 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, + 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1d, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0xa6, 0x03, 0x0a, 0x10, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x4c, 0x0a, + 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a, 0x14, 0x75, + 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, + 0x64, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, + 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, + 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x57, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 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, 0x4a, 0x04, 0x08, + 0x03, 0x10, 0x04, 0x22, 0x7a, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, + 0x4a, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, + 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x22, 0x68, 0x0a, 0x13, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, + 0x6f, 0x6b, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x5f, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x72, + 0x65, 0x64, 0x69, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, + 0x75, 0x64, 0x67, 0x65, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, + 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x11, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x0b, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x61, + 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, + 0x6b, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x50, + 0x69, 0x65, 0x63, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x34, 0x0a, 0x09, + 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x52, 0x4f, + 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, 0x4d, 0x4f, 0x4e, 0x10, + 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, + 0x10, 0x01, 0x32, 0x8b, 0x04, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0a, 0x41, 0x63, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x52, 0x0a, 0x14, 0x41, + 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x57, 0x69, 0x74, 0x68, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x28, 0x01, 0x30, 0x01, 0x12, + 0x52, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x37, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, - 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, - 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x42, 0x2e, - 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, - 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, + 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x37, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, + 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x0a, 0x55, 0x70, + 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, + 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, + 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1938,9 +1959,10 @@ var file_provisionerd_proto_provisionerd_proto_goTypes = []interface{}{ (*proto.Resource)(nil), // 32: provisioner.Resource (*proto.Module)(nil), // 33: provisioner.Module (*proto.ResourceReplacement)(nil), // 34: provisioner.ResourceReplacement - (*proto.RichParameter)(nil), // 35: provisioner.RichParameter - (*proto.ExternalAuthProviderResource)(nil), // 36: provisioner.ExternalAuthProviderResource - (*proto.Preset)(nil), // 37: provisioner.Preset + (*proto.AITask)(nil), // 35: provisioner.AITask + (*proto.RichParameter)(nil), // 36: provisioner.RichParameter + (*proto.ExternalAuthProviderResource)(nil), // 37: provisioner.ExternalAuthProviderResource + (*proto.Preset)(nil), // 38: provisioner.Preset } var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 12, // 0: provisionerd.AcquiredJob.workspace_build:type_name -> provisionerd.AcquiredJob.WorkspaceBuild @@ -1977,34 +1999,35 @@ var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 31, // 31: provisionerd.CompletedJob.WorkspaceBuild.timings:type_name -> provisioner.Timing 33, // 32: provisionerd.CompletedJob.WorkspaceBuild.modules:type_name -> provisioner.Module 34, // 33: provisionerd.CompletedJob.WorkspaceBuild.resource_replacements:type_name -> provisioner.ResourceReplacement - 32, // 34: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource - 32, // 35: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource - 35, // 36: provisionerd.CompletedJob.TemplateImport.rich_parameters:type_name -> provisioner.RichParameter - 36, // 37: provisionerd.CompletedJob.TemplateImport.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource - 33, // 38: provisionerd.CompletedJob.TemplateImport.start_modules:type_name -> provisioner.Module - 33, // 39: provisionerd.CompletedJob.TemplateImport.stop_modules:type_name -> provisioner.Module - 37, // 40: provisionerd.CompletedJob.TemplateImport.presets:type_name -> provisioner.Preset - 32, // 41: provisionerd.CompletedJob.TemplateDryRun.resources:type_name -> provisioner.Resource - 33, // 42: provisionerd.CompletedJob.TemplateDryRun.modules:type_name -> provisioner.Module - 1, // 43: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty - 10, // 44: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:input_type -> provisionerd.CancelAcquire - 8, // 45: provisionerd.ProvisionerDaemon.CommitQuota:input_type -> provisionerd.CommitQuotaRequest - 6, // 46: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest - 3, // 47: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob - 4, // 48: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob - 11, // 49: provisionerd.ProvisionerDaemon.UploadFile:input_type -> provisionerd.UploadFileRequest - 2, // 50: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob - 2, // 51: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:output_type -> provisionerd.AcquiredJob - 9, // 52: provisionerd.ProvisionerDaemon.CommitQuota:output_type -> provisionerd.CommitQuotaResponse - 7, // 53: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse - 1, // 54: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty - 1, // 55: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty - 1, // 56: provisionerd.ProvisionerDaemon.UploadFile:output_type -> provisionerd.Empty - 50, // [50:57] is the sub-list for method output_type - 43, // [43:50] is the sub-list for method input_type - 43, // [43:43] is the sub-list for extension type_name - 43, // [43:43] is the sub-list for extension extendee - 0, // [0:43] is the sub-list for field type_name + 35, // 34: provisionerd.CompletedJob.WorkspaceBuild.ai_tasks:type_name -> provisioner.AITask + 32, // 35: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource + 32, // 36: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource + 36, // 37: provisionerd.CompletedJob.TemplateImport.rich_parameters:type_name -> provisioner.RichParameter + 37, // 38: provisionerd.CompletedJob.TemplateImport.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource + 33, // 39: provisionerd.CompletedJob.TemplateImport.start_modules:type_name -> provisioner.Module + 33, // 40: provisionerd.CompletedJob.TemplateImport.stop_modules:type_name -> provisioner.Module + 38, // 41: provisionerd.CompletedJob.TemplateImport.presets:type_name -> provisioner.Preset + 32, // 42: provisionerd.CompletedJob.TemplateDryRun.resources:type_name -> provisioner.Resource + 33, // 43: provisionerd.CompletedJob.TemplateDryRun.modules:type_name -> provisioner.Module + 1, // 44: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty + 10, // 45: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:input_type -> provisionerd.CancelAcquire + 8, // 46: provisionerd.ProvisionerDaemon.CommitQuota:input_type -> provisionerd.CommitQuotaRequest + 6, // 47: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest + 3, // 48: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob + 4, // 49: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob + 11, // 50: provisionerd.ProvisionerDaemon.UploadFile:input_type -> provisionerd.UploadFileRequest + 2, // 51: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob + 2, // 52: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:output_type -> provisionerd.AcquiredJob + 9, // 53: provisionerd.ProvisionerDaemon.CommitQuota:output_type -> provisionerd.CommitQuotaResponse + 7, // 54: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse + 1, // 55: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty + 1, // 56: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty + 1, // 57: provisionerd.ProvisionerDaemon.UploadFile:output_type -> provisionerd.Empty + 51, // [51:58] is the sub-list for method output_type + 44, // [44:51] is the sub-list for method input_type + 44, // [44:44] is the sub-list for extension type_name + 44, // [44:44] is the sub-list for extension extendee + 0, // [0:44] is the sub-list for field type_name } func init() { file_provisionerd_proto_provisionerd_proto_init() } diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index 1b5ede6e13c71..eeeb5f02da0fb 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -80,6 +80,7 @@ message CompletedJob { repeated provisioner.Timing timings = 3; repeated provisioner.Module modules = 4; repeated provisioner.ResourceReplacement resource_replacements = 5; + repeated provisioner.AITask ai_tasks = 6; } message TemplateImport { repeated provisioner.Resource start_resources = 1; @@ -93,6 +94,7 @@ message CompletedJob { bytes plan = 9; bytes module_files = 10; bytes module_files_hash = 11; + bool has_ai_tasks = 12; } message TemplateDryRun { repeated provisioner.Resource resources = 1; diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 12dd709aeba7f..5c614bb508e3a 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -325,6 +325,15 @@ enum PrebuiltWorkspaceBuildStage { CLAIM = 2; // A prebuilt workspace is being claimed. } +message AITaskSidebarApp { + string id = 1; +} + +message AITask { + string id = 1; + AITaskSidebarApp sidebar_app = 2; +} + // Metadata is information about a workspace used in the execution of a build message Metadata { string coder_url = 1; @@ -400,6 +409,13 @@ message PlanComplete { repeated ResourceReplacement resource_replacements = 10; bytes module_files = 11; bytes module_files_hash = 12; + // Whether a template has any `coder_ai_task` resources defined, even if not planned for creation. + // During a template import, a plan is run which may not yield in any `coder_ai_task` resources, but nonetheless we + // still need to know that such resources are defined. + // + // See `hasAITaskResources` in provisioner/terraform/resources.go for more details. + bool has_ai_tasks = 13; + repeated provisioner.AITask ai_tasks = 14; } // ApplyRequest asks the provisioner to apply the changes. Apply MUST be preceded by a successful plan request/response @@ -416,6 +432,7 @@ message ApplyComplete { repeated RichParameter parameters = 4; repeated ExternalAuthProviderResource external_auth_providers = 5; repeated Timing timings = 6; + repeated provisioner.AITask ai_tasks = 7; } message Timing { From 438335039ab6d62488d90dd4ff06ca44b7507de0 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Wed, 18 Jun 2025 12:20:36 +0200 Subject: [PATCH 03/20] feat: store coder_ai_task resource state Signed-off-by: Danny Kopping --- .../provisionerdserver/provisionerdserver.go | 40 ++++++++++++++++ provisioner/terraform/executor.go | 3 ++ provisioner/terraform/resources.go | 46 +++++++++++++++++++ provisionerd/runner/runner.go | 20 +++++++- 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index a8f7c63a586fe..7d9ac3aaeba16 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -28,6 +28,7 @@ import ( protobuf "google.golang.org/protobuf/proto" "cdr.dev/slog" + "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/codersdk/drpcsdk" @@ -1654,6 +1655,17 @@ func (s *server) completeTemplateImportJob(ctx context.Context, job database.Pro if err != nil { return xerrors.Errorf("update template version external auth providers: %w", err) } + err = db.UpdateTemplateVersionAITaskByJobID(ctx, database.UpdateTemplateVersionAITaskByJobIDParams{ + JobID: jobID, + HasAITask: sql.NullBool{ + Bool: jobType.TemplateImport.HasAiTasks, + Valid: true, + }, + UpdatedAt: now, + }) + if err != nil { + return xerrors.Errorf("update template version external auth providers: %w", err) + } // Process terraform values plan := jobType.TemplateImport.Plan @@ -1866,6 +1878,34 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro } } + var sidebarAppID uuid.NullUUID + if len(jobType.WorkspaceBuild.AiTasks) == 1 { + task := jobType.WorkspaceBuild.AiTasks[0] + if task.SidebarApp == nil { + return xerrors.Errorf("update ai task: sidebar app is nil") + } + + id, err := uuid.Parse(task.SidebarApp.Id) + if err != nil { + return xerrors.Errorf("parse sidebar app id: %w", err) + } + + sidebarAppID = uuid.NullUUID{UUID: id, Valid: true} + } + + err = db.UpdateWorkspaceBuildAITaskByID(ctx, database.UpdateWorkspaceBuildAITaskByIDParams{ + ID: workspaceBuild.ID, + HasAITask: sql.NullBool{ + Bool: len(jobType.WorkspaceBuild.AiTasks) > 0, + Valid: true, + }, + SidebarAppID: sidebarAppID, + UpdatedAt: now, + }) + if err != nil { + return xerrors.Errorf("update workspace build ai tasks flag: %w", err) + } + // Insert timings inside the transaction now // nolint:exhaustruct // The other fields are set further down. params := database.InsertProvisionerJobTimingsParams{ diff --git a/provisioner/terraform/executor.go b/provisioner/terraform/executor.go index b29c21eff000c..ea63f8c59877e 100644 --- a/provisioner/terraform/executor.go +++ b/provisioner/terraform/executor.go @@ -361,6 +361,8 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l Plan: planJSON, ResourceReplacements: resReps, ModuleFiles: moduleFiles, + HasAiTasks: state.HasAITasks, + AiTasks: state.AITasks, } return msg, nil @@ -577,6 +579,7 @@ func (e *executor) apply( ExternalAuthProviders: state.ExternalAuthProviders, State: stateContent, Timings: e.timings.aggregate(), + AiTasks: state.AITasks, }, nil } diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index a46953f030dda..42f13a33f0596 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -162,10 +162,29 @@ type State struct { Parameters []*proto.RichParameter Presets []*proto.Preset ExternalAuthProviders []*proto.ExternalAuthProviderResource + AITasks []*proto.AITask + HasAITasks bool } var ErrInvalidTerraformAddr = xerrors.New("invalid terraform address") +// hasAITaskResources is used to determine if a template has *any* `coder_ai_task` resources defined. During template +// import, it's possible that none of these have `count=1` since count may be dependent on the value of a `coder_parameter` +// or something else. +// We need to know at template import if these resources exist to inform the frontend of their existence. +func hasAITaskResources(graph *gographviz.Graph) bool { + for _, node := range graph.Nodes.Lookup { + // Check if this node is a coder_ai_task resource + if label, exists := node.Attrs["label"]; exists { + labelValue := strings.Trim(label, `"`) + if strings.Contains(labelValue, "coder_ai_task.") { + return true + } + } + } + return false +} + // ConvertState consumes Terraform state and a GraphViz representation // produced by `terraform graph` to produce resources consumable by Coder. // nolint:gocognit // This function makes more sense being large for now, until refactored. @@ -189,6 +208,7 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s // Extra array to preserve the order of rich parameters. tfResourcesRichParameters := make([]*tfjson.StateResource, 0) tfResourcesPresets := make([]*tfjson.StateResource, 0) + tfResourcesAITasks := make([]*tfjson.StateResource, 0) var findTerraformResources func(mod *tfjson.StateModule) findTerraformResources = func(mod *tfjson.StateModule) { for _, module := range mod.ChildModules { @@ -201,6 +221,9 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s if resource.Type == "coder_workspace_preset" { tfResourcesPresets = append(tfResourcesPresets, resource) } + if resource.Type == "coder_ai_task" { + tfResourcesAITasks = append(tfResourcesAITasks, resource) + } label := convertAddressToLabel(resource.Address) if tfResourcesByLabel[label] == nil { @@ -957,6 +980,27 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s ) } + // This will only pick up resources which will actually be created. + aiTasks := make([]*proto.AITask, 0, len(tfResourcesAITasks)) + for _, resource := range tfResourcesAITasks { + var task provider.AITask + err = mapstructure.Decode(resource.AttributeValues, &task) + if err != nil { + return nil, xerrors.Errorf("decode coder_ai_task attributes: %w", err) + } + + if len(task.SidebarApp) < 1 { + return nil, xerrors.Errorf("coder_ai_task has no sidebar_app defined") + } + + aiTasks = append(aiTasks, &proto.AITask{ + Id: task.ID, + SidebarApp: &proto.AITaskSidebarApp{ + Id: task.SidebarApp[0].ID, + }, + }) + } + // A map is used to ensure we don't have duplicates! externalAuthProvidersMap := map[string]*proto.ExternalAuthProviderResource{} for _, tfResources := range tfResourcesByLabel { @@ -992,6 +1036,8 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s Parameters: parameters, Presets: presets, ExternalAuthProviders: externalAuthProviders, + HasAITasks: hasAITaskResources(graph), + AITasks: aiTasks, }, nil } diff --git a/provisionerd/runner/runner.go b/provisionerd/runner/runner.go index 305bd2543dd82..0fb3696ec509c 100644 --- a/provisionerd/runner/runner.go +++ b/provisionerd/runner/runner.go @@ -7,11 +7,13 @@ import ( "errors" "fmt" "reflect" + "slices" "strings" "sync" "sync/atomic" "time" + "github.com/coder/terraform-provider-coder/v2/provider" "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/attribute" @@ -584,8 +586,6 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p externalAuthProviderNames = append(externalAuthProviderNames, it.Id) } - // fmt.Println("completed job: template import: graph:", startProvision.Graph) - return &proto.CompletedJob{ JobId: r.job.JobId, Type: &proto.CompletedJob_TemplateImport_{ @@ -603,6 +603,7 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p ModuleFiles: startProvision.ModuleFiles, // ModuleFileHash will be populated if the file is uploaded async ModuleFilesHash: []byte{}, + HasAiTasks: startProvision.HasAITasks, }, }, }, nil @@ -666,6 +667,7 @@ type templateImportProvision struct { Presets []*sdkproto.Preset Plan json.RawMessage ModuleFiles []byte + HasAITasks bool } // Performs a dry-run provision when importing a template. @@ -799,6 +801,15 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters( } } + if c.HasAiTasks { + hasPromptParam := slices.ContainsFunc(c.Parameters, func(param *sdkproto.RichParameter) bool { + return param.Name == provider.TaskPromptParameterName + }) + if !hasPromptParam { + return nil, xerrors.Errorf("coder_parameter named '%s' is required when 'coder_ai_task' resource is defined", provider.TaskPromptParameterName) + } + } + return &templateImportProvision{ Resources: c.Resources, Parameters: c.Parameters, @@ -807,6 +818,7 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters( Presets: c.Presets, Plan: c.Plan, ModuleFiles: moduleFilesData, + HasAITasks: c.HasAiTasks, }, nil default: return nil, xerrors.Errorf("invalid message type %q received from provisioner", @@ -1047,6 +1059,9 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p }, } } + if len(planComplete.AiTasks) > 1 { + return nil, r.failedWorkspaceBuildf("only one 'coder_ai_task' resource can be provisioned per template") + } r.logger.Info(context.Background(), "plan request successful", slog.F("resource_count", len(planComplete.Resources)), @@ -1124,6 +1139,7 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p Modules: planComplete.Modules, // Resource replacements are discovered at plan time, only. ResourceReplacements: planComplete.ResourceReplacements, + AiTasks: applyComplete.AiTasks, }, }, }, nil From 957fb0812f8b367ab83d369eda740daa62be948c Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Thu, 19 Jun 2025 11:43:25 +0200 Subject: [PATCH 04/20] chore: rename ai_tasks_sidebar_app_id to ai_task_sidebar_app_id Signed-off-by: Danny Kopping --- coderd/database/dump.sql | 6 +-- coderd/database/foreign_key_constraint.go | 2 +- ...38_rename_ai_tasks_sidebar_app_id.down.sql | 49 +++++++++++++++++++ ...0338_rename_ai_tasks_sidebar_app_id.up.sql | 49 +++++++++++++++++++ coderd/database/models.go | 4 +- coderd/database/queries/workspacebuilds.sql | 2 +- coderd/database/sqlc.yaml | 2 +- enterprise/audit/table.go | 2 +- 8 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.down.sql create mode 100644 coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.up.sql diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 17b16abc5715c..132ad514c9db6 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -2098,7 +2098,7 @@ CREATE TABLE workspace_builds ( max_deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL, template_version_preset_id uuid, has_ai_task boolean, - ai_tasks_sidebar_app_id uuid + ai_task_sidebar_app_id uuid ); CREATE VIEW workspace_build_with_user AS @@ -2118,7 +2118,7 @@ CREATE VIEW workspace_build_with_user AS workspace_builds.max_deadline, workspace_builds.template_version_preset_id, workspace_builds.has_ai_task, - workspace_builds.ai_tasks_sidebar_app_id, + workspace_builds.ai_task_sidebar_app_id, COALESCE(visible_users.avatar_url, ''::text) AS initiator_by_avatar_url, COALESCE(visible_users.username, ''::text) AS initiator_by_username, COALESCE(visible_users.name, ''::text) AS initiator_by_name @@ -3092,7 +3092,7 @@ ALTER TABLE ONLY workspace_build_parameters ADD CONSTRAINT workspace_build_parameters_workspace_build_id_fkey FOREIGN KEY (workspace_build_id) REFERENCES workspace_builds(id) ON DELETE CASCADE; ALTER TABLE ONLY workspace_builds - ADD CONSTRAINT workspace_builds_ai_tasks_sidebar_app_id_fkey FOREIGN KEY (ai_tasks_sidebar_app_id) REFERENCES workspace_apps(id); + ADD CONSTRAINT workspace_builds_ai_task_sidebar_app_id_fkey FOREIGN KEY (ai_task_sidebar_app_id) REFERENCES workspace_apps(id); ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE; diff --git a/coderd/database/foreign_key_constraint.go b/coderd/database/foreign_key_constraint.go index ea1ffaf4c8064..c0720bcb5fcdd 100644 --- a/coderd/database/foreign_key_constraint.go +++ b/coderd/database/foreign_key_constraint.go @@ -83,7 +83,7 @@ const ( ForeignKeyWorkspaceAppStatusesWorkspaceID ForeignKeyConstraint = "workspace_app_statuses_workspace_id_fkey" // ALTER TABLE ONLY workspace_app_statuses ADD CONSTRAINT workspace_app_statuses_workspace_id_fkey FOREIGN KEY (workspace_id) REFERENCES workspaces(id); ForeignKeyWorkspaceAppsAgentID ForeignKeyConstraint = "workspace_apps_agent_id_fkey" // ALTER TABLE ONLY workspace_apps ADD CONSTRAINT workspace_apps_agent_id_fkey FOREIGN KEY (agent_id) REFERENCES workspace_agents(id) ON DELETE CASCADE; ForeignKeyWorkspaceBuildParametersWorkspaceBuildID ForeignKeyConstraint = "workspace_build_parameters_workspace_build_id_fkey" // ALTER TABLE ONLY workspace_build_parameters ADD CONSTRAINT workspace_build_parameters_workspace_build_id_fkey FOREIGN KEY (workspace_build_id) REFERENCES workspace_builds(id) ON DELETE CASCADE; - ForeignKeyWorkspaceBuildsAiTasksSidebarAppID ForeignKeyConstraint = "workspace_builds_ai_tasks_sidebar_app_id_fkey" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_ai_tasks_sidebar_app_id_fkey FOREIGN KEY (ai_tasks_sidebar_app_id) REFERENCES workspace_apps(id); + ForeignKeyWorkspaceBuildsAiTaskSidebarAppID ForeignKeyConstraint = "workspace_builds_ai_task_sidebar_app_id_fkey" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_ai_task_sidebar_app_id_fkey FOREIGN KEY (ai_task_sidebar_app_id) REFERENCES workspace_apps(id); ForeignKeyWorkspaceBuildsJobID ForeignKeyConstraint = "workspace_builds_job_id_fkey" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_jobs(id) ON DELETE CASCADE; ForeignKeyWorkspaceBuildsTemplateVersionID ForeignKeyConstraint = "workspace_builds_template_version_id_fkey" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_template_version_id_fkey FOREIGN KEY (template_version_id) REFERENCES template_versions(id) ON DELETE CASCADE; ForeignKeyWorkspaceBuildsTemplateVersionPresetID ForeignKeyConstraint = "workspace_builds_template_version_preset_id_fkey" // ALTER TABLE ONLY workspace_builds ADD CONSTRAINT workspace_builds_template_version_preset_id_fkey FOREIGN KEY (template_version_preset_id) REFERENCES template_version_presets(id) ON DELETE SET NULL; diff --git a/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.down.sql b/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.down.sql new file mode 100644 index 0000000000000..6c3a64aa1f4a4 --- /dev/null +++ b/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.down.sql @@ -0,0 +1,49 @@ +-- Revert ai_task_sidebar_app_id back to ai_tasks_sidebar_app_id in workspace_builds table +ALTER TABLE workspace_builds DROP CONSTRAINT workspace_builds_ai_task_sidebar_app_id_fkey; + +ALTER TABLE workspace_builds RENAME COLUMN ai_task_sidebar_app_id TO ai_tasks_sidebar_app_id; + +ALTER TABLE workspace_builds ADD CONSTRAINT workspace_builds_ai_tasks_sidebar_app_id_fkey FOREIGN KEY (ai_tasks_sidebar_app_id) REFERENCES workspace_apps(id); + +-- Revert the workspace_build_with_user view to use the original column name +DROP VIEW workspace_build_with_user; + +CREATE VIEW workspace_build_with_user AS +SELECT + workspace_builds.id, + workspace_builds.created_at, + workspace_builds.updated_at, + workspace_builds.workspace_id, + workspace_builds.template_version_id, + workspace_builds.build_number, + workspace_builds.transition, + workspace_builds.initiator_id, + workspace_builds.provisioner_state, + workspace_builds.job_id, + workspace_builds.deadline, + workspace_builds.reason, + workspace_builds.daily_cost, + workspace_builds.max_deadline, + workspace_builds.template_version_preset_id, + workspace_builds.has_ai_task, + workspace_builds.ai_tasks_sidebar_app_id, + COALESCE( + visible_users.avatar_url, + '' :: text + ) AS initiator_by_avatar_url, + COALESCE( + visible_users.username, + '' :: text + ) AS initiator_by_username, + COALESCE(visible_users.name, '' :: text) AS initiator_by_name +FROM + ( + workspace_builds + LEFT JOIN visible_users ON ( + ( + workspace_builds.initiator_id = visible_users.id + ) + ) + ); + +COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; \ No newline at end of file diff --git a/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.up.sql b/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.up.sql new file mode 100644 index 0000000000000..4f0fab260fdd4 --- /dev/null +++ b/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.up.sql @@ -0,0 +1,49 @@ +-- Rename ai_tasks_sidebar_app_id to ai_task_sidebar_app_id in workspace_builds table +ALTER TABLE workspace_builds DROP CONSTRAINT workspace_builds_ai_tasks_sidebar_app_id_fkey; + +ALTER TABLE workspace_builds RENAME COLUMN ai_tasks_sidebar_app_id TO ai_task_sidebar_app_id; + +ALTER TABLE workspace_builds ADD CONSTRAINT workspace_builds_ai_task_sidebar_app_id_fkey FOREIGN KEY (ai_task_sidebar_app_id) REFERENCES workspace_apps(id); + +-- Update the workspace_build_with_user view to use the new column name +DROP VIEW workspace_build_with_user; + +CREATE VIEW workspace_build_with_user AS +SELECT + workspace_builds.id, + workspace_builds.created_at, + workspace_builds.updated_at, + workspace_builds.workspace_id, + workspace_builds.template_version_id, + workspace_builds.build_number, + workspace_builds.transition, + workspace_builds.initiator_id, + workspace_builds.provisioner_state, + workspace_builds.job_id, + workspace_builds.deadline, + workspace_builds.reason, + workspace_builds.daily_cost, + workspace_builds.max_deadline, + workspace_builds.template_version_preset_id, + workspace_builds.has_ai_task, + workspace_builds.ai_task_sidebar_app_id, + COALESCE( + visible_users.avatar_url, + '' :: text + ) AS initiator_by_avatar_url, + COALESCE( + visible_users.username, + '' :: text + ) AS initiator_by_username, + COALESCE(visible_users.name, '' :: text) AS initiator_by_name +FROM + ( + workspace_builds + LEFT JOIN visible_users ON ( + ( + workspace_builds.initiator_id = visible_users.id + ) + ) + ); + +COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; \ No newline at end of file diff --git a/coderd/database/models.go b/coderd/database/models.go index ce65c4c559d65..0cc931285705c 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -3864,7 +3864,7 @@ type WorkspaceBuild struct { MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` TemplateVersionPresetID uuid.NullUUID `db:"template_version_preset_id" json:"template_version_preset_id"` HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` - AITasksSidebarAppID uuid.NullUUID `db:"ai_tasks_sidebar_app_id" json:"ai_tasks_sidebar_app_id"` + AITaskSidebarAppID uuid.NullUUID `db:"ai_task_sidebar_app_id" json:"ai_task_sidebar_app_id"` InitiatorByAvatarUrl string `db:"initiator_by_avatar_url" json:"initiator_by_avatar_url"` InitiatorByUsername string `db:"initiator_by_username" json:"initiator_by_username"` InitiatorByName string `db:"initiator_by_name" json:"initiator_by_name"` @@ -3895,7 +3895,7 @@ type WorkspaceBuildTable struct { MaxDeadline time.Time `db:"max_deadline" json:"max_deadline"` TemplateVersionPresetID uuid.NullUUID `db:"template_version_preset_id" json:"template_version_preset_id"` HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` - AITasksSidebarAppID uuid.NullUUID `db:"ai_tasks_sidebar_app_id" json:"ai_tasks_sidebar_app_id"` + AITaskSidebarAppID uuid.NullUUID `db:"ai_task_sidebar_app_id" json:"ai_task_sidebar_app_id"` } type WorkspaceLatestBuild struct { diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql index 0526477866e81..be76b6642df1f 100644 --- a/coderd/database/queries/workspacebuilds.sql +++ b/coderd/database/queries/workspacebuilds.sql @@ -156,7 +156,7 @@ UPDATE workspace_builds SET has_ai_task = @has_ai_task, - ai_tasks_sidebar_app_id = @sidebar_app_id, + ai_task_sidebar_app_id = @sidebar_app_id, updated_at = @updated_at::timestamptz WHERE id = @id::uuid; diff --git a/coderd/database/sqlc.yaml b/coderd/database/sqlc.yaml index 85bb286881f97..b96dabd1fc187 100644 --- a/coderd/database/sqlc.yaml +++ b/coderd/database/sqlc.yaml @@ -148,7 +148,7 @@ sql: crypto_key_feature_oidc_convert: CryptoKeyFeatureOIDCConvert stale_interval_ms: StaleIntervalMS has_ai_task: HasAITask - ai_tasks_sidebar_app_id: AITasksSidebarAppID + ai_task_sidebar_app_id: AITaskSidebarAppID latest_build_has_ai_task: LatestBuildHasAITask rules: - name: do-not-use-public-schema-in-queries diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index bd4987bae24e2..120b4ed684bdf 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -195,7 +195,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "initiator_by_name": ActionIgnore, "template_version_preset_id": ActionIgnore, // Never changes. "has_ai_task": ActionIgnore, // Never changes. - "ai_tasks_sidebar_app_id": ActionIgnore, // Never changes. + "ai_task_sidebar_app_id": ActionIgnore, // Never changes. }, &database.AuditableGroup{}: { "id": ActionTrack, From 91c8f0cf0cc97be99ff15d954dbb17edff6b63b9 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Thu, 19 Jun 2025 11:53:06 +0200 Subject: [PATCH 05/20] chore: update to d9b0f892f9c2b3768b9647b089900b0628cb7828, prompt name changed Signed-off-by: Danny Kopping --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4298c0d4c59bf..84637c5f307de 100644 --- a/go.mod +++ b/go.mod @@ -537,4 +537,4 @@ require ( ) // TODO: replace once new version is cut. -replace github.com/coder/terraform-provider-coder/v2 v2.5.3 => github.com/coder/terraform-provider-coder/v2 v2.5.4-0.20250618103053-97e45841d2c8 +replace github.com/coder/terraform-provider-coder/v2 => github.com/coder/terraform-provider-coder/v2 v2.5.4-0.20250619093524-d9b0f892f9c2 From efe5da97ec690d37ccab2c643bfe2e2012c7bcda Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Thu, 19 Jun 2025 11:58:30 +0200 Subject: [PATCH 06/20] chore: update provisioner API version comments Signed-off-by: Danny Kopping --- provisionerd/proto/version.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/provisionerd/proto/version.go b/provisionerd/proto/version.go index 3ac93d7497860..4747eec52d5d3 100644 --- a/provisionerd/proto/version.go +++ b/provisionerd/proto/version.go @@ -38,6 +38,11 @@ import "github.com/coder/coder/v2/apiversion" // and schedule rules to define cron-based scaling of prebuilt workspace // instances based on time patterns. // - Added new field named `id` to `App`, which transports the ID generated by the coder_app provider to be persisted. +// - Added various fields in support of AI Tasks: +// - `ai_tasks` in `CompleteJob.WorkspaceBuild` +// - `has_ai_tasks` in `CompleteJob.TemplateImport` +// - `has_ai_tasks` and `ai_tasks` in `PlanComplete` +// - new message types `AITaskSidebarApp` and `AITask` const ( CurrentMajor = 1 CurrentMinor = 7 From 5e0d28abafa80d0cdbb596d4d80cb59bf466ffb3 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Thu, 19 Jun 2025 16:31:23 +0200 Subject: [PATCH 07/20] chore: move prompt param validation to ConvertState with other validations, add test Signed-off-by: Danny Kopping --- provisioner/terraform/resources.go | 13 +- provisioner/terraform/resources_test.go | 51 +++ .../ai-tasks-missing-prompt.tfplan.dot | 22 ++ .../ai-tasks-missing-prompt.tfplan.json | 307 +++++++++++++++++ .../ai-tasks-missing-prompt.tfstate.dot | 22 ++ .../ai-tasks-missing-prompt.tfstate.json | 142 ++++++++ .../resources/ai-tasks-missing-prompt/main.tf | 23 ++ .../ai-tasks-multiple.tfplan.dot | 26 ++ .../ai-tasks-multiple.tfplan.json | 319 ++++++++++++++++++ .../ai-tasks-multiple.tfstate.dot | 26 ++ .../ai-tasks-multiple.tfstate.json | 146 ++++++++ .../resources/ai-tasks-multiple/main.tf | 31 ++ .../external-auth-providers.tfplan.json | 8 +- .../external-auth-providers.tfstate.json | 4 +- .../resources/presets/presets.tfplan.json | 76 +---- .../resources/presets/presets.tfstate.json | 37 +- .../rich-parameters-order.tfplan.json | 8 +- .../rich-parameters-order.tfstate.json | 4 +- .../rich-parameters-validation.tfplan.json | 24 +- .../rich-parameters-validation.tfstate.json | 12 +- .../rich-parameters.tfplan.json | 40 +-- .../rich-parameters.tfstate.json | 20 +- .../terraform/testdata/resources/version.txt | 2 +- provisionerd/runner/runner.go | 12 - 24 files changed, 1211 insertions(+), 164 deletions(-) create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.dot create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.dot create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.json create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.dot create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.dot create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.json create mode 100644 provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 42f13a33f0596..5420789e8d525 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math" + "slices" "strings" "github.com/awalterschulze/gographviz" @@ -1031,12 +1032,22 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s externalAuthProviders = append(externalAuthProviders, it) } + hasAITasks := hasAITaskResources(graph) + if hasAITasks { + hasPromptParam := slices.ContainsFunc(parameters, func(param *proto.RichParameter) bool { + return param.Name == provider.TaskPromptParameterName + }) + if !hasPromptParam { + return nil, xerrors.Errorf("coder_parameter named '%s' is required when 'coder_ai_task' resource is defined", provider.TaskPromptParameterName) + } + } + return &State{ Resources: resources, Parameters: parameters, Presets: presets, ExternalAuthProviders: externalAuthProviders, - HasAITasks: hasAITaskResources(graph), + HasAITasks: hasAITasks, AITasks: aiTasks, }, nil } diff --git a/provisioner/terraform/resources_test.go b/provisioner/terraform/resources_test.go index 56077eed9eee9..4308f554a0a8a 100644 --- a/provisioner/terraform/resources_test.go +++ b/provisioner/terraform/resources_test.go @@ -11,6 +11,7 @@ import ( "strings" "testing" + "github.com/coder/terraform-provider-coder/v2/provider" "github.com/google/go-cmp/cmp" tfjson "github.com/hashicorp/terraform-json" "github.com/stretchr/testify/require" @@ -18,6 +19,7 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" + "github.com/coder/coder/v2/testutil" "github.com/coder/coder/v2/cryptorand" @@ -1447,6 +1449,55 @@ func TestInstanceIDAssociation(t *testing.T) { } } +func TestAITasks(t *testing.T) { + t.Parallel() + ctx, logger := ctxAndLogger(t) + + t.Run("Prompt parameter is required", func(t *testing.T) { + t.Parallel() + + // nolint:dogsled + _, filename, _, _ := runtime.Caller(0) + + dir := filepath.Join(filepath.Dir(filename), "testdata", "resources", "ai-tasks-missing-prompt") + tfPlanRaw, err := os.ReadFile(filepath.Join(dir, "ai-tasks-missing-prompt.tfplan.json")) + require.NoError(t, err) + var tfPlan tfjson.Plan + err = json.Unmarshal(tfPlanRaw, &tfPlan) + require.NoError(t, err) + tfPlanGraph, err := os.ReadFile(filepath.Join(dir, "ai-tasks-missing-prompt.tfplan.dot")) + require.NoError(t, err) + + state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{tfPlan.PlannedValues.RootModule, tfPlan.PriorState.Values.RootModule}, string(tfPlanGraph), logger) + require.Nil(t, state) + require.ErrorContains(t, err, fmt.Sprintf("coder_parameter named '%s' is required when 'coder_ai_task' resource is defined", provider.TaskPromptParameterName)) + }) + + t.Run("Multiple tasks can be defined", func(t *testing.T) { + t.Parallel() + + // nolint:dogsled + _, filename, _, _ := runtime.Caller(0) + + dir := filepath.Join(filepath.Dir(filename), "testdata", "resources", "ai-tasks-multiple") + tfPlanRaw, err := os.ReadFile(filepath.Join(dir, "ai-tasks-multiple.tfplan.json")) + require.NoError(t, err) + var tfPlan tfjson.Plan + err = json.Unmarshal(tfPlanRaw, &tfPlan) + require.NoError(t, err) + tfPlanGraph, err := os.ReadFile(filepath.Join(dir, "ai-tasks-multiple.tfplan.dot")) + require.NoError(t, err) + + state, err := terraform.ConvertState(ctx, []*tfjson.StateModule{tfPlan.PlannedValues.RootModule, tfPlan.PriorState.Values.RootModule}, string(tfPlanGraph), logger) + require.NotNil(t, state) + require.NoError(t, err) + require.True(t, state.HasAITasks) + // Multiple coder_ai_tasks resources can be defined, but only 1 is allowed. + // This is validated once all parameters are resolved etc as part of the workspace build, but for now we can allow it. + require.Len(t, state.AITasks, 2) + }) +} + // sortResource ensures resources appear in a consistent ordering // to prevent tests from flaking. func sortResources(resources []*proto.Resource) { diff --git a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.dot b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.dot new file mode 100644 index 0000000000000..758e6c990ec1e --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.dot @@ -0,0 +1,22 @@ +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] coder_agent.main (expand)" [label = "coder_agent.main", shape = "box"] + "[root] coder_ai_task.a (expand)" [label = "coder_ai_task.a", shape = "box"] + "[root] data.coder_provisioner.me (expand)" [label = "data.coder_provisioner.me", shape = "box"] + "[root] data.coder_workspace.me (expand)" [label = "data.coder_workspace.me", shape = "box"] + "[root] data.coder_workspace_owner.me (expand)" [label = "data.coder_workspace_owner.me", shape = "box"] + "[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"] + "[root] coder_agent.main (expand)" -> "[root] data.coder_provisioner.me (expand)" + "[root] coder_ai_task.a (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_provisioner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace_owner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.main (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_ai_task.a (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace.me (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace_owner.me (expand)" + "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" + } +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json new file mode 100644 index 0000000000000..df772e18ecb6b --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json @@ -0,0 +1,307 @@ +{ + "format_version": "1.2", + "terraform_version": "1.12.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "coder_agent.main", + "mode": "managed", + "type": "coder_agent", + "name": "main", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "api_key_scope": "all", + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "env": null, + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "troubleshooting_url": null + }, + "sensitive_values": { + "display_apps": [], + "metadata": [], + "resources_monitoring": [], + "token": true + } + }, + { + "address": "coder_ai_task.a", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "sensitive_values": { + "sidebar_app": [ + {} + ] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "coder_agent.main", + "mode": "managed", + "type": "coder_agent", + "name": "main", + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "api_key_scope": "all", + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "env": null, + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "troubleshooting_url": null + }, + "after_unknown": { + "display_apps": true, + "id": true, + "init_script": true, + "metadata": [], + "resources_monitoring": [], + "token": true + }, + "before_sensitive": false, + "after_sensitive": { + "display_apps": [], + "metadata": [], + "resources_monitoring": [], + "token": true + } + } + }, + { + "address": "coder_ai_task.a", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "after_unknown": { + "id": true, + "sidebar_app": [ + {} + ] + }, + "before_sensitive": false, + "after_sensitive": { + "sidebar_app": [ + {} + ] + } + } + } + ], + "prior_state": { + "format_version": "1.0", + "terraform_version": "1.12.2", + "values": { + "root_module": { + "resources": [ + { + "address": "data.coder_provisioner.me", + "mode": "data", + "type": "coder_provisioner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "id": "5a6ecb8b-fd26-4cfc-91b1-651d06bee98c", + "os": "linux" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace.me", + "mode": "data", + "type": "coder_workspace", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "access_port": 443, + "access_url": "https://dev.coder.com/", + "id": "bf9ee323-4f3a-4d45-9841-2dcd6265e830", + "is_prebuild": false, + "is_prebuild_claim": false, + "name": "sebenza-nonix", + "prebuild_count": 0, + "start_count": 1, + "template_id": "", + "template_name": "", + "template_version": "", + "transition": "start" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace_owner.me", + "mode": "data", + "type": "coder_workspace_owner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 0, + "values": { + "email": "default@example.com", + "full_name": "default", + "groups": [], + "id": "0b8cbfb8-3925-41fe-9f21-21b76d21edc7", + "login_type": null, + "name": "default", + "oidc_access_token": "", + "rbac_roles": [], + "session_token": "", + "ssh_private_key": "", + "ssh_public_key": "" + }, + "sensitive_values": { + "groups": [], + "rbac_roles": [], + "ssh_private_key": true + } + } + ] + } + } + }, + "configuration": { + "provider_config": { + "coder": { + "name": "coder", + "full_name": "registry.terraform.io/coder/coder", + "version_constraint": ">= 2.5.0" + } + }, + "root_module": { + "resources": [ + { + "address": "coder_agent.main", + "mode": "managed", + "type": "coder_agent", + "name": "main", + "provider_config_key": "coder", + "expressions": { + "arch": { + "references": [ + "data.coder_provisioner.me.arch", + "data.coder_provisioner.me" + ] + }, + "os": { + "references": [ + "data.coder_provisioner.me.os", + "data.coder_provisioner.me" + ] + } + }, + "schema_version": 1 + }, + { + "address": "coder_ai_task.a", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "provider_config_key": "coder", + "expressions": { + "sidebar_app": [ + { + "id": { + "constant_value": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + } + ] + }, + "schema_version": 1 + }, + { + "address": "data.coder_provisioner.me", + "mode": "data", + "type": "coder_provisioner", + "name": "me", + "provider_config_key": "coder", + "schema_version": 1 + }, + { + "address": "data.coder_workspace.me", + "mode": "data", + "type": "coder_workspace", + "name": "me", + "provider_config_key": "coder", + "schema_version": 1 + }, + { + "address": "data.coder_workspace_owner.me", + "mode": "data", + "type": "coder_workspace_owner", + "name": "me", + "provider_config_key": "coder", + "schema_version": 0 + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "data.coder_provisioner.me", + "attribute": [ + "arch" + ] + }, + { + "resource": "data.coder_provisioner.me", + "attribute": [ + "os" + ] + } + ], + "timestamp": "2025-06-19T14:30:00Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.dot b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.dot new file mode 100644 index 0000000000000..758e6c990ec1e --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.dot @@ -0,0 +1,22 @@ +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] coder_agent.main (expand)" [label = "coder_agent.main", shape = "box"] + "[root] coder_ai_task.a (expand)" [label = "coder_ai_task.a", shape = "box"] + "[root] data.coder_provisioner.me (expand)" [label = "data.coder_provisioner.me", shape = "box"] + "[root] data.coder_workspace.me (expand)" [label = "data.coder_workspace.me", shape = "box"] + "[root] data.coder_workspace_owner.me (expand)" [label = "data.coder_workspace_owner.me", shape = "box"] + "[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"] + "[root] coder_agent.main (expand)" -> "[root] data.coder_provisioner.me (expand)" + "[root] coder_ai_task.a (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_provisioner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace_owner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.main (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_ai_task.a (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace.me (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace_owner.me (expand)" + "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" + } +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.json b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.json new file mode 100644 index 0000000000000..4d3affb7a31ed --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfstate.json @@ -0,0 +1,142 @@ +{ + "format_version": "1.0", + "terraform_version": "1.12.2", + "values": { + "root_module": { + "resources": [ + { + "address": "data.coder_provisioner.me", + "mode": "data", + "type": "coder_provisioner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "id": "e838328b-8dc2-49d0-b16c-42d6375cfb34", + "os": "linux" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace.me", + "mode": "data", + "type": "coder_workspace", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "access_port": 443, + "access_url": "https://dev.coder.com/", + "id": "6a64b978-bd81-424a-92e5-d4004296f420", + "is_prebuild": false, + "is_prebuild_claim": false, + "name": "sebenza-nonix", + "prebuild_count": 0, + "start_count": 1, + "template_id": "", + "template_name": "", + "template_version": "", + "transition": "start" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace_owner.me", + "mode": "data", + "type": "coder_workspace_owner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 0, + "values": { + "email": "default@example.com", + "full_name": "default", + "groups": [], + "id": "ffb2e99a-efa7-4fb9-bb2c-aa282bb636c9", + "login_type": null, + "name": "default", + "oidc_access_token": "", + "rbac_roles": [], + "session_token": "", + "ssh_private_key": "", + "ssh_public_key": "" + }, + "sensitive_values": { + "groups": [], + "rbac_roles": [], + "ssh_private_key": true + } + }, + { + "address": "coder_agent.main", + "mode": "managed", + "type": "coder_agent", + "name": "main", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "api_key_scope": "all", + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "display_apps": [ + { + "port_forwarding_helper": true, + "ssh_helper": true, + "vscode": true, + "vscode_insiders": false, + "web_terminal": true + } + ], + "env": null, + "id": "0c95434c-9e4b-40aa-bd9b-2a0cc86f11af", + "init_script": "", + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "token": "ac32e23e-336a-4e63-a7a4-71ab85f16831", + "troubleshooting_url": null + }, + "sensitive_values": { + "display_apps": [ + {} + ], + "metadata": [], + "resources_monitoring": [], + "token": true + }, + "depends_on": [ + "data.coder_provisioner.me" + ] + }, + { + "address": "coder_ai_task.a", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "id": "b83734ee-765f-45db-a37b-a1e89414be5f", + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "sensitive_values": { + "sidebar_app": [ + {} + ] + } + } + ] + } + } +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf new file mode 100644 index 0000000000000..0b53740fef94f --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf @@ -0,0 +1,23 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = ">=2.5.0" + } + } +} + +data "coder_provisioner" "me" {} +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +resource "coder_agent" "main" { + arch = data.coder_provisioner.me.arch + os = data.coder_provisioner.me.os +} + +resource "coder_ai_task" "a" { + sidebar_app { + id = "5ece4674-dd35-4f16-88c8-82e40e72e2fd" # fake ID to satisfy requirement, irrelevant otherwise + } +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.dot b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.dot new file mode 100644 index 0000000000000..4e660599e7a9b --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.dot @@ -0,0 +1,26 @@ +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] coder_ai_task.a (expand)" [label = "coder_ai_task.a", shape = "box"] + "[root] coder_ai_task.b (expand)" [label = "coder_ai_task.b", shape = "box"] + "[root] data.coder_parameter.prompt (expand)" [label = "data.coder_parameter.prompt", shape = "box"] + "[root] data.coder_provisioner.me (expand)" [label = "data.coder_provisioner.me", shape = "box"] + "[root] data.coder_workspace.me (expand)" [label = "data.coder_workspace.me", shape = "box"] + "[root] data.coder_workspace_owner.me (expand)" [label = "data.coder_workspace_owner.me", shape = "box"] + "[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"] + "[root] coder_ai_task.a (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] coder_ai_task.b (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_parameter.prompt (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_provisioner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace_owner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_ai_task.a (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_ai_task.b (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_parameter.prompt (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_provisioner.me (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace.me (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace_owner.me (expand)" + "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" + } +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json new file mode 100644 index 0000000000000..d42a0714d0f33 --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json @@ -0,0 +1,319 @@ +{ + "format_version": "1.2", + "terraform_version": "1.12.2", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "coder_ai_task.a[0]", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "index": 0, + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "sensitive_values": { + "sidebar_app": [ + {} + ] + } + }, + { + "address": "coder_ai_task.b[0]", + "mode": "managed", + "type": "coder_ai_task", + "name": "b", + "index": 0, + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "sensitive_values": { + "sidebar_app": [ + {} + ] + } + } + ] + } + }, + "resource_changes": [ + { + "address": "coder_ai_task.a[0]", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "index": 0, + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "after_unknown": { + "id": true, + "sidebar_app": [ + {} + ] + }, + "before_sensitive": false, + "after_sensitive": { + "sidebar_app": [ + {} + ] + } + } + }, + { + "address": "coder_ai_task.b[0]", + "mode": "managed", + "type": "coder_ai_task", + "name": "b", + "index": 0, + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "after_unknown": { + "id": true, + "sidebar_app": [ + {} + ] + }, + "before_sensitive": false, + "after_sensitive": { + "sidebar_app": [ + {} + ] + } + } + } + ], + "prior_state": { + "format_version": "1.0", + "terraform_version": "1.12.2", + "values": { + "root_module": { + "resources": [ + { + "address": "data.coder_parameter.prompt", + "mode": "data", + "type": "coder_parameter", + "name": "prompt", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "default": null, + "description": null, + "display_name": null, + "ephemeral": false, + "form_type": "input", + "icon": null, + "id": "f9502ef2-226e-49a6-8831-99a74f8415e7", + "mutable": false, + "name": "AI Prompt", + "option": null, + "optional": false, + "order": null, + "styling": "{}", + "type": "string", + "validation": [], + "value": "" + }, + "sensitive_values": { + "validation": [] + } + }, + { + "address": "data.coder_provisioner.me", + "mode": "data", + "type": "coder_provisioner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "id": "6b538d81-f0db-4e2b-8d85-4b87a1563d89", + "os": "linux" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace.me", + "mode": "data", + "type": "coder_workspace", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "access_port": 443, + "access_url": "https://dev.coder.com/", + "id": "344575c1-55b9-43bb-89b5-35f547e2cf08", + "is_prebuild": false, + "is_prebuild_claim": false, + "name": "sebenza-nonix", + "prebuild_count": 0, + "start_count": 1, + "template_id": "", + "template_name": "", + "template_version": "", + "transition": "start" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace_owner.me", + "mode": "data", + "type": "coder_workspace_owner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 0, + "values": { + "email": "default@example.com", + "full_name": "default", + "groups": [], + "id": "acb465b5-2709-4392-9486-4ad6eb1c06e0", + "login_type": null, + "name": "default", + "oidc_access_token": "", + "rbac_roles": [], + "session_token": "", + "ssh_private_key": "", + "ssh_public_key": "" + }, + "sensitive_values": { + "groups": [], + "rbac_roles": [], + "ssh_private_key": true + } + } + ] + } + } + }, + "configuration": { + "provider_config": { + "coder": { + "name": "coder", + "full_name": "registry.terraform.io/coder/coder", + "version_constraint": ">= 2.5.0" + } + }, + "root_module": { + "resources": [ + { + "address": "coder_ai_task.a", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "provider_config_key": "coder", + "expressions": { + "sidebar_app": [ + { + "id": { + "constant_value": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + } + ] + }, + "schema_version": 1, + "count_expression": { + "constant_value": 1 + } + }, + { + "address": "coder_ai_task.b", + "mode": "managed", + "type": "coder_ai_task", + "name": "b", + "provider_config_key": "coder", + "expressions": { + "sidebar_app": [ + { + "id": { + "constant_value": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + } + ] + }, + "schema_version": 1, + "count_expression": { + "constant_value": 1 + } + }, + { + "address": "data.coder_parameter.prompt", + "mode": "data", + "type": "coder_parameter", + "name": "prompt", + "provider_config_key": "coder", + "expressions": { + "name": { + "constant_value": "AI Prompt" + }, + "type": { + "constant_value": "string" + } + }, + "schema_version": 1 + }, + { + "address": "data.coder_provisioner.me", + "mode": "data", + "type": "coder_provisioner", + "name": "me", + "provider_config_key": "coder", + "schema_version": 1 + }, + { + "address": "data.coder_workspace.me", + "mode": "data", + "type": "coder_workspace", + "name": "me", + "provider_config_key": "coder", + "schema_version": 1 + }, + { + "address": "data.coder_workspace_owner.me", + "mode": "data", + "type": "coder_workspace_owner", + "name": "me", + "provider_config_key": "coder", + "schema_version": 0 + } + ] + } + }, + "timestamp": "2025-06-19T14:30:00Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.dot b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.dot new file mode 100644 index 0000000000000..4e660599e7a9b --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.dot @@ -0,0 +1,26 @@ +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] coder_ai_task.a (expand)" [label = "coder_ai_task.a", shape = "box"] + "[root] coder_ai_task.b (expand)" [label = "coder_ai_task.b", shape = "box"] + "[root] data.coder_parameter.prompt (expand)" [label = "data.coder_parameter.prompt", shape = "box"] + "[root] data.coder_provisioner.me (expand)" [label = "data.coder_provisioner.me", shape = "box"] + "[root] data.coder_workspace.me (expand)" [label = "data.coder_workspace.me", shape = "box"] + "[root] data.coder_workspace_owner.me (expand)" [label = "data.coder_workspace_owner.me", shape = "box"] + "[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"] + "[root] coder_ai_task.a (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] coder_ai_task.b (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_parameter.prompt (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_provisioner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] data.coder_workspace_owner.me (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_ai_task.a (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_ai_task.b (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_parameter.prompt (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_provisioner.me (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace.me (expand)" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] data.coder_workspace_owner.me (expand)" + "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" + } +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.json b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.json new file mode 100644 index 0000000000000..8eb9ccecd7636 --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfstate.json @@ -0,0 +1,146 @@ +{ + "format_version": "1.0", + "terraform_version": "1.12.2", + "values": { + "root_module": { + "resources": [ + { + "address": "data.coder_parameter.prompt", + "mode": "data", + "type": "coder_parameter", + "name": "prompt", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "default": null, + "description": null, + "display_name": null, + "ephemeral": false, + "form_type": "input", + "icon": null, + "id": "d3c415c0-c6bc-42e3-806e-8c792a7e7b3b", + "mutable": false, + "name": "AI Prompt", + "option": null, + "optional": false, + "order": null, + "styling": "{}", + "type": "string", + "validation": [], + "value": "" + }, + "sensitive_values": { + "validation": [] + } + }, + { + "address": "data.coder_provisioner.me", + "mode": "data", + "type": "coder_provisioner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "id": "764f8b0b-d931-4356-b1a8-446fa95fbeb0", + "os": "linux" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace.me", + "mode": "data", + "type": "coder_workspace", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "access_port": 443, + "access_url": "https://dev.coder.com/", + "id": "b6713709-6736-4d2f-b3da-7b5b242df5f4", + "is_prebuild": false, + "is_prebuild_claim": false, + "name": "sebenza-nonix", + "prebuild_count": 0, + "start_count": 1, + "template_id": "", + "template_name": "", + "template_version": "", + "transition": "start" + }, + "sensitive_values": {} + }, + { + "address": "data.coder_workspace_owner.me", + "mode": "data", + "type": "coder_workspace_owner", + "name": "me", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 0, + "values": { + "email": "default@example.com", + "full_name": "default", + "groups": [], + "id": "0cc15fa2-24fc-4249-bdc7-56cf0af0f782", + "login_type": null, + "name": "default", + "oidc_access_token": "", + "rbac_roles": [], + "session_token": "", + "ssh_private_key": "", + "ssh_public_key": "" + }, + "sensitive_values": { + "groups": [], + "rbac_roles": [], + "ssh_private_key": true + } + }, + { + "address": "coder_ai_task.a[0]", + "mode": "managed", + "type": "coder_ai_task", + "name": "a", + "index": 0, + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "id": "89e6ab36-2e98-4d13-9b4c-69b7588b7e1d", + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "sensitive_values": { + "sidebar_app": [ + {} + ] + } + }, + { + "address": "coder_ai_task.b[0]", + "mode": "managed", + "type": "coder_ai_task", + "name": "b", + "index": 0, + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "id": "d4643699-519d-44c8-a878-556789256cbd", + "sidebar_app": [ + { + "id": "5ece4674-dd35-4f16-88c8-82e40e72e2fd" + } + ] + }, + "sensitive_values": { + "sidebar_app": [ + {} + ] + } + } + ] + } + } +} diff --git a/provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf b/provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf new file mode 100644 index 0000000000000..a54a218929312 --- /dev/null +++ b/provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf @@ -0,0 +1,31 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = ">=2.5.0" + } + } +} + +data "coder_provisioner" "me" {} +data "coder_workspace" "me" {} +data "coder_workspace_owner" "me" {} + +data "coder_parameter" "prompt" { + name = "AI Prompt" + type = "string" +} + +resource "coder_ai_task" "a" { + count = 1 + sidebar_app { + id = "5ece4674-dd35-4f16-88c8-82e40e72e2fd" # fake ID to satisfy requirement, irrelevant otherwise + } +} + +resource "coder_ai_task" "b" { + count = 1 + sidebar_app { + id = "5ece4674-dd35-4f16-88c8-82e40e72e2fd" # fake ID to satisfy requirement, irrelevant otherwise + } +} diff --git a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json index 18ccfa17a86fc..696a7ee61f2c2 100644 --- a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json +++ b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_external_auth", "name": "github", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "access_token": "", "id": "github", @@ -144,7 +144,7 @@ "type": "coder_external_auth", "name": "gitlab", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "access_token": "", "id": "gitlab", @@ -208,7 +208,7 @@ "constant_value": "github" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_external_auth.gitlab", @@ -224,7 +224,7 @@ "constant_value": true } }, - "schema_version": 0 + "schema_version": 1 } ] } diff --git a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json index afe4bd90fb722..35e407dff4667 100644 --- a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json +++ b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_external_auth", "name": "github", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "access_token": "", "id": "github", @@ -24,7 +24,7 @@ "type": "coder_external_auth", "name": "gitlab", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "access_token": "", "id": "gitlab", diff --git a/provisioner/terraform/testdata/resources/presets/presets.tfplan.json b/provisioner/terraform/testdata/resources/presets/presets.tfplan.json index f98b90d073439..cf59bd2b2e38c 100644 --- a/provisioner/terraform/testdata/resources/presets/presets.tfplan.json +++ b/provisioner/terraform/testdata/resources/presets/presets.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ok", "description": "blah blah", @@ -159,7 +159,7 @@ "type": "coder_workspace_preset", "name": "MyFirstProject", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "id": "My First Project", "name": "My First Project", @@ -174,21 +174,7 @@ } ], "instances": 4, - "scheduling": [ - { - "schedule": [ - { - "cron": "* 8-18 * * 1-5", - "instances": 3 - }, - { - "cron": "* 8-14 * * 6", - "instances": 1 - } - ], - "timezone": "America/Los_Angeles" - } - ] + "scheduling": [] } ] }, @@ -199,14 +185,7 @@ "expiration_policy": [ {} ], - "scheduling": [ - { - "schedule": [ - {}, - {} - ] - } - ] + "scheduling": [] } ] } @@ -221,7 +200,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from module", @@ -250,7 +229,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -284,7 +263,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -313,7 +292,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from child module", @@ -412,7 +391,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_workspace_preset.MyFirstProject", @@ -441,36 +420,11 @@ ], "instances": { "constant_value": 4 - }, - "scheduling": [ - { - "schedule": [ - { - "cron": { - "constant_value": "* 8-18 * * 1-5" - }, - "instances": { - "constant_value": 3 - } - }, - { - "cron": { - "constant_value": "* 8-14 * * 6" - }, - "instances": { - "constant_value": 1 - } - } - ], - "timezone": { - "constant_value": "America/Los_Angeles" - } - } - ] + } } ] }, - "schema_version": 0 + "schema_version": 1 } ], "module_calls": { @@ -501,7 +455,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.second_parameter_from_module", @@ -526,7 +480,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 } ], "module_calls": { @@ -557,7 +511,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.child_second_parameter_from_module", @@ -582,7 +536,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 } ] } diff --git a/provisioner/terraform/testdata/resources/presets/presets.tfstate.json b/provisioner/terraform/testdata/resources/presets/presets.tfstate.json index f5dae972c774d..9ec09ecab6466 100644 --- a/provisioner/terraform/testdata/resources/presets/presets.tfstate.json +++ b/provisioner/terraform/testdata/resources/presets/presets.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ok", "description": "blah blah", @@ -39,7 +39,7 @@ "type": "coder_workspace_preset", "name": "MyFirstProject", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "id": "My First Project", "name": "My First Project", @@ -54,21 +54,7 @@ } ], "instances": 4, - "scheduling": [ - { - "schedule": [ - { - "cron": "* 8-18 * * 1-5", - "instances": 3 - }, - { - "cron": "* 8-14 * * 6", - "instances": 1 - } - ], - "timezone": "America/Los_Angeles" - } - ] + "scheduling": [] } ] }, @@ -79,14 +65,7 @@ "expiration_policy": [ {} ], - "scheduling": [ - { - "schedule": [ - {}, - {} - ] - } - ] + "scheduling": [] } ] } @@ -162,7 +141,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from module", @@ -191,7 +170,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -225,7 +204,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -254,7 +233,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from child module", diff --git a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json index 55226481d34b5..14b5d186fa93a 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": null, "description": null, @@ -159,7 +159,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ok", "description": "blah blah", @@ -244,7 +244,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.sample", @@ -269,7 +269,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 } ] } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json index 58b0950e84d73..c44de8192d7f9 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": null, "description": null, @@ -39,7 +39,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ok", "description": "blah blah", diff --git a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json index 54e4e33c826c3..19c8ca91656f2 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -159,7 +159,7 @@ "type": "coder_parameter", "name": "number_example_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -200,7 +200,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "-3", "description": null, @@ -241,7 +241,7 @@ "type": "coder_parameter", "name": "number_example_min", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -282,7 +282,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -323,7 +323,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -426,7 +426,7 @@ "constant_value": "number" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_max", @@ -452,7 +452,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_max_zero", @@ -478,7 +478,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_min", @@ -504,7 +504,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_min_max", @@ -533,7 +533,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_min_zero", @@ -559,7 +559,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 } ] } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json index 2c718e2b48b21..d7a0d3ce03ddb 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -39,7 +39,7 @@ "type": "coder_parameter", "name": "number_example_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -80,7 +80,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "-3", "description": null, @@ -121,7 +121,7 @@ "type": "coder_parameter", "name": "number_example_min", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -162,7 +162,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -203,7 +203,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, diff --git a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json index 66151089fb40a..bfd6afb3bbd82 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json +++ b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": null, "description": null, @@ -176,7 +176,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -205,7 +205,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "-2", "description": null, @@ -246,7 +246,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -287,7 +287,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -328,7 +328,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ok", "description": "blah blah", @@ -361,7 +361,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from module", @@ -390,7 +390,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -424,7 +424,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -453,7 +453,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from child module", @@ -564,7 +564,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example", @@ -583,7 +583,7 @@ "constant_value": "number" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_max_zero", @@ -612,7 +612,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_min_max", @@ -641,7 +641,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.number_example_min_zero", @@ -670,7 +670,7 @@ } ] }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.sample", @@ -692,7 +692,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 } ], "module_calls": { @@ -723,7 +723,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.second_parameter_from_module", @@ -748,7 +748,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 } ], "module_calls": { @@ -779,7 +779,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "data.coder_parameter.child_second_parameter_from_module", @@ -804,7 +804,7 @@ "constant_value": "string" } }, - "schema_version": 0 + "schema_version": 1 } ] } diff --git a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json index 3c1725721d774..5e1b0c1fc8884 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json +++ b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": null, "description": null, @@ -56,7 +56,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -85,7 +85,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "-2", "description": null, @@ -126,7 +126,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -167,7 +167,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "4", "description": null, @@ -208,7 +208,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ok", "description": "blah blah", @@ -302,7 +302,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from module", @@ -331,7 +331,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -365,7 +365,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -394,7 +394,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "default": "ghijkl", "description": "Second parameter from child module", diff --git a/provisioner/terraform/testdata/resources/version.txt b/provisioner/terraform/testdata/resources/version.txt index 3d0e62313ced1..6b89d58f861a7 100644 --- a/provisioner/terraform/testdata/resources/version.txt +++ b/provisioner/terraform/testdata/resources/version.txt @@ -1 +1 @@ -1.11.4 +1.12.2 diff --git a/provisionerd/runner/runner.go b/provisionerd/runner/runner.go index 0fb3696ec509c..b80cf9060b358 100644 --- a/provisionerd/runner/runner.go +++ b/provisionerd/runner/runner.go @@ -7,13 +7,11 @@ import ( "errors" "fmt" "reflect" - "slices" "strings" "sync" "sync/atomic" "time" - "github.com/coder/terraform-provider-coder/v2/provider" "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/attribute" @@ -800,16 +798,6 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters( return nil, xerrors.Errorf("module files hash mismatch, uploaded: %x, expected: %x", moduleFilesUpload.Hash, c.ModuleFilesHash) } } - - if c.HasAiTasks { - hasPromptParam := slices.ContainsFunc(c.Parameters, func(param *sdkproto.RichParameter) bool { - return param.Name == provider.TaskPromptParameterName - }) - if !hasPromptParam { - return nil, xerrors.Errorf("coder_parameter named '%s' is required when 'coder_ai_task' resource is defined", provider.TaskPromptParameterName) - } - } - return &templateImportProvision{ Resources: c.Resources, Parameters: c.Parameters, From 57da39f8b8ff541758023fd5c54e234fc1f15028 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 20 Jun 2025 16:56:11 +0200 Subject: [PATCH 08/20] chore: unify tf testdata versions & fix tests Signed-off-by: Danny Kopping --- .../ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json | 2 +- .../testdata/resources/ai-tasks-missing-prompt/main.tf | 2 +- .../resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json | 2 +- .../terraform/testdata/resources/ai-tasks-multiple/main.tf | 2 +- .../testdata/resources/calling-module/calling-module.tf | 2 +- .../testdata/resources/chaining-resources/chaining-resources.tf | 2 +- .../resources/conflicting-resources/conflicting-resources.tf | 2 +- .../terraform/testdata/resources/devcontainer/devcontainer.tf | 2 +- .../resources/display-apps-disabled/display-apps-disabled.tf | 2 +- .../terraform/testdata/resources/display-apps/display-apps.tf | 2 +- .../external-auth-providers/external-auth-providers.tf | 2 +- .../terraform/testdata/resources/instance-id/instance-id.tf | 2 +- .../resources/kubernetes-metadata/kubernetes-metadata.tf | 2 +- .../terraform/testdata/resources/mapped-apps/mapped-apps.tf | 2 +- .../multiple-agents-multiple-apps.tf | 2 +- .../multiple-agents-multiple-envs.tf | 2 +- .../multiple-agents-multiple-monitors.tf | 2 +- .../multiple-agents-multiple-monitors.tfplan.json | 2 +- .../multiple-agents-multiple-scripts.tf | 2 +- .../testdata/resources/multiple-agents/multiple-agents.tf | 2 +- .../terraform/testdata/resources/multiple-apps/multiple-apps.tf | 2 +- .../presets/external-module/child-external-module/main.tf | 2 +- .../testdata/resources/presets/external-module/main.tf | 2 +- provisioner/terraform/testdata/resources/presets/presets.tf | 2 +- .../terraform/testdata/resources/presets/presets.tfplan.json | 2 +- .../resource-metadata-duplicate/resource-metadata-duplicate.tf | 2 +- .../testdata/resources/resource-metadata/resource-metadata.tf | 2 +- .../resources/rich-parameters-order/rich-parameters-order.tf | 2 +- .../rich-parameters-validation/rich-parameters-validation.tf | 2 +- .../external-module/child-external-module/main.tf | 2 +- .../testdata/resources/rich-parameters/external-module/main.tf | 2 +- .../testdata/resources/rich-parameters/rich-parameters.tf | 2 +- 32 files changed, 32 insertions(+), 32 deletions(-) diff --git a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json index df772e18ecb6b..ad255c7db7624 100644 --- a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json +++ b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/ai-tasks-missing-prompt.tfplan.json @@ -215,7 +215,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": ">= 2.5.0" + "version_constraint": ">= 2.0.0" } }, "root_module": { diff --git a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf index 0b53740fef94f..236baa1c9535b 100644 --- a/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf +++ b/provisioner/terraform/testdata/resources/ai-tasks-missing-prompt/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.5.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json index d42a0714d0f33..c9f8fded6c192 100644 --- a/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json +++ b/provisioner/terraform/testdata/resources/ai-tasks-multiple/ai-tasks-multiple.tfplan.json @@ -224,7 +224,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": ">= 2.5.0" + "version_constraint": ">= 2.0.0" } }, "root_module": { diff --git a/provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf b/provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf index a54a218929312..6c15ee4dc5a69 100644 --- a/provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf +++ b/provisioner/terraform/testdata/resources/ai-tasks-multiple/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.5.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/calling-module/calling-module.tf b/provisioner/terraform/testdata/resources/calling-module/calling-module.tf index 33fcbb3f1984f..a24b4ab010b19 100644 --- a/provisioner/terraform/testdata/resources/calling-module/calling-module.tf +++ b/provisioner/terraform/testdata/resources/calling-module/calling-module.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf b/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf index 6ad44a62de986..6f37a90f35409 100644 --- a/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf +++ b/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf b/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf index 86585b6a85357..afcf6841c0c94 100644 --- a/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf +++ b/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf b/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf index c611ad4001f04..4a0e4c9d58857 100644 --- a/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf +++ b/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf b/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf index 155b81889540e..8021186a98453 100644 --- a/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf +++ b/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/display-apps/display-apps.tf b/provisioner/terraform/testdata/resources/display-apps/display-apps.tf index 3544ab535ad2f..8be6eddaed622 100644 --- a/provisioner/terraform/testdata/resources/display-apps/display-apps.tf +++ b/provisioner/terraform/testdata/resources/display-apps/display-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf index 5f45a88aacb6a..cf56fbcf3e804 100644 --- a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf +++ b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/instance-id/instance-id.tf b/provisioner/terraform/testdata/resources/instance-id/instance-id.tf index 84e010a79d6e9..8f1939fe62a69 100644 --- a/provisioner/terraform/testdata/resources/instance-id/instance-id.tf +++ b/provisioner/terraform/testdata/resources/instance-id/instance-id.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf b/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf index faa08706de380..86751fec0a841 100644 --- a/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf +++ b/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } kubernetes = { source = "hashicorp/kubernetes" diff --git a/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf b/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf index 7664ead2b4962..16fd128b3d074 100644 --- a/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf +++ b/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf index 8ac412b5b3894..064ac4f44e0a3 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf index e12a895d14baa..10ed541b3992b 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf index f86ceb180edb5..9bbab0776c514 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "2.2.0-pre0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json index ae850f57d1369..2680c4ce34f9d 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json @@ -456,7 +456,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "2.2.0-pre0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf index c0aee0d2d97e5..021db79668e96 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf b/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf index b9187beb93acf..306ec1597f042 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf b/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf index c52f4a58b36f4..b5229bb6f488f 100644 --- a/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf +++ b/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf b/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf index 395f766d48c4c..b7f71bcc3d29b 100644 --- a/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf +++ b/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "2.3.0-pre2" + version = ">= 2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/presets/external-module/main.tf b/provisioner/terraform/testdata/resources/presets/external-module/main.tf index bdfd29c301c06..00997ec835d48 100644 --- a/provisioner/terraform/testdata/resources/presets/external-module/main.tf +++ b/provisioner/terraform/testdata/resources/presets/external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "2.3.0-pre2" + version = ">= 2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/presets/presets.tf b/provisioner/terraform/testdata/resources/presets/presets.tf index ff0db7d924d86..eb9ae6a92b6c8 100644 --- a/provisioner/terraform/testdata/resources/presets/presets.tf +++ b/provisioner/terraform/testdata/resources/presets/presets.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "2.3.0-pre2" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/presets/presets.tfplan.json b/provisioner/terraform/testdata/resources/presets/presets.tfplan.json index cf59bd2b2e38c..8b1ad87592b53 100644 --- a/provisioner/terraform/testdata/resources/presets/presets.tfplan.json +++ b/provisioner/terraform/testdata/resources/presets/presets.tfplan.json @@ -329,7 +329,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "2.3.0-pre2" + "version_constraint": ">= 2.0.0" }, "module.this_is_external_module:docker": { "name": "docker", diff --git a/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf b/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf index b88a672f0047a..1ca31e2a41cc0 100644 --- a/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf +++ b/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf b/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf index eb9f2eff89877..cda7cfbd20e25 100644 --- a/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf +++ b/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf index fc684a6e583ee..23e9c2ba75ebe 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf index 8067c0fa9337c..7e59bcfbde974 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf b/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf index e8afbbf917fb5..b7f71bcc3d29b 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf b/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf index 0cf81d0162d07..00997ec835d48 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf index 24582eac30a5d..c271cd39ea6e6 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">=2.0.0" + version = ">= 2.0.0" } } } From c6c7b5c17d5334c5b6f2e2ff8ef2af8f0f2becfc Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 20 Jun 2025 17:12:15 +0200 Subject: [PATCH 09/20] chore: dbauthz Signed-off-by: Danny Kopping --- coderd/database/dbauthz/dbauthz.go | 13 ++++++- coderd/database/dbauthz/dbauthz_test.go | 52 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 03c42c19c6028..f328215808f28 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -4914,7 +4914,18 @@ func (q *querier) UpdateWorkspaceAutostart(ctx context.Context, arg database.Upd } func (q *querier) UpdateWorkspaceBuildAITaskByID(ctx context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error { - if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil { + build, err := q.db.GetWorkspaceBuildByID(ctx, arg.ID) + if err != nil { + return err + } + + workspace, err := q.db.GetWorkspaceByID(ctx, build.WorkspaceID) + if err != nil { + return err + } + + err = q.authorizeContext(ctx, policy.ActionUpdate, workspace.RBACObject()) + if err != nil { return err } return q.db.UpdateWorkspaceBuildAITaskByID(ctx, arg) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 0ccd867040116..785ed85179a6e 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1391,6 +1391,24 @@ func (s *MethodTestSuite) TestTemplate() { ID: t1.ID, }).Asserts(t1, policy.ActionUpdate) })) + s.Run("UpdateTemplateVersionAITaskByJobID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + o := dbgen.Organization(s.T(), db, database.Organization{}) + u := dbgen.User(s.T(), db, database.User{}) + _ = dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{OrganizationID: o.ID, UserID: u.ID}) + t := dbgen.Template(s.T(), db, database.Template{OrganizationID: o.ID, CreatedBy: u.ID}) + job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{OrganizationID: o.ID}) + _ = dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + OrganizationID: o.ID, + CreatedBy: u.ID, + JobID: job.ID, + TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true}, + }) + check.Args(database.UpdateTemplateVersionAITaskByJobIDParams{ + JobID: job.ID, + HasAITask: sql.NullBool{Bool: true, Valid: true}, + }).Asserts(t, policy.ActionUpdate) + })) s.Run("UpdateTemplateWorkspacesLastUsedAt", s.Subtest(func(db database.Store, check *expects) { dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) @@ -3050,6 +3068,40 @@ func (s *MethodTestSuite) TestWorkspace() { Deadline: b.Deadline, }).Asserts(w, policy.ActionUpdate) })) + s.Run("UpdateWorkspaceBuildAITaskByID", s.Subtest(func(db database.Store, check *expects) { + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) + agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) + app := dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{AgentID: agt.ID}) + check.Args(database.UpdateWorkspaceBuildAITaskByIDParams{ + HasAITask: sql.NullBool{Bool: true, Valid: true}, + SidebarAppID: uuid.NullUUID{UUID: app.ID, Valid: true}, + ID: b.ID, + }).Asserts(w, policy.ActionUpdate) + })) s.Run("SoftDeleteWorkspaceByID", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) o := dbgen.Organization(s.T(), db, database.Organization{}) From 4816ed5b60b503cce26759deb722ecbe14f82529 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 20 Jun 2025 19:27:04 +0200 Subject: [PATCH 10/20] chore: fix TestWorkspaceAgentAppHealth test after agent ID field now required Signed-off-by: Danny Kopping --- coderd/workspaceagents_test.go | 62 +++++++++++++++++++++------------- go.sum | 1 + 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index b3fb53c228ef8..b946b655bf345 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -2,6 +2,7 @@ package coderd_test import ( "context" + "database/sql" "encoding/json" "fmt" "maps" @@ -1506,39 +1507,52 @@ func TestWorkspaceAgentAppHealth(t *testing.T) { t.Parallel() client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - apps := []*proto.App{ - { - Slug: "code-server", - Command: "some-command", - Url: "http://localhost:3000", - Icon: "/code.svg", - }, - { - Slug: "code-server-2", - DisplayName: "code-server-2", - Command: "some-command", - Url: "http://localhost:3000", - Icon: "/code.svg", - Healthcheck: &proto.Healthcheck{ - Url: "http://localhost:3000", - Interval: 5, - Threshold: 6, - }, - }, - } + + // When using WithAgent() here and setting some *proto.App instances on the agent, Do() ends up trying to insert duplicate records. r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, - }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { - agents[0].Apps = apps - return agents }).Do() + res := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{JobID: r.Build.JobID}) + agent := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{ResourceID: res.ID}) + + // It's simpler to call db.InsertWorkspaceApp directly than dbgen.WorkspaceApp because it's more terse and direct; + // the latter sets a bunch of defaults which make this test hard. + _, err := db.InsertWorkspaceApp(dbauthz.AsSystemRestricted(t.Context()), database.InsertWorkspaceAppParams{ + ID: uuid.New(), + Slug: "code-server", + AgentID: agent.ID, + Icon: "/code.svg", + Command: sql.NullString{String: "some-command", Valid: true}, + Url: sql.NullString{String: "http://localhost:3000", Valid: true}, + SharingLevel: database.AppSharingLevelOwner, + Health: database.WorkspaceAppHealthDisabled, + OpenIn: database.WorkspaceAppOpenInWindow, + }) + require.NoError(t, err) + _, err = db.InsertWorkspaceApp(dbauthz.AsSystemRestricted(t.Context()), database.InsertWorkspaceAppParams{ + ID: uuid.New(), + Slug: "code-server-2", + DisplayName: "code-server-2", + AgentID: agent.ID, + Icon: "/code.svg", + Command: sql.NullString{String: "some-command", Valid: true}, + Url: sql.NullString{String: "http://localhost:3000", Valid: true}, + HealthcheckInterval: 5, + HealthcheckUrl: "http://localhost:3000", + HealthcheckThreshold: 6, + Health: database.WorkspaceAppHealthInitializing, + SharingLevel: database.AppSharingLevelOwner, + OpenIn: database.WorkspaceAppOpenInWindow, + }) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() agentClient := agentsdk.New(client.URL) - agentClient.SetSessionToken(r.AgentToken) + agentClient.SetSessionToken(agent.AuthToken.String()) conn, err := agentClient.ConnectRPC(ctx) require.NoError(t, err) defer func() { diff --git a/go.sum b/go.sum index ee7587bfdd7b1..1e38ca19bd0fb 100644 --- a/go.sum +++ b/go.sum @@ -928,6 +928,7 @@ github.com/coder/tailscale v1.1.1-0.20250611020837-f14d20d23d8c h1:d/qBIi3Ez7Kko github.com/coder/tailscale v1.1.1-0.20250611020837-f14d20d23d8c/go.mod h1:l7ml5uu7lFh5hY28lGYM4b/oFSmuPHYX6uk4RAu23Lc= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e h1:JNLPDi2P73laR1oAclY6jWzAbucf70ASAvf5mh2cME0= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI= +github.com/coder/terraform-provider-coder/v2 v2.5.4-0.20250619093524-d9b0f892f9c2/go.mod h1:WrdLSbihuzH1RZhwrU+qmkqEhUbdZT/sjHHdarm5b5g= github.com/coder/terraform-provider-coder/v2 v2.6.0 h1:ybSVxkblpFdanNX7hibex41yvwjswUlA3RPh4BAHjBI= github.com/coder/terraform-provider-coder/v2 v2.6.0/go.mod h1:WrdLSbihuzH1RZhwrU+qmkqEhUbdZT/sjHHdarm5b5g= github.com/coder/trivy v0.0.0-20250527170238-9416a59d7019 h1:MHkv/W7l9eRAN9gOG0qZ1TLRGWIIfNi92273vPAQ8Fs= From e48df2ebad8df16623ddd4f6833ba8728f2b310a Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 20 Jun 2025 19:31:00 +0200 Subject: [PATCH 11/20] chore: add tests Signed-off-by: Danny Kopping # Conflicts: # go.sum --- coderd/database/dbmem/dbmem.go | 1 + .../provisionerdserver_test.go | 290 ++++++++++++++++++ go.mod | 5 +- go.sum | 5 +- provisioner/terraform/provision_test.go | 91 ++++++ provisioner/terraform/resources_test.go | 3 +- 6 files changed, 387 insertions(+), 8 deletions(-) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 1ae6531f07b9e..8a7e2aec661d8 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -12075,6 +12075,7 @@ func (q *FakeQuerier) UpdateWorkspaceBuildAITaskByID(_ context.Context, arg data continue } workspaceBuild.HasAITask = arg.HasAITask + workspaceBuild.AITaskSidebarAppID = arg.SidebarAppID workspaceBuild.UpdatedAt = dbtime.Now() q.workspaceBuilds[index] = workspaceBuild return nil diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index dfa767b297f4c..0928f44dee6e2 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -1564,6 +1564,69 @@ func TestCompleteJob(t *testing.T) { require.Contains(t, job.Error.String, `external auth provider "github" is not configured`) }) + t.Run("TemplateImport_WithAITasks", func(t *testing.T) { + t.Parallel() + + t.Run("WithoutPromptParam", func(t *testing.T) { + t.Parallel() + + srv, db, _, pd := setup(t, false, &overrides{}) + jobID := uuid.New() + versionID := uuid.New() + err := db.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ + ID: versionID, + JobID: jobID, + OrganizationID: pd.OrganizationID, + }) + require.NoError(t, err) + job, err := db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ + ID: jobID, + Provisioner: database.ProvisionerTypeEcho, + Input: []byte(`{"template_version_id": "` + versionID.String() + `"}`), + StorageMethod: database.ProvisionerStorageMethodFile, + Type: database.ProvisionerJobTypeWorkspaceBuild, + OrganizationID: pd.OrganizationID, + Tags: pd.Tags, + }) + require.NoError(t, err) + _, err = db.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{ + OrganizationID: pd.OrganizationID, + WorkerID: uuid.NullUUID{ + UUID: pd.ID, + Valid: true, + }, + Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, + StartedAt: sql.NullTime{ + Time: dbtime.Now(), + Valid: true, + }, + ProvisionerTags: must(json.Marshal(job.Tags)), + }) + require.NoError(t, err) + completeJob := func() { + _, err = srv.CompleteJob(ctx, &proto.CompletedJob{ + JobId: job.ID.String(), + Type: &proto.CompletedJob_TemplateImport_{ + TemplateImport: &proto.CompletedJob_TemplateImport{ + StartResources: []*sdkproto.Resource{{ + Name: "my_task", + Type: "coder_ai_task", + }}, + StopResources: []*sdkproto.Resource{}, + HasAiTasks: true, + Plan: []byte("{}"), + }, + }, + }) + require.NoError(t, err) + } + completeJob() + job, err = db.GetProvisionerJobByID(ctx, job.ID) + require.NoError(t, err) + require.Contains(t, job.Error.String, `external auth provider "github" is not configured`) + }) + }) + t.Run("TemplateImport_WithGitAuth", func(t *testing.T) { t.Parallel() srv, db, _, pd := setup(t, false, &overrides{ @@ -2435,6 +2498,233 @@ func TestCompleteJob(t *testing.T) { testutil.RequireReceive(ctx, t, done) require.Equal(t, replacements, orchestrator.replacements) }) + + t.Run("AITasks", func(t *testing.T) { + t.Parallel() + + // has_ai_task has a default value of nil, but once the template import completes it will have a value; + // it is set to "true" if the template has any coder_ai_task resources defined. + t.Run("TemplateImport", func(t *testing.T) { + type testcase struct { + name string + input *proto.CompletedJob_TemplateImport + expected bool + } + + for _, tc := range []testcase{ + { + name: "has_ai_task is false by default", + input: &proto.CompletedJob_TemplateImport{ + // HasAiTasks is not set. + Plan: []byte("{}"), + }, + expected: false, + }, + { + name: "has_ai_task gets set to true", + input: &proto.CompletedJob_TemplateImport{ + HasAiTasks: true, + Plan: []byte("{}"), + }, + expected: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + srv, db, _, pd := setup(t, false, &overrides{}) + + importJobID := uuid.New() + tvID := uuid.New() + template := dbgen.Template(t, db, database.Template{ + Name: "template", + Provisioner: database.ProvisionerTypeEcho, + OrganizationID: pd.OrganizationID, + }) + version := dbgen.TemplateVersion(t, db, database.TemplateVersion{ + ID: tvID, + OrganizationID: pd.OrganizationID, + TemplateID: uuid.NullUUID{ + UUID: template.ID, + Valid: true, + }, + JobID: importJobID, + }) + _ = version + + ctx := testutil.Context(t, testutil.WaitShort) + job, err := db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ + ID: importJobID, + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + OrganizationID: pd.OrganizationID, + InitiatorID: uuid.New(), + Input: must(json.Marshal(provisionerdserver.TemplateVersionImportJob{ + TemplateVersionID: tvID, + })), + Provisioner: database.ProvisionerTypeEcho, + StorageMethod: database.ProvisionerStorageMethodFile, + Type: database.ProvisionerJobTypeTemplateVersionImport, + Tags: pd.Tags, + }) + require.NoError(t, err) + + _, err = db.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{ + OrganizationID: pd.OrganizationID, + WorkerID: uuid.NullUUID{ + UUID: pd.ID, + Valid: true, + }, + Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, + ProvisionerTags: must(json.Marshal(job.Tags)), + StartedAt: sql.NullTime{Time: job.CreatedAt, Valid: true}, + }) + require.NoError(t, err) + + version, err = db.GetTemplateVersionByID(ctx, tvID) + require.NoError(t, err) + require.False(t, version.HasAITask.Valid) // Value should be nil (i.e. valid = false). + + completedJob := proto.CompletedJob{ + JobId: job.ID.String(), + Type: &proto.CompletedJob_TemplateImport_{ + TemplateImport: tc.input, + }, + } + _, err = srv.CompleteJob(ctx, &completedJob) + require.NoError(t, err) + + version, err = db.GetTemplateVersionByID(ctx, tvID) + require.NoError(t, err) + require.True(t, version.HasAITask.Valid) // We ALWAYS expect a value to be set, therefore not nil, i.e. valid = true. + require.Equal(t, tc.expected, version.HasAITask.Bool) + }) + } + }) + + // has_ai_task has a default value of nil, but once the workspace build completes it will have a value; + // it is set to "true" if the related template has any coder_ai_task resources defined, and its sidebar app ID + // will be set as well in that case. + t.Run("WorkspaceBuild", func(t *testing.T) { + type testcase struct { + name string + input *proto.CompletedJob_WorkspaceBuild + expected bool + } + + sidebarAppID := uuid.NewString() + for _, tc := range []testcase{ + { + name: "has_ai_task is false by default", + input: &proto.CompletedJob_WorkspaceBuild{ + // No AiTasks defined. + }, + expected: false, + }, + { + name: "has_ai_task is set to true", + input: &proto.CompletedJob_WorkspaceBuild{ + AiTasks: []*sdkproto.AITask{ + { + Id: uuid.NewString(), + SidebarApp: &sdkproto.AITaskSidebarApp{ + Id: sidebarAppID, + }, + }, + }, + }, + expected: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + srv, db, _, pd := setup(t, false, &overrides{}) + + importJobID := uuid.New() + tvID := uuid.New() + template := dbgen.Template(t, db, database.Template{ + Name: "template", + Provisioner: database.ProvisionerTypeEcho, + OrganizationID: pd.OrganizationID, + }) + version := dbgen.TemplateVersion(t, db, database.TemplateVersion{ + ID: tvID, + OrganizationID: pd.OrganizationID, + TemplateID: uuid.NullUUID{ + UUID: template.ID, + Valid: true, + }, + JobID: importJobID, + }) + user := dbgen.User(t, db, database.User{}) + workspaceTable := dbgen.Workspace(t, db, database.WorkspaceTable{ + TemplateID: template.ID, + OwnerID: user.ID, + OrganizationID: pd.OrganizationID, + }) + build := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ + WorkspaceID: workspaceTable.ID, + TemplateVersionID: version.ID, + InitiatorID: user.ID, + Transition: database.WorkspaceTransitionStart, + }) + + ctx := testutil.Context(t, testutil.WaitShort) + job, err := db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ + ID: importJobID, + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + OrganizationID: pd.OrganizationID, + InitiatorID: uuid.New(), + Input: must(json.Marshal(provisionerdserver.WorkspaceProvisionJob{ + WorkspaceBuildID: build.ID, + LogLevel: "DEBUG", + })), + Provisioner: database.ProvisionerTypeEcho, + StorageMethod: database.ProvisionerStorageMethodFile, + Type: database.ProvisionerJobTypeWorkspaceBuild, + Tags: pd.Tags, + }) + require.NoError(t, err) + + _, err = db.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{ + OrganizationID: pd.OrganizationID, + WorkerID: uuid.NullUUID{ + UUID: pd.ID, + Valid: true, + }, + Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, + ProvisionerTags: must(json.Marshal(job.Tags)), + StartedAt: sql.NullTime{Time: job.CreatedAt, Valid: true}, + }) + require.NoError(t, err) + + build, err = db.GetWorkspaceBuildByID(ctx, build.ID) + require.NoError(t, err) + require.False(t, build.HasAITask.Valid) // Value should be nil (i.e. valid = false). + + completedJob := proto.CompletedJob{ + JobId: job.ID.String(), + Type: &proto.CompletedJob_WorkspaceBuild_{ + WorkspaceBuild: tc.input, + }, + } + _, err = srv.CompleteJob(ctx, &completedJob) + require.NoError(t, err) + + build, err = db.GetWorkspaceBuildByID(ctx, build.ID) + require.NoError(t, err) + require.True(t, build.HasAITask.Valid) // We ALWAYS expect a value to be set, therefore not nil, i.e. valid = true. + require.Equal(t, tc.expected, build.HasAITask.Bool) + + if tc.expected { + require.Equal(t, sidebarAppID, build.AITaskSidebarAppID.UUID.String()) + } + }) + } + }) + }) } type mockPrebuildsOrchestrator struct { diff --git a/go.mod b/go.mod index 84637c5f307de..3bf63f08fafd0 100644 --- a/go.mod +++ b/go.mod @@ -101,7 +101,7 @@ require ( github.com/coder/quartz v0.2.1 github.com/coder/retry v1.5.1 github.com/coder/serpent v0.10.0 - github.com/coder/terraform-provider-coder/v2 v2.6.0 + github.com/coder/terraform-provider-coder/v2 v2.7.0 github.com/coder/websocket v1.8.13 github.com/coder/wgtunnel v0.1.13-0.20240522110300-ade90dfb2da0 github.com/coreos/go-oidc/v3 v3.14.1 @@ -535,6 +535,3 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect ) - -// TODO: replace once new version is cut. -replace github.com/coder/terraform-provider-coder/v2 => github.com/coder/terraform-provider-coder/v2 v2.5.4-0.20250619093524-d9b0f892f9c2 diff --git a/go.sum b/go.sum index 1e38ca19bd0fb..7433167763cc4 100644 --- a/go.sum +++ b/go.sum @@ -928,9 +928,8 @@ github.com/coder/tailscale v1.1.1-0.20250611020837-f14d20d23d8c h1:d/qBIi3Ez7Kko github.com/coder/tailscale v1.1.1-0.20250611020837-f14d20d23d8c/go.mod h1:l7ml5uu7lFh5hY28lGYM4b/oFSmuPHYX6uk4RAu23Lc= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e h1:JNLPDi2P73laR1oAclY6jWzAbucf70ASAvf5mh2cME0= github.com/coder/terraform-config-inspect v0.0.0-20250107175719-6d06d90c630e/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI= -github.com/coder/terraform-provider-coder/v2 v2.5.4-0.20250619093524-d9b0f892f9c2/go.mod h1:WrdLSbihuzH1RZhwrU+qmkqEhUbdZT/sjHHdarm5b5g= -github.com/coder/terraform-provider-coder/v2 v2.6.0 h1:ybSVxkblpFdanNX7hibex41yvwjswUlA3RPh4BAHjBI= -github.com/coder/terraform-provider-coder/v2 v2.6.0/go.mod h1:WrdLSbihuzH1RZhwrU+qmkqEhUbdZT/sjHHdarm5b5g= +github.com/coder/terraform-provider-coder/v2 v2.7.0 h1:0WV89TuboHnoy4J8MwNnCtNjF3Onx2Ny959FC2ClGQg= +github.com/coder/terraform-provider-coder/v2 v2.7.0/go.mod h1:WrdLSbihuzH1RZhwrU+qmkqEhUbdZT/sjHHdarm5b5g= github.com/coder/trivy v0.0.0-20250527170238-9416a59d7019 h1:MHkv/W7l9eRAN9gOG0qZ1TLRGWIIfNi92273vPAQ8Fs= github.com/coder/trivy v0.0.0-20250527170238-9416a59d7019/go.mod h1:eqk+w9RLBmbd/cB5XfPZFuVn77cf/A6fB7qmEVeSmXk= github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index dc4545d137e89..d067965997308 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -23,6 +23,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/coder/terraform-provider-coder/v2/provider" + "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" @@ -1046,6 +1048,93 @@ func TestProvision(t *testing.T) { }}, }, }, + { + Name: "ai-task-required-prompt-param", + Files: map[string]string{ + "main.tf": `terraform { + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.7.0" + } + } + } + resource "coder_ai_task" "a" { + sidebar_app { + id = "7128be08-8722-44cb-bbe1-b5a391c4d94b" # fake ID, irrelevant here anyway but needed for validation + } + } + `, + }, + Request: &proto.PlanRequest{}, + Response: &proto.PlanComplete{ + Error: fmt.Sprintf("plan resources: coder_parameter named '%s' is required when 'coder_ai_task' resource is defined", provider.TaskPromptParameterName), + }, + }, + { + Name: "ai-task-multiple-allowed-in-plan", + Files: map[string]string{ + "main.tf": fmt.Sprintf(`terraform { + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.7.0" + } + } + } + data "coder_parameter" "prompt" { + name = "%s" + type = "string" + } + resource "coder_ai_task" "a" { + sidebar_app { + id = "7128be08-8722-44cb-bbe1-b5a391c4d94b" # fake ID, irrelevant here anyway but needed for validation + } + } + resource "coder_ai_task" "b" { + sidebar_app { + id = "7128be08-8722-44cb-bbe1-b5a391c4d94b" # fake ID, irrelevant here anyway but needed for validation + } + } + `, provider.TaskPromptParameterName), + }, + Request: &proto.PlanRequest{}, + Response: &proto.PlanComplete{ + Resources: []*proto.Resource{ + { + Name: "a", + Type: "coder_ai_task", + }, + { + Name: "b", + Type: "coder_ai_task", + }, + }, + Parameters: []*proto.RichParameter{ + { + Name: provider.TaskPromptParameterName, + Type: "string", + Required: true, + FormType: proto.ParameterFormType_INPUT, + }, + }, + AiTasks: []*proto.AITask{ + { + Id: "a", + SidebarApp: &proto.AITaskSidebarApp{ + Id: "7128be08-8722-44cb-bbe1-b5a391c4d94b", + }, + }, + { + Id: "b", + SidebarApp: &proto.AITaskSidebarApp{ + Id: "7128be08-8722-44cb-bbe1-b5a391c4d94b", + }, + }, + }, + HasAiTasks: true, + }, + }, } // Remove unused cache dirs before running tests. @@ -1146,6 +1235,8 @@ func TestProvision(t *testing.T) { modulesWant, err := json.Marshal(testCase.Response.Modules) require.NoError(t, err) require.Equal(t, string(modulesWant), string(modulesGot)) + + require.Equal(t, planComplete.HasAiTasks, testCase.Response.HasAiTasks) } if testCase.Apply { diff --git a/provisioner/terraform/resources_test.go b/provisioner/terraform/resources_test.go index 4308f554a0a8a..2a40c1374edcd 100644 --- a/provisioner/terraform/resources_test.go +++ b/provisioner/terraform/resources_test.go @@ -11,12 +11,13 @@ import ( "strings" "testing" - "github.com/coder/terraform-provider-coder/v2/provider" "github.com/google/go-cmp/cmp" tfjson "github.com/hashicorp/terraform-json" "github.com/stretchr/testify/require" protobuf "google.golang.org/protobuf/proto" + "github.com/coder/terraform-provider-coder/v2/provider" + "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" From 0b2b732f652753a9f51931375db7b31057aced43 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 11:05:19 +0200 Subject: [PATCH 12/20] chore: correct bad rebase Signed-off-by: Danny Kopping --- cli/testdata/coder_list_--output_json.golden | 3 +- ...1_rename_ai_tasks_sidebar_app_id.down.sql} | 0 ...341_rename_ai_tasks_sidebar_app_id.up.sql} | 0 coderd/database/queries.sql.go | 42 +- coderd/workspacebuilds.go | 4 +- docs/admin/security/audit-logs.md | 2 +- provisionersdk/proto/provisioner.pb.go | 780 +++++++++++------- site/e2e/provisionerGenerated.ts | 49 ++ 8 files changed, 553 insertions(+), 327 deletions(-) rename coderd/database/migrations/{000338_rename_ai_tasks_sidebar_app_id.down.sql => 000341_rename_ai_tasks_sidebar_app_id.down.sql} (100%) rename coderd/database/migrations/{000338_rename_ai_tasks_sidebar_app_id.up.sql => 000341_rename_ai_tasks_sidebar_app_id.up.sql} (100%) diff --git a/cli/testdata/coder_list_--output_json.golden b/cli/testdata/coder_list_--output_json.golden index 5304f2ce262ee..e97894c4afb21 100644 --- a/cli/testdata/coder_list_--output_json.golden +++ b/cli/testdata/coder_list_--output_json.golden @@ -68,7 +68,8 @@ "available": 0, "most_recently_seen": null }, - "template_version_preset_id": null + "template_version_preset_id": null, + "has_ai_task": false }, "latest_app_status": null, "outdated": false, diff --git a/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.down.sql b/coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.down.sql similarity index 100% rename from coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.down.sql rename to coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.down.sql diff --git a/coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.up.sql b/coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.up.sql similarity index 100% rename from coderd/database/migrations/000338_rename_ai_tasks_sidebar_app_id.up.sql rename to coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.up.sql diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index fcfa06d12224b..cc532a1f25125 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -14321,7 +14321,7 @@ const getWorkspaceAgentAndLatestBuildByAuthToken = `-- name: GetWorkspaceAgentAn SELECT workspaces.id, workspaces.created_at, workspaces.updated_at, workspaces.owner_id, workspaces.organization_id, workspaces.template_id, workspaces.deleted, workspaces.name, workspaces.autostart_schedule, workspaces.ttl, workspaces.last_used_at, workspaces.dormant_at, workspaces.deleting_at, workspaces.automatic_updates, workspaces.favorite, workspaces.next_start_at, workspace_agents.id, workspace_agents.created_at, workspace_agents.updated_at, workspace_agents.name, workspace_agents.first_connected_at, workspace_agents.last_connected_at, workspace_agents.disconnected_at, workspace_agents.resource_id, workspace_agents.auth_token, workspace_agents.auth_instance_id, workspace_agents.architecture, workspace_agents.environment_variables, workspace_agents.operating_system, workspace_agents.instance_metadata, workspace_agents.resource_metadata, workspace_agents.directory, workspace_agents.version, workspace_agents.last_connected_replica_id, workspace_agents.connection_timeout_seconds, workspace_agents.troubleshooting_url, workspace_agents.motd_file, workspace_agents.lifecycle_state, workspace_agents.expanded_directory, workspace_agents.logs_length, workspace_agents.logs_overflowed, workspace_agents.started_at, workspace_agents.ready_at, workspace_agents.subsystems, workspace_agents.display_apps, workspace_agents.api_version, workspace_agents.display_order, workspace_agents.parent_id, workspace_agents.api_key_scope, workspace_agents.deleted, - workspace_build_with_user.id, workspace_build_with_user.created_at, workspace_build_with_user.updated_at, workspace_build_with_user.workspace_id, workspace_build_with_user.template_version_id, workspace_build_with_user.build_number, workspace_build_with_user.transition, workspace_build_with_user.initiator_id, workspace_build_with_user.provisioner_state, workspace_build_with_user.job_id, workspace_build_with_user.deadline, workspace_build_with_user.reason, workspace_build_with_user.daily_cost, workspace_build_with_user.max_deadline, workspace_build_with_user.template_version_preset_id, workspace_build_with_user.has_ai_task, workspace_build_with_user.ai_tasks_sidebar_app_id, workspace_build_with_user.initiator_by_avatar_url, workspace_build_with_user.initiator_by_username, workspace_build_with_user.initiator_by_name + workspace_build_with_user.id, workspace_build_with_user.created_at, workspace_build_with_user.updated_at, workspace_build_with_user.workspace_id, workspace_build_with_user.template_version_id, workspace_build_with_user.build_number, workspace_build_with_user.transition, workspace_build_with_user.initiator_id, workspace_build_with_user.provisioner_state, workspace_build_with_user.job_id, workspace_build_with_user.deadline, workspace_build_with_user.reason, workspace_build_with_user.daily_cost, workspace_build_with_user.max_deadline, workspace_build_with_user.template_version_preset_id, workspace_build_with_user.has_ai_task, workspace_build_with_user.ai_task_sidebar_app_id, workspace_build_with_user.initiator_by_avatar_url, workspace_build_with_user.initiator_by_username, workspace_build_with_user.initiator_by_name FROM workspace_agents JOIN @@ -14431,7 +14431,7 @@ func (q *sqlQuerier) GetWorkspaceAgentAndLatestBuildByAuthToken(ctx context.Cont &i.WorkspaceBuild.MaxDeadline, &i.WorkspaceBuild.TemplateVersionPresetID, &i.WorkspaceBuild.HasAITask, - &i.WorkspaceBuild.AITasksSidebarAppID, + &i.WorkspaceBuild.AITaskSidebarAppID, &i.WorkspaceBuild.InitiatorByAvatarUrl, &i.WorkspaceBuild.InitiatorByUsername, &i.WorkspaceBuild.InitiatorByName, @@ -17029,7 +17029,7 @@ func (q *sqlQuerier) InsertWorkspaceBuildParameters(ctx context.Context, arg Ins } const getActiveWorkspaceBuildsByTemplateID = `-- name: GetActiveWorkspaceBuildsByTemplateID :many -SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.ai_tasks_sidebar_app_id, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name +SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.ai_task_sidebar_app_id, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name FROM ( SELECT workspace_id, MAX(build_number) as max_build_number @@ -17085,7 +17085,7 @@ func (q *sqlQuerier) GetActiveWorkspaceBuildsByTemplateID(ctx context.Context, t &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17185,7 +17185,7 @@ func (q *sqlQuerier) GetFailedWorkspaceBuildsByTemplateID(ctx context.Context, a const getLatestWorkspaceBuildByWorkspaceID = `-- name: GetLatestWorkspaceBuildByWorkspaceID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_tasks_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_task_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -17216,7 +17216,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, w &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17225,7 +17225,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, w } const getLatestWorkspaceBuilds = `-- name: GetLatestWorkspaceBuilds :many -SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.ai_tasks_sidebar_app_id, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name +SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.ai_task_sidebar_app_id, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name FROM ( SELECT workspace_id, MAX(build_number) as max_build_number @@ -17265,7 +17265,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuilds(ctx context.Context) ([]WorkspaceB &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17284,7 +17284,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuilds(ctx context.Context) ([]WorkspaceB } const getLatestWorkspaceBuildsByWorkspaceIDs = `-- name: GetLatestWorkspaceBuildsByWorkspaceIDs :many -SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.ai_tasks_sidebar_app_id, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name +SELECT wb.id, wb.created_at, wb.updated_at, wb.workspace_id, wb.template_version_id, wb.build_number, wb.transition, wb.initiator_id, wb.provisioner_state, wb.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.ai_task_sidebar_app_id, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name FROM ( SELECT workspace_id, MAX(build_number) as max_build_number @@ -17326,7 +17326,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17346,7 +17346,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, const getWorkspaceBuildByID = `-- name: GetWorkspaceBuildByID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_tasks_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_task_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -17375,7 +17375,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (W &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17385,7 +17385,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (W const getWorkspaceBuildByJobID = `-- name: GetWorkspaceBuildByJobID :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_tasks_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_task_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -17414,7 +17414,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UU &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17424,7 +17424,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UU const getWorkspaceBuildByWorkspaceIDAndBuildNumber = `-- name: GetWorkspaceBuildByWorkspaceIDAndBuildNumber :one SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_tasks_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_task_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -17457,7 +17457,7 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx context.Co &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17534,7 +17534,7 @@ func (q *sqlQuerier) GetWorkspaceBuildStatsByTemplates(ctx context.Context, sinc const getWorkspaceBuildsByWorkspaceID = `-- name: GetWorkspaceBuildsByWorkspaceID :many SELECT - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_tasks_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name + id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_task_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -17606,7 +17606,7 @@ func (q *sqlQuerier) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg Ge &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17625,7 +17625,7 @@ func (q *sqlQuerier) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg Ge } const getWorkspaceBuildsCreatedAfter = `-- name: GetWorkspaceBuildsCreatedAfter :many -SELECT id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_tasks_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user WHERE created_at > $1 +SELECT id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, provisioner_state, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, ai_task_sidebar_app_id, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user WHERE created_at > $1 ` func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceBuild, error) { @@ -17654,7 +17654,7 @@ func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, created &i.MaxDeadline, &i.TemplateVersionPresetID, &i.HasAITask, - &i.AITasksSidebarAppID, + &i.AITaskSidebarAppID, &i.InitiatorByAvatarUrl, &i.InitiatorByUsername, &i.InitiatorByName, @@ -17736,7 +17736,7 @@ UPDATE workspace_builds SET has_ai_task = $1, - ai_tasks_sidebar_app_id = $2, + ai_task_sidebar_app_id = $2, updated_at = $3::timestamptz WHERE id = $4::uuid ` diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 74946d46dcd9f..cfb5e540d10a7 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -1093,8 +1093,8 @@ func (api *API) convertWorkspaceBuild( hasAITask = &build.HasAITask.Bool } var aiTasksSidebarAppID *uuid.UUID - if build.AITasksSidebarAppID.Valid { - aiTasksSidebarAppID = &build.AITasksSidebarAppID.UUID + if build.AITaskSidebarAppID.Valid { + aiTasksSidebarAppID = &build.AITaskSidebarAppID.UUID } apiJob := convertProvisionerJob(job) diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index 7b0b852419f21..01b3d8e61d595 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -31,7 +31,7 @@ We track the following resources: | User
create, write, delete | |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_one_time_passcodefalse
hashed_passwordtrue
idtrue
is_systemtrue
last_seen_atfalse
login_typetrue
nametrue
one_time_passcode_expires_attrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
updated_atfalse
usernametrue
| | WorkspaceAgent
connect, disconnect | |
FieldTracked
api_key_scopefalse
api_versionfalse
architecturefalse
auth_instance_idfalse
auth_tokenfalse
connection_timeout_secondsfalse
created_atfalse
deletedfalse
directoryfalse
disconnected_atfalse
display_appsfalse
display_orderfalse
environment_variablesfalse
expanded_directoryfalse
first_connected_atfalse
idfalse
instance_metadatafalse
last_connected_atfalse
last_connected_replica_idfalse
lifecycle_statefalse
logs_lengthfalse
logs_overflowedfalse
motd_filefalse
namefalse
operating_systemfalse
parent_idfalse
ready_atfalse
resource_idfalse
resource_metadatafalse
started_atfalse
subsystemsfalse
troubleshooting_urlfalse
updated_atfalse
versionfalse
| | WorkspaceApp
open, close | |
FieldTracked
agent_idfalse
commandfalse
created_atfalse
display_groupfalse
display_namefalse
display_orderfalse
externalfalse
healthfalse
healthcheck_intervalfalse
healthcheck_thresholdfalse
healthcheck_urlfalse
hiddenfalse
iconfalse
idfalse
open_infalse
sharing_levelfalse
slugfalse
subdomainfalse
urlfalse
| -| WorkspaceBuild
start, stop | |
FieldTracked
ai_tasks_sidebar_app_idfalse
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
has_ai_taskfalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_namefalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
template_version_preset_idfalse
transitionfalse
updated_atfalse
workspace_idfalse
| +| WorkspaceBuild
start, stop | |
FieldTracked
ai_task_sidebar_app_idfalse
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
has_ai_taskfalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_namefalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
template_version_preset_idfalse
transitionfalse
updated_atfalse
workspace_idfalse
| | WorkspaceProxy
| |
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| | WorkspaceTable
| |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
next_start_attrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 047458457fedd..3dd165690ae4b 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -2775,6 +2775,108 @@ func (x *RunningAgentAuthToken) GetToken() string { return "" } +type AITaskSidebarApp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *AITaskSidebarApp) Reset() { + *x = AITaskSidebarApp{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AITaskSidebarApp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AITaskSidebarApp) ProtoMessage() {} + +func (x *AITaskSidebarApp) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[31] + 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 AITaskSidebarApp.ProtoReflect.Descriptor instead. +func (*AITaskSidebarApp) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{31} +} + +func (x *AITaskSidebarApp) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type AITask struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + SidebarApp *AITaskSidebarApp `protobuf:"bytes,2,opt,name=sidebar_app,json=sidebarApp,proto3" json:"sidebar_app,omitempty"` +} + +func (x *AITask) Reset() { + *x = AITask{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AITask) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AITask) ProtoMessage() {} + +func (x *AITask) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[32] + 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 AITask.ProtoReflect.Descriptor instead. +func (*AITask) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{32} +} + +func (x *AITask) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *AITask) GetSidebarApp() *AITaskSidebarApp { + if x != nil { + return x.SidebarApp + } + return nil +} + // Metadata is information about a workspace used in the execution of a build type Metadata struct { state protoimpl.MessageState @@ -2807,7 +2909,7 @@ type Metadata struct { func (x *Metadata) Reset() { *x = Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[31] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2820,7 +2922,7 @@ func (x *Metadata) String() string { func (*Metadata) ProtoMessage() {} func (x *Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[31] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2833,7 +2935,7 @@ func (x *Metadata) ProtoReflect() protoreflect.Message { // Deprecated: Use Metadata.ProtoReflect.Descriptor instead. func (*Metadata) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{31} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{33} } func (x *Metadata) GetCoderUrl() string { @@ -2999,7 +3101,7 @@ type Config struct { func (x *Config) Reset() { *x = Config{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[32] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3012,7 +3114,7 @@ func (x *Config) String() string { func (*Config) ProtoMessage() {} func (x *Config) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[32] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3025,7 +3127,7 @@ func (x *Config) ProtoReflect() protoreflect.Message { // Deprecated: Use Config.ProtoReflect.Descriptor instead. func (*Config) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{32} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{34} } func (x *Config) GetTemplateSourceArchive() []byte { @@ -3059,7 +3161,7 @@ type ParseRequest struct { func (x *ParseRequest) Reset() { *x = ParseRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[33] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3072,7 +3174,7 @@ func (x *ParseRequest) String() string { func (*ParseRequest) ProtoMessage() {} func (x *ParseRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[33] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3085,7 +3187,7 @@ func (x *ParseRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ParseRequest.ProtoReflect.Descriptor instead. func (*ParseRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{33} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{35} } // ParseComplete indicates a request to parse completed. @@ -3103,7 +3205,7 @@ type ParseComplete struct { func (x *ParseComplete) Reset() { *x = ParseComplete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[34] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3116,7 +3218,7 @@ func (x *ParseComplete) String() string { func (*ParseComplete) ProtoMessage() {} func (x *ParseComplete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[34] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3129,7 +3231,7 @@ func (x *ParseComplete) ProtoReflect() protoreflect.Message { // Deprecated: Use ParseComplete.ProtoReflect.Descriptor instead. func (*ParseComplete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{34} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{36} } func (x *ParseComplete) GetError() string { @@ -3182,7 +3284,7 @@ type PlanRequest struct { func (x *PlanRequest) Reset() { *x = PlanRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[35] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3195,7 +3297,7 @@ func (x *PlanRequest) String() string { func (*PlanRequest) ProtoMessage() {} func (x *PlanRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[35] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3208,7 +3310,7 @@ func (x *PlanRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PlanRequest.ProtoReflect.Descriptor instead. func (*PlanRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{35} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{37} } func (x *PlanRequest) GetMetadata() *Metadata { @@ -3270,12 +3372,19 @@ type PlanComplete struct { ResourceReplacements []*ResourceReplacement `protobuf:"bytes,10,rep,name=resource_replacements,json=resourceReplacements,proto3" json:"resource_replacements,omitempty"` ModuleFiles []byte `protobuf:"bytes,11,opt,name=module_files,json=moduleFiles,proto3" json:"module_files,omitempty"` ModuleFilesHash []byte `protobuf:"bytes,12,opt,name=module_files_hash,json=moduleFilesHash,proto3" json:"module_files_hash,omitempty"` + // Whether a template has any `coder_ai_task` resources defined, even if not planned for creation. + // During a template import, a plan is run which may not yield in any `coder_ai_task` resources, but nonetheless we + // still need to know that such resources are defined. + // + // See `hasAITaskResources` in provisioner/terraform/resources.go for more details. + HasAiTasks bool `protobuf:"varint,13,opt,name=has_ai_tasks,json=hasAiTasks,proto3" json:"has_ai_tasks,omitempty"` + AiTasks []*AITask `protobuf:"bytes,14,rep,name=ai_tasks,json=aiTasks,proto3" json:"ai_tasks,omitempty"` } func (x *PlanComplete) Reset() { *x = PlanComplete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[36] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3288,7 +3397,7 @@ func (x *PlanComplete) String() string { func (*PlanComplete) ProtoMessage() {} func (x *PlanComplete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[36] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3301,7 +3410,7 @@ func (x *PlanComplete) ProtoReflect() protoreflect.Message { // Deprecated: Use PlanComplete.ProtoReflect.Descriptor instead. func (*PlanComplete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{36} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{38} } func (x *PlanComplete) GetError() string { @@ -3381,6 +3490,20 @@ func (x *PlanComplete) GetModuleFilesHash() []byte { return nil } +func (x *PlanComplete) GetHasAiTasks() bool { + if x != nil { + return x.HasAiTasks + } + return false +} + +func (x *PlanComplete) GetAiTasks() []*AITask { + if x != nil { + return x.AiTasks + } + return nil +} + // ApplyRequest asks the provisioner to apply the changes. Apply MUST be preceded by a successful plan request/response // in the same Session. The plan data is not transmitted over the wire and is cached by the provisioner in the Session. type ApplyRequest struct { @@ -3394,7 +3517,7 @@ type ApplyRequest struct { func (x *ApplyRequest) Reset() { *x = ApplyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[37] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3407,7 +3530,7 @@ func (x *ApplyRequest) String() string { func (*ApplyRequest) ProtoMessage() {} func (x *ApplyRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[37] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3420,7 +3543,7 @@ func (x *ApplyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyRequest.ProtoReflect.Descriptor instead. func (*ApplyRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{37} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{39} } func (x *ApplyRequest) GetMetadata() *Metadata { @@ -3442,12 +3565,13 @@ type ApplyComplete struct { Parameters []*RichParameter `protobuf:"bytes,4,rep,name=parameters,proto3" json:"parameters,omitempty"` ExternalAuthProviders []*ExternalAuthProviderResource `protobuf:"bytes,5,rep,name=external_auth_providers,json=externalAuthProviders,proto3" json:"external_auth_providers,omitempty"` Timings []*Timing `protobuf:"bytes,6,rep,name=timings,proto3" json:"timings,omitempty"` + AiTasks []*AITask `protobuf:"bytes,7,rep,name=ai_tasks,json=aiTasks,proto3" json:"ai_tasks,omitempty"` } func (x *ApplyComplete) Reset() { *x = ApplyComplete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[38] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3460,7 +3584,7 @@ func (x *ApplyComplete) String() string { func (*ApplyComplete) ProtoMessage() {} func (x *ApplyComplete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[38] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3473,7 +3597,7 @@ func (x *ApplyComplete) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyComplete.ProtoReflect.Descriptor instead. func (*ApplyComplete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{38} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{40} } func (x *ApplyComplete) GetState() []byte { @@ -3518,6 +3642,13 @@ func (x *ApplyComplete) GetTimings() []*Timing { return nil } +func (x *ApplyComplete) GetAiTasks() []*AITask { + if x != nil { + return x.AiTasks + } + return nil +} + type Timing struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3535,7 +3666,7 @@ type Timing struct { func (x *Timing) Reset() { *x = Timing{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3548,7 +3679,7 @@ func (x *Timing) String() string { func (*Timing) ProtoMessage() {} func (x *Timing) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3561,7 +3692,7 @@ func (x *Timing) ProtoReflect() protoreflect.Message { // Deprecated: Use Timing.ProtoReflect.Descriptor instead. func (*Timing) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{39} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{41} } func (x *Timing) GetStart() *timestamppb.Timestamp { @@ -3623,7 +3754,7 @@ type CancelRequest struct { func (x *CancelRequest) Reset() { *x = CancelRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3636,7 +3767,7 @@ func (x *CancelRequest) String() string { func (*CancelRequest) ProtoMessage() {} func (x *CancelRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3649,7 +3780,7 @@ func (x *CancelRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelRequest.ProtoReflect.Descriptor instead. func (*CancelRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{40} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{42} } type Request struct { @@ -3670,7 +3801,7 @@ type Request struct { func (x *Request) Reset() { *x = Request{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3683,7 +3814,7 @@ func (x *Request) String() string { func (*Request) ProtoMessage() {} func (x *Request) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3696,7 +3827,7 @@ func (x *Request) ProtoReflect() protoreflect.Message { // Deprecated: Use Request.ProtoReflect.Descriptor instead. func (*Request) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{41} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{43} } func (m *Request) GetType() isRequest_Type { @@ -3794,7 +3925,7 @@ type Response struct { func (x *Response) Reset() { *x = Response{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3807,7 +3938,7 @@ func (x *Response) String() string { func (*Response) ProtoMessage() {} func (x *Response) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3820,7 +3951,7 @@ func (x *Response) ProtoReflect() protoreflect.Message { // Deprecated: Use Response.ProtoReflect.Descriptor instead. func (*Response) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{42} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{44} } func (m *Response) GetType() isResponse_Type { @@ -3930,7 +4061,7 @@ type DataUpload struct { func (x *DataUpload) Reset() { *x = DataUpload{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3943,7 +4074,7 @@ func (x *DataUpload) String() string { func (*DataUpload) ProtoMessage() {} func (x *DataUpload) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3956,7 +4087,7 @@ func (x *DataUpload) ProtoReflect() protoreflect.Message { // Deprecated: Use DataUpload.ProtoReflect.Descriptor instead. func (*DataUpload) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{43} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{45} } func (x *DataUpload) GetUploadType() DataUploadType { @@ -4003,7 +4134,7 @@ type ChunkPiece struct { func (x *ChunkPiece) Reset() { *x = ChunkPiece{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4016,7 +4147,7 @@ func (x *ChunkPiece) String() string { func (*ChunkPiece) ProtoMessage() {} func (x *ChunkPiece) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4029,7 +4160,7 @@ func (x *ChunkPiece) ProtoReflect() protoreflect.Message { // Deprecated: Use ChunkPiece.ProtoReflect.Descriptor instead. func (*ChunkPiece) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{44} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{46} } func (x *ChunkPiece) GetData() []byte { @@ -4069,7 +4200,7 @@ type Agent_Metadata struct { func (x *Agent_Metadata) Reset() { *x = Agent_Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4082,7 +4213,7 @@ func (x *Agent_Metadata) String() string { func (*Agent_Metadata) ProtoMessage() {} func (x *Agent_Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4154,7 +4285,7 @@ type Resource_Metadata struct { func (x *Resource_Metadata) Reset() { *x = Resource_Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4167,7 +4298,7 @@ func (x *Resource_Metadata) String() string { func (*Resource_Metadata) ProtoMessage() {} func (x *Resource_Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4554,181 +4685,194 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xca, 0x09, 0x0a, 0x08, 0x4d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, - 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x55, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, - 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, - 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x0a, - 0x0d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, - 0x21, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, - 0x5f, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, - 0x16, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, - 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x73, 0x12, 0x42, 0x0a, 0x1e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x73, 0x68, 0x50, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x1f, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, - 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, - 0x53, 0x73, 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, - 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, - 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x77, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6c, - 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4e, 0x0a, 0x1a, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x72, 0x62, 0x61, 0x63, - 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, - 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52, - 0x62, 0x61, 0x63, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x1e, 0x70, 0x72, 0x65, 0x62, - 0x75, 0x69, 0x6c, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, - 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, - 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x1b, 0x70, 0x72, 0x65, 0x62, - 0x75, 0x69, 0x6c, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, - 0x6c, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x5d, 0x0a, 0x19, 0x72, 0x75, 0x6e, 0x6e, 0x69, - 0x6e, 0x67, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x16, - 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x15, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x6c, - 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4c, 0x0a, 0x12, 0x74, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, - 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, - 0x64, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, - 0x65, 0x12, 0x54, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, - 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, - 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 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, 0xbe, 0x03, 0x0a, 0x0b, 0x50, 0x6c, - 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, 0x15, - 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, - 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x59, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, - 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x73, 0x12, 0x5b, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x70, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x17, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x2a, - 0x0a, 0x11, 0x6f, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, - 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6f, 0x6d, 0x69, 0x74, 0x4d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0xbf, 0x04, 0x0a, 0x0c, 0x50, - 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, - 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x15, - 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, - 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, - 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, - 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x18, 0x08, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x22, 0x0a, 0x10, 0x41, 0x49, 0x54, + 0x61, 0x73, 0x6b, 0x53, 0x69, 0x64, 0x65, 0x62, 0x61, 0x72, 0x41, 0x70, 0x70, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x58, 0x0a, + 0x06, 0x41, 0x49, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x69, 0x64, 0x65, 0x62, + 0x61, 0x72, 0x5f, 0x61, 0x70, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x49, 0x54, 0x61, 0x73, + 0x6b, 0x53, 0x69, 0x64, 0x65, 0x62, 0x61, 0x72, 0x41, 0x70, 0x70, 0x52, 0x0a, 0x73, 0x69, 0x64, + 0x65, 0x62, 0x61, 0x72, 0x41, 0x70, 0x70, 0x22, 0xca, 0x09, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, + 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, + 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x74, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x21, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6f, + 0x69, 0x64, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x73, 0x12, 0x42, 0x0a, 0x1e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, + 0x6b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x73, 0x68, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x1f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1b, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x73, + 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, + 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, + 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4e, 0x0a, 0x1a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x72, 0x62, 0x61, 0x63, 0x5f, 0x72, + 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x17, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52, 0x62, 0x61, + 0x63, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x1e, 0x70, 0x72, 0x65, 0x62, 0x75, 0x69, + 0x6c, 0x74, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x65, + 0x62, 0x75, 0x69, 0x6c, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x52, 0x1b, 0x70, 0x72, 0x65, 0x62, 0x75, 0x69, + 0x6c, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x5d, 0x0a, 0x19, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x16, 0x72, 0x75, + 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x73, 0x22, 0x8a, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x36, 0x0a, 0x17, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x15, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, + 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, + 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, + 0x54, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x67, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x54, 0x61, 0x67, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 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, 0xbe, 0x03, 0x0a, 0x0b, 0x50, 0x6c, 0x61, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, 0x15, 0x72, 0x69, + 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, + 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x12, 0x59, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, + 0x5b, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x17, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, + 0x6f, 0x6d, 0x69, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6f, 0x6d, 0x69, 0x74, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0x91, 0x05, 0x0a, 0x0c, 0x50, 0x6c, 0x61, + 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, + 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, + 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x15, 0x65, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x55, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, - 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, - 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x41, 0x0a, 0x0c, + 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x55, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0a, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, + 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, + 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x61, + 0x73, 0x5f, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x68, 0x61, 0x73, 0x41, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x08, + 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x49, 0x54, + 0x61, 0x73, 0x6b, 0x52, 0x07, 0x61, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x41, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, - 0xbe, 0x02, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0xee, 0x02, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, 0x0a, @@ -4748,6 +4892,9 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, + 0x12, 0x2e, 0x0a, 0x08, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x41, 0x49, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x07, 0x61, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x06, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 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, @@ -4880,7 +5027,7 @@ func file_provisionersdk_proto_provisioner_proto_rawDescGZIP() []byte { } var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 8) -var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 49) +var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 51) var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ (ParameterFormType)(0), // 0: provisioner.ParameterFormType (LogLevel)(0), // 1: provisioner.LogLevel @@ -4921,25 +5068,27 @@ var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ (*Module)(nil), // 36: provisioner.Module (*Role)(nil), // 37: provisioner.Role (*RunningAgentAuthToken)(nil), // 38: provisioner.RunningAgentAuthToken - (*Metadata)(nil), // 39: provisioner.Metadata - (*Config)(nil), // 40: provisioner.Config - (*ParseRequest)(nil), // 41: provisioner.ParseRequest - (*ParseComplete)(nil), // 42: provisioner.ParseComplete - (*PlanRequest)(nil), // 43: provisioner.PlanRequest - (*PlanComplete)(nil), // 44: provisioner.PlanComplete - (*ApplyRequest)(nil), // 45: provisioner.ApplyRequest - (*ApplyComplete)(nil), // 46: provisioner.ApplyComplete - (*Timing)(nil), // 47: provisioner.Timing - (*CancelRequest)(nil), // 48: provisioner.CancelRequest - (*Request)(nil), // 49: provisioner.Request - (*Response)(nil), // 50: provisioner.Response - (*DataUpload)(nil), // 51: provisioner.DataUpload - (*ChunkPiece)(nil), // 52: provisioner.ChunkPiece - (*Agent_Metadata)(nil), // 53: provisioner.Agent.Metadata - nil, // 54: provisioner.Agent.EnvEntry - (*Resource_Metadata)(nil), // 55: provisioner.Resource.Metadata - nil, // 56: provisioner.ParseComplete.WorkspaceTagsEntry - (*timestamppb.Timestamp)(nil), // 57: google.protobuf.Timestamp + (*AITaskSidebarApp)(nil), // 39: provisioner.AITaskSidebarApp + (*AITask)(nil), // 40: provisioner.AITask + (*Metadata)(nil), // 41: provisioner.Metadata + (*Config)(nil), // 42: provisioner.Config + (*ParseRequest)(nil), // 43: provisioner.ParseRequest + (*ParseComplete)(nil), // 44: provisioner.ParseComplete + (*PlanRequest)(nil), // 45: provisioner.PlanRequest + (*PlanComplete)(nil), // 46: provisioner.PlanComplete + (*ApplyRequest)(nil), // 47: provisioner.ApplyRequest + (*ApplyComplete)(nil), // 48: provisioner.ApplyComplete + (*Timing)(nil), // 49: provisioner.Timing + (*CancelRequest)(nil), // 50: provisioner.CancelRequest + (*Request)(nil), // 51: provisioner.Request + (*Response)(nil), // 52: provisioner.Response + (*DataUpload)(nil), // 53: provisioner.DataUpload + (*ChunkPiece)(nil), // 54: provisioner.ChunkPiece + (*Agent_Metadata)(nil), // 55: provisioner.Agent.Metadata + nil, // 56: provisioner.Agent.EnvEntry + (*Resource_Metadata)(nil), // 57: provisioner.Resource.Metadata + nil, // 58: provisioner.ParseComplete.WorkspaceTagsEntry + (*timestamppb.Timestamp)(nil), // 59: google.protobuf.Timestamp } var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 10, // 0: provisioner.RichParameter.options:type_name -> provisioner.RichParameterOption @@ -4950,9 +5099,9 @@ var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 18, // 5: provisioner.Preset.parameters:type_name -> provisioner.PresetParameter 16, // 6: provisioner.Preset.prebuild:type_name -> provisioner.Prebuild 1, // 7: provisioner.Log.level:type_name -> provisioner.LogLevel - 54, // 8: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry + 56, // 8: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry 33, // 9: provisioner.Agent.apps:type_name -> provisioner.App - 53, // 10: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata + 55, // 10: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata 29, // 11: provisioner.Agent.display_apps:type_name -> provisioner.DisplayApps 31, // 12: provisioner.Agent.scripts:type_name -> provisioner.Script 30, // 13: provisioner.Agent.extra_envs:type_name -> provisioner.Env @@ -4964,52 +5113,55 @@ var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 2, // 19: provisioner.App.sharing_level:type_name -> provisioner.AppSharingLevel 3, // 20: provisioner.App.open_in:type_name -> provisioner.AppOpenIn 25, // 21: provisioner.Resource.agents:type_name -> provisioner.Agent - 55, // 22: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata - 4, // 23: provisioner.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition - 37, // 24: provisioner.Metadata.workspace_owner_rbac_roles:type_name -> provisioner.Role - 5, // 25: provisioner.Metadata.prebuilt_workspace_build_stage:type_name -> provisioner.PrebuiltWorkspaceBuildStage - 38, // 26: provisioner.Metadata.running_agent_auth_tokens:type_name -> provisioner.RunningAgentAuthToken - 9, // 27: provisioner.ParseComplete.template_variables:type_name -> provisioner.TemplateVariable - 56, // 28: provisioner.ParseComplete.workspace_tags:type_name -> provisioner.ParseComplete.WorkspaceTagsEntry - 39, // 29: provisioner.PlanRequest.metadata:type_name -> provisioner.Metadata - 12, // 30: provisioner.PlanRequest.rich_parameter_values:type_name -> provisioner.RichParameterValue - 20, // 31: provisioner.PlanRequest.variable_values:type_name -> provisioner.VariableValue - 24, // 32: provisioner.PlanRequest.external_auth_providers:type_name -> provisioner.ExternalAuthProvider - 12, // 33: provisioner.PlanRequest.previous_parameter_values:type_name -> provisioner.RichParameterValue - 35, // 34: provisioner.PlanComplete.resources:type_name -> provisioner.Resource - 11, // 35: provisioner.PlanComplete.parameters:type_name -> provisioner.RichParameter - 23, // 36: provisioner.PlanComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource - 47, // 37: provisioner.PlanComplete.timings:type_name -> provisioner.Timing - 36, // 38: provisioner.PlanComplete.modules:type_name -> provisioner.Module - 17, // 39: provisioner.PlanComplete.presets:type_name -> provisioner.Preset - 19, // 40: provisioner.PlanComplete.resource_replacements:type_name -> provisioner.ResourceReplacement - 39, // 41: provisioner.ApplyRequest.metadata:type_name -> provisioner.Metadata - 35, // 42: provisioner.ApplyComplete.resources:type_name -> provisioner.Resource - 11, // 43: provisioner.ApplyComplete.parameters:type_name -> provisioner.RichParameter - 23, // 44: provisioner.ApplyComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource - 47, // 45: provisioner.ApplyComplete.timings:type_name -> provisioner.Timing - 57, // 46: provisioner.Timing.start:type_name -> google.protobuf.Timestamp - 57, // 47: provisioner.Timing.end:type_name -> google.protobuf.Timestamp - 6, // 48: provisioner.Timing.state:type_name -> provisioner.TimingState - 40, // 49: provisioner.Request.config:type_name -> provisioner.Config - 41, // 50: provisioner.Request.parse:type_name -> provisioner.ParseRequest - 43, // 51: provisioner.Request.plan:type_name -> provisioner.PlanRequest - 45, // 52: provisioner.Request.apply:type_name -> provisioner.ApplyRequest - 48, // 53: provisioner.Request.cancel:type_name -> provisioner.CancelRequest - 21, // 54: provisioner.Response.log:type_name -> provisioner.Log - 42, // 55: provisioner.Response.parse:type_name -> provisioner.ParseComplete - 44, // 56: provisioner.Response.plan:type_name -> provisioner.PlanComplete - 46, // 57: provisioner.Response.apply:type_name -> provisioner.ApplyComplete - 51, // 58: provisioner.Response.data_upload:type_name -> provisioner.DataUpload - 52, // 59: provisioner.Response.chunk_piece:type_name -> provisioner.ChunkPiece - 7, // 60: provisioner.DataUpload.upload_type:type_name -> provisioner.DataUploadType - 49, // 61: provisioner.Provisioner.Session:input_type -> provisioner.Request - 50, // 62: provisioner.Provisioner.Session:output_type -> provisioner.Response - 62, // [62:63] is the sub-list for method output_type - 61, // [61:62] is the sub-list for method input_type - 61, // [61:61] is the sub-list for extension type_name - 61, // [61:61] is the sub-list for extension extendee - 0, // [0:61] is the sub-list for field type_name + 57, // 22: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata + 39, // 23: provisioner.AITask.sidebar_app:type_name -> provisioner.AITaskSidebarApp + 4, // 24: provisioner.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition + 37, // 25: provisioner.Metadata.workspace_owner_rbac_roles:type_name -> provisioner.Role + 5, // 26: provisioner.Metadata.prebuilt_workspace_build_stage:type_name -> provisioner.PrebuiltWorkspaceBuildStage + 38, // 27: provisioner.Metadata.running_agent_auth_tokens:type_name -> provisioner.RunningAgentAuthToken + 9, // 28: provisioner.ParseComplete.template_variables:type_name -> provisioner.TemplateVariable + 58, // 29: provisioner.ParseComplete.workspace_tags:type_name -> provisioner.ParseComplete.WorkspaceTagsEntry + 41, // 30: provisioner.PlanRequest.metadata:type_name -> provisioner.Metadata + 12, // 31: provisioner.PlanRequest.rich_parameter_values:type_name -> provisioner.RichParameterValue + 20, // 32: provisioner.PlanRequest.variable_values:type_name -> provisioner.VariableValue + 24, // 33: provisioner.PlanRequest.external_auth_providers:type_name -> provisioner.ExternalAuthProvider + 12, // 34: provisioner.PlanRequest.previous_parameter_values:type_name -> provisioner.RichParameterValue + 35, // 35: provisioner.PlanComplete.resources:type_name -> provisioner.Resource + 11, // 36: provisioner.PlanComplete.parameters:type_name -> provisioner.RichParameter + 23, // 37: provisioner.PlanComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource + 49, // 38: provisioner.PlanComplete.timings:type_name -> provisioner.Timing + 36, // 39: provisioner.PlanComplete.modules:type_name -> provisioner.Module + 17, // 40: provisioner.PlanComplete.presets:type_name -> provisioner.Preset + 19, // 41: provisioner.PlanComplete.resource_replacements:type_name -> provisioner.ResourceReplacement + 40, // 42: provisioner.PlanComplete.ai_tasks:type_name -> provisioner.AITask + 41, // 43: provisioner.ApplyRequest.metadata:type_name -> provisioner.Metadata + 35, // 44: provisioner.ApplyComplete.resources:type_name -> provisioner.Resource + 11, // 45: provisioner.ApplyComplete.parameters:type_name -> provisioner.RichParameter + 23, // 46: provisioner.ApplyComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource + 49, // 47: provisioner.ApplyComplete.timings:type_name -> provisioner.Timing + 40, // 48: provisioner.ApplyComplete.ai_tasks:type_name -> provisioner.AITask + 59, // 49: provisioner.Timing.start:type_name -> google.protobuf.Timestamp + 59, // 50: provisioner.Timing.end:type_name -> google.protobuf.Timestamp + 6, // 51: provisioner.Timing.state:type_name -> provisioner.TimingState + 42, // 52: provisioner.Request.config:type_name -> provisioner.Config + 43, // 53: provisioner.Request.parse:type_name -> provisioner.ParseRequest + 45, // 54: provisioner.Request.plan:type_name -> provisioner.PlanRequest + 47, // 55: provisioner.Request.apply:type_name -> provisioner.ApplyRequest + 50, // 56: provisioner.Request.cancel:type_name -> provisioner.CancelRequest + 21, // 57: provisioner.Response.log:type_name -> provisioner.Log + 44, // 58: provisioner.Response.parse:type_name -> provisioner.ParseComplete + 46, // 59: provisioner.Response.plan:type_name -> provisioner.PlanComplete + 48, // 60: provisioner.Response.apply:type_name -> provisioner.ApplyComplete + 53, // 61: provisioner.Response.data_upload:type_name -> provisioner.DataUpload + 54, // 62: provisioner.Response.chunk_piece:type_name -> provisioner.ChunkPiece + 7, // 63: provisioner.DataUpload.upload_type:type_name -> provisioner.DataUploadType + 51, // 64: provisioner.Provisioner.Session:input_type -> provisioner.Request + 52, // 65: provisioner.Provisioner.Session:output_type -> provisioner.Response + 65, // [65:66] is the sub-list for method output_type + 64, // [64:65] is the sub-list for method input_type + 64, // [64:64] is the sub-list for extension type_name + 64, // [64:64] is the sub-list for extension extendee + 0, // [0:64] is the sub-list for field type_name } func init() { file_provisionersdk_proto_provisioner_proto_init() } @@ -5391,7 +5543,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Metadata); i { + switch v := v.(*AITaskSidebarApp); i { case 0: return &v.state case 1: @@ -5403,7 +5555,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Config); i { + switch v := v.(*AITask); i { case 0: return &v.state case 1: @@ -5415,7 +5567,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ParseRequest); i { + switch v := v.(*Metadata); i { case 0: return &v.state case 1: @@ -5427,7 +5579,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ParseComplete); i { + switch v := v.(*Config); i { case 0: return &v.state case 1: @@ -5439,7 +5591,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PlanRequest); i { + switch v := v.(*ParseRequest); i { case 0: return &v.state case 1: @@ -5451,7 +5603,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PlanComplete); i { + switch v := v.(*ParseComplete); i { case 0: return &v.state case 1: @@ -5463,7 +5615,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplyRequest); i { + switch v := v.(*PlanRequest); i { case 0: return &v.state case 1: @@ -5475,7 +5627,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ApplyComplete); i { + switch v := v.(*PlanComplete); i { case 0: return &v.state case 1: @@ -5487,7 +5639,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Timing); i { + switch v := v.(*ApplyRequest); i { case 0: return &v.state case 1: @@ -5499,7 +5651,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CancelRequest); i { + switch v := v.(*ApplyComplete); i { case 0: return &v.state case 1: @@ -5511,7 +5663,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Request); i { + switch v := v.(*Timing); i { case 0: return &v.state case 1: @@ -5523,7 +5675,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Response); i { + switch v := v.(*CancelRequest); i { case 0: return &v.state case 1: @@ -5535,7 +5687,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataUpload); i { + switch v := v.(*Request); i { case 0: return &v.state case 1: @@ -5547,7 +5699,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChunkPiece); i { + switch v := v.(*Response); i { case 0: return &v.state case 1: @@ -5559,7 +5711,19 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Agent_Metadata); i { + switch v := v.(*DataUpload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_provisionersdk_proto_provisioner_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChunkPiece); i { case 0: return &v.state case 1: @@ -5571,6 +5735,18 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Agent_Metadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_provisionersdk_proto_provisioner_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Resource_Metadata); i { case 0: return &v.state @@ -5588,14 +5764,14 @@ func file_provisionersdk_proto_provisioner_proto_init() { (*Agent_Token)(nil), (*Agent_InstanceId)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[41].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[43].OneofWrappers = []interface{}{ (*Request_Config)(nil), (*Request_Parse)(nil), (*Request_Plan)(nil), (*Request_Apply)(nil), (*Request_Cancel)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[42].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[44].OneofWrappers = []interface{}{ (*Response_Log)(nil), (*Response_Parse)(nil), (*Response_Plan)(nil), @@ -5609,7 +5785,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_provisionersdk_proto_provisioner_proto_rawDesc, NumEnums: 8, - NumMessages: 49, + NumMessages: 51, NumExtensions: 0, NumServices: 1, }, diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts index 9b6a0b3109ef7..60712f5884dc3 100644 --- a/site/e2e/provisionerGenerated.ts +++ b/site/e2e/provisionerGenerated.ts @@ -359,6 +359,15 @@ export interface RunningAgentAuthToken { token: string; } +export interface AITaskSidebarApp { + id: string; +} + +export interface AITask { + id: string; + sidebarApp: AITaskSidebarApp | undefined; +} + /** Metadata is information about a workspace used in the execution of a build */ export interface Metadata { coderUrl: string; @@ -441,6 +450,15 @@ export interface PlanComplete { resourceReplacements: ResourceReplacement[]; moduleFiles: Uint8Array; moduleFilesHash: Uint8Array; + /** + * Whether a template has any `coder_ai_task` resources defined, even if not planned for creation. + * During a template import, a plan is run which may not yield in any `coder_ai_task` resources, but nonetheless we + * still need to know that such resources are defined. + * + * See `hasAITaskResources` in provisioner/terraform/resources.go for more details. + */ + hasAiTasks: boolean; + aiTasks: AITask[]; } /** @@ -459,6 +477,7 @@ export interface ApplyComplete { parameters: RichParameter[]; externalAuthProviders: ExternalAuthProviderResource[]; timings: Timing[]; + aiTasks: AITask[]; } export interface Timing { @@ -1158,6 +1177,27 @@ export const RunningAgentAuthToken = { }, }; +export const AITaskSidebarApp = { + encode(message: AITaskSidebarApp, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.id !== "") { + writer.uint32(10).string(message.id); + } + return writer; + }, +}; + +export const AITask = { + encode(message: AITask, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.id !== "") { + writer.uint32(10).string(message.id); + } + if (message.sidebarApp !== undefined) { + AITaskSidebarApp.encode(message.sidebarApp, writer.uint32(18).fork()).ldelim(); + } + return writer; + }, +}; + export const Metadata = { encode(message: Metadata, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { if (message.coderUrl !== "") { @@ -1337,6 +1377,12 @@ export const PlanComplete = { if (message.moduleFilesHash.length !== 0) { writer.uint32(98).bytes(message.moduleFilesHash); } + if (message.hasAiTasks === true) { + writer.uint32(104).bool(message.hasAiTasks); + } + for (const v of message.aiTasks) { + AITask.encode(v!, writer.uint32(114).fork()).ldelim(); + } return writer; }, }; @@ -1370,6 +1416,9 @@ export const ApplyComplete = { for (const v of message.timings) { Timing.encode(v!, writer.uint32(50).fork()).ldelim(); } + for (const v of message.aiTasks) { + AITask.encode(v!, writer.uint32(58).fork()).ldelim(); + } return writer; }, }; From 5edee0547bf76de707e64fc5077cf124c88caf4c Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 11:13:23 +0200 Subject: [PATCH 13/20] chore: undo changes to terraform testdata, so as to not complicate this PR This will be done in a separate PR Signed-off-by: Danny Kopping --- .../calling-module/calling-module.tf | 2 +- .../chaining-resources/chaining-resources.tf | 2 +- .../conflicting-resources.tf | 2 +- .../resources/devcontainer/devcontainer.tf | 2 +- .../display-apps-disabled.tf | 2 +- .../resources/display-apps/display-apps.tf | 2 +- .../external-auth-providers.tf | 2 +- .../external-auth-providers.tfplan.json | 8 +- .../external-auth-providers.tfstate.json | 4 +- .../resources/instance-id/instance-id.tf | 2 +- .../kubernetes-metadata.tf | 2 +- .../resources/mapped-apps/mapped-apps.tf | 2 +- .../multiple-agents-multiple-apps.tf | 2 +- .../multiple-agents-multiple-envs.tf | 2 +- .../multiple-agents-multiple-monitors.tf | 2 +- ...tiple-agents-multiple-monitors.tfplan.json | 2 +- .../multiple-agents-multiple-scripts.tf | 2 +- .../multiple-agents/multiple-agents.tf | 2 +- .../resources/multiple-apps/multiple-apps.tf | 2 +- .../child-external-module/main.tf | 2 +- .../resources/presets/external-module/main.tf | 2 +- .../testdata/resources/presets/presets.tf | 2 +- .../resources/presets/presets.tfplan.json | 78 +++++++++++++++---- .../resources/presets/presets.tfstate.json | 37 +++++++-- .../resource-metadata-duplicate.tf | 2 +- .../resource-metadata/resource-metadata.tf | 2 +- .../rich-parameters-order.tf | 2 +- .../rich-parameters-order.tfplan.json | 8 +- .../rich-parameters-order.tfstate.json | 4 +- .../rich-parameters-validation.tf | 2 +- .../rich-parameters-validation.tfplan.json | 24 +++--- .../rich-parameters-validation.tfstate.json | 12 +-- .../child-external-module/main.tf | 2 +- .../rich-parameters/external-module/main.tf | 2 +- .../rich-parameters/rich-parameters.tf | 2 +- .../rich-parameters.tfplan.json | 40 +++++----- .../rich-parameters.tfstate.json | 20 ++--- .../terraform/testdata/resources/version.txt | 2 +- 38 files changed, 179 insertions(+), 112 deletions(-) diff --git a/provisioner/terraform/testdata/resources/calling-module/calling-module.tf b/provisioner/terraform/testdata/resources/calling-module/calling-module.tf index a24b4ab010b19..33fcbb3f1984f 100644 --- a/provisioner/terraform/testdata/resources/calling-module/calling-module.tf +++ b/provisioner/terraform/testdata/resources/calling-module/calling-module.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf b/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf index 6f37a90f35409..6ad44a62de986 100644 --- a/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf +++ b/provisioner/terraform/testdata/resources/chaining-resources/chaining-resources.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf b/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf index afcf6841c0c94..86585b6a85357 100644 --- a/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf +++ b/provisioner/terraform/testdata/resources/conflicting-resources/conflicting-resources.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf b/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf index 4a0e4c9d58857..c611ad4001f04 100644 --- a/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf +++ b/provisioner/terraform/testdata/resources/devcontainer/devcontainer.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf b/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf index 8021186a98453..155b81889540e 100644 --- a/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf +++ b/provisioner/terraform/testdata/resources/display-apps-disabled/display-apps-disabled.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/display-apps/display-apps.tf b/provisioner/terraform/testdata/resources/display-apps/display-apps.tf index 8be6eddaed622..3544ab535ad2f 100644 --- a/provisioner/terraform/testdata/resources/display-apps/display-apps.tf +++ b/provisioner/terraform/testdata/resources/display-apps/display-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf index cf56fbcf3e804..5f45a88aacb6a 100644 --- a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf +++ b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json index 696a7ee61f2c2..18ccfa17a86fc 100644 --- a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json +++ b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_external_auth", "name": "github", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "access_token": "", "id": "github", @@ -144,7 +144,7 @@ "type": "coder_external_auth", "name": "gitlab", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "access_token": "", "id": "gitlab", @@ -208,7 +208,7 @@ "constant_value": "github" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_external_auth.gitlab", @@ -224,7 +224,7 @@ "constant_value": true } }, - "schema_version": 1 + "schema_version": 0 } ] } diff --git a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json index 35e407dff4667..afe4bd90fb722 100644 --- a/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json +++ b/provisioner/terraform/testdata/resources/external-auth-providers/external-auth-providers.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_external_auth", "name": "github", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "access_token": "", "id": "github", @@ -24,7 +24,7 @@ "type": "coder_external_auth", "name": "gitlab", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "access_token": "", "id": "gitlab", diff --git a/provisioner/terraform/testdata/resources/instance-id/instance-id.tf b/provisioner/terraform/testdata/resources/instance-id/instance-id.tf index 8f1939fe62a69..84e010a79d6e9 100644 --- a/provisioner/terraform/testdata/resources/instance-id/instance-id.tf +++ b/provisioner/terraform/testdata/resources/instance-id/instance-id.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf b/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf index 86751fec0a841..faa08706de380 100644 --- a/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf +++ b/provisioner/terraform/testdata/resources/kubernetes-metadata/kubernetes-metadata.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } kubernetes = { source = "hashicorp/kubernetes" diff --git a/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf b/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf index 16fd128b3d074..7664ead2b4962 100644 --- a/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf +++ b/provisioner/terraform/testdata/resources/mapped-apps/mapped-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf index 064ac4f44e0a3..8ac412b5b3894 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf index 10ed541b3992b..e12a895d14baa 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf index 9bbab0776c514..f86ceb180edb5 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = "2.2.0-pre0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json index 2680c4ce34f9d..ae850f57d1369 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json @@ -456,7 +456,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": ">= 2.0.0" + "version_constraint": "2.2.0-pre0" }, "null": { "name": "null", diff --git a/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf b/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf index 021db79668e96..c0aee0d2d97e5 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf b/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf index 306ec1597f042..b9187beb93acf 100644 --- a/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf +++ b/provisioner/terraform/testdata/resources/multiple-agents/multiple-agents.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf b/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf index b5229bb6f488f..c52f4a58b36f4 100644 --- a/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf +++ b/provisioner/terraform/testdata/resources/multiple-apps/multiple-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf b/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf index b7f71bcc3d29b..395f766d48c4c 100644 --- a/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf +++ b/provisioner/terraform/testdata/resources/presets/external-module/child-external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = "2.3.0-pre2" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/presets/external-module/main.tf b/provisioner/terraform/testdata/resources/presets/external-module/main.tf index 00997ec835d48..bdfd29c301c06 100644 --- a/provisioner/terraform/testdata/resources/presets/external-module/main.tf +++ b/provisioner/terraform/testdata/resources/presets/external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = "2.3.0-pre2" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/presets/presets.tf b/provisioner/terraform/testdata/resources/presets/presets.tf index eb9ae6a92b6c8..ff0db7d924d86 100644 --- a/provisioner/terraform/testdata/resources/presets/presets.tf +++ b/provisioner/terraform/testdata/resources/presets/presets.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = "2.3.0-pre2" } } } diff --git a/provisioner/terraform/testdata/resources/presets/presets.tfplan.json b/provisioner/terraform/testdata/resources/presets/presets.tfplan.json index 8b1ad87592b53..f98b90d073439 100644 --- a/provisioner/terraform/testdata/resources/presets/presets.tfplan.json +++ b/provisioner/terraform/testdata/resources/presets/presets.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ok", "description": "blah blah", @@ -159,7 +159,7 @@ "type": "coder_workspace_preset", "name": "MyFirstProject", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "id": "My First Project", "name": "My First Project", @@ -174,7 +174,21 @@ } ], "instances": 4, - "scheduling": [] + "scheduling": [ + { + "schedule": [ + { + "cron": "* 8-18 * * 1-5", + "instances": 3 + }, + { + "cron": "* 8-14 * * 6", + "instances": 1 + } + ], + "timezone": "America/Los_Angeles" + } + ] } ] }, @@ -185,7 +199,14 @@ "expiration_policy": [ {} ], - "scheduling": [] + "scheduling": [ + { + "schedule": [ + {}, + {} + ] + } + ] } ] } @@ -200,7 +221,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from module", @@ -229,7 +250,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -263,7 +284,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -292,7 +313,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from child module", @@ -329,7 +350,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": ">= 2.0.0" + "version_constraint": "2.3.0-pre2" }, "module.this_is_external_module:docker": { "name": "docker", @@ -391,7 +412,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_workspace_preset.MyFirstProject", @@ -420,11 +441,36 @@ ], "instances": { "constant_value": 4 - } + }, + "scheduling": [ + { + "schedule": [ + { + "cron": { + "constant_value": "* 8-18 * * 1-5" + }, + "instances": { + "constant_value": 3 + } + }, + { + "cron": { + "constant_value": "* 8-14 * * 6" + }, + "instances": { + "constant_value": 1 + } + } + ], + "timezone": { + "constant_value": "America/Los_Angeles" + } + } + ] } ] }, - "schema_version": 1 + "schema_version": 0 } ], "module_calls": { @@ -455,7 +501,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.second_parameter_from_module", @@ -480,7 +526,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 } ], "module_calls": { @@ -511,7 +557,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.child_second_parameter_from_module", @@ -536,7 +582,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 } ] } diff --git a/provisioner/terraform/testdata/resources/presets/presets.tfstate.json b/provisioner/terraform/testdata/resources/presets/presets.tfstate.json index 9ec09ecab6466..f5dae972c774d 100644 --- a/provisioner/terraform/testdata/resources/presets/presets.tfstate.json +++ b/provisioner/terraform/testdata/resources/presets/presets.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ok", "description": "blah blah", @@ -39,7 +39,7 @@ "type": "coder_workspace_preset", "name": "MyFirstProject", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "id": "My First Project", "name": "My First Project", @@ -54,7 +54,21 @@ } ], "instances": 4, - "scheduling": [] + "scheduling": [ + { + "schedule": [ + { + "cron": "* 8-18 * * 1-5", + "instances": 3 + }, + { + "cron": "* 8-14 * * 6", + "instances": 1 + } + ], + "timezone": "America/Los_Angeles" + } + ] } ] }, @@ -65,7 +79,14 @@ "expiration_policy": [ {} ], - "scheduling": [] + "scheduling": [ + { + "schedule": [ + {}, + {} + ] + } + ] } ] } @@ -141,7 +162,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from module", @@ -170,7 +191,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -204,7 +225,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -233,7 +254,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from child module", diff --git a/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf b/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf index 1ca31e2a41cc0..b88a672f0047a 100644 --- a/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf +++ b/provisioner/terraform/testdata/resources/resource-metadata-duplicate/resource-metadata-duplicate.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf b/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf index cda7cfbd20e25..eb9f2eff89877 100644 --- a/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf +++ b/provisioner/terraform/testdata/resources/resource-metadata/resource-metadata.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf index 23e9c2ba75ebe..fc684a6e583ee 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json index 14b5d186fa93a..55226481d34b5 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": null, "description": null, @@ -159,7 +159,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ok", "description": "blah blah", @@ -244,7 +244,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.sample", @@ -269,7 +269,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 } ] } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json index c44de8192d7f9..58b0950e84d73 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-order/rich-parameters-order.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": null, "description": null, @@ -39,7 +39,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ok", "description": "blah blah", diff --git a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf index 7e59bcfbde974..8067c0fa9337c 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json index 19c8ca91656f2..54e4e33c826c3 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -159,7 +159,7 @@ "type": "coder_parameter", "name": "number_example_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -200,7 +200,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "-3", "description": null, @@ -241,7 +241,7 @@ "type": "coder_parameter", "name": "number_example_min", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -282,7 +282,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -323,7 +323,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -426,7 +426,7 @@ "constant_value": "number" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_max", @@ -452,7 +452,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_max_zero", @@ -478,7 +478,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_min", @@ -504,7 +504,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_min_max", @@ -533,7 +533,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_min_zero", @@ -559,7 +559,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 } ] } diff --git a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json index d7a0d3ce03ddb..2c718e2b48b21 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json +++ b/provisioner/terraform/testdata/resources/rich-parameters-validation/rich-parameters-validation.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -39,7 +39,7 @@ "type": "coder_parameter", "name": "number_example_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -80,7 +80,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "-3", "description": null, @@ -121,7 +121,7 @@ "type": "coder_parameter", "name": "number_example_min", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -162,7 +162,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -203,7 +203,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, diff --git a/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf b/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf index b7f71bcc3d29b..e8afbbf917fb5 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters/external-module/child-external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf b/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf index 00997ec835d48..0cf81d0162d07 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters/external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf index c271cd39ea6e6..24582eac30a5d 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf +++ b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.0.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json index bfd6afb3bbd82..66151089fb40a 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json +++ b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfplan.json @@ -130,7 +130,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": null, "description": null, @@ -176,7 +176,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -205,7 +205,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "-2", "description": null, @@ -246,7 +246,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -287,7 +287,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -328,7 +328,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ok", "description": "blah blah", @@ -361,7 +361,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from module", @@ -390,7 +390,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -424,7 +424,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -453,7 +453,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from child module", @@ -564,7 +564,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example", @@ -583,7 +583,7 @@ "constant_value": "number" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_max_zero", @@ -612,7 +612,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_min_max", @@ -641,7 +641,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.number_example_min_zero", @@ -670,7 +670,7 @@ } ] }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.sample", @@ -692,7 +692,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 } ], "module_calls": { @@ -723,7 +723,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.second_parameter_from_module", @@ -748,7 +748,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 } ], "module_calls": { @@ -779,7 +779,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 }, { "address": "data.coder_parameter.child_second_parameter_from_module", @@ -804,7 +804,7 @@ "constant_value": "string" } }, - "schema_version": 1 + "schema_version": 0 } ] } diff --git a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json index 5e1b0c1fc8884..3c1725721d774 100644 --- a/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json +++ b/provisioner/terraform/testdata/resources/rich-parameters/rich-parameters.tfstate.json @@ -10,7 +10,7 @@ "type": "coder_parameter", "name": "example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": null, "description": null, @@ -56,7 +56,7 @@ "type": "coder_parameter", "name": "number_example", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -85,7 +85,7 @@ "type": "coder_parameter", "name": "number_example_max_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "-2", "description": null, @@ -126,7 +126,7 @@ "type": "coder_parameter", "name": "number_example_min_max", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -167,7 +167,7 @@ "type": "coder_parameter", "name": "number_example_min_zero", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "4", "description": null, @@ -208,7 +208,7 @@ "type": "coder_parameter", "name": "sample", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ok", "description": "blah blah", @@ -302,7 +302,7 @@ "type": "coder_parameter", "name": "first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from module", @@ -331,7 +331,7 @@ "type": "coder_parameter", "name": "second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from module", @@ -365,7 +365,7 @@ "type": "coder_parameter", "name": "child_first_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "abcdef", "description": "First parameter from child module", @@ -394,7 +394,7 @@ "type": "coder_parameter", "name": "child_second_parameter_from_module", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 1, + "schema_version": 0, "values": { "default": "ghijkl", "description": "Second parameter from child module", diff --git a/provisioner/terraform/testdata/resources/version.txt b/provisioner/terraform/testdata/resources/version.txt index 6b89d58f861a7..3d0e62313ced1 100644 --- a/provisioner/terraform/testdata/resources/version.txt +++ b/provisioner/terraform/testdata/resources/version.txt @@ -1 +1 @@ -1.12.2 +1.11.4 From 3614a5bc19493e7eb615435e2cc32932e060a270 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 12:56:21 +0200 Subject: [PATCH 14/20] chore: fixing tests Signed-off-by: Danny Kopping --- coderd/database/dbgen/dbgen.go | 26 +++++++- .../provisionerdserver_test.go | 63 ------------------- coderd/workspaces_test.go | 12 ++-- 3 files changed, 32 insertions(+), 69 deletions(-) diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 62c27babea2bd..280b66db76945 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -390,6 +390,9 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil t.Helper() buildID := takeFirst(orig.ID, uuid.New()) + jobID := takeFirst(orig.JobID, uuid.New()) + hasAITask := takeFirst(orig.HasAITask, sql.NullBool{}) + sidebarAppID := takeFirst(orig.AITaskSidebarAppID, uuid.NullUUID{}) var build database.WorkspaceBuild err := db.InTx(func(db database.Store) error { err := db.InsertWorkspaceBuild(genCtx, database.InsertWorkspaceBuildParams{ @@ -401,7 +404,7 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil BuildNumber: takeFirst(orig.BuildNumber, 1), Transition: takeFirst(orig.Transition, database.WorkspaceTransitionStart), InitiatorID: takeFirst(orig.InitiatorID, uuid.New()), - JobID: takeFirst(orig.JobID, uuid.New()), + JobID: jobID, ProvisionerState: takeFirstSlice(orig.ProvisionerState, []byte{}), Deadline: takeFirst(orig.Deadline, dbtime.Now().Add(time.Hour)), MaxDeadline: takeFirst(orig.MaxDeadline, time.Time{}), @@ -423,6 +426,15 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil require.NoError(t, err) } + if hasAITask.Valid { + require.NoError(t, db.UpdateWorkspaceBuildAITaskByID(genCtx, database.UpdateWorkspaceBuildAITaskByIDParams{ + HasAITask: hasAITask, + SidebarAppID: sidebarAppID, + UpdatedAt: dbtime.Now(), + ID: buildID, + })) + } + build, err = db.GetWorkspaceBuildByID(genCtx, buildID) if err != nil { return err @@ -970,6 +982,8 @@ func ExternalAuthLink(t testing.TB, db database.Store, orig database.ExternalAut func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVersion) database.TemplateVersion { var version database.TemplateVersion + hasAITask := takeFirst(orig.HasAITask, sql.NullBool{}) + jobID := takeFirst(orig.JobID, uuid.New()) err := db.InTx(func(db database.Store) error { versionID := takeFirst(orig.ID, uuid.New()) err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{ @@ -981,7 +995,7 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers Name: takeFirst(orig.Name, testutil.GetRandomName(t)), Message: orig.Message, Readme: takeFirst(orig.Readme, testutil.GetRandomName(t)), - JobID: takeFirst(orig.JobID, uuid.New()), + JobID: jobID, CreatedBy: takeFirst(orig.CreatedBy, uuid.New()), SourceExampleID: takeFirst(orig.SourceExampleID, sql.NullString{}), }) @@ -989,6 +1003,14 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers return err } + if hasAITask.Valid { + require.NoError(t, db.UpdateTemplateVersionAITaskByJobID(genCtx, database.UpdateTemplateVersionAITaskByJobIDParams{ + JobID: jobID, + HasAITask: hasAITask, + UpdatedAt: dbtime.Now(), + })) + } + version, err = db.GetTemplateVersionByID(genCtx, versionID) if err != nil { return err diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 0928f44dee6e2..66684835650a8 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -1564,69 +1564,6 @@ func TestCompleteJob(t *testing.T) { require.Contains(t, job.Error.String, `external auth provider "github" is not configured`) }) - t.Run("TemplateImport_WithAITasks", func(t *testing.T) { - t.Parallel() - - t.Run("WithoutPromptParam", func(t *testing.T) { - t.Parallel() - - srv, db, _, pd := setup(t, false, &overrides{}) - jobID := uuid.New() - versionID := uuid.New() - err := db.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{ - ID: versionID, - JobID: jobID, - OrganizationID: pd.OrganizationID, - }) - require.NoError(t, err) - job, err := db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ - ID: jobID, - Provisioner: database.ProvisionerTypeEcho, - Input: []byte(`{"template_version_id": "` + versionID.String() + `"}`), - StorageMethod: database.ProvisionerStorageMethodFile, - Type: database.ProvisionerJobTypeWorkspaceBuild, - OrganizationID: pd.OrganizationID, - Tags: pd.Tags, - }) - require.NoError(t, err) - _, err = db.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{ - OrganizationID: pd.OrganizationID, - WorkerID: uuid.NullUUID{ - UUID: pd.ID, - Valid: true, - }, - Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, - StartedAt: sql.NullTime{ - Time: dbtime.Now(), - Valid: true, - }, - ProvisionerTags: must(json.Marshal(job.Tags)), - }) - require.NoError(t, err) - completeJob := func() { - _, err = srv.CompleteJob(ctx, &proto.CompletedJob{ - JobId: job.ID.String(), - Type: &proto.CompletedJob_TemplateImport_{ - TemplateImport: &proto.CompletedJob_TemplateImport{ - StartResources: []*sdkproto.Resource{{ - Name: "my_task", - Type: "coder_ai_task", - }}, - StopResources: []*sdkproto.Resource{}, - HasAiTasks: true, - Plan: []byte("{}"), - }, - }, - }) - require.NoError(t, err) - } - completeJob() - job, err = db.GetProvisionerJobByID(ctx, job.ID) - require.NoError(t, err) - require.Contains(t, job.Error.String, `external auth provider "github" is not configured`) - }) - }) - t.Run("TemplateImport_WithGitAuth", func(t *testing.T) { t.Parallel() srv, db, _, pd := setup(t, false, &overrides{ diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 4f48136abb3ee..fdbd12a5fdb99 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -19,6 +19,8 @@ import ( "github.com/stretchr/testify/require" "cdr.dev/slog" + "github.com/coder/terraform-provider-coder/v2/provider" + "github.com/coder/coder/v2/agent/agenttest" "github.com/coder/coder/v2/coderd/audit" "github.com/coder/coder/v2/coderd/coderdtest" @@ -42,7 +44,6 @@ import ( "github.com/coder/coder/v2/provisioner/echo" "github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/testutil" - "github.com/coder/terraform-provider-coder/v2/provider" ) func TestWorkspace(t *testing.T) { @@ -4508,7 +4509,10 @@ func TestWorkspaceFilterHasAITask(t *testing.T) { // Helper function to create workspace with AI task configuration createWorkspaceWithAIConfig := func(hasAITask sql.NullBool, jobCompleted bool, aiTaskPrompt *string) database.WorkspaceTable { - // When a provisioner job uses these tags, no provisioner will match it + // When a provisioner job uses these tags, no provisioner will match it. + // We do this so jobs will always be stuck in "pending", allowing us to exercise the intermediary state when + // has_ai_task is nil and we compensate by looking at pending provisioning jobs. + // See GetWorkspaces clauses. unpickableTags := database.StringMap{"custom": "true"} ws := dbgen.Workspace(t, db, database.WorkspaceTable{ @@ -4540,7 +4544,7 @@ func TestWorkspaceFilterHasAITask(t *testing.T) { //nolint:gocritic // unit test err := db.InsertWorkspaceBuildParameters(dbauthz.AsSystemRestricted(ctx), database.InsertWorkspaceBuildParametersParams{ WorkspaceBuildID: build.ID, - Name: []string{"AI Prompt"}, + Name: []string{provider.TaskPromptParameterName}, Value: []string{*aiTaskPrompt}, }) require.NoError(t, err) @@ -4550,7 +4554,7 @@ func TestWorkspaceFilterHasAITask(t *testing.T) { } // Create test workspaces with different AI task configurations - wsWithAITask := createWorkspaceWithAIConfig(sql.NullBool{Bool: true, Valid: true}, false, nil) + wsWithAITask := createWorkspaceWithAIConfig(sql.NullBool{Bool: true, Valid: true}, true, nil) wsWithoutAITask := createWorkspaceWithAIConfig(sql.NullBool{Bool: false, Valid: true}, false, nil) aiTaskPrompt := "Build me a web app" From d7e47f9fd290725834c9dacc2d900ea7818b64f4 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 14:40:08 +0200 Subject: [PATCH 15/20] chore: ensure sidebar app ID must be set when has_ai_task is set Signed-off-by: Danny Kopping --- coderd/database/dbauthz/dbauthz_test.go | 2 +- coderd/database/dbmem/dbmem.go | 7 +++ ...bar_app_id_column_and_constraint.down.sql} | 5 +- ...debar_app_id_column_and_constraint.up.sql} | 18 +++++- coderd/workspaceagents_test.go | 62 +++++++------------ coderd/workspaces_test.go | 17 +++-- 6 files changed, 64 insertions(+), 47 deletions(-) rename coderd/database/migrations/{000341_rename_ai_tasks_sidebar_app_id.down.sql => 000341_ai_task_sidebar_app_id_column_and_constraint.down.sql} (90%) rename coderd/database/migrations/{000341_rename_ai_tasks_sidebar_app_id.up.sql => 000341_ai_task_sidebar_app_id_column_and_constraint.up.sql} (65%) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 785ed85179a6e..af7a8a83d676d 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1405,7 +1405,7 @@ func (s *MethodTestSuite) TestTemplate() { TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true}, }) check.Args(database.UpdateTemplateVersionAITaskByJobIDParams{ - JobID: job.ID, + JobID: job.ID, HasAITask: sql.NullBool{Bool: true, Valid: true}, }).Asserts(t, policy.ActionUpdate) })) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 8a7e2aec661d8..a729382a0ab37 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -12062,6 +12062,13 @@ func (q *FakeQuerier) UpdateWorkspaceAutostart(_ context.Context, arg database.U } func (q *FakeQuerier) UpdateWorkspaceBuildAITaskByID(_ context.Context, arg database.UpdateWorkspaceBuildAITaskByIDParams) error { + if arg.HasAITask.Bool && !arg.SidebarAppID.Valid { + return xerrors.Errorf("ai_task_sidebar_app_id is required when has_ai_task is true") + } + if !arg.HasAITask.Valid && arg.SidebarAppID.Valid { + return xerrors.Errorf("ai_task_sidebar_app_id is can only be set when has_ai_task is true") + } + err := validateDatabaseType(arg) if err != nil { return err diff --git a/coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.down.sql b/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.down.sql similarity index 90% rename from coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.down.sql rename to coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.down.sql index 6c3a64aa1f4a4..613e17ed20933 100644 --- a/coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.down.sql +++ b/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.down.sql @@ -1,3 +1,6 @@ +-- Drop the check constraint first +ALTER TABLE workspace_builds DROP CONSTRAINT workspace_builds_ai_task_sidebar_app_id_required; + -- Revert ai_task_sidebar_app_id back to ai_tasks_sidebar_app_id in workspace_builds table ALTER TABLE workspace_builds DROP CONSTRAINT workspace_builds_ai_task_sidebar_app_id_fkey; @@ -46,4 +49,4 @@ FROM ) ); -COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; \ No newline at end of file +COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; diff --git a/coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.up.sql b/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.up.sql similarity index 65% rename from coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.up.sql rename to coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.up.sql index 4f0fab260fdd4..914b6d153994c 100644 --- a/coderd/database/migrations/000341_rename_ai_tasks_sidebar_app_id.up.sql +++ b/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.up.sql @@ -5,6 +5,22 @@ ALTER TABLE workspace_builds RENAME COLUMN ai_tasks_sidebar_app_id TO ai_task_si ALTER TABLE workspace_builds ADD CONSTRAINT workspace_builds_ai_task_sidebar_app_id_fkey FOREIGN KEY (ai_task_sidebar_app_id) REFERENCES workspace_apps(id); +-- if has_ai_task is true, ai_task_sidebar_app_id MUST be set +-- ai_task_sidebar_app_id can ONLY be set if has_ai_task is true +-- +-- has_ai_task | ai_task_sidebar_app_id | Result +-- ------------|------------------------|--------------- +-- NULL | NULL | TRUE (passes) +-- NULL | NOT NULL | FALSE (fails) +-- FALSE | NULL | TRUE (passes) +-- FALSE | NOT NULL | FALSE (fails) +-- TRUE | NULL | FALSE (fails) +-- TRUE | NOT NULL | TRUE (passes) +ALTER TABLE workspace_builds ADD CONSTRAINT workspace_builds_ai_task_sidebar_app_id_required CHECK ( + (has_ai_task IS NULL OR has_ai_task = false) AND ai_task_sidebar_app_id IS NULL OR + (has_ai_task = true AND ai_task_sidebar_app_id IS NOT NULL) +); + -- Update the workspace_build_with_user view to use the new column name DROP VIEW workspace_build_with_user; @@ -46,4 +62,4 @@ FROM ) ); -COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; \ No newline at end of file +COMMENT ON VIEW workspace_build_with_user IS 'Joins in the username + avatar url of the initiated by user.'; diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index b946b655bf345..b3fb53c228ef8 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -2,7 +2,6 @@ package coderd_test import ( "context" - "database/sql" "encoding/json" "fmt" "maps" @@ -1507,52 +1506,39 @@ func TestWorkspaceAgentAppHealth(t *testing.T) { t.Parallel() client, db := coderdtest.NewWithDatabase(t, nil) user := coderdtest.CreateFirstUser(t, client) - - // When using WithAgent() here and setting some *proto.App instances on the agent, Do() ends up trying to insert duplicate records. + apps := []*proto.App{ + { + Slug: "code-server", + Command: "some-command", + Url: "http://localhost:3000", + Icon: "/code.svg", + }, + { + Slug: "code-server-2", + DisplayName: "code-server-2", + Command: "some-command", + Url: "http://localhost:3000", + Icon: "/code.svg", + Healthcheck: &proto.Healthcheck{ + Url: "http://localhost:3000", + Interval: 5, + Threshold: 6, + }, + }, + } r := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{ OrganizationID: user.OrganizationID, OwnerID: user.UserID, + }).WithAgent(func(agents []*proto.Agent) []*proto.Agent { + agents[0].Apps = apps + return agents }).Do() - res := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{JobID: r.Build.JobID}) - agent := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{ResourceID: res.ID}) - - // It's simpler to call db.InsertWorkspaceApp directly than dbgen.WorkspaceApp because it's more terse and direct; - // the latter sets a bunch of defaults which make this test hard. - _, err := db.InsertWorkspaceApp(dbauthz.AsSystemRestricted(t.Context()), database.InsertWorkspaceAppParams{ - ID: uuid.New(), - Slug: "code-server", - AgentID: agent.ID, - Icon: "/code.svg", - Command: sql.NullString{String: "some-command", Valid: true}, - Url: sql.NullString{String: "http://localhost:3000", Valid: true}, - SharingLevel: database.AppSharingLevelOwner, - Health: database.WorkspaceAppHealthDisabled, - OpenIn: database.WorkspaceAppOpenInWindow, - }) - require.NoError(t, err) - _, err = db.InsertWorkspaceApp(dbauthz.AsSystemRestricted(t.Context()), database.InsertWorkspaceAppParams{ - ID: uuid.New(), - Slug: "code-server-2", - DisplayName: "code-server-2", - AgentID: agent.ID, - Icon: "/code.svg", - Command: sql.NullString{String: "some-command", Valid: true}, - Url: sql.NullString{String: "http://localhost:3000", Valid: true}, - HealthcheckInterval: 5, - HealthcheckUrl: "http://localhost:3000", - HealthcheckThreshold: 6, - Health: database.WorkspaceAppHealthInitializing, - SharingLevel: database.AppSharingLevelOwner, - OpenIn: database.WorkspaceAppOpenInWindow, - }) - require.NoError(t, err) - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() agentClient := agentsdk.New(client.URL) - agentClient.SetSessionToken(agent.AuthToken.String()) + agentClient.SetSessionToken(r.AgentToken) conn, err := agentClient.ConnectRPC(ctx) require.NoError(t, err) defer func() { diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index fdbd12a5fdb99..28f4f79e57dda 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -4531,13 +4531,18 @@ func TestWorkspaceFilterHasAITask(t *testing.T) { } job := dbgen.ProvisionerJob(t, db, pubsub, jobConfig) + res := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{JobID: job.ID}) + agnt := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{ResourceID: res.ID}) + sidebarApp := dbgen.WorkspaceApp(t, db, database.WorkspaceApp{AgentID: agnt.ID}) + build := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ - WorkspaceID: ws.ID, - TemplateVersionID: version.ID, - InitiatorID: user.UserID, - JobID: job.ID, - BuildNumber: 1, - HasAITask: hasAITask, + WorkspaceID: ws.ID, + TemplateVersionID: version.ID, + InitiatorID: user.UserID, + JobID: job.ID, + BuildNumber: 1, + HasAITask: hasAITask, + AITaskSidebarAppID: uuid.NullUUID{UUID: sidebarApp.ID, Valid: true}, }) if aiTaskPrompt != nil { From f4111df9cd3fcaee6d38cbfb99453ee430157dee Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 16:04:37 +0200 Subject: [PATCH 16/20] chore: test multiple coder_ai_tasks cannot be configured Signed-off-by: Danny Kopping --- coderd/workspaces_test.go | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 28f4f79e57dda..23fe6b4fc5b2a 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -4623,3 +4623,51 @@ func TestWorkspaceFilterHasAITask(t *testing.T) { require.NoError(t, err) require.Len(t, res.Workspaces, 5) } + +func TestMultipleAITasksDisallowed(t *testing.T) { + t.Parallel() + + db, pubsub := dbtestutil.NewDB(t) + client := coderdtest.New(t, &coderdtest.Options{ + Database: db, + Pubsub: pubsub, + IncludeProvisionerDaemon: true, + }) + user := coderdtest.CreateFirstUser(t, client) + + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + HasAiTasks: true, + AiTasks: []*proto.AITask{ + { + Id: uuid.NewString(), + SidebarApp: &proto.AITaskSidebarApp{ + Id: uuid.NewString(), + }, + }, + { + Id: uuid.NewString(), + SidebarApp: &proto.AITaskSidebarApp{ + Id: uuid.NewString(), + }, + }, + }, + }, + }, + }}, + }) + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + + ws := coderdtest.CreateWorkspace(t, client, template.ID) + coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID) + + //nolint: gocritic // testing + ctx := dbauthz.AsSystemRestricted(t.Context()) + pj, err := db.GetProvisionerJobByID(ctx, ws.LatestBuild.Job.ID) + require.NoError(t, err) + require.Contains(t, pj.Error.String, "only one 'coder_ai_task' resource can be provisioned per template") +} From cc0e29066b6034d9c2c9f70002a53f352d1349fc Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 16:24:46 +0200 Subject: [PATCH 17/20] chore: fix CI Signed-off-by: Danny Kopping --- coderd/database/dump.sql | 3 ++- coderd/workspaces_test.go | 9 +++++++-- site/e2e/helpers.ts | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 132ad514c9db6..0c59e73d7537d 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -2098,7 +2098,8 @@ CREATE TABLE workspace_builds ( max_deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL, template_version_preset_id uuid, has_ai_task boolean, - ai_task_sidebar_app_id uuid + ai_task_sidebar_app_id uuid, + CONSTRAINT workspace_builds_ai_task_sidebar_app_id_required CHECK (((((has_ai_task IS NULL) OR (has_ai_task = false)) AND (ai_task_sidebar_app_id IS NULL)) OR ((has_ai_task = true) AND (ai_task_sidebar_app_id IS NOT NULL)))) ); CREATE VIEW workspace_build_with_user AS diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 23fe6b4fc5b2a..8d60808d11e9b 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -4533,7 +4533,12 @@ func TestWorkspaceFilterHasAITask(t *testing.T) { res := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{JobID: job.ID}) agnt := dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{ResourceID: res.ID}) - sidebarApp := dbgen.WorkspaceApp(t, db, database.WorkspaceApp{AgentID: agnt.ID}) + + var sidebarAppID uuid.UUID + if hasAITask.Bool { + sidebarApp := dbgen.WorkspaceApp(t, db, database.WorkspaceApp{AgentID: agnt.ID}) + sidebarAppID = sidebarApp.ID + } build := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ WorkspaceID: ws.ID, @@ -4542,7 +4547,7 @@ func TestWorkspaceFilterHasAITask(t *testing.T) { JobID: job.ID, BuildNumber: 1, HasAITask: hasAITask, - AITaskSidebarAppID: uuid.NullUUID{UUID: sidebarApp.ID, Valid: true}, + AITaskSidebarAppID: uuid.NullUUID{UUID: sidebarAppID, Valid: sidebarAppID != uuid.Nil}, }) if aiTaskPrompt != nil { diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 262567b7d7c96..a738899b25f2c 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -691,6 +691,7 @@ const createTemplateVersionTar = async ( parameters: [], externalAuthProviders: [], timings: [], + aiTasks: [], ...response.apply, } as ApplyComplete; response.apply.resources = response.apply.resources?.map(fillResource); @@ -713,6 +714,7 @@ const createTemplateVersionTar = async ( plan: emptyPlan, moduleFiles: new Uint8Array(), moduleFilesHash: new Uint8Array(), + aiTasks: [], ...response.plan, } as PlanComplete; response.plan.resources = response.plan.resources?.map(fillResource); From 138d865344fde060800ab6eeb2a4a76b840bf5f5 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 16:46:23 +0200 Subject: [PATCH 18/20] chore: minor refactor Signed-off-by: Danny Kopping --- coderd/provisionerdserver/provisionerdserver.go | 7 +++++-- provisionerd/proto/version.go | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 7d9ac3aaeba16..deebb7aa50f09 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -1879,7 +1879,8 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro } var sidebarAppID uuid.NullUUID - if len(jobType.WorkspaceBuild.AiTasks) == 1 { + hasAITask := len(jobType.WorkspaceBuild.AiTasks) == 1 + if hasAITask { task := jobType.WorkspaceBuild.AiTasks[0] if task.SidebarApp == nil { return xerrors.Errorf("update ai task: sidebar app is nil") @@ -1893,10 +1894,12 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro sidebarAppID = uuid.NullUUID{UUID: id, Valid: true} } + // Regardless of whether there is an AI task or not, update the field to indicate one way or the other since it + // always defaults to nil. ONLY if has_ai_task=true MUST ai_task_sidebar_app_id be set. err = db.UpdateWorkspaceBuildAITaskByID(ctx, database.UpdateWorkspaceBuildAITaskByIDParams{ ID: workspaceBuild.ID, HasAITask: sql.NullBool{ - Bool: len(jobType.WorkspaceBuild.AiTasks) > 0, + Bool: hasAITask, Valid: true, }, SidebarAppID: sidebarAppID, diff --git a/provisionerd/proto/version.go b/provisionerd/proto/version.go index 4747eec52d5d3..6b80380bb78d9 100644 --- a/provisionerd/proto/version.go +++ b/provisionerd/proto/version.go @@ -39,10 +39,10 @@ import "github.com/coder/coder/v2/apiversion" // instances based on time patterns. // - Added new field named `id` to `App`, which transports the ID generated by the coder_app provider to be persisted. // - Added various fields in support of AI Tasks: -// - `ai_tasks` in `CompleteJob.WorkspaceBuild` -// - `has_ai_tasks` in `CompleteJob.TemplateImport` -// - `has_ai_tasks` and `ai_tasks` in `PlanComplete` -// - new message types `AITaskSidebarApp` and `AITask` +// -> `ai_tasks` in `CompleteJob.WorkspaceBuild` +// -> `has_ai_tasks` in `CompleteJob.TemplateImport` +// -> `has_ai_tasks` and `ai_tasks` in `PlanComplete` +// -> new message types `AITaskSidebarApp` and `AITask` const ( CurrentMajor = 1 CurrentMinor = 7 From 1aba76b0353bef20dc8812131ea62f477f672d94 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 23 Jun 2025 21:04:12 +0200 Subject: [PATCH 19/20] chore: add clarifying/defensive parentheses Signed-off-by: Danny Kopping --- ...1_ai_task_sidebar_app_id_column_and_constraint.up.sql | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.up.sql b/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.up.sql index 914b6d153994c..3577b9396b0df 100644 --- a/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.up.sql +++ b/coderd/database/migrations/000341_ai_task_sidebar_app_id_column_and_constraint.up.sql @@ -16,10 +16,11 @@ ALTER TABLE workspace_builds ADD CONSTRAINT workspace_builds_ai_task_sidebar_app -- FALSE | NOT NULL | FALSE (fails) -- TRUE | NULL | FALSE (fails) -- TRUE | NOT NULL | TRUE (passes) -ALTER TABLE workspace_builds ADD CONSTRAINT workspace_builds_ai_task_sidebar_app_id_required CHECK ( - (has_ai_task IS NULL OR has_ai_task = false) AND ai_task_sidebar_app_id IS NULL OR - (has_ai_task = true AND ai_task_sidebar_app_id IS NOT NULL) -); +ALTER TABLE workspace_builds + ADD CONSTRAINT workspace_builds_ai_task_sidebar_app_id_required CHECK ( + ((has_ai_task IS NULL OR has_ai_task = false) AND ai_task_sidebar_app_id IS NULL) + OR (has_ai_task = true AND ai_task_sidebar_app_id IS NOT NULL) + ); -- Update the workspace_build_with_user view to use the new column name DROP VIEW workspace_build_with_user; From bce4a889582d9ac9ed66e4202b39f631f6fe4c80 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Tue, 24 Jun 2025 10:58:52 +0200 Subject: [PATCH 20/20] chore: review comments Signed-off-by: Danny Kopping --- provisioner/terraform/resources.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 5420789e8d525..64ac4bb1063ef 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -178,7 +178,7 @@ func hasAITaskResources(graph *gographviz.Graph) bool { // Check if this node is a coder_ai_task resource if label, exists := node.Attrs["label"]; exists { labelValue := strings.Trim(label, `"`) - if strings.Contains(labelValue, "coder_ai_task.") { + if strings.HasPrefix(labelValue, "coder_ai_task.") { return true } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy