feat: amending audit string to show workspace owner (#5364)

* resolves #5269

* clean up

* fixed audit link
This commit is contained in:
Kira Pilot 2022-12-09 12:19:30 -05:00 committed by GitHub
parent 66ec98f647
commit c6ae151f49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 19 deletions

View File

@ -161,8 +161,9 @@ func (api *API) convertAuditLogs(ctx context.Context, dblogs []database.GetAudit
}
type AdditionalFields struct {
WorkspaceName string
BuildNumber string
WorkspaceName string
BuildNumber string
WorkspaceOwner string
}
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
if err != nil {
api.Logger.Error(ctx, "unmarshal additional fields", slog.Error(err))
resourceInfo := map[string]string{
"workspaceName": "unknown",
"buildNumber": "unknown",
"workspaceName": "unknown",
"buildNumber": "unknown",
"workspaceOwner": "unknown",
}
dblog.AdditionalFields, err = json.Marshal(resourceInfo)
api.Logger.Error(ctx, "marshal additional fields", slog.Error(err))
@ -331,8 +333,12 @@ func auditLogResourceLink(alog database.GetAuditLogsOffsetRow, additionalFields
return fmt.Sprintf("/users?filter=%s",
alog.ResourceTarget)
case database.ResourceTypeWorkspace:
workspaceOwner := alog.UserUsername.String
if len(additionalFields.WorkspaceOwner) != 0 && additionalFields.WorkspaceOwner != "unknown" {
workspaceOwner = additionalFields.WorkspaceOwner
}
return fmt.Sprintf("/@%s/%s",
alog.UserUsername.String, alog.ResourceTarget)
workspaceOwner, alog.ResourceTarget)
case database.ResourceTypeWorkspaceBuild:
if len(additionalFields.WorkspaceName) == 0 || len(additionalFields.BuildNumber) == 0 {
return ""

View File

@ -237,18 +237,27 @@ func (api *API) workspaceByOwnerAndName(rw http.ResponseWriter, r *http.Request)
// Create a new workspace for the currently authenticated user.
func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
organization = httpmw.OrganizationParam(r)
apiKey = httpmw.APIKey(r)
auditor = api.Auditor.Load()
user = httpmw.UserParam(r)
aReq, commitAudit = audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
Audit: *auditor,
Log: api.Logger,
Request: r,
Action: database.AuditActionCreate,
})
ctx = r.Context()
organization = httpmw.OrganizationParam(r)
apiKey = httpmw.APIKey(r)
auditor = api.Auditor.Load()
user = httpmw.UserParam(r)
workspaceResourceInfo = map[string]string{
"workspaceOwner": user.Username,
}
)
wriBytes, err := json.Marshal(workspaceResourceInfo)
if err != nil {
api.Logger.Warn(ctx, "marshal workspace owner name")
}
aReq, commitAudit := audit.InitRequest[database.Workspace](rw, &audit.RequestParams{
Audit: *auditor,
Log: api.Logger,
Request: r,
Action: database.AuditActionCreate,
AdditionalFields: wriBytes,
})
defer commitAudit()
if !api.Authorize(r, rbac.ActionCreate,

View File

@ -1,6 +1,7 @@
import {
MockAuditLog,
MockAuditLogWithWorkspaceBuild,
MockWorkspaceCreateAuditLogForDifferentOwner,
} from "testHelpers/entities"
import { AuditLogDescription } from "./AuditLogDescription"
import { render } from "../../testHelpers/renderHelpers"
@ -46,4 +47,16 @@ describe("AuditLogDescription", () => {
getByTextContent("TestUser stopped build for workspace workspace"),
).toBeDefined()
})
it("renders the correct string for a workspace created for a different owner", async () => {
render(
<AuditLogDescription
auditLog={MockWorkspaceCreateAuditLogForDifferentOwner}
/>,
)
expect(
getByTextContent(
`TestUser created workspace bruno-dev on behalf of ${MockWorkspaceCreateAuditLogForDifferentOwner.additional_fields.workspaceOwner}`,
),
).toBeDefined()
})
})

View File

@ -45,9 +45,20 @@ export const AuditLogDescription: FC<{ auditLog: AuditLog }> = ({
)}
{auditLog.is_deleted && (
<span className={classes.deletedLabel}>
<> {t("auditLog:table.logRow.deletedLabel")}</>
<>{t("auditLog:table.logRow.deletedLabel")}</>
</span>
)}
{/* logs for workspaces created on behalf of other users indicate ownership in the description */}
{auditLog.additional_fields.workspaceOwner &&
auditLog.additional_fields.workspaceOwner !== "unknown" && (
<span>
<>
{t("auditLog:table.logRow.onBehalfOf", {
owner: auditLog.additional_fields.workspaceOwner,
})}
</>
</span>
)}
</span>
)
}

View File

@ -8,11 +8,12 @@
"emptyPage": "No audit logs available on this page",
"noLogs": "No audit logs available",
"logRow": {
"deletedLabel": "(deleted)",
"deletedLabel": " (deleted)",
"ip": "IP: ",
"os": "OS: ",
"browser": "Browser: ",
"notAvailable": "Not available"
"notAvailable": "Not available",
"onBehalfOf": " on behalf of {{owner}}"
}
}
}

View File

@ -1020,6 +1020,13 @@ export const MockAuditLog2: TypesGen.AuditLog = {
},
}
export const MockWorkspaceCreateAuditLogForDifferentOwner = {
...MockAuditLog,
additional_fields: {
workspaceOwner: "Member",
},
}
export const MockAuditLogWithWorkspaceBuild: TypesGen.AuditLog = {
...MockAuditLog,
id: "f90995bf-4a2b-4089-b597-e66e025e523e",