Skip to content

Commit

Permalink
Issue 31: Support trivy scan2html k8s --report summary cluster intera…
Browse files Browse the repository at this point in the history
…ctive_result.html (#34)

* Support trivy scan2html k8s --report summary cluster interactive_result.html

* Support trivy scan2html k8s --report summary cluster interactive_result.html
  • Loading branch information
fatihtokus authored Apr 18, 2024
1 parent d0c7d23 commit 049c8ed
Show file tree
Hide file tree
Showing 15 changed files with 35,307 additions and 90 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ trivy scan2html k8s cluster interactive_result.html
![result](docs/result-2.png)
</details>

### Scan a k8s cluster for summary
### Scan a k8s cluster all
```sh
trivy scan2html k8s --report=all all interactive_result.html
```
Expand All @@ -46,6 +46,16 @@ trivy scan2html k8s --report=all all interactive_result.html
![result](docs/result-3.png)
</details>

### Scan a k8s cluster summary
```sh
trivy scan2html k8s --report summary cluster interactive_result.html
```
<details>
<summary>Result</summary>

![result](docs/result-4.png)
</details>

## Help
```sh
$ trivy scan2html -h
Expand Down
Binary file added docs/result-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions plugin.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
name: "scan2html"
repository: github.com/fatihtokus/scan2html
version: "0.2.5"
version: "0.2.6"
usage: scan targets into a smart html file
description: |-
A Trivy plugin that scans and outputs the results to a html file.
trivy scan2html [-h,--help] command target filename
platforms:
- selector:
os: windows
uri: https://github.com/fatihtokus/scan2html/releases/download/v0.2.5/scan2html.tar.gz
uri: https://github.com/fatihtokus/scan2html/releases/download/v0.2.6/scan2html.tar.gz
bin: ./scan2html.sh
-
uri: https://github.com/fatihtokus/scan2html/releases/download/v0.2.5/scan2html.tar.gz
uri: https://github.com/fatihtokus/scan2html/releases/download/v0.2.6/scan2html.tar.gz
bin: ./scan2html
8 changes: 6 additions & 2 deletions scan2html
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ Examples:
# Scan a k8s cluster
trivy scan2html k8s cluster interactive_result.html
# Scan a k8s cluster for summary
# Scan a k8s cluster all
trivy scan2html k8s --report=all all interactive_result.html
# Scan a k8s cluster summary
trivy scan2html k8s --report summary cluster interactive_result.html
EOS
exit
}
Expand Down Expand Up @@ -125,7 +129,7 @@ function scan {
fi

# Using replace_text function
replace_text "$reportName" "{TEMP_DATA:B7}" "$result_json"
replace_text "$reportName" "{TEMP_DATA:n9}" "$result_json"

echo "$reportName has been created!"
trap 'rm -f $tmp_result' EXIT
Expand Down
14 changes: 11 additions & 3 deletions src/frontend-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Title from "antd/es/typography/Title";
import TrivyReport from "./components/trivy-report/TrivyReport";
import defaultData from "./data/data.json";
import { NormalizedResultForDataTable } from "./types";
import { getMisconfigurationSummary, getMisconfigurations, getVulnerabilities } from "./utils/index";
import { getMisconfigurationSummary, getK8sClusterSummaryForInfraAssessment, getK8sClusterSummaryForRBACAssessment, getMisconfigurations, getVulnerabilities } from "./utils/index";
import { UploadOutlined } from '@ant-design/icons';
import "./App.css";

Expand Down Expand Up @@ -33,7 +33,9 @@ function App() {
const [vulnerabilities, setVulnerabilities] = useState<NormalizedResultForDataTable[]>([]);
const [misconfigurations, setMisconfigurations] = useState<NormalizedResultForDataTable[]>([]);
const [misconfigurationSummary, setMisconfigurationSummary] = useState<NormalizedResultForDataTable[]>([]);
const [vulnerabilitiesOrMisconfigurations, setVulnerabilitiesOrMisconfigurations] = useState("vulnerabilities");
const [k8sClusterSummaryInfraAssessment, setK8sClusterSummaryInfraAssessment] = useState<NormalizedResultForDataTable[]>([]);
const [k8sClusterSummaryRBACAssessment, setK8sClusterSummaryRBACAssessment] = useState<NormalizedResultForDataTable[]>([]);
const [vulnerabilitiesOrMisconfigurations, setVulnerabilitiesOrMisconfigurations] = useState("k8sClusterSummary");
const [loadedFile, setLoadedFile] = useState("");

const handleUpload = (info: UploadInfo) => {
Expand All @@ -55,6 +57,8 @@ function App() {
setVulnerabilities(getVulnerabilities(jsonObject));
setMisconfigurations(getMisconfigurations(jsonObject));
setMisconfigurationSummary(getMisconfigurationSummary(jsonObject));
setK8sClusterSummaryInfraAssessment(getK8sClusterSummaryForInfraAssessment(jsonObject));
setK8sClusterSummaryRBACAssessment(getK8sClusterSummaryForRBACAssessment(jsonObject));
} catch (error) {
console.error('Error parsing JSON:', error);
}
Expand All @@ -74,11 +78,13 @@ function App() {
setVulnerabilities(getVulnerabilities(defaultData));
setMisconfigurations(getMisconfigurations(defaultData));
setMisconfigurationSummary(getMisconfigurationSummary(defaultData));
setK8sClusterSummaryInfraAssessment(getK8sClusterSummaryForInfraAssessment(defaultData));
setK8sClusterSummaryRBACAssessment(getK8sClusterSummaryForRBACAssessment(defaultData));
}, []);

return (
<>
<Title level={3}>Trivy Report via scan2html</Title>
<Title level={3}>Trivy Report via scan2html(v0.2.6)</Title>
<Upload
onChange={handleUpload}
accept='.json'
Expand All @@ -92,6 +98,8 @@ function App() {
vulnerabilities={vulnerabilities}
misconfigurations={misconfigurations}
misconfigurationSummary={misconfigurationSummary}
k8sClusterSummaryInfraAssessment={k8sClusterSummaryInfraAssessment}
k8sClusterSummaryRBACAssessment={k8sClusterSummaryRBACAssessment}
vulnerabilitiesOrMisconfigurations={vulnerabilitiesOrMisconfigurations}
setVulnerabilitiesOrMisconfigurations={setVulnerabilitiesOrMisconfigurations}
/>
Expand Down
105 changes: 105 additions & 0 deletions src/frontend-app/src/components/trivy-report/K8sClusterSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { Table } from "antd";
const { Column, ColumnGroup } = Table;
import { NormalizedResultForDataTable } from "../../types";

interface K8sClusterSummaryProps {
k8sClusterSummaryInfraAssessment: NormalizedResultForDataTable[];
k8sClusterSummaryRBACAssessment: NormalizedResultForDataTable[];
}

const K8sClusterSummary: React.FC<K8sClusterSummaryProps> = ({ k8sClusterSummaryInfraAssessment, k8sClusterSummaryRBACAssessment }) => {
console.log("K8sClusterSummary-k8sSummaryInfraAssessment:", k8sClusterSummaryInfraAssessment);
console.log("K8sClusterSummary-k8sSummaryRBACAssessment:", k8sClusterSummaryRBACAssessment);

return (
<>
<Table dataSource={k8sClusterSummaryInfraAssessment} size="small" bordered title={() => 'Infra Assessment'} footer={() => 'CRITICAL=C HIGH= H, MEDIUM=M LOW=L UNDEFINED=U'}>
<Column title="Namespace" dataIndex="Namespace" key="Namespace"
/>
<Column title="Resource" dataIndex="Target" key="Resource" defaultSortOrder="descend"
sorter={(a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Target.localeCompare(b.Target)}/>
<ColumnGroup title="Vulnerabilities">
<Column title="C" key="c" render={(record: NormalizedResultForDataTable) =>
record.VulnerabilitiesSummary?.Critical === 0 ? "" : record.VulnerabilitiesSummary?.Critical }
sorter={(a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) =>
a.VulnerabilitiesSummary && b.VulnerabilitiesSummary ? a.VulnerabilitiesSummary.Critical - b.VulnerabilitiesSummary.Critical : 0
}/>
<Column title="H" key="h" render={(record: NormalizedResultForDataTable) => (
record.VulnerabilitiesSummary?.High === 0 ? "" : record.VulnerabilitiesSummary?.High
)}/>
<Column title="M" key="m" render={(record: NormalizedResultForDataTable) => (
record.VulnerabilitiesSummary?.Medium === 0 ? "" : record.VulnerabilitiesSummary?.Medium
)}/>
<Column title="L" key="l" render={(record: NormalizedResultForDataTable) => (
record.VulnerabilitiesSummary?.Low === 0 ? "" : record.VulnerabilitiesSummary?.Low
)}/>
<Column title="U" key="u" render={(record: NormalizedResultForDataTable) => (
record.VulnerabilitiesSummary?.Undefined === 0 ? "" : record.VulnerabilitiesSummary?.Undefined
)}/>
</ColumnGroup>
<ColumnGroup title="Misconfigurations">
<Column title="C" key="c" render={(record: NormalizedResultForDataTable) =>
record.MisconfigurationsSummary?.Critical === 0 ? "" : record.MisconfigurationsSummary?.Critical
}/>
<Column title="H" key="h" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.High === 0 ? "" : record.MisconfigurationsSummary?.High
)}/>
<Column title="M" key="m" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.Medium === 0 ? "" : record.MisconfigurationsSummary?.Medium
)}/>
<Column title="L" key="l" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.Low === 0 ? "" : record.MisconfigurationsSummary?.Low
)}/>
<Column title="U" key="u" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.Undefined === 0 ? "" : record.MisconfigurationsSummary?.Undefined
)}/>
</ColumnGroup>
<ColumnGroup title="Secrets">
<Column title="C" key="c" render={(record: NormalizedResultForDataTable) =>
record.SecretsSummary?.Critical === 0 ? "" : record.SecretsSummary?.Critical
}/>
<Column title="H" key="h" render={(record: NormalizedResultForDataTable) => (
record.SecretsSummary?.High === 0 ? "" : record.SecretsSummary?.High
)}/>
<Column title="M" key="m" render={(record: NormalizedResultForDataTable) => (
record.SecretsSummary?.Medium === 0 ? "" : record.SecretsSummary?.Medium
)}/>
<Column title="L" key="l" render={(record: NormalizedResultForDataTable) => (
record.SecretsSummary?.Low === 0 ? "" : record.SecretsSummary?.Low
)}/>
<Column title="U" key="u" render={(record: NormalizedResultForDataTable) => (
record.SecretsSummary?.Undefined === 0 ? "" : record.SecretsSummary?.Undefined
)}/>
</ColumnGroup>
</Table>

<Table dataSource={k8sClusterSummaryRBACAssessment} size="small" title={() => 'RBAC Assessment'} bordered>
<Column title="Namespace" dataIndex="Namespace" key="Namespace" />
<Column title="Resource" dataIndex="Target" key="Resource" defaultSortOrder="descend"
sorter={(a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Target.localeCompare(b.Target)
}/>
<ColumnGroup title="RBAC Assessment">
<Column title="C" key="c" render={(record: NormalizedResultForDataTable) =>
record.MisconfigurationsSummary?.Critical === 0 ? "" : record.MisconfigurationsSummary?.Critical}
sorter={(a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) =>
a.MisconfigurationsSummary && b.MisconfigurationsSummary ? a.MisconfigurationsSummary.Critical - b.MisconfigurationsSummary.Critical : 0
}/>
<Column title="H" key="h" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.High === 0 ? "" : record.MisconfigurationsSummary?.High
)}/>
<Column title="M" key="m" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.Medium === 0 ? "" : record.MisconfigurationsSummary?.Medium
)}/>
<Column title="L" key="l" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.Low === 0 ? "" : record.MisconfigurationsSummary?.Low
)}/>
<Column title="U" key="u" render={(record: NormalizedResultForDataTable) => (
record.MisconfigurationsSummary?.Undefined === 0 ? "" : record.MisconfigurationsSummary?.Undefined
)}/>
</ColumnGroup>
</Table>
</>
);
};

export default K8sClusterSummary;
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const MisconfigurationSummary: React.FC<MisconfigurationSummaryProps> = ({ resul
<SearchOutlined style={{ color: filtered ? "#1677ff" : undefined }} />
),
onFilter: (value, record) =>
record[dataIndex]
record
.toString()
.toLowerCase()
.includes((value as string).toLowerCase()),
Expand Down Expand Up @@ -150,7 +150,7 @@ const MisconfigurationSummary: React.FC<MisconfigurationSummaryProps> = ({ resul
key: "Class",
width: "15%",
...getColumnSearchProps("Class"),
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Class.length - b.Class.length,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Class && b.Class ? a.Class.length - b.Class.length : 0,
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -159,7 +159,7 @@ const MisconfigurationSummary: React.FC<MisconfigurationSummaryProps> = ({ resul
key: "Successes",
width: "5%",
...getColumnSearchProps("Successes"),
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Successes- b.Successes,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Successes && b.Successes ? a.Successes- b.Successes : 0,
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -169,7 +169,7 @@ const MisconfigurationSummary: React.FC<MisconfigurationSummaryProps> = ({ resul
width: "5%",
...getColumnSearchProps("Failures"),
defaultSortOrder: 'descend',
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Failures-b.Failures,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Failures && b.Failures ? a.Failures-b.Failures : 0,
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -179,7 +179,7 @@ const MisconfigurationSummary: React.FC<MisconfigurationSummaryProps> = ({ resul
width: "5%",
...getColumnSearchProps("Exceptions"),
defaultSortOrder: 'descend',
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Exceptions-b.Exceptions,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Exceptions && b.Exceptions ? a.Exceptions-b.Exceptions : 0,
sortDirections: ["descend", "ascend"],
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const Misconfigurations: React.FC<MisconfigurationsProps> = ({ result }) => {
<SearchOutlined style={{ color: filtered ? "#1677ff" : undefined }} />
),
onFilter: (value, record) =>
record[dataIndex]
record
.toString()
.toLowerCase()
.includes((value as string).toLowerCase()),
Expand Down Expand Up @@ -134,7 +134,7 @@ const Misconfigurations: React.FC<MisconfigurationsProps> = ({ result }) => {
key: "Target",
width: "8%",
...getColumnSearchProps("Target"),
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Target.length - b.Target.length,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Target.localeCompare(b.Target),
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -143,7 +143,7 @@ const Misconfigurations: React.FC<MisconfigurationsProps> = ({ result }) => {
key: "ID",
width: "7%",
...getColumnSearchProps("ID"),
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.ID.length - b.ID.length,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.ID && b.ID ? a.ID.localeCompare(b.ID) : 0,
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -152,7 +152,7 @@ const Misconfigurations: React.FC<MisconfigurationsProps> = ({ result }) => {
key: "Title",
width: "15%",
...getColumnSearchProps("Title"),
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Title.length - b.Title.length,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Title && b.Title ? a.Title.localeCompare(b.Title) : 0,
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -162,9 +162,9 @@ const Misconfigurations: React.FC<MisconfigurationsProps> = ({ result }) => {
width: "5%",
filters: severityFilters,
onFilter: (value, record) => record.Severity === value,
render: (_, { Severity }) => <SeverityTag severity={Severity} />,
render: (_, { Severity }) => <SeverityTag severity={Severity ? Severity : ""} />,
defaultSortOrder: 'descend',
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Severity.length - b.Severity.length,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Severity && b.Severity ? a.Severity.length - b.Severity.length : 0,//this is wrong
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -173,7 +173,7 @@ const Misconfigurations: React.FC<MisconfigurationsProps> = ({ result }) => {
key: "Type",
width: "10%",
...getColumnSearchProps("Type"),
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Type.length - b.Type.length,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Type.localeCompare(b.Type),
sortDirections: ["descend", "ascend"],
},
{
Expand All @@ -182,7 +182,7 @@ const Misconfigurations: React.FC<MisconfigurationsProps> = ({ result }) => {
key: "Message",
width: "15%",
...getColumnSearchProps("Message"),
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Message.length - b.Message.length,
sorter: (a: NormalizedResultForDataTable, b: NormalizedResultForDataTable) => a.Message && b.Message ? a.Message.localeCompare(b.Message) : 0,
sortDirections: ["descend", "ascend"],
}
];
Expand Down
Loading

0 comments on commit 049c8ed

Please sign in to comment.