|
8 | 8 | from bs4 import BeautifulSoup |
9 | 9 | import traceback |
10 | 10 | sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) |
11 | | -from scripts.html_utils import html_header, html_footer, generate_visual_summary_section, generate_overall_summary_and_links_section |
| 11 | +from scripts.html_utils import html_header, html_footer, generate_visual_summary_section, generate_overall_summary_and_links_section, generate_executive_summary, generate_tool_status_section |
12 | 12 | from scripts.zap_processor import zap_summary, generate_zap_html_section |
13 | 13 | from scripts.zap_xml_parser import parse_zap_xml, generate_html_report |
14 | 14 | from scripts.semgrep_processor import semgrep_summary, generate_semgrep_html_section |
@@ -157,12 +157,58 @@ def main(): |
157 | 157 | ios_findings_summary = ios_plist_summary(ios_plist_json_path) |
158 | 158 |
|
159 | 159 | try: |
| 160 | + # Extract ZAP alerts list if available, otherwise use empty list |
| 161 | + zap_findings_list = zap_alerts.get('alerts', []) if isinstance(zap_alerts, dict) else [] |
| 162 | + |
| 163 | + # Collect all findings for executive summary |
| 164 | + all_findings = { |
| 165 | + 'ZAP': zap_findings_list, |
| 166 | + 'Semgrep': semgrep_findings, |
| 167 | + 'Trivy': trivy_vulns, |
| 168 | + 'CodeQL': codeql_findings, |
| 169 | + 'Nuclei': nuclei_findings, |
| 170 | + 'OWASP DC': owasp_dc_vulns, |
| 171 | + 'Safety': safety_findings, |
| 172 | + 'Snyk': snyk_findings, |
| 173 | + 'SonarQube': sonarqube_findings, |
| 174 | + 'Checkov': checkov_comprehensive_findings, |
| 175 | + 'TruffleHog': trufflehog_findings, |
| 176 | + 'GitLeaks': gitleaks_findings, |
| 177 | + 'Detect-secrets': detect_secrets_findings, |
| 178 | + 'npm audit': npm_audit_findings, |
| 179 | + 'Wapiti': wapiti_findings, |
| 180 | + 'Nikto': nikto_findings, |
| 181 | + 'Burp Suite': burp_findings, |
| 182 | + 'Kube-hunter': kube_hunter_findings, |
| 183 | + 'Kube-bench': kube_bench_findings, |
| 184 | + 'Docker Bench': docker_bench_findings, |
| 185 | + 'ESLint': eslint_findings, |
| 186 | + 'Clair': clair_vulns, |
| 187 | + 'Anchore': anchore_vulns, |
| 188 | + 'Brakeman': brakeman_findings, |
| 189 | + 'Bandit': bandit_findings, |
| 190 | + } |
| 191 | + |
| 192 | + # Determine which tools were executed |
| 193 | + # A tool was executed if it has actual findings or if it was run but found nothing |
| 194 | + # We need to check if findings exist AND are not None |
| 195 | + # None means skipped, [] or items means executed but may have no findings |
| 196 | + executed_tools = {} |
| 197 | + for tool, findings in all_findings.items(): |
| 198 | + # Tools that have findings (even if empty list) or ZAP with alerts should show as executed |
| 199 | + if findings is not None: |
| 200 | + executed_tools[tool] = {'status': 'complete'} |
| 201 | + elif tool == 'ZAP' and isinstance(zap_alerts, dict): |
| 202 | + # ZAP returns a dict, not a list |
| 203 | + executed_tools[tool] = {'status': 'complete'} |
| 204 | + |
160 | 205 | with open(OUTPUT_FILE, 'w') as f: |
161 | | - f.write(html_header('SimpleSecCheck Security Scan Summary')) |
162 | | - f.write(f'<p><b>Scan Date:</b> {now}<br>') |
163 | | - f.write(f'<b>Target:</b> {target}</p>\n') |
| 206 | + f.write(html_header(f'{target} - {now}')) |
164 | 207 | # WebUI Controls Block |
165 | | - f.write('''\n<!-- WebUI Controls -->\n<div style="margin: 1em 0;">\n <button id="scan-btn">Jetzt neuen Scan starten</button>\n <button id="refresh-status-btn">Status aktualisieren</button>\n <span id="scan-status" style="margin-left:1em; color: #007bff;">Status wird geladen...</span>\n</div>\n<!-- Hinweis: Scan-Status und Trigger laufen über Port 9100 (Watchdog) -->\n''') |
| 208 | + # WebUI Controls removed - using single-shot scans only |
| 209 | + |
| 210 | + # Executive Summary Dashboard |
| 211 | + f.write(generate_executive_summary(all_findings)) |
166 | 212 |
|
167 | 213 | # --- Visual summary with icons/colors for each tool --- |
168 | 214 | f.write(generate_visual_summary_section(zap_alerts.get('summary', zap_alerts), semgrep_findings, trivy_vulns, codeql_findings, nuclei_findings, owasp_dc_vulns, safety_findings, snyk_findings, sonarqube_findings, checkov_comprehensive_findings, trufflehog_findings, gitleaks_findings, detect_secrets_findings, npm_audit_findings, wapiti_findings, nikto_findings, burp_findings, kube_hunter_findings, kube_bench_findings, docker_bench_findings, eslint_findings, clair_vulns, anchore_vulns, brakeman_findings, bandit_findings, android_findings_summary, ios_findings_summary)) |
@@ -195,8 +241,8 @@ def main(): |
195 | 241 | if len(safety_findings) > 0: |
196 | 242 | f.write(generate_safety_html_section(safety_findings)) |
197 | 243 |
|
198 | | - # Snyk Section (only if findings exist) |
199 | | - if len(snyk_findings) > 0: |
| 244 | + # Snyk Section - show if skipped (None) or if there are findings |
| 245 | + if snyk_findings is None or len(snyk_findings) > 0: |
200 | 246 | f.write(generate_snyk_html_section(snyk_findings)) |
201 | 247 |
|
202 | 248 | # SonarQube Section (only if findings exist) |
|
0 commit comments