mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
feat(coderd): add audit resource for tasks (#20301)
Updates coder/internal#976
This commit is contained in:
Generated
+4
-2
@@ -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": {
|
||||
|
||||
Generated
+4
-2
@@ -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": {
|
||||
|
||||
@@ -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 ""
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Generated
+2
-1
@@ -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 (
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
-- Nothing to do
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TYPE resource_type ADD VALUE IF NOT EXISTS 'task';
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ We track the following resources:
|
||||
| OrganizationSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>assign_default</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| PrebuildsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>reconciliation_paused</td><td>true</td></tr></tbody></table> |
|
||||
| RoleSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| TaskTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted_at</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>prompt</td><td>true</td></tr><tr><td>template_parameters</td><td>true</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>cors_behavior</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_classic_parameter_flow</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>is_system</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
|
||||
Generated
+1
@@ -7367,6 +7367,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
| `idp_sync_settings_role` |
|
||||
| `workspace_agent` |
|
||||
| `workspace_app` |
|
||||
| `task` |
|
||||
|
||||
## codersdk.Response
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Generated
+2
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user