diff --git a/coderd/audit/diff.go b/coderd/audit/diff.go index 56ac9f88ccaae..b8139bb63b290 100644 --- a/coderd/audit/diff.go +++ b/coderd/audit/diff.go @@ -31,9 +31,7 @@ type Auditable interface { database.NotificationTemplate | idpsync.OrganizationSyncSettings | idpsync.GroupSyncSettings | - idpsync.RoleSyncSettings | - database.WorkspaceAgent | - database.WorkspaceApp + idpsync.RoleSyncSettings } // 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 ae6a57e6c2775..a973bdb915e3c 100644 --- a/coderd/audit/request.go +++ b/coderd/audit/request.go @@ -131,10 +131,6 @@ func ResourceTarget[T Auditable](tgt T) string { return "Organization Group Sync" case idpsync.RoleSyncSettings: return "Organization Role Sync" - case database.WorkspaceAgent: - return typed.Name - case database.WorkspaceApp: - return typed.Slug default: panic(fmt.Sprintf("unknown resource %T for ResourceTarget", tgt)) } @@ -197,10 +193,6 @@ 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.WorkspaceAgent: - return typed.ID - case database.WorkspaceApp: - return typed.ID default: panic(fmt.Sprintf("unknown resource %T for ResourceID", tgt)) } @@ -254,10 +246,6 @@ func ResourceType[T Auditable](tgt T) database.ResourceType { return database.ResourceTypeIdpSyncSettingsRole case idpsync.GroupSyncSettings: return database.ResourceTypeIdpSyncSettingsGroup - case database.WorkspaceAgent: - return database.ResourceTypeWorkspaceAgent - case database.WorkspaceApp: - return database.ResourceTypeWorkspaceApp default: panic(fmt.Sprintf("unknown resource %T for ResourceType", typed)) } @@ -314,10 +302,6 @@ func ResourceRequiresOrgID[T Auditable]() bool { return true case idpsync.RoleSyncSettings: return true - case database.WorkspaceAgent: - return true - case database.WorkspaceApp: - return true default: panic(fmt.Sprintf("unknown resource %T for ResourceRequiresOrgID", tgt)) } diff --git a/coderd/audit_test.go b/coderd/audit_test.go index e6fa985038155..13dbc9ccd8406 100644 --- a/coderd/audit_test.go +++ b/coderd/audit_test.go @@ -15,6 +15,7 @@ import ( "github.com/coder/coder/v2/coderd/audit" "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" + "github.com/coder/coder/v2/coderd/database/dbgen" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/provisioner/echo" @@ -531,3 +532,112 @@ func completeWithAgentAndApp() *echo.Responses { }, } } + +// TestDeprecatedConnEvents tests the deprecated connection and disconnection +// events in the audit logs. These events are no longer created, but need to be +// returned by the API. +func TestDeprecatedConnEvents(t *testing.T) { + t.Parallel() + var ( + ctx = context.Background() + client, _, api = coderdtest.NewWithAPI(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user = coderdtest.CreateFirstUser(t, client) + version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, completeWithAgentAndApp()) + template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + ) + + coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, template.ID) + workspace.LatestBuild = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) + + type additionalFields struct { + audit.AdditionalFields + ConnectionType string `json:"connection_type"` + } + + sshFields := additionalFields{ + AdditionalFields: audit.AdditionalFields{ + WorkspaceName: workspace.Name, + BuildNumber: "999", + BuildReason: "initiator", + WorkspaceOwner: workspace.OwnerName, + WorkspaceID: workspace.ID, + }, + ConnectionType: "SSH", + } + + sshFieldsBytes, err := json.Marshal(sshFields) + require.NoError(t, err) + + appFields := audit.AdditionalFields{ + WorkspaceName: workspace.Name, + // Deliberately empty + BuildNumber: "", + BuildReason: "", + WorkspaceOwner: workspace.OwnerName, + WorkspaceID: workspace.ID, + } + + appFieldsBytes, err := json.Marshal(appFields) + require.NoError(t, err) + + dbgen.AuditLog(t, api.Database, database.AuditLog{ + OrganizationID: user.OrganizationID, + Action: database.AuditActionConnect, + ResourceType: database.ResourceTypeWorkspaceAgent, + ResourceID: workspace.LatestBuild.Resources[0].Agents[0].ID, + ResourceTarget: workspace.LatestBuild.Resources[0].Agents[0].Name, + Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45 + AdditionalFields: sshFieldsBytes, + }) + + dbgen.AuditLog(t, api.Database, database.AuditLog{ + OrganizationID: user.OrganizationID, + Action: database.AuditActionDisconnect, + ResourceType: database.ResourceTypeWorkspaceAgent, + ResourceID: workspace.LatestBuild.Resources[0].Agents[0].ID, + ResourceTarget: workspace.LatestBuild.Resources[0].Agents[0].Name, + Time: time.Date(2022, 8, 15, 14, 35, 0o0, 100, time.UTC), // 2022-8-15 14:35:00 + AdditionalFields: sshFieldsBytes, + }) + + dbgen.AuditLog(t, api.Database, database.AuditLog{ + OrganizationID: user.OrganizationID, + UserID: user.UserID, + Action: database.AuditActionOpen, + ResourceType: database.ResourceTypeWorkspaceApp, + ResourceID: workspace.LatestBuild.Resources[0].Agents[0].Apps[0].ID, + ResourceTarget: workspace.LatestBuild.Resources[0].Agents[0].Apps[0].Slug, + Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45 + AdditionalFields: appFieldsBytes, + }) + + connLog, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ + SearchQuery: "action:connect", + }) + require.NoError(t, err) + require.Len(t, connLog.AuditLogs, 1) + var sshOutFields additionalFields + err = json.Unmarshal(connLog.AuditLogs[0].AdditionalFields, &sshOutFields) + require.NoError(t, err) + require.Equal(t, sshFields, sshOutFields) + + dcLog, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ + SearchQuery: "action:disconnect", + }) + require.NoError(t, err) + require.Len(t, dcLog.AuditLogs, 1) + err = json.Unmarshal(dcLog.AuditLogs[0].AdditionalFields, &sshOutFields) + require.NoError(t, err) + require.Equal(t, sshFields, sshOutFields) + + openLog, err := client.AuditLogs(ctx, codersdk.AuditLogsRequest{ + SearchQuery: "action:open", + }) + require.NoError(t, err) + require.Len(t, openLog.AuditLogs, 1) + var appOutFields audit.AdditionalFields + err = json.Unmarshal(openLog.AuditLogs[0].AdditionalFields, &appOutFields) + require.NoError(t, err) + require.Equal(t, appFields, appOutFields) +} diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 9720050a43cb1..d5693afe98826 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -65,7 +65,7 @@ func AuditLog(t testing.TB, db database.Store, seed database.AuditLog) database. Action: takeFirst(seed.Action, database.AuditActionCreate), Diff: takeFirstSlice(seed.Diff, []byte("{}")), StatusCode: takeFirst(seed.StatusCode, 200), - AdditionalFields: takeFirstSlice(seed.Diff, []byte("{}")), + AdditionalFields: takeFirstSlice(seed.AdditionalFields, []byte("{}")), RequestID: takeFirst(seed.RequestID, uuid.New()), ResourceIcon: takeFirst(seed.ResourceIcon, ""), }) diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index af033d02df2d5..4d66260fb2f7c 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -30,8 +30,6 @@ We track the following resources: | 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
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
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
| -| WorkspaceAgent
connect, disconnect | |
FieldTracked
api_key_scopefalse
api_versionfalse
architecturefalse
auth_instance_idfalse
auth_tokenfalse
connection_timeout_secondsfalse
created_atfalse
deletedfalse
directoryfalse
disconnected_atfalse
display_appsfalse
display_orderfalse
environment_variablesfalse
expanded_directoryfalse
first_connected_atfalse
idfalse
instance_metadatafalse
last_connected_atfalse
last_connected_replica_idfalse
lifecycle_statefalse
logs_lengthfalse
logs_overflowedfalse
motd_filefalse
namefalse
operating_systemfalse
parent_idfalse
ready_atfalse
resource_idfalse
resource_metadatafalse
started_atfalse
subsystemsfalse
troubleshooting_urlfalse
updated_atfalse
versionfalse
| -| WorkspaceApp
open, close | |
FieldTracked
agent_idfalse
commandfalse
created_atfalse
display_groupfalse
display_namefalse
display_orderfalse
externalfalse
healthfalse
healthcheck_intervalfalse
healthcheck_thresholdfalse
healthcheck_urlfalse
hiddenfalse
iconfalse
idfalse
open_infalse
sharing_levelfalse
slugfalse
subdomainfalse
urlfalse
| | WorkspaceBuild
start, stop | |
FieldTracked
ai_task_sidebar_app_idfalse
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
has_ai_taskfalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_namefalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
template_version_preset_idfalse
transitionfalse
updated_atfalse
workspace_idfalse
| | WorkspaceProxy
| |
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| | WorkspaceTable
| |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
next_start_attrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| @@ -91,16 +89,16 @@ log entry: "ts": "2023-06-13T03:45:37.294730279Z", "level": "INFO", "msg": "audit_log", - "caller": "/home/runner/work/coder/coder/enterprise/audit/backends/slog.go:36", - "func": "github.com/coder/coder/enterprise/audit/backends.slogBackend.Export", + "caller": "/home/coder/coder/enterprise/audit/backends/slog.go:38", + "func": "github.com/coder/coder/v2/enterprise/audit/backends.(*SlogExporter).ExportStruct", "logger_names": ["coderd"], "fields": { "ID": "033a9ffa-b54d-4c10-8ec3-2aaf9e6d741a", "Time": "2023-06-13T03:45:37.288506Z", "UserID": "6c405053-27e3-484a-9ad7-bcb64e7bfde6", "OrganizationID": "00000000-0000-0000-0000-000000000000", - "Ip": "{IPNet:{IP:\u003cnil\u003e Mask:\u003cnil\u003e} Valid:false}", - "UserAgent": "{String: Valid:false}", + "Ip": null, + "UserAgent": null, "ResourceType": "workspace_build", "ResourceID": "ca5647e0-ef50-4202-a246-717e04447380", "ResourceTarget": "", diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index 2a563946dc347..6c1f907abfa00 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -27,8 +27,6 @@ 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}, - "WorkspaceAgent": {codersdk.AuditActionConnect, codersdk.AuditActionDisconnect}, - "WorkspaceApp": {codersdk.AuditActionOpen, codersdk.AuditActionClose}, } type Action string @@ -343,63 +341,6 @@ var auditableResourcesTypes = map[any]map[string]Action{ "field": ActionTrack, "mapping": ActionTrack, }, - &database.WorkspaceAgent{}: { - "id": ActionIgnore, - "created_at": ActionIgnore, - "updated_at": ActionIgnore, - "name": ActionIgnore, - "first_connected_at": ActionIgnore, - "last_connected_at": ActionIgnore, - "disconnected_at": ActionIgnore, - "resource_id": ActionIgnore, - "auth_token": ActionIgnore, - "auth_instance_id": ActionIgnore, - "architecture": ActionIgnore, - "environment_variables": ActionIgnore, - "operating_system": ActionIgnore, - "instance_metadata": ActionIgnore, - "resource_metadata": ActionIgnore, - "directory": ActionIgnore, - "version": ActionIgnore, - "last_connected_replica_id": ActionIgnore, - "connection_timeout_seconds": ActionIgnore, - "troubleshooting_url": ActionIgnore, - "motd_file": ActionIgnore, - "lifecycle_state": ActionIgnore, - "expanded_directory": ActionIgnore, - "logs_length": ActionIgnore, - "logs_overflowed": ActionIgnore, - "started_at": ActionIgnore, - "ready_at": ActionIgnore, - "subsystems": ActionIgnore, - "display_apps": ActionIgnore, - "api_version": ActionIgnore, - "display_order": ActionIgnore, - "parent_id": ActionIgnore, - "api_key_scope": ActionIgnore, - "deleted": ActionIgnore, - }, - &database.WorkspaceApp{}: { - "id": ActionIgnore, - "created_at": ActionIgnore, - "agent_id": ActionIgnore, - "display_name": ActionIgnore, - "icon": ActionIgnore, - "command": ActionIgnore, - "url": ActionIgnore, - "healthcheck_url": ActionIgnore, - "healthcheck_interval": ActionIgnore, - "healthcheck_threshold": ActionIgnore, - "health": ActionIgnore, - "subdomain": ActionIgnore, - "sharing_level": ActionIgnore, - "slug": ActionIgnore, - "external": ActionIgnore, - "display_group": ActionIgnore, - "display_order": ActionIgnore, - "hidden": ActionIgnore, - "open_in": ActionIgnore, - }, } // auditMap converts a map of struct pointers to a map of struct names as pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy