Skip to content

Commit

Permalink
Merge pull request #7 from carlosmmatos/add-runtime-detections
Browse files Browse the repository at this point in the history
feat: add Runtime Detections for Pod view
  • Loading branch information
carlosmmatos authored Sep 26, 2024
2 parents 8dbc558 + 8eeefe5 commit 37080a4
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 2 deletions.
4 changes: 4 additions & 0 deletions src/components/pod/PodTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { FalconClient } from 'crowdstrike-falcon';
import { useK8sModel, k8sGet } from '@openshift-console/dynamic-plugin-sdk';
import ImageDetectionsCard from './ImageDetectionsCard';
import ImageVulnsCard from './ImageVulnsCard';
import RuntimeDetectionsCard from './RuntimeDetectionsCard';

export default function PodDetails({ obj }) {
const [loading, setLoading] = React.useState(true);
Expand Down Expand Up @@ -66,6 +67,9 @@ export default function PodDetails({ obj }) {
{!loading && !error && (
<PageSection isFilled>
<Grid hasGutter>
<GridItem span={12}>
<RuntimeDetectionsCard client={client} pod={obj} />
</GridItem>
<GridItem span={12}>
<ImageDetectionsCard client={client} pod={obj} />
</GridItem>
Expand Down
99 changes: 99 additions & 0 deletions src/components/pod/RuntimeDetectionsCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Card, CardTitle, CardBody } from '@patternfly/react-core';
import * as React from 'react';
import SeverityLabel from '../shared/SeverityLabel';
import FindingsList from '../shared/FindingsList';
import { FalconClient } from 'crowdstrike-falcon';

interface RuntimeDetectionsCardProps {
client: FalconClient;
pod: any;
}

export default function RuntimeDetectionsCard({ client, pod }: RuntimeDetectionsCardProps) {
const [promise, setPromise] = React.useState(null);

const sevs = ['unknown', 'informational', 'low', 'medium', 'high', 'critical'];
function sorter(a, b) {
return sevs.indexOf(b.severity.toLowerCase()) - sevs.indexOf(a.severity.toLowerCase());
}

const header = [
{
field: 'detectionDescription',
width: 4,
},
{
field: 'detectTimestamp',
width: 1,
},
{
field: 'severity',
width: 1,
},
] as {
// ensure width matches the component params, not generic number
field: string;
width?: 1 | 2 | 3 | 4 | 5;
}[];

const body = [
{
field: 'containerName',
name: 'Container name',
},
{
field: 'tacticAndTechnique',
name: 'Tactic & technique',
},
{
field: 'actionTaken',
name: 'Action taken',
},
{
field: 'commandLine',
name: 'Command line',
},
];

const displayFns = {
severity: function (s) {
return <SeverityLabel name={s} />;
},
detectTimestamp: function (d) {
return new Date(d).toUTCString();
},
commandLine: function (f) {
// wrap in <pre> block
return <pre>{f}</pre>;
},
};

React.useEffect(() => {
if (client == null) return;

const filter = pod.status.containerStatuses.map((c) => {
// format: cri-o://2ab4f0fd47cf217aa345b75f64cf18c88bf5aaa1e9e7daf43157841ee0fb8026
// split on '//' and take the second part
return `container_id:'${c.containerID.split('//')[1]}'`;
});

setPromise(client.runtimeDetections.getRuntimeDetectionsCombinedV2(filter));
}, [client]);

return (
<Card>
<CardTitle>Runtime detections</CardTitle>
<CardBody>
<FindingsList
queryPromise={promise}
sortFn={sorter}
idField="detectionId"
header={header}
body={body}
termWidth="15ch"
displayFns={displayFns}
/>
</CardBody>
</Card>
);
}
6 changes: 4 additions & 2 deletions src/components/shared/FindingsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import './finding-list.css';

interface FindingsListProps {
queryPromise: Promise<any>;
sortFn: (a: any, b: any) => number;
sortFn?: (a: any, b: any) => number;
idField: string;
header: {
field: string;
Expand All @@ -34,6 +34,7 @@ interface FindingsListProps {
field: string;
name?: string;
}[];
termWidth?: string;
displayFns: Record<string, (value: any) => any>;
}

Expand All @@ -43,6 +44,7 @@ export default function FindingsList({
idField,
header,
body,
termWidth = null,
displayFns,
}: FindingsListProps) {
const [loading, setLoading] = React.useState(true);
Expand Down Expand Up @@ -114,7 +116,7 @@ export default function FindingsList({
aria-label="Finding details"
isHidden={!expanded.includes(f[idField])}
>
<DescriptionList isHorizontal isCompact>
<DescriptionList isHorizontal termWidth={termWidth} isCompact>
{body.map((b) => {
return (
<DescriptionListGroup key={b.field}>
Expand Down

0 comments on commit 37080a4

Please sign in to comment.