Skip to content

Commit 2fa6cae

Browse files
committed
feat: add workspace agent connect and app open audit types
This commit adds new audit resource types for workspace agents and workspace apps, as well as connect and open actions. The idea is that we will log new audit events for connecting to the agent via editor or SSH. Likewise, we will log openings of `coder_app`s. Updates #15139
1 parent 71cbf73 commit 2fa6cae

File tree

14 files changed

+256
-16
lines changed

14 files changed

+256
-16
lines changed

coderd/apidoc/docs.go

+12-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

+12-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/audit/diff.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ type Auditable interface {
3030
database.NotificationTemplate |
3131
idpsync.OrganizationSyncSettings |
3232
idpsync.GroupSyncSettings |
33-
idpsync.RoleSyncSettings
33+
idpsync.RoleSyncSettings |
34+
database.WorkspaceAgent |
35+
database.WorkspaceApp
3436
}
3537

3638
// Map is a map of changed fields in an audited resource. It maps field names to

coderd/audit/request.go

+16
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ func ResourceTarget[T Auditable](tgt T) string {
128128
return "Organization Group Sync"
129129
case idpsync.RoleSyncSettings:
130130
return "Organization Role Sync"
131+
case database.WorkspaceAgent:
132+
return typed.Name
133+
case database.WorkspaceApp:
134+
return typed.Slug
131135
default:
132136
panic(fmt.Sprintf("unknown resource %T for ResourceTarget", tgt))
133137
}
@@ -187,6 +191,10 @@ func ResourceID[T Auditable](tgt T) uuid.UUID {
187191
return noID // Org field on audit log has org id
188192
case idpsync.RoleSyncSettings:
189193
return noID // Org field on audit log has org id
194+
case database.WorkspaceAgent:
195+
return typed.ID
196+
case database.WorkspaceApp:
197+
return typed.ID
190198
default:
191199
panic(fmt.Sprintf("unknown resource %T for ResourceID", tgt))
192200
}
@@ -238,6 +246,10 @@ func ResourceType[T Auditable](tgt T) database.ResourceType {
238246
return database.ResourceTypeIdpSyncSettingsRole
239247
case idpsync.GroupSyncSettings:
240248
return database.ResourceTypeIdpSyncSettingsGroup
249+
case database.WorkspaceAgent:
250+
return database.ResourceTypeWorkspaceAgent
251+
case database.WorkspaceApp:
252+
return database.ResourceTypeWorkspaceApp
241253
default:
242254
panic(fmt.Sprintf("unknown resource %T for ResourceType", typed))
243255
}
@@ -291,6 +303,10 @@ func ResourceRequiresOrgID[T Auditable]() bool {
291303
return true
292304
case idpsync.RoleSyncSettings:
293305
return true
306+
case database.WorkspaceAgent:
307+
return true
308+
case database.WorkspaceApp:
309+
return true
294310
default:
295311
panic(fmt.Sprintf("unknown resource %T for ResourceRequiresOrgID", tgt))
296312
}

coderd/audit_test.go

+98-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"github.com/coder/coder/v2/coderd/database"
1818
"github.com/coder/coder/v2/coderd/rbac"
1919
"github.com/coder/coder/v2/codersdk"
20+
"github.com/coder/coder/v2/provisioner/echo"
21+
"github.com/coder/coder/v2/provisionersdk/proto"
2022
)
2123

2224
func TestAuditLogs(t *testing.T) {
@@ -229,12 +231,13 @@ func TestAuditLogsFilter(t *testing.T) {
229231
ctx = context.Background()
230232
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
231233
user = coderdtest.CreateFirstUser(t, client)
232-
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
234+
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, completeWithAgentAndApp())
233235
template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
234236
)
235237

236238
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
237239
workspace := coderdtest.CreateWorkspace(t, client, template.ID)
240+
workspace.LatestBuild = coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
238241

239242
// Create two logs with "Create"
240243
err := client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{
@@ -279,6 +282,28 @@ func TestAuditLogsFilter(t *testing.T) {
279282
})
280283
require.NoError(t, err)
281284

285+
for _, resource := range workspace.LatestBuild.Resources {
286+
t.Logf("Resource: %#v", resource)
287+
}
288+
289+
// Create one log with "Connect"
290+
err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{
291+
Action: codersdk.AuditActionConnect,
292+
ResourceType: codersdk.ResourceTypeWorkspaceAgent,
293+
ResourceID: workspace.LatestBuild.Resources[0].Agents[0].ID,
294+
Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45
295+
})
296+
require.NoError(t, err)
297+
298+
// Create one log with "Open"
299+
err = client.CreateTestAuditLog(ctx, codersdk.CreateTestAuditLogRequest{
300+
Action: codersdk.AuditActionOpen,
301+
ResourceType: codersdk.ResourceTypeWorkspaceApp,
302+
ResourceID: workspace.LatestBuild.Resources[0].Agents[0].Apps[0].ID,
303+
Time: time.Date(2022, 8, 15, 14, 30, 45, 100, time.UTC), // 2022-8-15 14:30:45
304+
})
305+
require.NoError(t, err)
306+
282307
// Test cases
283308
testCases := []struct {
284309
Name string
@@ -309,12 +334,12 @@ func TestAuditLogsFilter(t *testing.T) {
309334
{
310335
Name: "FilterByEmail",
311336
SearchQuery: "email:" + coderdtest.FirstUserParams.Email,
312-
ExpectedResult: 5,
337+
ExpectedResult: 7,
313338
},
314339
{
315340
Name: "FilterByUsername",
316341
SearchQuery: "username:" + coderdtest.FirstUserParams.Username,
317-
ExpectedResult: 5,
342+
ExpectedResult: 7,
318343
},
319344
{
320345
Name: "FilterByResourceID",
@@ -366,6 +391,16 @@ func TestAuditLogsFilter(t *testing.T) {
366391
SearchQuery: "resource_type:workspace_build action:start build_reason:initiator",
367392
ExpectedResult: 1,
368393
},
394+
{
395+
Name: "FilterOnWorkspaceAgentConnect",
396+
SearchQuery: "resource_type:workspace_agent action:connect",
397+
ExpectedResult: 1,
398+
},
399+
{
400+
Name: "FilterOnWorkspaceAppOpen",
401+
SearchQuery: "resource_type:workspace_app action:open",
402+
ExpectedResult: 1,
403+
},
369404
}
370405

371406
for _, testCase := range testCases {
@@ -387,3 +422,63 @@ func TestAuditLogsFilter(t *testing.T) {
387422
}
388423
})
389424
}
425+
426+
func completeWithAgentAndApp() *echo.Responses {
427+
return &echo.Responses{
428+
Parse: echo.ParseComplete,
429+
ProvisionPlan: []*proto.Response{
430+
{
431+
Type: &proto.Response_Plan{
432+
Plan: &proto.PlanComplete{
433+
Resources: []*proto.Resource{
434+
{
435+
Type: "compute",
436+
Name: "main",
437+
Agents: []*proto.Agent{
438+
{
439+
Name: "smith",
440+
OperatingSystem: "linux",
441+
Architecture: "i386",
442+
Apps: []*proto.App{
443+
{
444+
Slug: "app",
445+
DisplayName: "App",
446+
},
447+
},
448+
},
449+
},
450+
},
451+
},
452+
},
453+
},
454+
},
455+
},
456+
ProvisionApply: []*proto.Response{
457+
{
458+
Type: &proto.Response_Apply{
459+
Apply: &proto.ApplyComplete{
460+
Resources: []*proto.Resource{
461+
{
462+
Type: "compute",
463+
Name: "main",
464+
Agents: []*proto.Agent{
465+
{
466+
Name: "smith",
467+
OperatingSystem: "linux",
468+
Architecture: "i386",
469+
Apps: []*proto.App{
470+
{
471+
Slug: "app",
472+
DisplayName: "App",
473+
},
474+
},
475+
},
476+
},
477+
},
478+
},
479+
},
480+
},
481+
},
482+
},
483+
}
484+
}

coderd/database/dump.sql

+6-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-- No-op, enum values can't be dropped.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- Add new audit types for connect and open actions.
2+
ALTER TYPE audit_action
3+
ADD VALUE IF NOT EXISTS 'connect';
4+
ALTER TYPE audit_action
5+
ADD VALUE IF NOT EXISTS 'disconnect';
6+
ALTER TYPE resource_type
7+
ADD VALUE IF NOT EXISTS 'workspace_agent';
8+
ALTER TYPE audit_action
9+
ADD VALUE IF NOT EXISTS 'open';
10+
ALTER TYPE audit_action
11+
ADD VALUE IF NOT EXISTS 'close';
12+
ALTER TYPE resource_type
13+
ADD VALUE IF NOT EXISTS 'workspace_app';

coderd/database/models.go

+14-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)