mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: support session audit log (#16703)
Related to https://github.com/coder/coder/issues/15139 Demo: <img width="1213" alt="Screenshot 2025-02-25 at 16 27 12" src="https://github.com/user-attachments/assets/9995a68d-5cd4-4b95-9523-dfd5bf4ff48d" /> --------- Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
This commit is contained in:
co-authored by
Mathias Fredriksson
parent
2971957b88
commit
f1b357d6f2
@@ -11,12 +11,15 @@ interface AuditLogDescriptionProps {
|
||||
export const AuditLogDescription: FC<AuditLogDescriptionProps> = ({
|
||||
auditLog,
|
||||
}) => {
|
||||
let target = auditLog.resource_target.trim();
|
||||
let user = auditLog.user?.username.trim();
|
||||
|
||||
if (auditLog.resource_type === "workspace_build") {
|
||||
return <BuildAuditDescription auditLog={auditLog} />;
|
||||
}
|
||||
if (auditLog.additional_fields?.connection_type) {
|
||||
return <AppSessionAuditLogDescription auditLog={auditLog} />;
|
||||
}
|
||||
|
||||
let target = auditLog.resource_target.trim();
|
||||
let user = auditLog.user?.username.trim();
|
||||
|
||||
// SSH key entries have no links
|
||||
if (auditLog.resource_type === "git_ssh_key") {
|
||||
@@ -57,3 +60,19 @@ export const AuditLogDescription: FC<AuditLogDescriptionProps> = ({
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
function AppSessionAuditLogDescription({ auditLog }: AuditLogDescriptionProps) {
|
||||
const { connection_type, workspace_owner, workspace_name } =
|
||||
auditLog.additional_fields;
|
||||
|
||||
return (
|
||||
<>
|
||||
{connection_type} session to {workspace_owner}'s{" "}
|
||||
<Link component={RouterLink} to={`${auditLog.resource_link}`}>
|
||||
<strong>{workspace_name}</strong>
|
||||
</Link>{" "}
|
||||
workspace{" "}
|
||||
<strong>{auditLog.action === "disconnect" ? "closed" : "opened"}</strong>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -159,3 +159,43 @@ export const NoUserAgent: Story = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithConnectionType: Story = {
|
||||
args: {
|
||||
showOrgDetails: true,
|
||||
auditLog: {
|
||||
id: "725ea2f2-faae-4bdd-a821-c2384a67d89c",
|
||||
request_id: "a486c1cb-6acb-41c9-9bce-1f4f24a2e8ff",
|
||||
time: "2025-02-24T10:20:08.054072Z",
|
||||
ip: "fd7a:115c:a1e0:4fa5:9ccd:27e4:5d72:c66a",
|
||||
user_agent: "",
|
||||
resource_type: "workspace_agent",
|
||||
resource_id: "813311fb-bad3-4a92-98cd-09ee57e73d6e",
|
||||
resource_target: "main",
|
||||
resource_icon: "",
|
||||
action: "disconnect",
|
||||
diff: {},
|
||||
status_code: 255,
|
||||
additional_fields: {
|
||||
reason: "process exited with error status: -1",
|
||||
build_number: "1",
|
||||
build_reason: "initiator",
|
||||
workspace_id: "6a7cfb32-d208-47bb-91d0-ec54b69912b6",
|
||||
workspace_name: "test2",
|
||||
connection_type: "SSH",
|
||||
workspace_owner: "admin",
|
||||
},
|
||||
description: "{user} disconnected workspace agent {target}",
|
||||
resource_link: "",
|
||||
is_deleted: false,
|
||||
organization_id: "0e6fa63f-b625-4a6f-ab5b-a8217f8c80b3",
|
||||
organization: {
|
||||
id: "0e6fa63f-b625-4a6f-ab5b-a8217f8c80b3",
|
||||
name: "coder",
|
||||
display_name: "Coder",
|
||||
icon: "",
|
||||
},
|
||||
user: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -128,6 +128,8 @@ export const AuditLogRow: FC<AuditLogRowProps> = ({
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" alignItems="center">
|
||||
<StatusPill code={auditLog.status_code} />
|
||||
|
||||
{/* With multi-org, there is not enough space so show
|
||||
everything in a tooltip. */}
|
||||
{showOrgDetails ? (
|
||||
@@ -169,6 +171,12 @@ export const AuditLogRow: FC<AuditLogRowProps> = ({
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
{auditLog.additional_fields?.reason && (
|
||||
<div>
|
||||
<h4 css={styles.auditLogInfoHeader}>Reason:</h4>
|
||||
<div>{auditLog.additional_fields?.reason}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
@@ -203,13 +211,6 @@ export const AuditLogRow: FC<AuditLogRowProps> = ({
|
||||
)}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
<Pill
|
||||
css={styles.httpStatusPill}
|
||||
type={httpStatusColor(auditLog.status_code)}
|
||||
>
|
||||
{auditLog.status_code.toString()}
|
||||
</Pill>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
@@ -218,7 +219,7 @@ export const AuditLogRow: FC<AuditLogRowProps> = ({
|
||||
{shouldDisplayDiff ? (
|
||||
<div> {<DropdownArrow close={isDiffOpen} />}</div>
|
||||
) : (
|
||||
<div css={styles.columnWithoutDiff}></div>
|
||||
<div css={styles.columnWithoutDiff} />
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -232,6 +233,19 @@ export const AuditLogRow: FC<AuditLogRowProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
function StatusPill({ code }: { code: number }) {
|
||||
const isHttp = code >= 100;
|
||||
|
||||
return (
|
||||
<Pill
|
||||
css={styles.statusCodePill}
|
||||
type={isHttp ? httpStatusColor(code) : code === 0 ? "success" : "error"}
|
||||
>
|
||||
{code.toString()}
|
||||
</Pill>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = {
|
||||
auditLogCell: {
|
||||
padding: "0 !important",
|
||||
@@ -287,7 +301,7 @@ const styles = {
|
||||
width: "100%",
|
||||
},
|
||||
|
||||
httpStatusPill: {
|
||||
statusCodePill: {
|
||||
fontSize: 10,
|
||||
height: 20,
|
||||
paddingLeft: 10,
|
||||
|
||||
Reference in New Issue
Block a user