remove argo

This commit is contained in:
Morten Olsen
2025-09-05 13:51:33 +02:00
parent ff06613e99
commit 42cc50948d
13 changed files with 645 additions and 38 deletions

3
security/trivy-report/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/security_report.pdf
/transformed_data.json
/all_data.json

View File

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Data Extraction Function
extract_data() {
crd_type="$1"
kubectl get "$crd_type" -A -o json | jq -r '.items[] | {
namespace: .metadata.namespace,
name: .metadata.name,
report: .report
}'
}
# Vulnerability Reports
vulnerability_data=$(extract_data vulnerabilityreports)
# Example of capturing ConfigAuditReports (adjust jq filter as needed)
config_audit_data=$(extract_data configauditreports)
# Combine the data into a proper JSON array using jq
{
echo "$vulnerability_data"
echo "$config_audit_data"
} | jq -s '.' > all_data.json

View File

@@ -0,0 +1,82 @@
import json
from jinja2 import Environment, FileSystemLoader
import weasyprint
def generate_pdf_report(transformed_data, template_file, output_file):
"""Generates a PDF report from the transformed data and Jinja2 template."""
env = Environment(
loader=FileSystemLoader(".")
) # Load templates from the current directory
template = env.get_template(template_file)
html_output = template.render(transformed_data) # Render the template with the data
# Generate PDF using WeasyPrint
weasyprint.HTML(string=html_output).write_pdf(output_file)
# Load the already transformed JSON data
with open("transformed_data.json", "r") as f:
raw_data = json.load(f)
# Sort by severity (CRITICAL, HIGH, MEDIUM, LOW)
severity_order = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3}
# Group vulnerabilities by CVE ID
vuln_groups = {}
for vuln in raw_data["vulnerabilities"]:
cve_id = vuln["vulnerabilityID"]
if cve_id not in vuln_groups:
vuln_groups[cve_id] = {
"vulnerabilityID": vuln["vulnerabilityID"],
"severity": vuln["severity"],
"title": vuln["title"],
"packagePURL": vuln.get("packagePURL"),
"installedVersion": vuln.get("installedVersion"),
"fixedVersion": vuln.get("fixedVersion"),
"affected_resources": [],
}
vuln_groups[cve_id]["affected_resources"].append(
{"namespace": vuln["namespace"], "resource": vuln["resource"]}
)
# Convert to list and sort by severity
grouped_vulnerabilities = sorted(
list(vuln_groups.values()), key=lambda x: severity_order.get(x["severity"], 4)
)
# Group config issues by checkID
config_groups = {}
for issue in raw_data["config_issues"]:
check_id = issue["checkID"]
if check_id not in config_groups:
config_groups[check_id] = {
"checkID": issue["checkID"],
"severity": issue["severity"],
"title": issue["title"],
"description": issue["description"],
"remediation": issue["remediation"],
"affected_resources": [],
}
config_groups[check_id]["affected_resources"].append(
{"namespace": issue["namespace"], "resource": issue["resource"]}
)
# Convert to list and sort by severity
grouped_config_issues = sorted(
list(config_groups.values()), key=lambda x: severity_order.get(x["severity"], 4)
)
transformed_data = {
"vulnerabilities": grouped_vulnerabilities,
"config_issues": grouped_config_issues,
}
# Generate the PDF report
generate_pdf_report(transformed_data, "report_template.html", "security_report.pdf")
print("PDF report generated successfully: security_report.pdf")

View File

@@ -0,0 +1,6 @@
def main():
print("Hello from trivy-report!")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,10 @@
[project]
name = "trivy-report"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"jinja2>=3.1.6",
"weasyprint>=66.0",
]

View File

@@ -0,0 +1,136 @@
<!DOCTYPE html>
<html>
<head>
<title>Kubernetes Security Report</title>
<style>
@page {
size: A4;
margin: 0.5in;
}
body {
font-family: Arial, sans-serif;
font-size: 10px;
line-height: 1.3;
margin: 0;
padding: 0;
}
h1 {
color: #333;
font-size: 16px;
margin-bottom: 10px;
}
h2 {
color: #666;
font-size: 14px;
margin: 15px 0 8px 0;
}
table {
border-collapse: collapse;
width: 100%;
margin-bottom: 20px;
font-size: 8px;
}
th, td {
border: 1px solid #ccc;
padding: 4px;
text-align: left;
vertical-align: top;
word-wrap: break-word;
max-width: 150px;
}
th {
background-color: #f5f5f5;
font-weight: bold;
font-size: 9px;
}
.severity-critical { background-color: #ffebee; color: #c62828; font-weight: bold; }
.severity-high { background-color: #fff3e0; color: #ef6c00; font-weight: bold; }
.severity-medium { background-color: #fff8e1; color: #f57f17; }
.severity-low { background-color: #f3e5f5; color: #7b1fa2; }
.resource-col { max-width: 120px; }
.vuln-id-col { max-width: 80px; }
.severity-col { max-width: 60px; text-align: center; }
.namespace-col { max-width: 80px; }
.description-col { max-width: 200px; font-size: 7px; }
</style>
</head>
<body>
<h1>Kubernetes Security Report</h1>
<h2>Vulnerabilities ({{ vulnerabilities|length }})</h2>
<table>
<thead>
<tr>
<th class="vuln-id-col">CVE ID</th>
<th class="severity-col">Severity</th>
<th style="max-width: 180px;">Title</th>
<th style="max-width: 100px;">Package</th>
<th style="max-width: 60px;">Count</th>
<th style="max-width: 250px;">Affected Resources</th>
</tr>
</thead>
<tbody>
{% for vuln in vulnerabilities %}
<tr>
<td class="vuln-id-col">{{ vuln.vulnerabilityID }}</td>
<td class="severity-col severity-{{ vuln.severity|lower }}">{{ vuln.severity }}</td>
<td style="max-width: 180px;">{{ vuln.title }}</td>
<td style="max-width: 100px;">{{ vuln.packagePURL or 'N/A' }}</td>
<td style="max-width: 60px; text-align: center;">{{ vuln.affected_resources|length }}</td>
<td style="max-width: 250px; font-size: 7px;">
{% for resource in vuln.affected_resources[:10] %}
{{ resource.namespace }}/{{ resource.resource }}{% if not loop.last %}, {% endif %}
{% endfor %}
{% if vuln.affected_resources|length > 10 %}
<br/><em>... and {{ vuln.affected_resources|length - 10 }} more</em>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<h2>Configuration Issues ({{ config_issues|length }})</h2>
<table>
<thead>
<tr>
<th class="vuln-id-col">Check ID</th>
<th class="severity-col">Severity</th>
<th style="max-width: 180px;">Title</th>
<th style="max-width: 200px;">Remediation</th>
<th style="max-width: 60px;">Count</th>
<th style="max-width: 200px;">Affected Resources</th>
</tr>
</thead>
<tbody>
{% for issue in config_issues %}
<tr>
<td class="vuln-id-col">{{ issue.checkID }}</td>
<td class="severity-col severity-{{ issue.severity|lower }}">{{ issue.severity }}</td>
<td style="max-width: 180px;">{{ issue.title }}</td>
<td style="max-width: 200px; font-size: 7px;">{{ issue.remediation }}</td>
<td style="max-width: 60px; text-align: center;">{{ issue.affected_resources|length }}</td>
<td style="max-width: 200px; font-size: 7px;">
{% for resource in issue.affected_resources[:8] %}
{{ resource.namespace }}/{{ resource.resource }}{% if not loop.last %}, {% endif %}
{% endfor %}
{% if issue.affected_resources|length > 8 %}
<br/><em>... and {{ issue.affected_resources|length - 8 }} more</em>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>

View File

@@ -0,0 +1,56 @@
import json
def transform_data(json_data):
"""Transforms the raw JSON data into a structured format for reporting."""
reports = json.loads(json_data)
all_vulnerabilities = []
all_config_audit_issues = []
for report in reports:
if "vulnerabilities" in report["report"]:
for vuln in report["report"]["vulnerabilities"]:
all_vulnerabilities.append(
{
"namespace": report["namespace"],
"resource": report["name"],
"vulnerabilityID": vuln["vulnerabilityID"],
"severity": vuln["severity"],
"title": vuln["title"],
"packagePURL": vuln.get("packagePURL"),
"installedVersion": vuln.get("installedVersion"),
"fixedVersion": vuln.get("fixedVersion"),
}
)
elif "checks" in report["report"]: # ConfigAuditReports have "checks"
for check in report["report"]["checks"]:
all_config_audit_issues.append(
{
"namespace": report["namespace"],
"resource": report["name"],
"checkID": check["checkID"],
"severity": check["severity"],
"title": check["title"],
"description": check["description"],
"remediation": check["remediation"],
"success": check["success"],
}
)
return {
"vulnerabilities": all_vulnerabilities,
"config_issues": all_config_audit_issues,
}
# Load the JSON data
with open("all_data.json", "r") as f:
raw_data = f.read()
transformed_data = transform_data(raw_data)
# Print the transformed data (for verification)
print(json.dumps(transformed_data, indent=2)) # print for check
# Save it for the next step:
with open("transformed_data.json", "w") as f:
json.dump(transformed_data, f, indent=2)