diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 14f7f33c7e4e6..4b281f074c8b6 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -8335,7 +8335,7 @@ func (q *querier) UpdateTemplateVersionExternalAuthProvidersByJobID(ctx context. } func (q *querier) UpdateTemplateVersionFlagsByJobID(ctx context.Context, arg database.UpdateTemplateVersionFlagsByJobIDParams) error { - // An actor is allowed to update the template version ai task and external agent flag if they are authorized to update the template. + // An actor is allowed to update the template version external agent flag if they are authorized to update the template. tv, err := q.db.GetTemplateVersionByJobID(ctx, arg.JobID) if err != nil { return err diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 3cd7b3a3faa9e..9f87cfec00850 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -2906,7 +2906,7 @@ func (s *MethodTestSuite) TestTemplate() { s.Run("UpdateTemplateVersionFlagsByJobID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { t := testutil.Fake(s.T(), faker, database.Template{}) tv := testutil.Fake(s.T(), faker, database.TemplateVersion{TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true}}) - arg := database.UpdateTemplateVersionFlagsByJobIDParams{JobID: tv.JobID, HasAITask: sql.NullBool{Bool: true, Valid: true}, HasExternalAgent: sql.NullBool{Bool: true, Valid: true}} + arg := database.UpdateTemplateVersionFlagsByJobIDParams{JobID: tv.JobID, HasExternalAgent: sql.NullBool{Bool: true, Valid: true}} dbm.EXPECT().GetTemplateVersionByJobID(gomock.Any(), tv.JobID).Return(tv, nil).AnyTimes() dbm.EXPECT().GetTemplateByID(gomock.Any(), t.ID).Return(t, nil).AnyTimes() dbm.EXPECT().UpdateTemplateVersionFlagsByJobID(gomock.Any(), arg).Return(nil).AnyTimes() @@ -4453,7 +4453,6 @@ func (s *MethodTestSuite) TestWorkspace() { dbm.EXPECT().UpdateWorkspaceBuildFlagsByID(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() check.Args(database.UpdateWorkspaceBuildFlagsByIDParams{ ID: b.ID, - HasAITask: sql.NullBool{Bool: true, Valid: true}, HasExternalAgent: sql.NullBool{Bool: true, Valid: true}, UpdatedAt: b.UpdatedAt, }).Asserts(w, policy.ActionUpdate) diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index d2d0834df662c..1bcd25408a35a 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -297,13 +297,6 @@ func (b WorkspaceBuildBuilder) doInTX() WorkspaceResponse { b.seed.ID = uuid.New() b.seed.JobID = jobID - if b.taskAppID != uuid.Nil { - b.seed.HasAITask = sql.NullBool{ - Bool: true, - Valid: true, - } - } - resp := WorkspaceResponse{ AgentToken: b.agentToken, Agents: make([]database.WorkspaceAgent, 0), diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index ad67930ddfec0..b6a8f82867ce5 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -936,7 +936,6 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil buildID := takeFirst(orig.ID, uuid.New()) jobID := takeFirst(orig.JobID, uuid.New()) - hasAITask := takeFirst(orig.HasAITask, sql.NullBool{}) hasExternalAgent := takeFirst(orig.HasExternalAgent, sql.NullBool{}) var build database.WorkspaceBuild err := db.InTx(func(db database.Store) error { @@ -971,10 +970,9 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil require.NoError(t, err) } - if hasAITask.Valid || hasExternalAgent.Valid { + if hasExternalAgent.Valid { require.NoError(t, db.UpdateWorkspaceBuildFlagsByID(genCtx, database.UpdateWorkspaceBuildFlagsByIDParams{ ID: buildID, - HasAITask: hasAITask, HasExternalAgent: hasExternalAgent, UpdatedAt: dbtime.Now(), })) @@ -1592,7 +1590,6 @@ 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{}) hasExternalAgent := takeFirst(orig.HasExternalAgent, sql.NullBool{}) jobID := takeFirst(orig.JobID, uuid.New()) err := db.InTx(func(db database.Store) error { @@ -1614,10 +1611,9 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers return err } - if hasAITask.Valid || hasExternalAgent.Valid { + if hasExternalAgent.Valid { require.NoError(t, db.UpdateTemplateVersionFlagsByJobID(genCtx, database.UpdateTemplateVersionFlagsByJobIDParams{ JobID: jobID, - HasAITask: hasAITask, HasExternalAgent: hasExternalAgent, UpdatedAt: dbtime.Now(), })) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index abbfda38e5c9b..d33a18ef14b3f 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -334,10 +334,7 @@ CREATE TYPE build_reason AS ENUM ( 'cli', 'ssh_connection', 'vscode_connection', - 'jetbrains_connection', - 'task_auto_pause', - 'task_manual_pause', - 'task_resume' + 'jetbrains_connection' ); CREATE TYPE chat_client_type AS ENUM ( @@ -3189,7 +3186,6 @@ CREATE TABLE workspace_builds ( daily_cost integer DEFAULT 0 NOT NULL, 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, has_external_agent boolean, notified_autostop_deadline timestamp with time zone DEFAULT '0001-01-01 00:00:00+00'::timestamp with time zone NOT NULL, CONSTRAINT workspace_builds_deadline_below_max_deadline CHECK ((((deadline <> '0001-01-01 00:00:00+00'::timestamp with time zone) AND (deadline <= max_deadline)) OR (max_deadline = '0001-01-01 00:00:00+00'::timestamp with time zone))) @@ -3500,7 +3496,6 @@ CREATE TABLE template_versions ( message character varying(1048576) DEFAULT ''::character varying NOT NULL, archived boolean DEFAULT false NOT NULL, source_example_id text, - has_ai_task boolean, has_external_agent boolean ); @@ -3522,7 +3517,6 @@ CREATE VIEW template_version_with_user AS template_versions.message, template_versions.archived, template_versions.source_example_id, - template_versions.has_ai_task, template_versions.has_external_agent, COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url, COALESCE(visible_users.username, ''::text) AS created_by_username, @@ -4132,7 +4126,6 @@ CREATE VIEW workspace_build_with_user AS workspace_builds.daily_cost, workspace_builds.max_deadline, workspace_builds.template_version_preset_id, - workspace_builds.has_ai_task, workspace_builds.has_external_agent, workspace_builds.notified_autostop_deadline, COALESCE(visible_users.avatar_url, ''::text) AS initiator_by_avatar_url, @@ -5019,8 +5012,6 @@ CREATE INDEX idx_telemetry_locks_period_ending_at ON telemetry_locks USING btree CREATE UNIQUE INDEX idx_template_version_presets_default ON template_version_presets USING btree (template_version_id) WHERE (is_default = true); -CREATE INDEX idx_template_versions_has_ai_task ON template_versions USING btree (has_ai_task); - CREATE UNIQUE INDEX idx_unique_preset_name ON template_version_presets USING btree (name, template_version_id); CREATE UNIQUE INDEX idx_usage_events_agent_runtime ON usage_events USING btree (event_type, created_at) WHERE (event_type = 'hb_agent_runtime_v1'::text); diff --git a/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.down.sql b/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.down.sql new file mode 100644 index 0000000000000..d633f79969934 --- /dev/null +++ b/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.down.sql @@ -0,0 +1,91 @@ +-- Drop views before modifying underlying tables and columns. +DROP VIEW IF EXISTS template_version_with_user; +DROP VIEW IF EXISTS workspace_build_with_user; + +-- Recreate has_ai_task columns and index. The dropped values are not +-- recoverable, so backfill false to satisfy older migrations that restore +-- NOT NULL on the way further down. +ALTER TABLE template_versions ADD COLUMN has_ai_task boolean DEFAULT false; +ALTER TABLE template_versions ALTER COLUMN has_ai_task DROP DEFAULT; +CREATE INDEX idx_template_versions_has_ai_task ON template_versions USING btree (has_ai_task); +ALTER TABLE workspace_builds ADD COLUMN has_ai_task boolean DEFAULT false; +ALTER TABLE workspace_builds ALTER COLUMN has_ai_task DROP DEFAULT; + +-- Recreate build_reason enum with task values. +ALTER TYPE build_reason RENAME TO build_reason_old; + +CREATE TYPE build_reason AS ENUM ( + 'initiator', + 'autostart', + 'autostop', + 'dormancy', + 'failedstop', + 'autodelete', + 'dashboard', + 'cli', + 'ssh_connection', + 'vscode_connection', + 'jetbrains_connection', + 'task_auto_pause', + 'task_manual_pause', + 'task_resume' +); + +ALTER TABLE workspace_builds ALTER COLUMN reason DROP DEFAULT; +ALTER TABLE workspace_builds ALTER COLUMN reason TYPE build_reason USING (reason::text::build_reason); +ALTER TABLE workspace_builds ALTER COLUMN reason SET DEFAULT 'initiator'::build_reason; + +ALTER TABLE workspace_build_orchestrations ALTER COLUMN child_reason TYPE build_reason USING (child_reason::text::build_reason); + +DROP TYPE build_reason_old; + +-- Recreate views. +CREATE VIEW template_version_with_user AS + SELECT template_versions.id, + template_versions.template_id, + template_versions.organization_id, + template_versions.created_at, + template_versions.updated_at, + template_versions.name, + template_versions.readme, + template_versions.job_id, + template_versions.created_by, + template_versions.external_auth_providers, + template_versions.message, + template_versions.archived, + template_versions.source_example_id, + template_versions.has_ai_task, + template_versions.has_external_agent, + COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url, + COALESCE(visible_users.username, ''::text) AS created_by_username, + COALESCE(visible_users.name, ''::text) AS created_by_name + FROM (template_versions + LEFT JOIN visible_users ON ((template_versions.created_by = visible_users.id))); + +COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by 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.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.has_external_agent, + workspace_builds.notified_autostop_deadline, + 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.'; diff --git a/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.up.sql b/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.up.sql new file mode 100644 index 0000000000000..9de1cdfe69510 --- /dev/null +++ b/coderd/database/migrations/000593_remove_has_ai_task_and_task_build_reasons.up.sql @@ -0,0 +1,99 @@ +DROP VIEW IF EXISTS template_version_with_user; +DROP VIEW IF EXISTS workspace_build_with_user; + +-- Drop has_ai_task index and columns. +DROP INDEX IF EXISTS idx_template_versions_has_ai_task; +ALTER TABLE template_versions DROP COLUMN IF EXISTS has_ai_task; +ALTER TABLE workspace_builds DROP COLUMN IF EXISTS has_ai_task; + +-- Remove task-related build reasons from build_reason enum. Automatic +-- pauses stay system-attributed; manual pauses and resumes were created by +-- authenticated user requests, so they keep user attribution as initiator. +UPDATE workspace_builds +SET reason = 'autostop' +WHERE reason::text = 'task_auto_pause'; + +UPDATE workspace_builds +SET reason = 'initiator' +WHERE reason::text IN ('task_manual_pause', 'task_resume'); + +UPDATE workspace_build_orchestrations +SET child_reason = 'autostop' +WHERE child_reason::text = 'task_auto_pause'; + +UPDATE workspace_build_orchestrations +SET child_reason = 'initiator' +WHERE child_reason::text IN ('task_manual_pause', 'task_resume'); + +ALTER TYPE build_reason RENAME TO build_reason_old; + +CREATE TYPE build_reason AS ENUM ( + 'initiator', + 'autostart', + 'autostop', + 'dormancy', + 'failedstop', + 'autodelete', + 'dashboard', + 'cli', + 'ssh_connection', + 'vscode_connection', + 'jetbrains_connection' +); + +ALTER TABLE workspace_builds ALTER COLUMN reason DROP DEFAULT; +ALTER TABLE workspace_builds ALTER COLUMN reason TYPE build_reason USING (reason::text::build_reason); +ALTER TABLE workspace_builds ALTER COLUMN reason SET DEFAULT 'initiator'::build_reason; + +ALTER TABLE workspace_build_orchestrations ALTER COLUMN child_reason TYPE build_reason USING (child_reason::text::build_reason); + +DROP TYPE build_reason_old; + +-- Recreate views without task columns. +CREATE VIEW template_version_with_user AS + SELECT template_versions.id, + template_versions.template_id, + template_versions.organization_id, + template_versions.created_at, + template_versions.updated_at, + template_versions.name, + template_versions.readme, + template_versions.job_id, + template_versions.created_by, + template_versions.external_auth_providers, + template_versions.message, + template_versions.archived, + template_versions.source_example_id, + template_versions.has_external_agent, + COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url, + COALESCE(visible_users.username, ''::text) AS created_by_username, + COALESCE(visible_users.name, ''::text) AS created_by_name + FROM (template_versions + LEFT JOIN visible_users ON ((template_versions.created_by = visible_users.id))); + +COMMENT ON VIEW template_version_with_user IS 'Joins in the username + avatar url of the created by 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.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_external_agent, + workspace_builds.notified_autostop_deadline, + 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.'; diff --git a/coderd/database/migrations/migrate_test.go b/coderd/database/migrations/migrate_test.go index 9844d8ec4bdbc..19457e9ce9f37 100644 --- a/coderd/database/migrations/migrate_test.go +++ b/coderd/database/migrations/migrate_test.go @@ -1190,6 +1190,277 @@ func TestMigration000475AgentsAccessOrgRole(t *testing.T) { ) } +func TestMigration000593RemoveHasAITaskAndTaskBuildReasons(t *testing.T) { + t.Parallel() + + const migrationVersion = 593 + sqlDB := testSQLDB(t) + next, err := migrations.Stepper(sqlDB) + require.NoError(t, err) + for { + version, more, err := next() + require.NoError(t, err) + if !more { + t.Fatalf("migration %d not found", migrationVersion) + } + if version == migrationVersion-1 { + break + } + } + + ctx := testutil.Context(t, testutil.WaitLong) + now := time.Now().UTC().Truncate(time.Microsecond) + orgID, userID, templateID, versionID, templateJobID, workspaceID := uuid.New(), uuid.New(), uuid.New(), uuid.New(), uuid.New(), uuid.New() + buildIDs := []uuid.UUID{uuid.New(), uuid.New(), uuid.New(), uuid.New(), uuid.New()} + fixtures := []struct { + query string + args []any + }{ + { + "INSERT INTO organizations (id, name, display_name, description, created_at, updated_at, default_org_member_roles) VALUES ($1, $2, '', '', $3, $3, '{}')", + []any{orgID, orgID.String(), now}, + }, + { + "INSERT INTO users (id, username, email, hashed_password, created_at, updated_at) VALUES ($1, $2, $3, '', $4, $4)", + []any{userID, userID.String(), userID.String() + "@test.com", now}, + }, + { + "INSERT INTO provisioner_jobs (id, created_at, updated_at, organization_id, initiator_id, provisioner, storage_method, file_id, type, input) VALUES ($1, $2, $2, $3, $4, 'echo', 'file', $1, 'template_version_import', '{}')", + []any{templateJobID, now, orgID, userID}, + }, + { + "INSERT INTO template_versions (id, organization_id, name, readme, created_at, updated_at, job_id, created_by, has_ai_task) VALUES ($1, $2, 'v1', '', $3, $3, $4, $5, true)", + []any{versionID, orgID, now, templateJobID, userID}, + }, + { + "INSERT INTO templates (id, organization_id, name, created_at, updated_at, provisioner, active_version_id, created_by) VALUES ($1, $2, 'build-reasons', $3, $3, 'echo', $4, $5)", + []any{templateID, orgID, now, versionID, userID}, + }, + { + "UPDATE template_versions SET template_id = $1 WHERE id = $2", + []any{templateID, versionID}, + }, + { + "INSERT INTO workspaces (id, created_at, updated_at, owner_id, organization_id, template_id, name) VALUES ($1, $2, $2, $3, $4, $5, 'build-reasons')", + []any{workspaceID, now, userID, orgID, templateID}, + }, + } + for _, fixture := range fixtures { + _, err := sqlDB.ExecContext(ctx, fixture.query, fixture.args...) + require.NoError(t, err) + } + for i, reason := range []string{"task_auto_pause", "task_manual_pause", "task_resume", "initiator", "autostop"} { + jobID := uuid.New() + _, err = sqlDB.ExecContext(ctx, + "INSERT INTO provisioner_jobs (id, created_at, updated_at, organization_id, initiator_id, provisioner, storage_method, file_id, type, input) VALUES ($1, $2, $2, $3, $4, 'echo', 'file', $1, 'workspace_build', '{}')", + jobID, now, orgID, userID) + require.NoError(t, err) + _, err = sqlDB.ExecContext(ctx, + "INSERT INTO workspace_builds (id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, reason, has_ai_task) VALUES ($1, $2, $2, $3, $4, $5, 'start', $6, $7, $8, $9)", + buildIDs[i], now, workspaceID, versionID, i+1, userID, jobID, reason, i == 0) + require.NoError(t, err) + } + _, err = sqlDB.ExecContext(ctx, + "INSERT INTO workspace_build_orchestrations (id, created_at, updated_at, workspace_id, parent_build_id, child_transition, child_reason) VALUES ($1, $2, $2, $3, $4, 'start', 'task_auto_pause')", + uuid.New(), now, workspaceID, buildIDs[0]) + require.NoError(t, err) + + version, _, err := next() + require.NoError(t, err) + require.EqualValues(t, migrationVersion, version) + var count int + var reasons pq.StringArray + const reasonsQuery = "SELECT array_agg(reason::text ORDER BY build_number) FROM workspace_builds WHERE workspace_id = $1" + wantReasons := pq.StringArray{"autostop", "initiator", "initiator", "initiator", "autostop"} + require.NoError(t, sqlDB.QueryRowContext(ctx, reasonsQuery, workspaceID).Scan(&reasons)) + require.Equal(t, wantReasons, reasons) + var childReason string + require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT child_reason FROM workspace_build_orchestrations WHERE workspace_id = $1", workspaceID).Scan(&childReason)) + require.Equal(t, "autostop", childReason) + require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM template_version_with_user").Scan(&count)) + require.Equal(t, 1, count) + require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_build_with_user").Scan(&count)) + require.Equal(t, len(buildIDs), count) + + downSQL, err := os.ReadFile("000593_remove_has_ai_task_and_task_build_reasons.down.sql") + require.NoError(t, err) + _, err = sqlDB.ExecContext(ctx, string(downSQL)) + require.NoError(t, err) + require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM template_versions WHERE has_ai_task IS FALSE").Scan(&count)) + require.Equal(t, 1, count) + require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_builds WHERE has_ai_task IS FALSE").Scan(&count)) + require.Equal(t, len(buildIDs), count) + // The original reasons cannot be recovered after remapping. + require.NoError(t, sqlDB.QueryRowContext(ctx, reasonsQuery, workspaceID).Scan(&reasons)) + require.Equal(t, wantReasons, reasons) + require.NoError(t, sqlDB.QueryRowContext(ctx, "SELECT child_reason FROM workspace_build_orchestrations WHERE workspace_id = $1", workspaceID).Scan(&childReason)) + require.Equal(t, "autostop", childReason) + + upSQL, err := os.ReadFile("000593_remove_has_ai_task_and_task_build_reasons.up.sql") + require.NoError(t, err) + _, err = sqlDB.ExecContext(ctx, string(upSQL)) + require.NoError(t, err) +} + +func TestMigration000593TaskBuildReasonRewriteTiming(t *testing.T) { + t.Parallel() + + if testing.Short() { + t.SkipNow() + return + } + + // The enum replacement rewrites workspace_builds, risking slow upgrades + // on large deployments. + const ( + migrationVersion = 593 + workspaceCount = 1_000 + buildCount = 100_000 + buildsPerWorkspace = buildCount / workspaceCount + orchestrationCount = 5_000 + taskReasonBuilds = 3 * buildCount / 10 + ) + + sqlDB := testSQLDB(t) + next, err := migrations.Stepper(sqlDB) + require.NoError(t, err) + for { + version, more, err := next() + require.NoError(t, err) + if !more { + t.Fatalf("migration %d not found", migrationVersion) + } + if version == migrationVersion-1 { + break + } + } + + ctx := testutil.Context(t, testutil.WaitSuperLong) + now := time.Now().UTC().Truncate(time.Microsecond) + + orgID := uuid.New() + userID := uuid.New() + templateID := uuid.New() + templateVersionID := uuid.New() + templateJobID := uuid.New() + + // Deterministic IDs let the bulk inserts join rows generated by + // generate_series without round-tripping IDs through the test. + const ( + workspaceIDPattern = "('a0000000-0000-4000-8000-' || lpad(%s::text, 12, '0'))::uuid" + jobIDPattern = "('b0000000-0000-4000-8000-' || lpad(%s::text, 12, '0'))::uuid" + buildIDPattern = "('c0000000-0000-4000-8000-' || lpad(%s::text, 12, '0'))::uuid" + ) + + fixtures := []struct { + query string + args []any + }{ + { + `INSERT INTO organizations (id, name, display_name, description, created_at, updated_at, default_org_member_roles) VALUES ($1, $2, $3, $4, $5, $6, '{}')`, + []any{orgID, "timing-org", "Timing Org", "", now, now}, + }, + { + `INSERT INTO users (id, username, email, hashed_password, created_at, updated_at, status, rbac_roles, login_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, + []any{userID, "timinguser", "timing@example.com", []byte{}, now, now, "active", []byte("{}"), "password"}, + }, + { + `INSERT INTO provisioner_jobs (id, created_at, updated_at, started_at, completed_at, error, organization_id, initiator_id, provisioner, storage_method, file_id, type, input, tags) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`, + []any{templateJobID, now, now, now, now, "", orgID, userID, "terraform", "file", uuid.New(), "template_version_import", []byte("{}"), []byte("{}")}, + }, + { + `INSERT INTO template_versions (id, organization_id, name, readme, created_at, updated_at, job_id, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, + []any{templateVersionID, orgID, "v1.0", "", now, now, templateJobID, userID}, + }, + { + `INSERT INTO templates (id, organization_id, name, created_at, updated_at, provisioner, active_version_id, created_by) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, + []any{templateID, orgID, "timing-template", now, now, "terraform", templateVersionID, userID}, + }, + { + `UPDATE template_versions SET template_id = $1 WHERE id = $2`, + []any{templateID, templateVersionID}, + }, + { + fmt.Sprintf(`INSERT INTO workspaces (id, created_at, updated_at, owner_id, organization_id, template_id, name, last_used_at) + SELECT `+workspaceIDPattern+`, $1, $1, $2, $3, $4, 'timing-ws-' || g, $1 + FROM generate_series(0, %d) AS g`, "g", workspaceCount-1), + []any{now, userID, orgID, templateID}, + }, + { + fmt.Sprintf(`INSERT INTO provisioner_jobs (id, created_at, updated_at, started_at, completed_at, error, organization_id, initiator_id, provisioner, storage_method, file_id, type, input, tags) + SELECT `+jobIDPattern+`, $1, $1, $1, $1, '', $2, $3, 'terraform', 'file', $4, 'workspace_build', '{}'::jsonb, '{}'::jsonb + FROM generate_series(0, %d) AS g`, "g", buildCount-1), + []any{now, orgID, userID, uuid.New()}, + }, + { + fmt.Sprintf(`INSERT INTO workspace_builds (id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, reason, has_ai_task) + SELECT `+buildIDPattern+`, $1, $1, `+fmt.Sprintf(workspaceIDPattern, "(g / %d)")+`, $2, (g %% %d) + 1, + CASE WHEN g %% 2 = 0 THEN 'start' ELSE 'stop' END::workspace_transition, $3, `+jobIDPattern+`, + CASE g %% 10 + WHEN 0 THEN 'task_auto_pause' + WHEN 1 THEN 'task_manual_pause' + WHEN 2 THEN 'task_resume' + WHEN 3 THEN 'autostart' + WHEN 4 THEN 'autostop' + ELSE 'initiator' + END::build_reason, + CASE WHEN g %% 10 < 3 THEN true END + FROM generate_series(0, %d) AS g`, "g", buildsPerWorkspace, buildsPerWorkspace, "g", buildCount-1), + []any{now, templateVersionID, userID}, + }, + { + fmt.Sprintf(`INSERT INTO workspace_build_orchestrations (id, created_at, updated_at, workspace_id, parent_build_id, child_transition, child_reason) + SELECT ('e0000000-0000-4000-8000-' || lpad(g::text, 12, '0'))::uuid, $1, $1, `+fmt.Sprintf(workspaceIDPattern, "(g * 20 / %d)")+`, `+fmt.Sprintf(buildIDPattern, "(g * 20)")+`, 'start', + CASE g %% 3 + WHEN 0 THEN 'task_auto_pause' + WHEN 1 THEN 'task_resume' + ELSE 'initiator' + END::build_reason + FROM generate_series(0, %d) AS g`, buildsPerWorkspace, orchestrationCount-1), + []any{now}, + }, + } + for i, fixture := range fixtures { + _, err := sqlDB.ExecContext(ctx, fixture.query, fixture.args...) + require.NoErrorf(t, err, "fixture %d", i) + } + + countByReason := func(table, column, reason string) int { + var n int + //nolint:gosec // Test-only query built from constant table/column names. + err := sqlDB.QueryRowContext(ctx, fmt.Sprintf("SELECT count(*) FROM %s WHERE %s::text = $1", table, column), reason).Scan(&n) + require.NoError(t, err) + return n + } + wantAutostop := countByReason("workspace_builds", "reason", "autostop") + countByReason("workspace_builds", "reason", "task_auto_pause") + wantInitiator := countByReason("workspace_builds", "reason", "initiator") + countByReason("workspace_builds", "reason", "task_manual_pause") + countByReason("workspace_builds", "reason", "task_resume") + wantChildAutostop := countByReason("workspace_build_orchestrations", "child_reason", "autostop") + countByReason("workspace_build_orchestrations", "child_reason", "task_auto_pause") + wantChildInitiator := countByReason("workspace_build_orchestrations", "child_reason", "initiator") + countByReason("workspace_build_orchestrations", "child_reason", "task_resume") + + start := time.Now() + version, _, err := next() + require.NoError(t, err) + require.EqualValues(t, migrationVersion, version) + elapsed := time.Since(start) + t.Logf("migration %d over %d workspace builds (%d with task reasons) and %d orchestrations took %s", migrationVersion, buildCount, taskReasonBuilds, orchestrationCount, elapsed) + // Bound migration time to catch regressions that could prolong upgrade downtime. + require.Lessf(t, elapsed, 2*time.Minute, "migration %d took %s at %d workspace builds", migrationVersion, elapsed, buildCount) + + var totalBuilds int + err = sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM workspace_builds").Scan(&totalBuilds) + require.NoError(t, err) + require.Equal(t, buildCount, totalBuilds) + require.Equal(t, wantAutostop, countByReason("workspace_builds", "reason", "autostop")) + require.Equal(t, wantInitiator, countByReason("workspace_builds", "reason", "initiator")) + require.Equal(t, wantChildAutostop, countByReason("workspace_build_orchestrations", "child_reason", "autostop")) + require.Equal(t, wantChildInitiator, countByReason("workspace_build_orchestrations", "child_reason", "initiator")) + + var count int + err = sqlDB.QueryRowContext(ctx, "SELECT count(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'workspace_builds' AND column_name = 'has_ai_task'").Scan(&count) + require.NoError(t, err) + require.Zero(t, count) +} + func TestMigration000587RemoveAgentsAccessRole(t *testing.T) { t.Parallel() diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go index 8345b8bd5a4b3..b0d06b65d5d72 100644 --- a/coderd/database/modelqueries.go +++ b/coderd/database/modelqueries.go @@ -145,7 +145,6 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate arg.FuzzyDisplayName, pq.Array(arg.IDs), arg.Deprecated, - arg.HasAITask, arg.AgentsAllowed, arg.AuthorID, arg.AuthorUsername, @@ -340,7 +339,6 @@ func (q *sqlQuerier) GetAuthorizedWorkspaces(ctx context.Context, arg GetWorkspa arg.LastUsedBefore, arg.LastUsedAfter, arg.UsingActive, - arg.HasAITask, arg.HasExternalAgent, arg.Shared, arg.SharedWithUserID, diff --git a/coderd/database/models.go b/coderd/database/models.go index b5a1340b353c4..d60a493c22c61 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -1366,9 +1366,6 @@ const ( BuildReasonSshConnection BuildReason = "ssh_connection" BuildReasonVscodeConnection BuildReason = "vscode_connection" BuildReasonJetbrainsConnection BuildReason = "jetbrains_connection" - BuildReasonTaskAutoPause BuildReason = "task_auto_pause" - BuildReasonTaskManualPause BuildReason = "task_manual_pause" - BuildReasonTaskResume BuildReason = "task_resume" ) func (e *BuildReason) Scan(src interface{}) error { @@ -1418,10 +1415,7 @@ func (e BuildReason) Valid() bool { BuildReasonCli, BuildReasonSshConnection, BuildReasonVscodeConnection, - BuildReasonJetbrainsConnection, - BuildReasonTaskAutoPause, - BuildReasonTaskManualPause, - BuildReasonTaskResume: + BuildReasonJetbrainsConnection: return true } return false @@ -1440,9 +1434,6 @@ func AllBuildReasonValues() []BuildReason { BuildReasonSshConnection, BuildReasonVscodeConnection, BuildReasonJetbrainsConnection, - BuildReasonTaskAutoPause, - BuildReasonTaskManualPause, - BuildReasonTaskResume, } } @@ -6214,7 +6205,6 @@ type TemplateVersion struct { Message string `db:"message" json:"message"` Archived bool `db:"archived" json:"archived"` SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"` - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"` CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"` CreatedByUsername string `db:"created_by_username" json:"created_by_username"` @@ -6306,7 +6296,6 @@ type TemplateVersionTable struct { Message string `db:"message" json:"message"` Archived bool `db:"archived" json:"archived"` SourceExampleID sql.NullString `db:"source_example_id" json:"source_example_id"` - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"` } @@ -6840,7 +6829,6 @@ type WorkspaceBuild struct { DailyCost int32 `db:"daily_cost" json:"daily_cost"` 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"` HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"` NotifiedAutostopDeadline time.Time `db:"notified_autostop_deadline" json:"notified_autostop_deadline"` InitiatorByAvatarUrl string `db:"initiator_by_avatar_url" json:"initiator_by_avatar_url"` @@ -6897,7 +6885,6 @@ type WorkspaceBuildTable struct { DailyCost int32 `db:"daily_cost" json:"daily_cost"` 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"` HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"` // The autostop deadline value that an autostop reminder notification was last sent for. Used for idempotence: when it equals the build deadline the reminder has already been sent, and it re-arms automatically when the deadline changes. NotifiedAutostopDeadline time.Time `db:"notified_autostop_deadline" json:"notified_autostop_deadline"` diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 26d2a934c618f..fe06b407691ee 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -28275,35 +28275,29 @@ WHERE END ELSE true END - -- Filter by has_ai_task in latest version - AND CASE - WHEN $9 :: boolean IS NOT NULL THEN - tv.has_ai_task = $9 :: boolean - ELSE true - END -- Filter by agents_allowed AND CASE - WHEN $10 :: boolean IS NOT NULL THEN - t.agents_allowed = $10 :: boolean + WHEN $9 :: boolean IS NOT NULL THEN + t.agents_allowed = $9 :: boolean ELSE true END -- Filter by author_id AND CASE - WHEN $11 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN - t.created_by = $11 + WHEN $10 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN + t.created_by = $10 ELSE true END -- Filter by author_username AND CASE - WHEN $12 :: text != '' THEN - t.created_by = (SELECT id FROM users WHERE lower(users.username) = lower($12) AND deleted = false) + WHEN $11 :: text != '' THEN + t.created_by = (SELECT id FROM users WHERE lower(users.username) = lower($11) AND deleted = false) ELSE true END -- Filter by has_external_agent in latest version AND CASE - WHEN $13 :: boolean IS NOT NULL THEN - tv.has_external_agent = $13 :: boolean + WHEN $12 :: boolean IS NOT NULL THEN + tv.has_external_agent = $12 :: boolean ELSE true END -- Authorize Filter clause will be injected below in GetAuthorizedTemplates @@ -28320,7 +28314,6 @@ type GetTemplatesWithFilterParams struct { FuzzyDisplayName string `db:"fuzzy_display_name" json:"fuzzy_display_name"` IDs []uuid.UUID `db:"ids" json:"ids"` Deprecated sql.NullBool `db:"deprecated" json:"deprecated"` - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` AgentsAllowed sql.NullBool `db:"agents_allowed" json:"agents_allowed"` AuthorID uuid.UUID `db:"author_id" json:"author_id"` AuthorUsername string `db:"author_username" json:"author_username"` @@ -28337,7 +28330,6 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate arg.FuzzyDisplayName, pq.Array(arg.IDs), arg.Deprecated, - arg.HasAITask, arg.AgentsAllowed, arg.AuthorID, arg.AuthorUsername, @@ -28848,7 +28840,7 @@ FROM -- Scope an archive to a single template and ignore already archived template versions ( SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent FROM template_versions WHERE @@ -28949,7 +28941,7 @@ func (q *sqlQuerier) ArchiveUnusedTemplateVersions(ctx context.Context, arg Arch const getPreviousTemplateVersion = `-- name: GetPreviousTemplateVersion :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE @@ -28987,7 +28979,6 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev &i.Message, &i.Archived, &i.SourceExampleID, - &i.HasAITask, &i.HasExternalAgent, &i.CreatedByAvatarURL, &i.CreatedByUsername, @@ -28998,7 +28989,7 @@ func (q *sqlQuerier) GetPreviousTemplateVersion(ctx context.Context, arg GetPrev const getTemplateVersionByID = `-- name: GetTemplateVersionByID :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE @@ -29022,7 +29013,6 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) ( &i.Message, &i.Archived, &i.SourceExampleID, - &i.HasAITask, &i.HasExternalAgent, &i.CreatedByAvatarURL, &i.CreatedByUsername, @@ -29033,7 +29023,7 @@ func (q *sqlQuerier) GetTemplateVersionByID(ctx context.Context, id uuid.UUID) ( const getTemplateVersionByJobID = `-- name: GetTemplateVersionByJobID :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE @@ -29057,7 +29047,6 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U &i.Message, &i.Archived, &i.SourceExampleID, - &i.HasAITask, &i.HasExternalAgent, &i.CreatedByAvatarURL, &i.CreatedByUsername, @@ -29068,7 +29057,7 @@ func (q *sqlQuerier) GetTemplateVersionByJobID(ctx context.Context, jobID uuid.U const getTemplateVersionByTemplateIDAndName = `-- name: GetTemplateVersionByTemplateIDAndName :one SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE @@ -29098,7 +29087,6 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context, &i.Message, &i.Archived, &i.SourceExampleID, - &i.HasAITask, &i.HasExternalAgent, &i.CreatedByAvatarURL, &i.CreatedByUsername, @@ -29109,7 +29097,7 @@ func (q *sqlQuerier) GetTemplateVersionByTemplateIDAndName(ctx context.Context, const getTemplateVersionsByIDs = `-- name: GetTemplateVersionsByIDs :many SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE @@ -29139,7 +29127,6 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU &i.Message, &i.Archived, &i.SourceExampleID, - &i.HasAITask, &i.HasExternalAgent, &i.CreatedByAvatarURL, &i.CreatedByUsername, @@ -29160,7 +29147,7 @@ func (q *sqlQuerier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UU const getTemplateVersionsByTemplateID = `-- name: GetTemplateVersionsByTemplateID :many SELECT - id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name + id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE @@ -29237,7 +29224,6 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge &i.Message, &i.Archived, &i.SourceExampleID, - &i.HasAITask, &i.HasExternalAgent, &i.CreatedByAvatarURL, &i.CreatedByUsername, @@ -29257,7 +29243,7 @@ func (q *sqlQuerier) GetTemplateVersionsByTemplateID(ctx context.Context, arg Ge } const getTemplateVersionsCreatedAfter = `-- name: GetTemplateVersionsCreatedAfter :many -SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_ai_task, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE created_at > $1 +SELECT id, template_id, organization_id, created_at, updated_at, name, readme, job_id, created_by, external_auth_providers, message, archived, source_example_id, has_external_agent, created_by_avatar_url, created_by_username, created_by_name FROM template_version_with_user AS template_versions WHERE created_at > $1 ` func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error) { @@ -29283,7 +29269,6 @@ func (q *sqlQuerier) GetTemplateVersionsCreatedAfter(ctx context.Context, create &i.Message, &i.Archived, &i.SourceExampleID, - &i.HasAITask, &i.HasExternalAgent, &i.CreatedByAvatarURL, &i.CreatedByUsername, @@ -29450,27 +29435,20 @@ const updateTemplateVersionFlagsByJobID = `-- name: UpdateTemplateVersionFlagsBy UPDATE template_versions SET - has_ai_task = $2, - has_external_agent = $3, - updated_at = $4 + has_external_agent = $2, + updated_at = $3 WHERE job_id = $1 ` type UpdateTemplateVersionFlagsByJobIDParams struct { JobID uuid.UUID `db:"job_id" json:"job_id"` - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } func (q *sqlQuerier) UpdateTemplateVersionFlagsByJobID(ctx context.Context, arg UpdateTemplateVersionFlagsByJobIDParams) error { - _, err := q.db.ExecContext(ctx, updateTemplateVersionFlagsByJobID, - arg.JobID, - arg.HasAITask, - arg.HasExternalAgent, - arg.UpdatedAt, - ) + _, err := q.db.ExecContext(ctx, updateTemplateVersionFlagsByJobID, arg.JobID, arg.HasExternalAgent, arg.UpdatedAt) return err } @@ -33990,7 +33968,7 @@ const getAuthenticatedWorkspaceAgentAndBuildByAuthToken = `-- name: GetAuthentic 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, workspaces.group_acl, workspaces.user_acl, 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.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.has_external_agent, workspace_build_with_user.notified_autostop_deadline, 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.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_external_agent, workspace_build_with_user.notified_autostop_deadline, workspace_build_with_user.initiator_by_avatar_url, workspace_build_with_user.initiator_by_username, workspace_build_with_user.initiator_by_name, tasks.id AS task_id FROM workspace_agents @@ -34134,7 +34112,6 @@ func (q *sqlQuerier) GetAuthenticatedWorkspaceAgentAndBuildByAuthToken(ctx conte &i.WorkspaceBuild.DailyCost, &i.WorkspaceBuild.MaxDeadline, &i.WorkspaceBuild.TemplateVersionPresetID, - &i.WorkspaceBuild.HasAITask, &i.WorkspaceBuild.HasExternalAgent, &i.WorkspaceBuild.NotifiedAutostopDeadline, &i.WorkspaceBuild.InitiatorByAvatarUrl, @@ -37673,7 +37650,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.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_ai_task, wb.has_external_agent, wb.notified_autostop_deadline, 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.job_id, wb.deadline, wb.reason, wb.daily_cost, wb.max_deadline, wb.template_version_preset_id, wb.has_external_agent, wb.notified_autostop_deadline, wb.initiator_by_avatar_url, wb.initiator_by_username, wb.initiator_by_name FROM ( SELECT workspace_id, MAX(build_number) as max_build_number @@ -37727,7 +37704,6 @@ func (q *sqlQuerier) GetActiveWorkspaceBuildsByTemplateID(ctx context.Context, t &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -37829,7 +37805,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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, 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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -37858,7 +37834,6 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildByWorkspaceID(ctx context.Context, w &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -37926,7 +37901,7 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildWithStatusByWorkspaceID(ctx context. const getLatestWorkspaceBuildsByWorkspaceIDs = `-- name: GetLatestWorkspaceBuildsByWorkspaceIDs :many SELECT DISTINCT ON (workspace_id) - id, created_at, updated_at, workspace_id, template_version_id, build_number, transition, initiator_id, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, 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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -37959,7 +37934,6 @@ func (q *sqlQuerier) GetLatestWorkspaceBuildsByWorkspaceIDs(ctx context.Context, &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -37981,7 +37955,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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, 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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -38008,7 +37982,6 @@ func (q *sqlQuerier) GetWorkspaceBuildByID(ctx context.Context, id uuid.UUID) (W &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -38020,7 +37993,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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, 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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -38047,7 +38020,6 @@ func (q *sqlQuerier) GetWorkspaceBuildByJobID(ctx context.Context, jobID uuid.UU &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -38059,7 +38031,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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, 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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -38090,7 +38062,6 @@ func (q *sqlQuerier) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx context.Co &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -38267,7 +38238,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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, 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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, initiator_by_avatar_url, initiator_by_username, initiator_by_name FROM workspace_build_with_user AS workspace_builds WHERE @@ -38337,7 +38308,6 @@ func (q *sqlQuerier) GetWorkspaceBuildsByWorkspaceID(ctx context.Context, arg Ge &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -38358,7 +38328,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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_ai_task, has_external_agent, notified_autostop_deadline, 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, job_id, deadline, reason, daily_cost, max_deadline, template_version_preset_id, has_external_agent, notified_autostop_deadline, 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) { @@ -38385,7 +38355,6 @@ func (q *sqlQuerier) GetWorkspaceBuildsCreatedAfter(ctx context.Context, created &i.DailyCost, &i.MaxDeadline, &i.TemplateVersionPresetID, - &i.HasAITask, &i.HasExternalAgent, &i.NotifiedAutostopDeadline, &i.InitiatorByAvatarUrl, @@ -38522,26 +38491,19 @@ const updateWorkspaceBuildFlagsByID = `-- name: UpdateWorkspaceBuildFlagsByID :e UPDATE workspace_builds SET - has_ai_task = $1, - has_external_agent = $2, - updated_at = $3::timestamptz -WHERE id = $4::uuid + has_external_agent = $1, + updated_at = $2::timestamptz +WHERE id = $3::uuid ` type UpdateWorkspaceBuildFlagsByIDParams struct { - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` ID uuid.UUID `db:"id" json:"id"` } func (q *sqlQuerier) UpdateWorkspaceBuildFlagsByID(ctx context.Context, arg UpdateWorkspaceBuildFlagsByIDParams) error { - _, err := q.db.ExecContext(ctx, updateWorkspaceBuildFlagsByID, - arg.HasAITask, - arg.HasExternalAgent, - arg.UpdatedAt, - arg.ID, - ) + _, err := q.db.ExecContext(ctx, updateWorkspaceBuildFlagsByID, arg.HasExternalAgent, arg.UpdatedAt, arg.ID) return err } @@ -39808,7 +39770,6 @@ LEFT JOIN LATERAL ( workspace_builds.id, workspace_builds.transition, workspace_builds.template_version_id, - workspace_builds.has_ai_task, workspace_builds.has_external_agent, template_versions.name AS template_version_name, provisioner_jobs.id AS provisioner_job_id, @@ -40029,43 +39990,28 @@ WHERE (latest_build.template_version_id = template.active_version_id) = $19 :: boolean ELSE true END - -- Filter by has_ai_task, checks if this is a task workspace. - AND CASE - WHEN $20::boolean IS NOT NULL - THEN $20::boolean = EXISTS ( - SELECT - 1 - FROM - tasks - WHERE - -- Consider all tasks, deleting a task does not turn the - -- workspace into a non-task workspace. - tasks.workspace_id = workspaces.id - ) - ELSE true - END -- Filter by has_external_agent in latest build AND CASE - WHEN $21 :: boolean IS NOT NULL THEN - latest_build.has_external_agent = $21 :: boolean + WHEN $20 :: boolean IS NOT NULL THEN + latest_build.has_external_agent = $20 :: boolean ELSE true END -- Filter by shared status AND CASE - WHEN $22 :: boolean IS NOT NULL THEN - (workspaces.user_acl != '{}'::jsonb OR workspaces.group_acl != '{}'::jsonb) = $22 :: boolean + WHEN $21 :: boolean IS NOT NULL THEN + (workspaces.user_acl != '{}'::jsonb OR workspaces.group_acl != '{}'::jsonb) = $21 :: boolean ELSE true END -- Filter by shared_with_user_id AND CASE - WHEN $23 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN - workspaces.user_acl ? ($23 :: uuid) :: text + WHEN $22 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN + workspaces.user_acl ? ($22 :: uuid) :: text ELSE true END -- Filter by shared_with_group_id AND CASE - WHEN $24 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN - workspaces.group_acl ? ($24 :: uuid) :: text + WHEN $23 :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN + workspaces.group_acl ? ($23 :: uuid) :: text ELSE true END @@ -40078,7 +40024,7 @@ WHERE filtered_workspaces fw ORDER BY -- To ensure that 'favorite' workspaces show up first in the list only for their owner. - CASE WHEN favorite AND owner_username = (SELECT users.username FROM users WHERE users.id = $25) THEN 0 ELSE 1 END ASC, + CASE WHEN favorite AND owner_username = (SELECT users.username FROM users WHERE users.id = $24) THEN 0 ELSE 1 END ASC, (latest_build_completed_at IS NOT NULL AND latest_build_canceled_at IS NULL AND latest_build_error IS NULL AND @@ -40087,11 +40033,11 @@ WHERE LOWER(name) ASC LIMIT CASE - WHEN $27 :: integer > 0 THEN - $27 + WHEN $26 :: integer > 0 THEN + $26 END OFFSET - $26 + $25 ), filtered_workspaces_order_with_summary AS ( SELECT fwo.id, fwo.created_at, fwo.updated_at, fwo.owner_id, fwo.organization_id, fwo.template_id, fwo.deleted, fwo.name, fwo.autostart_schedule, fwo.ttl, fwo.last_used_at, fwo.dormant_at, fwo.deleting_at, fwo.automatic_updates, fwo.favorite, fwo.next_start_at, fwo.group_acl, fwo.user_acl, fwo.owner_avatar_url, fwo.owner_username, fwo.owner_name, fwo.organization_name, fwo.organization_display_name, fwo.organization_icon, fwo.organization_description, fwo.template_name, fwo.template_display_name, fwo.template_icon, fwo.template_description, fwo.task_id, fwo.group_acl_display_info, fwo.user_acl_display_info, fwo.template_version_id, fwo.template_version_name, fwo.latest_build_completed_at, fwo.latest_build_canceled_at, fwo.latest_build_error, fwo.latest_build_transition, fwo.latest_build_status, fwo.latest_build_has_external_agent, fwo.latest_build_provisioner_job_id @@ -40144,7 +40090,7 @@ WHERE false, -- latest_build_has_external_agent '00000000-0000-0000-0000-000000000000'::uuid -- latest_build_provisioner_job_id WHERE - $28 :: boolean = true + $27 :: boolean = true ), total_count AS ( SELECT count(*) AS count @@ -40233,7 +40179,6 @@ type GetWorkspacesParams struct { LastUsedBefore time.Time `db:"last_used_before" json:"last_used_before"` LastUsedAfter time.Time `db:"last_used_after" json:"last_used_after"` UsingActive sql.NullBool `db:"using_active" json:"using_active"` - HasAITask sql.NullBool `db:"has_ai_task" json:"has_ai_task"` HasExternalAgent sql.NullBool `db:"has_external_agent" json:"has_external_agent"` Shared sql.NullBool `db:"shared" json:"shared"` SharedWithUserID uuid.UUID `db:"shared_with_user_id" json:"shared_with_user_id"` @@ -40314,7 +40259,6 @@ func (q *sqlQuerier) GetWorkspaces(ctx context.Context, arg GetWorkspacesParams) arg.LastUsedBefore, arg.LastUsedAfter, arg.UsingActive, - arg.HasAITask, arg.HasExternalAgent, arg.Shared, arg.SharedWithUserID, diff --git a/coderd/database/queries/templates.sql b/coderd/database/queries/templates.sql index ba4836086448c..d05c78a61ad3a 100644 --- a/coderd/database/queries/templates.sql +++ b/coderd/database/queries/templates.sql @@ -71,12 +71,6 @@ WHERE END ELSE true END - -- Filter by has_ai_task in latest version - AND CASE - WHEN sqlc.narg('has_ai_task') :: boolean IS NOT NULL THEN - tv.has_ai_task = sqlc.narg('has_ai_task') :: boolean - ELSE true - END -- Filter by agents_allowed AND CASE WHEN sqlc.narg('agents_allowed') :: boolean IS NOT NULL THEN diff --git a/coderd/database/queries/templateversions.sql b/coderd/database/queries/templateversions.sql index e68383aa0632e..4813c0f83d92c 100644 --- a/coderd/database/queries/templateversions.sql +++ b/coderd/database/queries/templateversions.sql @@ -230,8 +230,7 @@ RETURNING template_versions.id; UPDATE template_versions SET - has_ai_task = $2, - has_external_agent = $3, - updated_at = $4 + has_external_agent = $2, + updated_at = $3 WHERE job_id = $1; diff --git a/coderd/database/queries/workspacebuilds.sql b/coderd/database/queries/workspacebuilds.sql index 390ffefab9e01..7afe146d39791 100644 --- a/coderd/database/queries/workspacebuilds.sql +++ b/coderd/database/queries/workspacebuilds.sql @@ -252,7 +252,6 @@ ORDER BY UPDATE workspace_builds SET - has_ai_task = @has_ai_task, has_external_agent = @has_external_agent, updated_at = @updated_at::timestamptz WHERE id = @id::uuid; diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index 15251b56ca0a8..81d57c167f085 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -130,7 +130,6 @@ LEFT JOIN LATERAL ( workspace_builds.id, workspace_builds.transition, workspace_builds.template_version_id, - workspace_builds.has_ai_task, workspace_builds.has_external_agent, template_versions.name AS template_version_name, provisioner_jobs.id AS provisioner_job_id, @@ -351,21 +350,6 @@ WHERE (latest_build.template_version_id = template.active_version_id) = sqlc.narg('using_active') :: boolean ELSE true END - -- Filter by has_ai_task, checks if this is a task workspace. - AND CASE - WHEN sqlc.narg('has_ai_task')::boolean IS NOT NULL - THEN sqlc.narg('has_ai_task')::boolean = EXISTS ( - SELECT - 1 - FROM - tasks - WHERE - -- Consider all tasks, deleting a task does not turn the - -- workspace into a non-task workspace. - tasks.workspace_id = workspaces.id - ) - ELSE true - END -- Filter by has_external_agent in latest build AND CASE WHEN sqlc.narg('has_external_agent') :: boolean IS NOT NULL THEN diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 2052edd2c0b63..771b121a6d138 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -2038,9 +2038,6 @@ func (s *server) completeTemplateImportJob(ctx context.Context, job database.Pro } err = db.UpdateTemplateVersionFlagsByJobID(ctx, database.UpdateTemplateVersionFlagsByJobIDParams{ JobID: jobID, - // Tasks are removed; the has_ai_task column is dropped in a - // follow-up migration. - HasAITask: sql.NullBool{Bool: false, Valid: true}, HasExternalAgent: sql.NullBool{ Bool: jobType.TemplateImport.HasExternalAgents, Valid: true, @@ -2320,9 +2317,6 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro }) if err := db.UpdateWorkspaceBuildFlagsByID(ctx, database.UpdateWorkspaceBuildFlagsByIDParams{ ID: workspaceBuild.ID, - // Tasks are removed; the has_ai_task column is dropped in a - // follow-up migration. - HasAITask: sql.NullBool{Bool: false, Valid: true}, HasExternalAgent: sql.NullBool{ Bool: hasExternalAgent, Valid: true, diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index c2e4d884b2bfa..8bfca3fe8b4da 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -45,11 +45,11 @@ We track the following resources: | PrebuildsSettings
| |
FieldTracked
idfalse
reconciliation_pausedtrue
| | RoleSyncSettings
| |
FieldTracked
fieldtrue
mappingtrue
| | Template
write, delete | |
FieldTracked
active_version_idtrue
activity_bumptrue
agents_allowedtrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
allow_workspace_renamestrue
autostart_block_days_of_weektrue
autostop_requirement_days_of_weektrue
autostop_requirement_weekstrue
cors_behaviortrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_namefalse
created_by_usernamefalse
default_ttltrue
deletedfalse
deprecatedtrue
descriptiontrue
disable_module_cachetrue
display_nametrue
failure_ttltrue
group_acltrue
icontrue
idtrue
max_port_sharing_leveltrue
nametrue
organization_display_namefalse
organization_iconfalse
organization_idfalse
organization_namefalse
provisionertrue
require_active_versiontrue
time_til_autostop_notifytrue
time_til_dormanttrue
time_til_dormant_autodeletetrue
updated_atfalse
use_classic_parameter_flowtrue
user_acltrue
| -| TemplateVersion
create, write | |
FieldTracked
archivedtrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_namefalse
created_by_usernamefalse
external_auth_providersfalse
has_ai_taskfalse
has_external_agentfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
source_example_idfalse
template_idtrue
updated_atfalse
| +| TemplateVersion
create, write | |
FieldTracked
archivedtrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_namefalse
created_by_usernamefalse
external_auth_providersfalse
has_external_agentfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
source_example_idfalse
template_idtrue
updated_atfalse
| | User
create, write, delete | |
FieldTracked
avatar_urlfalse
chat_spend_limit_microstrue
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_one_time_passcodefalse
hashed_passwordtrue
idtrue
is_service_accounttrue
is_systemtrue
last_seen_atfalse
login_typetrue
nametrue
one_time_passcode_expires_attrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
updated_atfalse
usernametrue
| | UserSecret
create, write, delete | |
FieldTracked
created_atfalse
descriptiontrue
enabledtrue
env_nametrue
file_pathtrue
idtrue
nametrue
updated_atfalse
user_idtrue
valuetrue
value_key_idfalse
| | UserSkill
create, write, delete | |
FieldTracked
contenttrue
created_atfalse
descriptiontrue
idtrue
nametrue
updated_atfalse
user_idtrue
| -| WorkspaceBuild
start, stop | |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
has_ai_taskfalse
has_external_agentfalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_namefalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
notified_autostop_deadlinefalse
reasonfalse
template_version_idtrue
template_version_preset_idfalse
transitionfalse
updated_atfalse
workspace_idfalse
| +| WorkspaceBuild
start, stop | |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
has_external_agentfalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_namefalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
notified_autostop_deadlinefalse
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
group_acltrue
idtrue
last_used_atfalse
nametrue
next_start_attrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
user_acltrue
| diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index e4339af2507ce..823db47223d5a 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -154,7 +154,6 @@ var auditableResourcesTypes = map[any]map[string]Action{ "created_by_name": ActionIgnore, "archived": ActionTrack, "source_example_id": ActionIgnore, // Never changes. - "has_ai_task": ActionIgnore, // Never changes. "has_external_agent": ActionIgnore, // Never changes. }, &database.User{}: { @@ -217,7 +216,6 @@ var auditableResourcesTypes = map[any]map[string]Action{ "initiator_by_username": ActionIgnore, "initiator_by_name": ActionIgnore, "template_version_preset_id": ActionIgnore, // Never changes. - "has_ai_task": ActionIgnore, // Never changes. "has_external_agent": ActionIgnore, // Never changes. "notified_autostop_deadline": ActionIgnore, // Updated by the notification system, not by user action. },