sec-report-kit 0.2.3__tar.gz → 0.2.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/.gitignore +1 -0
  2. sec_report_kit-0.2.5/CHANGELOG.md +60 -0
  3. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/PKG-INFO +46 -1
  4. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/README.md +45 -0
  5. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/pyproject.toml +1 -1
  6. sec_report_kit-0.2.5/requirements.txt +84 -0
  7. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/install_external_clis.py +85 -29
  8. sec_report_kit-0.2.5/scripts/render_consolidated_html.bat +25 -0
  9. sec_report_kit-0.2.5/scripts/render_consolidated_html.sh +34 -0
  10. sec_report_kit-0.2.5/scripts/run_codeql.bat +81 -0
  11. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_codeql.sh +7 -0
  12. sec_report_kit-0.2.5/scripts/run_osv_scanner.bat +80 -0
  13. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_tfsec.bat +13 -3
  14. sec_report_kit-0.2.5/scripts/run_trufflehog.bat +53 -0
  15. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/__init__.py +1 -1
  16. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/cli.py +96 -24
  17. sec_report_kit-0.2.5/src/sec_report_kit/generate_consolidated_security_report.py +27 -0
  18. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/tests/test_cli.py +93 -0
  19. sec_report_kit-0.2.3/CHANGELOG.md +0 -28
  20. sec_report_kit-0.2.3/scripts/run_codeql.bat +0 -30
  21. sec_report_kit-0.2.3/scripts/run_osv_scanner.bat +0 -27
  22. sec_report_kit-0.2.3/scripts/run_trufflehog.bat +0 -27
  23. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/.gitattributes +0 -0
  24. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/.github/workflows/pip-audit.yml +0 -0
  25. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/.github/workflows/publish-pypi.yml +0 -0
  26. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/.github/workflows/publish-testpypi.yml +0 -0
  27. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/.github/workflows/trivy-fs-audit.yml +0 -0
  28. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/.github/workflows/unit-test-coverage-gate.yml +0 -0
  29. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/bandit-gaps-vs-sast-open-source-tools.md +0 -0
  30. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/check_assets.py +0 -0
  31. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/download_safety_db.bat +0 -0
  32. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/download_safety_db.py +0 -0
  33. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/download_safety_db.sh +0 -0
  34. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/install_tools.bat +0 -0
  35. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/install_tools.sh +0 -0
  36. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_bandit_html.bat +0 -0
  37. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_bandit_html.sh +0 -0
  38. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_checkov_html.bat +0 -0
  39. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_checkov_html.sh +0 -0
  40. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_codeql_html.bat +0 -0
  41. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_codeql_html.sh +0 -0
  42. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_gitleaks_html.bat +0 -0
  43. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_gitleaks_html.sh +0 -0
  44. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_osv_scanner_html.bat +0 -0
  45. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_osv_scanner_html.sh +0 -0
  46. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_pip_audit_html.bat +0 -0
  47. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_pip_audit_html.sh +0 -0
  48. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_safety_html.bat +0 -0
  49. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_safety_html.sh +0 -0
  50. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_semgrep_html.bat +0 -0
  51. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_semgrep_html.sh +0 -0
  52. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_tfsec_html.bat +0 -0
  53. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_tfsec_html.sh +0 -0
  54. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_trivy_html.bat +0 -0
  55. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_trivy_html.sh +0 -0
  56. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_trufflehog_html.bat +0 -0
  57. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/render_trufflehog_html.sh +0 -0
  58. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_bandit.bat +0 -0
  59. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_bandit.sh +0 -0
  60. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_checkov.bat +0 -0
  61. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_checkov.sh +0 -0
  62. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_gitleaks.bat +0 -0
  63. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_gitleaks.sh +0 -0
  64. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_osv_scanner.sh +0 -0
  65. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_pip_audit.bat +0 -0
  66. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_pip_audit.sh +0 -0
  67. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_safety.bat +0 -0
  68. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_safety.sh +0 -0
  69. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_semgrep.bat +0 -0
  70. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_semgrep.sh +0 -0
  71. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_tfsec.sh +0 -0
  72. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_trivy.bat +0 -0
  73. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_trivy.sh +0 -0
  74. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_trufflehog.sh +0 -0
  75. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_unit_tests_with_coverage.bat +0 -0
  76. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/scripts/run_unit_tests_with_coverage.sh +0 -0
  77. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/__main__.py +0 -0
  78. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/mcp/__init__.py +0 -0
  79. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/mcp/server.py +0 -0
  80. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/models.py +0 -0
  81. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/__init__.py +0 -0
  82. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/bandit.py +0 -0
  83. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/checkov.py +0 -0
  84. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/codeql.py +0 -0
  85. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/gitleaks.py +0 -0
  86. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/osv_scanner.py +0 -0
  87. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/pip_audit.py +0 -0
  88. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/safety.py +0 -0
  89. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/semgrep.py +0 -0
  90. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/tfsec.py +0 -0
  91. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/trivy.py +0 -0
  92. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/parsers/trufflehog.py +0 -0
  93. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/report/__init__.py +0 -0
  94. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/report/html_renderer.py +0 -0
  95. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/services/__init__.py +0 -0
  96. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/services/normalize.py +0 -0
  97. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/src/sec_report_kit/services/summarize.py +0 -0
  98. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/tests/test_html_renderer.py +0 -0
  99. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/tests/test_mcp_server.py +0 -0
  100. {sec_report_kit-0.2.3 → sec_report_kit-0.2.5}/tests/test_parsers.py +0 -0
@@ -93,3 +93,4 @@ data/
93
93
  logs/
94
94
  security_reports/
95
95
  .tools/
96
+ codeql-db/
@@ -0,0 +1,60 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## 0.2.5 - 2026-05-17
6
+
7
+ ### Added
8
+ - New CLI command: `srk render consolidated` to build a single HTML report from all supported scanner reports in an input folder.
9
+ - New helper scripts for consolidated rendering:
10
+ - `scripts/render_consolidated_html.sh`
11
+ - `scripts/render_consolidated_html.bat`
12
+
13
+ ### Changed
14
+ - `src/sec_report_kit/generate_consolidated_security_report.py` now acts as a wrapper that accepts `--input`, `--output`, and `--target`, and delegates to the consolidated CLI renderer.
15
+
16
+ ### Fixed
17
+ - Unified package version metadata by aligning `src/sec_report_kit/__init__.py` with the project version.
18
+
19
+ ## 0.2.4 - 2026-05-14
20
+
21
+ ### Added
22
+ - `scripts/install_external_clis.py` now supports `--tool` for targeted installs.
23
+ - `scripts/install_external_clis.py` now supports `--force` to re-download tools even when already installed.
24
+ - `README.md` now documents external CLI installer options and usage examples.
25
+
26
+ ### Changed
27
+ - External CLI installer now skips already-installed tools by default.
28
+ - CodeQL install handling on Windows now uses staged extraction and merge to avoid directory lock errors during reinstall.
29
+ - `scripts/run_osv_scanner.bat` now auto-generates `requirements.txt` from installed packages when no supported lockfile is present.
30
+
31
+ ### Fixed
32
+ - `scripts/run_codeql.bat` now repairs incomplete local CodeQL installs and validates SARIF output existence.
33
+ - `scripts/run_codeql.sh` now validates SARIF output existence after analysis.
34
+ - `scripts/run_trufflehog.bat` now writes scanner output via temp files to avoid self-scan file locking.
35
+ - `scripts/run_trufflehog.bat` now writes `[]` when no findings are present.
36
+
37
+ ## 0.2.3 - 2026-05-13
38
+
39
+ ### Added
40
+ - Safety CLI parser support and HTML rendering flow.
41
+ - New CLI command: `srk render safety`.
42
+ - MCP support for `source_type="safety"`.
43
+ - Helper scripts for Safety scan and render:
44
+ - `scripts/run_safety.sh`
45
+ - `scripts/run_safety.bat`
46
+ - `scripts/render_safety_html.sh`
47
+ - `scripts/render_safety_html.bat`
48
+ - Offline Safety DB download helpers:
49
+ - `scripts/download_safety_db.py`
50
+ - `scripts/download_safety_db.sh`
51
+ - `scripts/download_safety_db.bat`
52
+
53
+ ### Changed
54
+ - Auto-detection now recognizes Safety JSON payloads.
55
+ - Tool installation scripts now install Safety CLI in the app venv.
56
+ - README updated with Safety usage and offline/local DB workflow guidance.
57
+
58
+ ### Fixed
59
+ - Safety run scripts now avoid false success when network failures occur.
60
+ - JSON output validation improved for Safety execution paths.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sec-report-kit
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Generate HTML security reports from Trivy, pip-audit, Safety, Bandit, and Gitleaks JSON
5
5
  Author: Ravi Konduru
6
6
  License: MIT
@@ -82,6 +82,14 @@ Render Safety JSON:
82
82
  srk render safety --input security_reports/safety.json --output security_reports/report-safety.html --target requirements.txt
83
83
  ```
84
84
 
85
+ Render a consolidated HTML report from all supported scanner files in a directory:
86
+
87
+ ```bash
88
+ srk render consolidated --input security_reports --output security_reports --target sec-report-kit
89
+ ```
90
+
91
+ This command writes `consolidated-security-report.html` to the output folder.
92
+
85
93
  ## Helper Scripts (bat/sh)
86
94
 
87
95
  Cross-platform helper scripts are available in `scripts/`.
@@ -100,6 +108,31 @@ scripts\install_tools.bat
100
108
 
101
109
  After cloning on a new machine, run the install script above to recreate the local `.tools/` directory and install required external CLI binaries (`codeql`, `tfsec`, `gitleaks`, `trufflehog`, `osv-scanner`) alongside Python dependencies. The `.tools/` folder is intentionally not committed to git.
102
110
 
111
+ Install or update external CLI binaries directly:
112
+
113
+ ```bash
114
+ python scripts/install_external_clis.py --repo-root .
115
+ ```
116
+
117
+ Default behavior skips tools that are already installed locally.
118
+
119
+ Force re-download/reinstall for all supported external tools:
120
+
121
+ ```bash
122
+ python scripts/install_external_clis.py --repo-root . --force
123
+ ```
124
+
125
+ Install only selected tool(s) with `--tool` (can be repeated or comma-separated):
126
+
127
+ ```bash
128
+ python scripts/install_external_clis.py --repo-root . --tool osv-scanner
129
+ python scripts/install_external_clis.py --repo-root . --tool tfsec --tool gitleaks --force
130
+ python scripts/install_external_clis.py --repo-root . --tool tfsec,gitleaks
131
+ ```
132
+
133
+ Supported `--tool` values: `codeql`, `tfsec`, `gitleaks`, `trufflehog`, `osv-scanner`.
134
+ For convenience, `ocs-scanner` is accepted as an alias for `osv-scanner`.
135
+
103
136
  Run all unit tests locally with coverage:
104
137
 
105
138
  ```bash
@@ -207,6 +240,18 @@ scripts\render_trivy_html.bat
207
240
  scripts\render_trivy_html.bat security_reports my-image
208
241
  ```
209
242
 
243
+ Convert all supported scanner reports in a folder to one consolidated HTML report:
244
+
245
+ ```bash
246
+ # Linux/macOS (optional args: <report_dir> <target_name>)
247
+ bash scripts/render_consolidated_html.sh
248
+ bash scripts/render_consolidated_html.sh security_reports sec-report-kit
249
+
250
+ # Windows (optional args: <report_dir> <target_name>)
251
+ scripts\render_consolidated_html.bat
252
+ scripts\render_consolidated_html.bat security_reports sec-report-kit
253
+ ```
254
+
210
255
  Convert sample Bandit JSON report to HTML:
211
256
 
212
257
  ```bash
@@ -55,6 +55,14 @@ Render Safety JSON:
55
55
  srk render safety --input security_reports/safety.json --output security_reports/report-safety.html --target requirements.txt
56
56
  ```
57
57
 
58
+ Render a consolidated HTML report from all supported scanner files in a directory:
59
+
60
+ ```bash
61
+ srk render consolidated --input security_reports --output security_reports --target sec-report-kit
62
+ ```
63
+
64
+ This command writes `consolidated-security-report.html` to the output folder.
65
+
58
66
  ## Helper Scripts (bat/sh)
59
67
 
60
68
  Cross-platform helper scripts are available in `scripts/`.
@@ -73,6 +81,31 @@ scripts\install_tools.bat
73
81
 
74
82
  After cloning on a new machine, run the install script above to recreate the local `.tools/` directory and install required external CLI binaries (`codeql`, `tfsec`, `gitleaks`, `trufflehog`, `osv-scanner`) alongside Python dependencies. The `.tools/` folder is intentionally not committed to git.
75
83
 
84
+ Install or update external CLI binaries directly:
85
+
86
+ ```bash
87
+ python scripts/install_external_clis.py --repo-root .
88
+ ```
89
+
90
+ Default behavior skips tools that are already installed locally.
91
+
92
+ Force re-download/reinstall for all supported external tools:
93
+
94
+ ```bash
95
+ python scripts/install_external_clis.py --repo-root . --force
96
+ ```
97
+
98
+ Install only selected tool(s) with `--tool` (can be repeated or comma-separated):
99
+
100
+ ```bash
101
+ python scripts/install_external_clis.py --repo-root . --tool osv-scanner
102
+ python scripts/install_external_clis.py --repo-root . --tool tfsec --tool gitleaks --force
103
+ python scripts/install_external_clis.py --repo-root . --tool tfsec,gitleaks
104
+ ```
105
+
106
+ Supported `--tool` values: `codeql`, `tfsec`, `gitleaks`, `trufflehog`, `osv-scanner`.
107
+ For convenience, `ocs-scanner` is accepted as an alias for `osv-scanner`.
108
+
76
109
  Run all unit tests locally with coverage:
77
110
 
78
111
  ```bash
@@ -180,6 +213,18 @@ scripts\render_trivy_html.bat
180
213
  scripts\render_trivy_html.bat security_reports my-image
181
214
  ```
182
215
 
216
+ Convert all supported scanner reports in a folder to one consolidated HTML report:
217
+
218
+ ```bash
219
+ # Linux/macOS (optional args: <report_dir> <target_name>)
220
+ bash scripts/render_consolidated_html.sh
221
+ bash scripts/render_consolidated_html.sh security_reports sec-report-kit
222
+
223
+ # Windows (optional args: <report_dir> <target_name>)
224
+ scripts\render_consolidated_html.bat
225
+ scripts\render_consolidated_html.bat security_reports sec-report-kit
226
+ ```
227
+
183
228
  Convert sample Bandit JSON report to HTML:
184
229
 
185
230
  ```bash
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sec-report-kit"
7
- version = "0.2.3"
7
+ version = "0.2.5"
8
8
  description = "Generate HTML security reports from Trivy, pip-audit, Safety, Bandit, and Gitleaks JSON"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,84 @@
1
+ annotated-doc==0.0.4
2
+ annotated-types==0.7.0
3
+ anyio==4.13.0
4
+ attrs==26.1.0
5
+ bandit==1.9.4
6
+ boolean.py==5.0
7
+ build==1.5.0
8
+ CacheControl==0.14.4
9
+ certifi==2026.4.22
10
+ cffi==2.0.0
11
+ charset-normalizer==3.4.7
12
+ click==8.3.3
13
+ colorama==0.4.6
14
+ coverage==7.14.0
15
+ cryptography==47.0.0
16
+ cyclonedx-python-lib==11.7.0
17
+ defusedxml==0.7.1
18
+ docutils==0.22.4
19
+ filelock==3.29.0
20
+ h11==0.16.0
21
+ httpcore==1.0.9
22
+ httpx==0.28.1
23
+ httpx-sse==0.4.3
24
+ id==1.6.1
25
+ idna==3.13
26
+ iniconfig==2.3.0
27
+ jaraco.classes==3.4.0
28
+ jaraco.context==6.1.2
29
+ jaraco.functools==4.4.0
30
+ jsonschema==4.26.0
31
+ jsonschema-specifications==2025.9.1
32
+ keyring==25.7.0
33
+ license-expression==30.4.4
34
+ markdown-it-py==4.0.0
35
+ mcp==1.27.0
36
+ mdurl==0.1.2
37
+ more-itertools==11.0.2
38
+ msgpack==1.1.2
39
+ nh3==0.3.5
40
+ packageurl-python==0.17.6
41
+ packaging==26.2
42
+ pip-api==0.0.34
43
+ pip-requirements-parser==32.0.1
44
+ pip_audit==2.10.0
45
+ platformdirs==4.9.6
46
+ pluggy==1.6.0
47
+ py-serializable==2.1.0
48
+ pycparser==3.0
49
+ pydantic==2.13.3
50
+ pydantic-settings==2.14.0
51
+ pydantic_core==2.46.3
52
+ pyfiglet==1.0.4
53
+ Pygments==2.20.0
54
+ PyJWT==2.12.1
55
+ pyparsing==3.3.2
56
+ pyproject_hooks==1.2.0
57
+ pytest==9.0.3
58
+ pytest-cov==7.1.0
59
+ python-dotenv==1.2.2
60
+ python-multipart==0.0.27
61
+ pywin32==311
62
+ pywin32-ctypes==0.2.3
63
+ PyYAML==6.0.3
64
+ readme_renderer==44.0
65
+ referencing==0.37.0
66
+ requests==2.33.1
67
+ requests-toolbelt==1.0.0
68
+ rfc3986==2.0.0
69
+ rich==15.0.0
70
+ rpds-py==0.30.0
71
+ -e git+https://github.com/ShanKonduru/sec-report-kit.git@b6d196bac687e07189e884e2fe25af5c8842da1d#egg=sec_report_kit
72
+ shellingham==1.5.4
73
+ sortedcontainers==2.4.0
74
+ sse-starlette==3.4.1
75
+ starlette==1.0.0
76
+ stevedore==5.7.0
77
+ tomli==2.4.1
78
+ tomli_w==1.2.0
79
+ twine==6.2.0
80
+ typer==0.25.1
81
+ typing-inspection==0.4.2
82
+ typing_extensions==4.15.0
83
+ urllib3==2.6.3
84
+ uvicorn==0.46.0
@@ -12,6 +12,7 @@ import re
12
12
  import shutil
13
13
  import stat
14
14
  import tarfile
15
+ import tempfile
15
16
  import urllib.error
16
17
  import urllib.request
17
18
  import zipfile
@@ -127,20 +128,26 @@ def extract_binary_from_archive(data: bytes, archive_name: str, binary_names: li
127
128
 
128
129
  def install_codeql(asset_data: bytes, asset_name: str, tools_bin: Path) -> None:
129
130
  target_dir = tools_bin / "codeql"
130
- if target_dir.exists():
131
- shutil.rmtree(target_dir)
132
-
133
- if asset_name.lower().endswith(".zip"):
134
- with zipfile.ZipFile(io.BytesIO(asset_data)) as zf:
135
- zf.extractall(tools_bin)
136
- elif asset_name.lower().endswith(".tar.gz") or asset_name.lower().endswith(".tgz"):
137
- with tarfile.open(fileobj=io.BytesIO(asset_data), mode="r:gz") as tf:
138
- tf.extractall(tools_bin)
139
- else:
140
- raise RuntimeError(f"Unsupported codeql archive format: {asset_name}")
141
-
142
- if not target_dir.exists():
143
- raise RuntimeError("CodeQL extraction failed: missing .tools/bin/codeql directory")
131
+ with tempfile.TemporaryDirectory(prefix="codeql-stage-") as staging_dir:
132
+ staging_path = Path(staging_dir)
133
+
134
+ if asset_name.lower().endswith(".zip"):
135
+ with zipfile.ZipFile(io.BytesIO(asset_data)) as zf:
136
+ zf.extractall(staging_path)
137
+ elif asset_name.lower().endswith(".tar.gz") or asset_name.lower().endswith(".tgz"):
138
+ with tarfile.open(fileobj=io.BytesIO(asset_data), mode="r:gz") as tf:
139
+ tf.extractall(staging_path)
140
+ else:
141
+ raise RuntimeError(f"Unsupported codeql archive format: {asset_name}")
142
+
143
+ extracted_dir = staging_path / "codeql"
144
+ if not extracted_dir.exists():
145
+ raise RuntimeError("CodeQL extraction failed: missing codeql directory in archive")
146
+
147
+ if target_dir.exists():
148
+ shutil.copytree(extracted_dir, target_dir, dirs_exist_ok=True)
149
+ else:
150
+ shutil.move(str(extracted_dir), str(target_dir))
144
151
 
145
152
  codeql_bin = target_dir / ("codeql.exe" if os.name == "nt" else "codeql")
146
153
  if codeql_bin.exists():
@@ -171,14 +178,34 @@ def install_tool(tool_name: str, repo: str, patterns: list[str], tools_bin: Path
171
178
 
172
179
  def has_installed_tool(tool_name: str, tools_bin: Path, dest_name: str) -> bool:
173
180
  if tool_name == "codeql":
174
- candidate = tools_bin / "codeql" / ("codeql.exe" if os.name == "nt" else "codeql")
175
- return candidate.exists()
181
+ codeql_root = tools_bin / "codeql"
182
+ codeql_bin = codeql_root / ("codeql.exe" if os.name == "nt" else "codeql")
183
+ if not codeql_bin.exists():
184
+ return False
185
+ # A healthy CodeQL bundle includes an embedded Java runtime under tools/<platform>/java/bin.
186
+ java_glob = "java.exe" if os.name == "nt" else "java"
187
+ has_embedded_java = any(codeql_root.glob(f"tools/*/java/bin/{java_glob}"))
188
+ return has_embedded_java
176
189
  return (tools_bin / dest_name).exists()
177
190
 
178
191
 
179
192
  def main() -> int:
180
193
  parser = argparse.ArgumentParser(description="Install external scanner CLIs into .tools/bin")
181
194
  parser.add_argument("--repo-root", required=True, help="Repository root path")
195
+ parser.add_argument(
196
+ "--tool",
197
+ action="append",
198
+ default=[],
199
+ help=(
200
+ "Install only selected tool(s). Can be passed multiple times or as a comma-separated list "
201
+ "(e.g. --tool tfsec --tool gitleaks or --tool tfsec,gitleaks)"
202
+ ),
203
+ )
204
+ parser.add_argument(
205
+ "--force",
206
+ action="store_true",
207
+ help="Force re-download/reinstall even when a local install already exists",
208
+ )
182
209
  args = parser.parse_args()
183
210
 
184
211
  repo_root = Path(args.repo_root).resolve()
@@ -193,8 +220,8 @@ def main() -> int:
193
220
  "repo": "github/codeql-action",
194
221
  "patterns": {
195
222
  "windows": [r"codeql-bundle-win64\.tar\.gz$", r"codeql-bundle-win64\.zip$"],
196
- "linux": [r"codeql-bundle-linux64\\.tar\\.gz$"],
197
- "darwin": [r"codeql-bundle-osx64\\.tar\\.gz$", r"codeql-bundle-osx64\\.zip$"],
223
+ "linux": [r"codeql-bundle-linux64\.tar\.gz$"],
224
+ "darwin": [r"codeql-bundle-osx64\.tar\.gz$", r"codeql-bundle-osx64\.zip$"],
198
225
  },
199
226
  "binary_names": [f"codeql{ext}"],
200
227
  "dest_name": f"codeql{ext}",
@@ -202,7 +229,7 @@ def main() -> int:
202
229
  "tfsec": {
203
230
  "repo": "aquasecurity/tfsec",
204
231
  "patterns": {
205
- "windows": [r"tfsec-windows-amd64(?:\\.exe)?$"],
232
+ "windows": [r"tfsec-windows-amd64(?:\.exe)?$", r"tfsec_.*_windows_amd64\.tar\.gz$"],
206
233
  "linux": [r"tfsec-linux-amd64$"],
207
234
  "darwin": [r"tfsec-darwin-amd64$", r"tfsec-darwin-arm64$"],
208
235
  },
@@ -212,9 +239,9 @@ def main() -> int:
212
239
  "gitleaks": {
213
240
  "repo": "gitleaks/gitleaks",
214
241
  "patterns": {
215
- "windows": [r"gitleaks_.*_windows_x64\\.zip$"],
216
- "linux": [r"gitleaks_.*_linux_x64\\.tar\\.gz$"],
217
- "darwin": [r"gitleaks_.*_darwin_arm64\\.tar\\.gz$", r"gitleaks_.*_darwin_x64\\.tar\\.gz$"],
242
+ "windows": [r"gitleaks_.*_windows_x64\.zip$"],
243
+ "linux": [r"gitleaks_.*_linux_x64\.tar\.gz$"],
244
+ "darwin": [r"gitleaks_.*_darwin_arm64\.tar\.gz$", r"gitleaks_.*_darwin_x64\.tar\.gz$"],
218
245
  },
219
246
  "binary_names": [f"gitleaks{ext}"],
220
247
  "dest_name": f"gitleaks{ext}",
@@ -222,9 +249,9 @@ def main() -> int:
222
249
  "trufflehog": {
223
250
  "repo": "trufflesecurity/trufflehog",
224
251
  "patterns": {
225
- "windows": [r"trufflehog_.*_windows_amd64\\.tar\\.gz$", r"trufflehog_.*_windows_amd64\\.zip$"],
226
- "linux": [r"trufflehog_.*_linux_amd64\\.tar\\.gz$"],
227
- "darwin": [r"trufflehog_.*_darwin_arm64\\.tar\\.gz$", r"trufflehog_.*_darwin_amd64\\.tar\\.gz$"],
252
+ "windows": [r"trufflehog_.*_windows_amd64\.tar\.gz$", r"trufflehog_.*_windows_amd64\.zip$"],
253
+ "linux": [r"trufflehog_.*_linux_amd64\.tar\.gz$"],
254
+ "darwin": [r"trufflehog_.*_darwin_arm64\.tar\.gz$", r"trufflehog_.*_darwin_amd64\.tar\.gz$"],
228
255
  },
229
256
  "binary_names": [f"trufflehog{ext}"],
230
257
  "dest_name": f"trufflehog{ext}",
@@ -232,19 +259,48 @@ def main() -> int:
232
259
  "osv-scanner": {
233
260
  "repo": "google/osv-scanner",
234
261
  "patterns": {
235
- "windows": [r"osv-scanner_windows_amd64(?:\\.exe)?(?:\\.zip)?$", r"osv-scanner_.*_windows_amd64(?:\\.exe)?(?:\\.zip)?$", r"osv-scanner-windows-amd64(?:\\.exe)?$"],
236
- "linux": [r"osv-scanner_.*_linux_amd64(?:\\.tar\\.gz)?$", r"osv-scanner-linux-amd64$"],
237
- "darwin": [r"osv-scanner_.*_darwin_amd64(?:\\.tar\\.gz)?$", r"osv-scanner_.*_darwin_arm64(?:\\.tar\\.gz)?$"],
262
+ "windows": [r"osv-scanner_windows_amd64(?:\.exe)?(?:\.zip)?$", r"osv-scanner_.*_windows_amd64(?:\.exe)?(?:\.zip)?$", r"osv-scanner-windows-amd64(?:\.exe)?$"],
263
+ "linux": [r"osv-scanner_.*_linux_amd64(?:\.tar\.gz)?$", r"osv-scanner-linux-amd64$"],
264
+ "darwin": [r"osv-scanner_.*_darwin_amd64(?:\.tar\.gz)?$", r"osv-scanner_.*_darwin_arm64(?:\.tar\.gz)?$"],
238
265
  },
239
266
  "binary_names": [f"osv-scanner{ext}"],
240
267
  "dest_name": f"osv-scanner{ext}",
241
268
  },
242
269
  }
243
270
 
271
+ tool_aliases = {
272
+ "ocs-scanner": "osv-scanner",
273
+ }
274
+
275
+ selected_tools: set[str] = set()
276
+ if args.tool:
277
+ for raw_value in args.tool:
278
+ for item in raw_value.split(","):
279
+ normalized = item.strip().lower()
280
+ if not normalized:
281
+ continue
282
+ normalized = tool_aliases.get(normalized, normalized)
283
+ if normalized not in tool_matrix:
284
+ available = ", ".join(sorted(tool_matrix.keys()))
285
+ print(f"Unknown tool: {item}")
286
+ print(f"Available tools: {available}")
287
+ return 1
288
+ selected_tools.add(normalized)
289
+
290
+ tools_to_process = [
291
+ (tool_name, cfg)
292
+ for tool_name, cfg in tool_matrix.items()
293
+ if not selected_tools or tool_name in selected_tools
294
+ ]
295
+
244
296
  failures: list[str] = []
245
297
  rate_limited = False
246
298
 
247
- for tool_name, cfg in tool_matrix.items():
299
+ for tool_name, cfg in tools_to_process:
300
+ if not args.force and has_installed_tool(tool_name, tools_bin, cfg["dest_name"]):
301
+ print(f"Skipping {tool_name}: already installed (use --force to reinstall)")
302
+ continue
303
+
248
304
  patterns = cfg["patterns"][platform_name]
249
305
  try:
250
306
  install_tool(
@@ -0,0 +1,25 @@
1
+ @echo off
2
+ setlocal
3
+
4
+ set "PYTHON_BIN=python"
5
+ if exist "%~dp0..\.venv\Scripts\python.exe" set "PYTHON_BIN=%~dp0..\.venv\Scripts\python.exe"
6
+
7
+ set "REPORT_DIR=%~1"
8
+ if "%REPORT_DIR%"=="" set "REPORT_DIR=security_reports"
9
+
10
+ set "TARGET_NAME=%~2"
11
+ if "%TARGET_NAME%"=="" for %%I in ("%~dp0..") do set "TARGET_NAME=%%~nxI"
12
+
13
+ if not exist "%REPORT_DIR%" (
14
+ echo Missing input directory: %REPORT_DIR%
15
+ exit /b 1
16
+ )
17
+
18
+ set "OUT_HTML=%REPORT_DIR%\consolidated-security-report.html"
19
+
20
+ "%PYTHON_BIN%" -m sec_report_kit render consolidated --input "%REPORT_DIR%" --output "%REPORT_DIR%" --target "%TARGET_NAME%"
21
+ if errorlevel 1 exit /b 1
22
+
23
+ echo HTML report written to %OUT_HTML%
24
+ for %%I in ("%OUT_HTML%") do set "OUT_HTML_ABS=%%~fI"
25
+ start "" "%OUT_HTML_ABS%"
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ PYTHON_BIN="${PYTHON_BIN:-python}"
5
+ if [[ -x "$(dirname "$0")/../.venv/bin/python" ]]; then
6
+ PYTHON_BIN="$(dirname "$0")/../.venv/bin/python"
7
+ fi
8
+
9
+ REPORT_DIR="${1:-security_reports}"
10
+ ROOT_NAME="$(basename "$(cd "$(dirname "$0")/.." && pwd)")"
11
+ TARGET_NAME="${2:-${ROOT_NAME}}"
12
+ OUT_HTML="${REPORT_DIR}/consolidated-security-report.html"
13
+
14
+ open_html() {
15
+ if command -v xdg-open >/dev/null 2>&1; then
16
+ xdg-open "$1" >/dev/null 2>&1 &
17
+ return 0
18
+ fi
19
+ if command -v open >/dev/null 2>&1; then
20
+ open "$1" >/dev/null 2>&1 &
21
+ return 0
22
+ fi
23
+ echo "HTML generated but no supported browser opener was found. Open manually: $1"
24
+ }
25
+
26
+ if [[ ! -d "${REPORT_DIR}" ]]; then
27
+ echo "Missing input directory: ${REPORT_DIR}"
28
+ exit 1
29
+ fi
30
+
31
+ "${PYTHON_BIN}" -m sec_report_kit render consolidated --input "${REPORT_DIR}" --output "${REPORT_DIR}" --target "${TARGET_NAME}"
32
+
33
+ echo "HTML report written to ${OUT_HTML}"
34
+ open_html "${OUT_HTML}"
@@ -0,0 +1,81 @@
1
+ @echo off
2
+ setlocal
3
+
4
+ set "REPO_ROOT=%~dp0.."
5
+ set "APP_PYTHON=python"
6
+ if exist "%REPO_ROOT%\.venv\Scripts\python.exe" set "APP_PYTHON=%REPO_ROOT%\.venv\Scripts\python.exe"
7
+
8
+ set "REPORT_DIR=%~1"
9
+ if "%REPORT_DIR%"=="" set "REPORT_DIR=security_reports"
10
+
11
+ set "DATABASE_PATH=%~2"
12
+ if "%DATABASE_PATH%"=="" set "DATABASE_PATH=codeql-db"
13
+
14
+ set "QUERY_SUITE=%~3"
15
+ if "%QUERY_SUITE%"=="" set "QUERY_SUITE=codeql/python-queries"
16
+
17
+ set "OUT_JSON=%REPORT_DIR%\codeql.sarif.json"
18
+ set "CODEQL_CMD=codeql"
19
+ set "LOCAL_CODEQL_EXE=%~dp0..\.tools\bin\codeql\codeql.exe"
20
+ set "LOCAL_CODEQL_JAVA=%~dp0..\.tools\bin\codeql\tools\win64\java\bin\java.exe"
21
+
22
+ if exist "%LOCAL_CODEQL_EXE%" set "CODEQL_CMD=%LOCAL_CODEQL_EXE%"
23
+ set "CODEQL_CMD=%CODEQL_CMD:\"=%"
24
+ set "CODEQL_CMD=%CODEQL_CMD:'=%"
25
+
26
+ if not exist "%REPORT_DIR%" mkdir "%REPORT_DIR%"
27
+
28
+ where "%CODEQL_CMD%" >nul 2>&1
29
+ if errorlevel 1 if /I "%CODEQL_CMD%"=="codeql" (
30
+ echo codeql not found. Attempting local install into .tools\bin...
31
+ "%APP_PYTHON%" "%~dp0install_external_clis.py" --repo-root "%REPO_ROOT%" --tool codeql --force
32
+ if errorlevel 1 (
33
+ echo Failed to install CodeQL CLI.
34
+ exit /b 1
35
+ )
36
+ if exist "%LOCAL_CODEQL_EXE%" set "CODEQL_CMD=%LOCAL_CODEQL_EXE%"
37
+ set "CODEQL_CMD=%CODEQL_CMD:\"=%"
38
+ set "CODEQL_CMD=%CODEQL_CMD:'=%"
39
+ where "%CODEQL_CMD%" >nul 2>&1
40
+ if errorlevel 1 if /I "%CODEQL_CMD%"=="codeql" (
41
+ echo codeql is not installed or not on PATH.
42
+ echo Install from: https://codeql.github.com/docs/codeql-overview/codeql-changelog/
43
+ exit /b 1
44
+ )
45
+ )
46
+
47
+ if exist "%LOCAL_CODEQL_EXE%" if not exist "%LOCAL_CODEQL_JAVA%" (
48
+ echo Local CodeQL install appears incomplete ^(missing embedded Java^). Reinstalling CodeQL...
49
+ "%APP_PYTHON%" "%~dp0install_external_clis.py" --repo-root "%REPO_ROOT%" --tool codeql --force
50
+ if errorlevel 1 (
51
+ echo Failed to reinstall CodeQL CLI.
52
+ exit /b 1
53
+ )
54
+ if not exist "%LOCAL_CODEQL_JAVA%" (
55
+ echo CodeQL reinstall completed, but embedded Java is still missing:
56
+ echo %LOCAL_CODEQL_JAVA%
57
+ exit /b 1
58
+ )
59
+ )
60
+
61
+ if not exist "%DATABASE_PATH%" (
62
+ echo CodeQL database not found at %DATABASE_PATH%. Creating database...
63
+ "%CODEQL_CMD%" database create "%DATABASE_PATH%" --language=python --source-root="%REPO_ROOT%"
64
+ if errorlevel 1 (
65
+ echo Failed to create CodeQL database at %DATABASE_PATH%
66
+ exit /b 1
67
+ )
68
+ )
69
+
70
+ "%CODEQL_CMD%" database finalize "%DATABASE_PATH%" >nul 2>&1
71
+
72
+ "%CODEQL_CMD%" database analyze "%DATABASE_PATH%" "%QUERY_SUITE%" --format=sarifv2.1.0 --output="%OUT_JSON%"
73
+ if errorlevel 1 exit /b 1
74
+
75
+ if not exist "%OUT_JSON%" (
76
+ echo CodeQL analyze completed but did not produce output file:
77
+ echo %OUT_JSON%
78
+ exit /b 1
79
+ )
80
+
81
+ echo CodeQL SARIF report written to %OUT_JSON%
@@ -19,6 +19,13 @@ if ! command -v "${CODEQL_CMD}" >/dev/null 2>&1; then
19
19
  exit 1
20
20
  fi
21
21
 
22
+ "${CODEQL_CMD}" database finalize "${DATABASE_PATH}" >/dev/null 2>&1 || true
23
+
22
24
  "${CODEQL_CMD}" database analyze "${DATABASE_PATH}" "${QUERY_SUITE}" --format=sarifv2.1.0 --output="${OUT_JSON}"
23
25
 
26
+ if [[ ! -f "${OUT_JSON}" ]]; then
27
+ echo "CodeQL analyze completed but did not produce output file: ${OUT_JSON}" >&2
28
+ exit 1
29
+ fi
30
+
24
31
  echo "CodeQL SARIF report written to ${OUT_JSON}"