feat: Auditing group members as part of group resource (#5730)

* added AuditableGroup type

* added json tags

* Anonymizing gGroup struct

* adding support on the FE for nested group diffs

* added type for GroupMember

* Update coderd/database/modelmethods.go

Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com>

* Update coderd/database/modelmethods.go

Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com>

* fetching group members in group.delete

* passing through right error

* broke out into util function and added tests

Co-authored-by: Steven Masley <Emyrk@users.noreply.github.com>
This commit is contained in:
Kira Pilot
2023-01-18 15:13:39 -05:00
committed by GitHub
co-authored by Steven Masley
parent 56b996532f
commit 6b68fbbf18
10 changed files with 230 additions and 27 deletions
@@ -3,6 +3,7 @@ import { AuditLog } from "api/typesGenerated"
import { colors } from "theme/colors"
import { MONOSPACE_FONT_FAMILY } from "theme/constants"
import { combineClasses } from "util/combineClasses"
import { FC } from "react"
const getDiffValue = (value: unknown): string => {
if (typeof value === "string") {
@@ -21,9 +22,7 @@ const getDiffValue = (value: unknown): string => {
return value.toString()
}
export const AuditLogDiff: React.FC<{ diff: AuditLog["diff"] }> = ({
diff,
}) => {
export const AuditLogDiff: FC<{ diff: AuditLog["diff"] }> = ({ diff }) => {
const styles = useStyles()
const diffEntries = Object.entries(diff)
@@ -16,6 +16,7 @@ import userAgentParser from "ua-parser-js"
import { AuditLogDiff } from "./AuditLogDiff"
import i18next from "i18next"
import { AuditLogDescription } from "./AuditLogDescription"
import { determineGroupDiff } from "./auditUtils"
const httpStatusColor = (httpStatus: number): PaletteIndex => {
if (httpStatus >= 300 && httpStatus < 500) {
@@ -49,6 +50,13 @@ export const AuditLogRow: React.FC<AuditLogRowProps> = ({
? `${browser.name} ${browser.version}`
: t("auditLog:table.logRow.notAvailable")
let auditDiff = auditLog.diff
// groups have nested diffs (group members)
if (auditLog.resource_type === "group") {
auditDiff = determineGroupDiff(auditLog.diff)
}
const toggle = () => {
if (shouldDisplayDiff) {
setIsDiffOpen((v) => !v)
@@ -153,7 +161,7 @@ export const AuditLogRow: React.FC<AuditLogRowProps> = ({
{shouldDisplayDiff && (
<Collapse in={isDiffOpen}>
<AuditLogDiff diff={auditLog.diff} />
<AuditLogDiff diff={auditDiff} />
</Collapse>
)}
</TableCell>
@@ -0,0 +1,122 @@
import { determineGroupDiff } from "./auditUtils"
const auditDiffForNewGroup = {
id: {
old: "",
new: "e22e0eb9-625a-468b-b962-269b19473789",
secret: false,
},
members: {
new: [],
secret: false,
},
name: {
old: "",
new: "another-test-group",
secret: false,
},
}
const auditDiffForAddedGroupMember = {
members: {
old: [],
new: [
{
group_id: "e22e0eb9-625a-468b-b962-269b19473789",
user_id: "cea4c2b0-6373-4858-b26a-df3cbfce8845",
},
],
secret: false,
},
}
const auditDiffForRemovedGroupMember = {
members: {
old: [
{
group_id: "25793395-b093-4a3c-a473-9ecf9b243478",
user_id: "84d1cd5a-17e1-4022-898c-52e64256e737",
},
{
group_id: "25793395-b093-4a3c-a473-9ecf9b243478",
user_id: "cea4c2b0-6373-4858-b26a-df3cbfce8845",
},
],
new: [
{
group_id: "25793395-b093-4a3c-a473-9ecf9b243478",
user_id: "84d1cd5a-17e1-4022-898c-52e64256e737",
},
],
secret: false,
},
}
const AuditDiffForDeletedGroup = {
id: {
old: "25793395-b093-4a3c-a473-9ecf9b243478",
new: "",
secret: false,
},
members: {
old: [
{
group_id: "25793395-b093-4a3c-a473-9ecf9b243478",
user_id: "84d1cd5a-17e1-4022-898c-52e64256e737",
},
],
secret: false,
},
name: {
old: "test-group",
new: "",
secret: false,
},
}
describe("determineAuditDiff", () => {
it("auditDiffForNewGroup", () => {
// there should be no change as members are not added when a group is created
expect(determineGroupDiff(auditDiffForNewGroup)).toEqual(
auditDiffForNewGroup,
)
})
it("auditDiffForAddedGroupMember", () => {
const result = {
members: {
...auditDiffForAddedGroupMember.members,
new: ["cea4c2b0-6373-4858-b26a-df3cbfce8845"],
},
}
expect(determineGroupDiff(auditDiffForAddedGroupMember)).toEqual(result)
})
it("auditDiffForRemovedGroupMember", () => {
const result = {
members: {
...auditDiffForRemovedGroupMember.members,
old: [
"84d1cd5a-17e1-4022-898c-52e64256e737",
"cea4c2b0-6373-4858-b26a-df3cbfce8845",
],
new: ["84d1cd5a-17e1-4022-898c-52e64256e737"],
},
}
expect(determineGroupDiff(auditDiffForRemovedGroupMember)).toEqual(result)
})
it("AuditDiffForDeletedGroup", () => {
const result = {
...AuditDiffForDeletedGroup,
members: {
...AuditDiffForDeletedGroup.members,
old: ["84d1cd5a-17e1-4022-898c-52e64256e737"],
},
}
expect(determineGroupDiff(AuditDiffForDeletedGroup)).toEqual(result)
})
})
@@ -0,0 +1,26 @@
import { AuditDiff } from "api/typesGenerated"
interface GroupMember {
user_id: string
group_id: string
}
/**
*
* @param auditLogDiff
* @returns a diff with the 'members' key flattened to be an array of user_ids
*/
export const determineGroupDiff = (auditLogDiff: AuditDiff): AuditDiff => {
return {
...auditLogDiff,
members: {
old: auditLogDiff.members.old?.map(
(groupMember: GroupMember) => groupMember.user_id,
),
new: auditLogDiff.members.new?.map(
(groupMember: GroupMember) => groupMember.user_id,
),
secret: auditLogDiff.members.secret,
},
}
}