diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 617678ab99..0fc64ef9b0 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -17247,7 +17247,8 @@ const docTemplate = `{ "idp_sync_settings_group", "idp_sync_settings_role", "workspace_agent", - "workspace_app" + "workspace_app", + "task" ], "x-enum-varnames": [ "ResourceTypeTemplate", @@ -17274,7 +17275,8 @@ const docTemplate = `{ "ResourceTypeIdpSyncSettingsGroup", "ResourceTypeIdpSyncSettingsRole", "ResourceTypeWorkspaceAgent", - "ResourceTypeWorkspaceApp" + "ResourceTypeWorkspaceApp", + "ResourceTypeTask" ] }, "codersdk.Response": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 83a51e31b8..867e5e5818 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -15759,7 +15759,8 @@ "idp_sync_settings_group", "idp_sync_settings_role", "workspace_agent", - "workspace_app" + "workspace_app", + "task" ], "x-enum-varnames": [ "ResourceTypeTemplate", @@ -15786,7 +15787,8 @@ "ResourceTypeIdpSyncSettingsGroup", "ResourceTypeIdpSyncSettingsRole", "ResourceTypeWorkspaceAgent", - "ResourceTypeWorkspaceApp" + "ResourceTypeWorkspaceApp", + "ResourceTypeTask" ] }, "codersdk.Response": { diff --git a/coderd/audit.go b/coderd/audit.go index e8d7c4dfe9..e43ed1c512 100644 --- a/coderd/audit.go +++ b/coderd/audit.go @@ -420,6 +420,14 @@ func (api *API) auditLogIsResourceDeleted(ctx context.Context, alog database.Get api.Logger.Error(ctx, "unable to fetch oauth2 app secret", slog.Error(err)) } return false + case database.ResourceTypeTask: + task, err := api.Database.GetTaskByID(ctx, alog.AuditLog.ResourceID) + if xerrors.Is(err, sql.ErrNoRows) { + return true + } else if err != nil { + api.Logger.Error(ctx, "unable to fetch task", slog.Error(err)) + } + return task.DeletedAt.Valid && task.DeletedAt.Time.Before(time.Now()) default: return false } @@ -496,6 +504,17 @@ func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAudit } return fmt.Sprintf("/deployment/oauth2-provider/apps/%s", secret.AppID) + case database.ResourceTypeTask: + task, err := api.Database.GetTaskByID(ctx, alog.AuditLog.ResourceID) + if err != nil { + return "" + } + workspace, err := api.Database.GetWorkspaceByID(ctx, task.WorkspaceID.UUID) + if err != nil { + return "" + } + return fmt.Sprintf("/tasks/%s/%s", workspace.OwnerName, task.Name) + default: return "" } diff --git a/coderd/audit/diff.go b/coderd/audit/diff.go index b8139bb63b..c14dbc392f 100644 --- a/coderd/audit/diff.go +++ b/coderd/audit/diff.go @@ -31,7 +31,8 @@ type Auditable interface { database.NotificationTemplate | idpsync.OrganizationSyncSettings | idpsync.GroupSyncSettings | - idpsync.RoleSyncSettings + idpsync.RoleSyncSettings | + database.TaskTable } // Map is a map of changed fields in an audited resource. It maps field names to diff --git a/coderd/audit/request.go b/coderd/audit/request.go index a973bdb915..20aa89f6a8 100644 --- a/coderd/audit/request.go +++ b/coderd/audit/request.go @@ -131,6 +131,8 @@ func ResourceTarget[T Auditable](tgt T) string { return "Organization Group Sync" case idpsync.RoleSyncSettings: return "Organization Role Sync" + case database.TaskTable: + return typed.Name default: panic(fmt.Sprintf("unknown resource %T for ResourceTarget", tgt)) } @@ -193,6 +195,8 @@ func ResourceID[T Auditable](tgt T) uuid.UUID { return noID // Org field on audit log has org id case idpsync.RoleSyncSettings: return noID // Org field on audit log has org id + case database.TaskTable: + return typed.ID default: panic(fmt.Sprintf("unknown resource %T for ResourceID", tgt)) } @@ -246,6 +250,8 @@ func ResourceType[T Auditable](tgt T) database.ResourceType { return database.ResourceTypeIdpSyncSettingsRole case idpsync.GroupSyncSettings: return database.ResourceTypeIdpSyncSettingsGroup + case database.TaskTable: + return database.ResourceTypeTask default: panic(fmt.Sprintf("unknown resource %T for ResourceType", typed)) } @@ -302,6 +308,8 @@ func ResourceRequiresOrgID[T Auditable]() bool { return true case idpsync.RoleSyncSettings: return true + case database.TaskTable: + return true default: panic(fmt.Sprintf("unknown resource %T for ResourceRequiresOrgID", tgt)) } diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 5b23e7b288..71e2845d1c 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -460,7 +460,8 @@ CREATE TYPE resource_type AS ENUM ( 'idp_sync_settings_role', 'workspace_agent', 'workspace_app', - 'prebuilds_settings' + 'prebuilds_settings', + 'task' ); CREATE TYPE startup_script_behavior AS ENUM ( diff --git a/coderd/database/migrations/000381_add_task_audit.down.sql b/coderd/database/migrations/000381_add_task_audit.down.sql new file mode 100644 index 0000000000..362f597df0 --- /dev/null +++ b/coderd/database/migrations/000381_add_task_audit.down.sql @@ -0,0 +1 @@ +-- Nothing to do diff --git a/coderd/database/migrations/000381_add_task_audit.up.sql b/coderd/database/migrations/000381_add_task_audit.up.sql new file mode 100644 index 0000000000..006391ac1f --- /dev/null +++ b/coderd/database/migrations/000381_add_task_audit.up.sql @@ -0,0 +1 @@ +ALTER TYPE resource_type ADD VALUE IF NOT EXISTS 'task'; diff --git a/coderd/database/models.go b/coderd/database/models.go index 8f62f1a307..741d70f9d2 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -2670,6 +2670,7 @@ const ( ResourceTypeWorkspaceAgent ResourceType = "workspace_agent" ResourceTypeWorkspaceApp ResourceType = "workspace_app" ResourceTypePrebuildsSettings ResourceType = "prebuilds_settings" + ResourceTypeTask ResourceType = "task" ) func (e *ResourceType) Scan(src interface{}) error { @@ -2733,7 +2734,8 @@ func (e ResourceType) Valid() bool { ResourceTypeIdpSyncSettingsRole, ResourceTypeWorkspaceAgent, ResourceTypeWorkspaceApp, - ResourceTypePrebuildsSettings: + ResourceTypePrebuildsSettings, + ResourceTypeTask: return true } return false @@ -2766,6 +2768,7 @@ func AllResourceTypeValues() []ResourceType { ResourceTypeWorkspaceAgent, ResourceTypeWorkspaceApp, ResourceTypePrebuildsSettings, + ResourceTypeTask, } } diff --git a/codersdk/audit.go b/codersdk/audit.go index 1e529202b5..0b2eca7d79 100644 --- a/codersdk/audit.go +++ b/codersdk/audit.go @@ -44,6 +44,7 @@ const ( // Deprecated: Workspace App connections are now included in the // connection log. ResourceTypeWorkspaceApp ResourceType = "workspace_app" + ResourceTypeTask ResourceType = "task" ) func (r ResourceType) FriendlyString() string { @@ -100,6 +101,8 @@ func (r ResourceType) FriendlyString() string { return "workspace agent" case ResourceTypeWorkspaceApp: return "workspace app" + case ResourceTypeTask: + return "task" default: return "unknown" } diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index 2c72528f38..387bdd9836 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -32,6 +32,7 @@ We track the following resources: | OrganizationSyncSettings
| |
FieldTracked
assign_defaulttrue
fieldtrue
mappingtrue
| | PrebuildsSettings
| |
FieldTracked
idfalse
reconciliation_pausedtrue
| | RoleSyncSettings
| |
FieldTracked
fieldtrue
mappingtrue
| +| TaskTable
| |
FieldTracked
created_atfalse
deleted_atfalse
idtrue
nametrue
organization_idfalse
owner_idtrue
prompttrue
template_parameterstrue
template_version_idtrue
workspace_idtrue
| | Template
write, delete | |
FieldTracked
active_version_idtrue
activity_bumptrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
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
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_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
| | 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
| diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 4c8fcba929..526deff931 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -7367,6 +7367,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit| | `idp_sync_settings_role` | | `workspace_agent` | | `workspace_app` | +| `task` | ## codersdk.Response diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index 8cba29f2e9..9b887b30ef 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -27,6 +27,7 @@ var AuditActionMap = map[string][]codersdk.AuditAction{ "Group": {codersdk.AuditActionCreate, codersdk.AuditActionWrite, codersdk.AuditActionDelete}, "APIKey": {codersdk.AuditActionLogin, codersdk.AuditActionLogout, codersdk.AuditActionRegister, codersdk.AuditActionCreate, codersdk.AuditActionDelete}, "License": {codersdk.AuditActionCreate, codersdk.AuditActionDelete}, + "Task": {codersdk.AuditActionCreate, codersdk.AuditActionWrite, codersdk.AuditActionDelete}, } type Action string @@ -347,6 +348,18 @@ var auditableResourcesTypes = map[any]map[string]Action{ "field": ActionTrack, "mapping": ActionTrack, }, + &database.TaskTable{}: { + "id": ActionTrack, + "organization_id": ActionIgnore, // Never changes. + "owner_id": ActionTrack, + "name": ActionTrack, + "workspace_id": ActionTrack, + "template_version_id": ActionTrack, + "template_parameters": ActionTrack, + "prompt": ActionTrack, + "created_at": ActionIgnore, // Never changes. + "deleted_at": ActionIgnore, // Changes, but is implicit when a delete event is fired. + }, } // auditMap converts a map of struct pointers to a map of struct names as diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index c84e4ed054..71329fb318 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -3060,6 +3060,7 @@ export type ResourceType = | "organization" | "organization_member" | "prebuilds_settings" + | "task" | "template" | "template_version" | "user" @@ -3087,6 +3088,7 @@ export const ResourceTypes: ResourceType[] = [ "organization", "organization_member", "prebuilds_settings", + "task", "template", "template_version", "user",