Skip to content

Commit c6ae151

Browse files
authored
feat: amending audit string to show workspace owner (#5364)
* resolves #5269 * clean up * fixed audit link
1 parent 66ec98f commit c6ae151

File tree

6 files changed

+66
-19
lines changed

6 files changed

+66
-19
lines changed

coderd/audit.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,9 @@ func (api *API) convertAuditLogs(ctx context.Context, dblogs []database.GetAudit
161161
}
162162

163163
type AdditionalFields struct {
164-
WorkspaceName string
165-
BuildNumber string
164+
WorkspaceName string
165+
BuildNumber string
166+
WorkspaceOwner string
166167
}
167168

168169
func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogsOffsetRow) codersdk.AuditLog {
@@ -198,8 +199,9 @@ func (api *API) convertAuditLog(ctx context.Context, dblog database.GetAuditLogs
198199
if err != nil {
199200
api.Logger.Error(ctx, "unmarshal additional fields", slog.Error(err))
200201
resourceInfo := map[string]string{
201-
"workspaceName": "unknown",
202-
"buildNumber": "unknown",
202+
"workspaceName": "unknown",
203+
"buildNumber": "unknown",
204+
"workspaceOwner": "unknown",
203205
}
204206
dblog.AdditionalFields, err = json.Marshal(resourceInfo)
205207
api.Logger.Error(ctx, "marshal additional fields", slog.Error(err))
@@ -331,8 +333,12 @@ func auditLogResourceLink(alog database.GetAuditLogsOffsetRow, additionalFields
331333
return fmt.Sprintf("/users?filter=%s",
332334
alog.ResourceTarget)
333335
case database.ResourceTypeWorkspace:
336+
workspaceOwner := alog.UserUsername.String
337+
if len(additionalFields.WorkspaceOwner) != 0 && additionalFields.WorkspaceOwner != "unknown" {
338+
workspaceOwner = additionalFields.WorkspaceOwner
339+
}
334340
return fmt.Sprintf("/@%s/%s",
335-
alog.UserUsername.String, alog.ResourceTarget)
341+
workspaceOwner, alog.ResourceTarget)
336342
case database.ResourceTypeWorkspaceBuild:
337343
if len(additionalFields.WorkspaceName) == 0 || len(additionalFields.BuildNumber) == 0 {
338344
return ""

coderd/workspaces.go

+20-11
Original file line numberDiff line numberDiff line change
@@ -237,18 +237,27 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
237237
// Create a new workspace for the currently authenticated user.
238238
func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) {
239239
var (
240-
ctx = r.Context()
241-
organization = httpmw.OrganizationParam(r)
242-
apiKey = httpmw.APIKey(r)
243-
auditor = api.Auditor.Load()
244-
user = httpmw.UserParam(r)
245-
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
246-
Audit: *auditor,
247-
Log: api.Logger,
248-
Request: r,
249-
Action: database.AuditActionCreate,
250-
})
240+
ctx = r.Context()
241+
organization = httpmw.OrganizationParam(r)
242+
apiKey = httpmw.APIKey(r)
243+
auditor = api.Auditor.Load()
244+
user = httpmw.UserParam(r)
245+
workspaceResourceInfo = map[string]string{
246+
"workspaceOwner": user.Username,
247+
}
251248
)
249+
wriBytes, err := json.Marshal(workspaceResourceInfo)
250+
if err != nil {
251+
api.Logger.Warn(ctx, "marshal workspace owner name")
252+
}
253+
254+
aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
255+
Audit: *auditor,
256+
Log: api.Logger,
257+
Request: r,
258+
Action: database.AuditActionCreate,
259+
AdditionalFields: wriBytes,
260+
})
252261
defer commitAudit()
253262

254263
if !api.Authorize(r, rbac.ActionCreate,

site/src/components/AuditLogRow/AuditLogDescription.test.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
MockAuditLog,
33
MockAuditLogWithWorkspaceBuild,
4+
MockWorkspaceCreateAuditLogForDifferentOwner,
45
} from "testHelpers/entities"
56
import { AuditLogDescription } from "./AuditLogDescription"
67
import { render } from "../../testHelpers/renderHelpers"
@@ -46,4 +47,16 @@ describe("AuditLogDescription", () => {
4647
getByTextContent("TestUser stopped build for workspace workspace"),
4748
).toBeDefined()
4849
})
50+
it("renders the correct string for a workspace created for a different owner", async () => {
51+
render(
52+
<AuditLogDescription
53+
auditLog={MockWorkspaceCreateAuditLogForDifferentOwner}
54+
/>,
55+
)
56+
expect(
57+
getByTextContent(
58+
`TestUser created workspace bruno-dev on behalf of ${MockWorkspaceCreateAuditLogForDifferentOwner.additional_fields.workspaceOwner}`,
59+
),
60+
).toBeDefined()
61+
})
4962
})

site/src/components/AuditLogRow/AuditLogDescription.tsx

+12-1
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,20 @@ export const AuditLogDescription: FC<{ auditLog: AuditLog }> = ({
4545
)}
4646
{auditLog.is_deleted && (
4747
<span className={classes.deletedLabel}>
48-
<> {t("auditLog:table.logRow.deletedLabel")}</>
48+
<>{t("auditLog:table.logRow.deletedLabel")}</>
4949
</span>
5050
)}
51+
{/* logs for workspaces created on behalf of other users indicate ownership in the description */}
52+
{auditLog.additional_fields.workspaceOwner &&
53+
auditLog.additional_fields.workspaceOwner !== "unknown" && (
54+
<span>
55+
<>
56+
{t("auditLog:table.logRow.onBehalfOf", {
57+
owner: auditLog.additional_fields.workspaceOwner,
58+
})}
59+
</>
60+
</span>
61+
)}
5162
</span>
5263
)
5364
}

site/src/i18n/en/auditLog.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
"emptyPage": "No audit logs available on this page",
99
"noLogs": "No audit logs available",
1010
"logRow": {
11-
"deletedLabel": "(deleted)",
11+
"deletedLabel": " (deleted)",
1212
"ip": "IP: ",
1313
"os": "OS: ",
1414
"browser": "Browser: ",
15-
"notAvailable": "Not available"
15+
"notAvailable": "Not available",
16+
"onBehalfOf": " on behalf of {{owner}}"
1617
}
1718
}
1819
}

site/src/testHelpers/entities.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,13 @@ export const MockAuditLog2: TypesGen.AuditLog = {
10201020
},
10211021
}
10221022

1023+
export const MockWorkspaceCreateAuditLogForDifferentOwner = {
1024+
...MockAuditLog,
1025+
additional_fields: {
1026+
workspaceOwner: "Member",
1027+
},
1028+
}
1029+
10231030
export const MockAuditLogWithWorkspaceBuild: TypesGen.AuditLog = {
10241031
...MockAuditLog,
10251032
id: "f90995bf-4a2b-4089-b597-e66e025e523e",

0 commit comments

Comments
 (0)