sec-report-kit 0.2.5__tar.gz → 0.2.7__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.
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/CHANGELOG.md +19 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/PKG-INFO +31 -1
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/README.md +30 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/pyproject.toml +1 -1
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/requirements.txt +1 -1
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_consolidated_html.bat +12 -1
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_consolidated_html.sh +8 -1
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/__init__.py +1 -1
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/cli.py +116 -13
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/generate_consolidated_security_report.py +16 -0
- sec_report_kit-0.2.7/src/sec_report_kit/report/html_renderer.py +573 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/tests/test_cli.py +249 -5
- sec_report_kit-0.2.7/tests/test_html_renderer.py +166 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/tests/test_parsers.py +73 -0
- sec_report_kit-0.2.5/src/sec_report_kit/report/html_renderer.py +0 -214
- sec_report_kit-0.2.5/tests/test_html_renderer.py +0 -83
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/.gitattributes +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/.github/workflows/pip-audit.yml +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/.github/workflows/publish-pypi.yml +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/.github/workflows/publish-testpypi.yml +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/.github/workflows/trivy-fs-audit.yml +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/.github/workflows/unit-test-coverage-gate.yml +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/.gitignore +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/bandit-gaps-vs-sast-open-source-tools.md +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/check_assets.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/download_safety_db.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/download_safety_db.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/download_safety_db.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/install_external_clis.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/install_tools.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/install_tools.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_bandit_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_bandit_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_checkov_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_checkov_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_codeql_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_codeql_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_gitleaks_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_gitleaks_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_osv_scanner_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_osv_scanner_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_pip_audit_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_pip_audit_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_safety_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_safety_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_semgrep_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_semgrep_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_tfsec_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_tfsec_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_trivy_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_trivy_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_trufflehog_html.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/render_trufflehog_html.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_bandit.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_bandit.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_checkov.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_checkov.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_codeql.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_codeql.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_gitleaks.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_gitleaks.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_osv_scanner.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_osv_scanner.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_pip_audit.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_pip_audit.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_safety.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_safety.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_semgrep.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_semgrep.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_tfsec.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_tfsec.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_trivy.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_trivy.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_trufflehog.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_trufflehog.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_unit_tests_with_coverage.bat +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/scripts/run_unit_tests_with_coverage.sh +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/__main__.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/mcp/__init__.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/mcp/server.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/models.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/__init__.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/bandit.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/checkov.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/codeql.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/gitleaks.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/osv_scanner.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/pip_audit.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/safety.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/semgrep.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/tfsec.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/trivy.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/parsers/trufflehog.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/report/__init__.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/services/__init__.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/services/normalize.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/src/sec_report_kit/services/summarize.py +0 -0
- {sec_report_kit-0.2.5 → sec_report_kit-0.2.7}/tests/test_mcp_server.py +0 -0
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.2.7 - 2026-05-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Test coverage now includes the consolidated date-filter helpers, Safety parser fallback branches, and consolidated HTML dashboard visibility paths, bringing enforced suite coverage to 100%.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- `requirements.txt` now pins `urllib3==2.7.0` to resolve the Trivy-reported CVEs affecting `2.6.3`.
|
|
12
|
+
|
|
13
|
+
## 0.2.6 - 2026-05-17
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Consolidated report rendering now supports bounded file pickup with `--modified-until`, enabling date-range selection when combined with `--modified-since`.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- README examples now document both date-range filtering and "from date until today" usage for consolidated report generation.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- `scripts/render_consolidated_html.bat` no longer forwards the first two positional arguments as unexpected extras on Windows.
|
|
23
|
+
|
|
5
24
|
## 0.2.5 - 2026-05-17
|
|
6
25
|
|
|
7
26
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sec-report-kit
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
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
|
|
@@ -252,6 +252,36 @@ scripts\render_consolidated_html.bat
|
|
|
252
252
|
scripts\render_consolidated_html.bat security_reports sec-report-kit
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
+
You can also restrict which report files are picked up by modification time and cap how many of the newest files are included:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Only files modified today
|
|
259
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since today
|
|
260
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since today
|
|
261
|
+
|
|
262
|
+
# Since yesterday
|
|
263
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since yesterday
|
|
264
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since yesterday
|
|
265
|
+
|
|
266
|
+
# Last 7 days
|
|
267
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since last-7-days
|
|
268
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since last-7-days
|
|
269
|
+
|
|
270
|
+
# Since a fixed date and only the 10 newest matching files
|
|
271
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since 2026-05-01 --limit 10
|
|
272
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since 2026-05-01 --limit 10
|
|
273
|
+
|
|
274
|
+
# Between two dates
|
|
275
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since 2026-05-01 --modified-until 2026-05-10
|
|
276
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since 2026-05-01 --modified-until 2026-05-10
|
|
277
|
+
|
|
278
|
+
# From a fixed date until today
|
|
279
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since 2026-05-01
|
|
280
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since 2026-05-01
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
`--modified-since` accepts ISO dates/datetimes plus `today`, `yesterday`, `last-week`, and `last-7-days`. `--modified-until` accepts ISO dates/datetimes plus `today` and `yesterday`. Use `--modified-since` by itself for "from date until now", or combine both options for a bounded date range. When `--limit` is used, the newest matching files are selected first.
|
|
284
|
+
|
|
255
285
|
Convert sample Bandit JSON report to HTML:
|
|
256
286
|
|
|
257
287
|
```bash
|
|
@@ -225,6 +225,36 @@ scripts\render_consolidated_html.bat
|
|
|
225
225
|
scripts\render_consolidated_html.bat security_reports sec-report-kit
|
|
226
226
|
```
|
|
227
227
|
|
|
228
|
+
You can also restrict which report files are picked up by modification time and cap how many of the newest files are included:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Only files modified today
|
|
232
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since today
|
|
233
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since today
|
|
234
|
+
|
|
235
|
+
# Since yesterday
|
|
236
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since yesterday
|
|
237
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since yesterday
|
|
238
|
+
|
|
239
|
+
# Last 7 days
|
|
240
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since last-7-days
|
|
241
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since last-7-days
|
|
242
|
+
|
|
243
|
+
# Since a fixed date and only the 10 newest matching files
|
|
244
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since 2026-05-01 --limit 10
|
|
245
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since 2026-05-01 --limit 10
|
|
246
|
+
|
|
247
|
+
# Between two dates
|
|
248
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since 2026-05-01 --modified-until 2026-05-10
|
|
249
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since 2026-05-01 --modified-until 2026-05-10
|
|
250
|
+
|
|
251
|
+
# From a fixed date until today
|
|
252
|
+
bash scripts/render_consolidated_html.sh security_reports sec-report-kit --modified-since 2026-05-01
|
|
253
|
+
scripts\render_consolidated_html.bat security_reports sec-report-kit --modified-since 2026-05-01
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`--modified-since` accepts ISO dates/datetimes plus `today`, `yesterday`, `last-week`, and `last-7-days`. `--modified-until` accepts ISO dates/datetimes plus `today` and `yesterday`. Use `--modified-since` by itself for "from date until now", or combine both options for a bounded date range. When `--limit` is used, the newest matching files are selected first.
|
|
257
|
+
|
|
228
258
|
Convert sample Bandit JSON report to HTML:
|
|
229
259
|
|
|
230
260
|
```bash
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sec-report-kit"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.7"
|
|
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"
|
|
@@ -10,6 +10,17 @@ if "%REPORT_DIR%"=="" set "REPORT_DIR=security_reports"
|
|
|
10
10
|
set "TARGET_NAME=%~2"
|
|
11
11
|
if "%TARGET_NAME%"=="" for %%I in ("%~dp0..") do set "TARGET_NAME=%%~nxI"
|
|
12
12
|
|
|
13
|
+
if not "%~1"=="" shift
|
|
14
|
+
if not "%~1"=="" shift
|
|
15
|
+
|
|
16
|
+
set "EXTRA_ARGS="
|
|
17
|
+
:collect_args
|
|
18
|
+
if "%~1"=="" goto after_collect_args
|
|
19
|
+
set "EXTRA_ARGS=%EXTRA_ARGS% "%~1""
|
|
20
|
+
shift
|
|
21
|
+
goto collect_args
|
|
22
|
+
:after_collect_args
|
|
23
|
+
|
|
13
24
|
if not exist "%REPORT_DIR%" (
|
|
14
25
|
echo Missing input directory: %REPORT_DIR%
|
|
15
26
|
exit /b 1
|
|
@@ -17,7 +28,7 @@ if not exist "%REPORT_DIR%" (
|
|
|
17
28
|
|
|
18
29
|
set "OUT_HTML=%REPORT_DIR%\consolidated-security-report.html"
|
|
19
30
|
|
|
20
|
-
"%PYTHON_BIN%" -m sec_report_kit render consolidated --input "%REPORT_DIR%" --output "%REPORT_DIR%" --target "%TARGET_NAME%"
|
|
31
|
+
"%PYTHON_BIN%" -m sec_report_kit render consolidated --input "%REPORT_DIR%" --output "%REPORT_DIR%" --target "%TARGET_NAME%" %EXTRA_ARGS%
|
|
21
32
|
if errorlevel 1 exit /b 1
|
|
22
33
|
|
|
23
34
|
echo HTML report written to %OUT_HTML%
|
|
@@ -11,6 +11,13 @@ ROOT_NAME="$(basename "$(cd "$(dirname "$0")/.." && pwd)")"
|
|
|
11
11
|
TARGET_NAME="${2:-${ROOT_NAME}}"
|
|
12
12
|
OUT_HTML="${REPORT_DIR}/consolidated-security-report.html"
|
|
13
13
|
|
|
14
|
+
if [[ $# -gt 0 ]]; then
|
|
15
|
+
shift
|
|
16
|
+
fi
|
|
17
|
+
if [[ $# -gt 0 ]]; then
|
|
18
|
+
shift
|
|
19
|
+
fi
|
|
20
|
+
|
|
14
21
|
open_html() {
|
|
15
22
|
if command -v xdg-open >/dev/null 2>&1; then
|
|
16
23
|
xdg-open "$1" >/dev/null 2>&1 &
|
|
@@ -28,7 +35,7 @@ if [[ ! -d "${REPORT_DIR}" ]]; then
|
|
|
28
35
|
exit 1
|
|
29
36
|
fi
|
|
30
37
|
|
|
31
|
-
"${PYTHON_BIN}" -m sec_report_kit render consolidated --input "${REPORT_DIR}" --output "${REPORT_DIR}" --target "${TARGET_NAME}"
|
|
38
|
+
"${PYTHON_BIN}" -m sec_report_kit render consolidated --input "${REPORT_DIR}" --output "${REPORT_DIR}" --target "${TARGET_NAME}" "$@"
|
|
32
39
|
|
|
33
40
|
echo "HTML report written to ${OUT_HTML}"
|
|
34
41
|
open_html "${OUT_HTML}"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import datetime as dt
|
|
3
4
|
import json
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Any
|
|
@@ -18,7 +19,7 @@ from sec_report_kit.parsers.semgrep import parse_semgrep_json
|
|
|
18
19
|
from sec_report_kit.parsers.tfsec import parse_tfsec_json
|
|
19
20
|
from sec_report_kit.parsers.trivy import parse_trivy_json
|
|
20
21
|
from sec_report_kit.parsers.trufflehog import parse_trufflehog_json
|
|
21
|
-
from sec_report_kit.report.html_renderer import render_html_report
|
|
22
|
+
from sec_report_kit.report.html_renderer import render_consolidated_dashboard_report, render_html_report
|
|
22
23
|
from sec_report_kit.services.summarize import count_by_severity, sort_findings
|
|
23
24
|
|
|
24
25
|
app = typer.Typer(help="Security report kit CLI")
|
|
@@ -28,6 +29,90 @@ app.add_typer(render_app, name="render")
|
|
|
28
29
|
app.add_typer(mcp_app, name="mcp")
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
def _parse_modified_since(value: str) -> dt.datetime:
|
|
33
|
+
local_tz = dt.datetime.now().astimezone().tzinfo or dt.timezone.utc
|
|
34
|
+
now = dt.datetime.now(local_tz)
|
|
35
|
+
normalized = value.strip().lower()
|
|
36
|
+
|
|
37
|
+
if normalized == "today":
|
|
38
|
+
return now.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
39
|
+
if normalized == "yesterday":
|
|
40
|
+
return (now - dt.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
41
|
+
if normalized in {"last-week", "last-7-days"}:
|
|
42
|
+
return now - dt.timedelta(days=7)
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
parsed = dt.datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
46
|
+
except ValueError as exc:
|
|
47
|
+
raise typer.BadParameter(
|
|
48
|
+
"Use ISO date/datetime or one of: today, yesterday, last-week, last-7-days"
|
|
49
|
+
) from exc
|
|
50
|
+
|
|
51
|
+
if parsed.tzinfo is None:
|
|
52
|
+
return parsed.replace(tzinfo=local_tz)
|
|
53
|
+
return parsed.astimezone(local_tz)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _parse_modified_until(value: str) -> dt.datetime:
|
|
57
|
+
local_tz = dt.datetime.now().astimezone().tzinfo or dt.timezone.utc
|
|
58
|
+
normalized = value.strip().lower()
|
|
59
|
+
|
|
60
|
+
if normalized == "today":
|
|
61
|
+
return dt.datetime.now(local_tz).replace(hour=23, minute=59, second=59, microsecond=999999)
|
|
62
|
+
if normalized == "yesterday":
|
|
63
|
+
return (dt.datetime.now(local_tz) - dt.timedelta(days=1)).replace(
|
|
64
|
+
hour=23,
|
|
65
|
+
minute=59,
|
|
66
|
+
second=59,
|
|
67
|
+
microsecond=999999,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
parsed = _parse_modified_since(value)
|
|
71
|
+
if "T" not in value and " " not in value:
|
|
72
|
+
return parsed.replace(hour=23, minute=59, second=59, microsecond=999999)
|
|
73
|
+
return parsed
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _collect_consolidated_candidates(
|
|
77
|
+
input_dir: Path,
|
|
78
|
+
modified_since: str | None,
|
|
79
|
+
modified_until: str | None,
|
|
80
|
+
limit: int | None,
|
|
81
|
+
) -> list[Path]:
|
|
82
|
+
candidates = [
|
|
83
|
+
path
|
|
84
|
+
for path in input_dir.iterdir()
|
|
85
|
+
if path.is_file()
|
|
86
|
+
and (
|
|
87
|
+
path.suffix.lower() in {".json", ".sarif", ".ndjson", ".jsonl"}
|
|
88
|
+
or path.name.lower().endswith(".sarif.json")
|
|
89
|
+
)
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
if modified_since:
|
|
93
|
+
cutoff = _parse_modified_since(modified_since)
|
|
94
|
+
candidates = [
|
|
95
|
+
path
|
|
96
|
+
for path in candidates
|
|
97
|
+
if dt.datetime.fromtimestamp(path.stat().st_mtime, tz=cutoff.tzinfo) >= cutoff
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
if modified_until:
|
|
101
|
+
cutoff = _parse_modified_until(modified_until)
|
|
102
|
+
candidates = [
|
|
103
|
+
path
|
|
104
|
+
for path in candidates
|
|
105
|
+
if dt.datetime.fromtimestamp(path.stat().st_mtime, tz=cutoff.tzinfo) <= cutoff
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
candidates.sort(key=lambda path: (-path.stat().st_mtime, path.name.lower()))
|
|
109
|
+
|
|
110
|
+
if limit is not None:
|
|
111
|
+
candidates = candidates[:limit]
|
|
112
|
+
|
|
113
|
+
return candidates
|
|
114
|
+
|
|
115
|
+
|
|
31
116
|
def _load_json(path: Path) -> Any:
|
|
32
117
|
# Accept both UTF-8 and UTF-8 BOM encoded JSON files.
|
|
33
118
|
raw = path.read_text(encoding="utf-8-sig")
|
|
@@ -227,18 +312,29 @@ def render_consolidated(
|
|
|
227
312
|
help="Output folder where consolidated HTML will be written",
|
|
228
313
|
),
|
|
229
314
|
target: str = typer.Option("consolidated-scan", "--target", help="Consolidated target label"),
|
|
315
|
+
modified_since: str | None = typer.Option(
|
|
316
|
+
None,
|
|
317
|
+
"--modified-since",
|
|
318
|
+
help="Only include files modified on or after this time. Accepts ISO date/datetime or: today, yesterday, last-week, last-7-days",
|
|
319
|
+
),
|
|
320
|
+
modified_until: str | None = typer.Option(
|
|
321
|
+
None,
|
|
322
|
+
"--modified-until",
|
|
323
|
+
help="Only include files modified on or before this time. Accepts ISO date/datetime, today, or yesterday. Combine with --modified-since for a date range.",
|
|
324
|
+
),
|
|
325
|
+
limit: int | None = typer.Option(
|
|
326
|
+
None,
|
|
327
|
+
"--limit",
|
|
328
|
+
min=1,
|
|
329
|
+
help="Maximum number of most recently modified report files to include after filtering",
|
|
330
|
+
),
|
|
230
331
|
) -> None:
|
|
231
332
|
"""Render a consolidated HTML report from all supported report files in a directory."""
|
|
232
|
-
candidates =
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
and (
|
|
238
|
-
path.suffix.lower() in {".json", ".sarif", ".ndjson", ".jsonl"}
|
|
239
|
-
or path.name.lower().endswith(".sarif.json")
|
|
240
|
-
)
|
|
241
|
-
]
|
|
333
|
+
candidates = _collect_consolidated_candidates(
|
|
334
|
+
input_dir=input,
|
|
335
|
+
modified_since=modified_since,
|
|
336
|
+
modified_until=modified_until,
|
|
337
|
+
limit=limit,
|
|
242
338
|
)
|
|
243
339
|
|
|
244
340
|
all_findings = []
|
|
@@ -258,11 +354,12 @@ def render_consolidated(
|
|
|
258
354
|
|
|
259
355
|
all_findings = sort_findings(all_findings)
|
|
260
356
|
counts = count_by_severity(all_findings)
|
|
261
|
-
report_html =
|
|
357
|
+
report_html = render_consolidated_dashboard_report(
|
|
262
358
|
target_ref=target,
|
|
263
|
-
source_label="consolidated",
|
|
264
359
|
findings=all_findings,
|
|
265
360
|
counts=counts,
|
|
361
|
+
reports_dir=input,
|
|
362
|
+
output_dir=output,
|
|
266
363
|
)
|
|
267
364
|
|
|
268
365
|
output.mkdir(parents=True, exist_ok=True)
|
|
@@ -271,6 +368,12 @@ def render_consolidated(
|
|
|
271
368
|
|
|
272
369
|
typer.echo(f"[OK] Report generated: {output_file}")
|
|
273
370
|
typer.echo(f"[INFO] Input directory: {input}")
|
|
371
|
+
if modified_since:
|
|
372
|
+
typer.echo(f"[INFO] Modified since filter: {modified_since}")
|
|
373
|
+
if modified_until:
|
|
374
|
+
typer.echo(f"[INFO] Modified until filter: {modified_until}")
|
|
375
|
+
if limit is not None:
|
|
376
|
+
typer.echo(f"[INFO] File limit: {limit}")
|
|
274
377
|
typer.echo(f"[INFO] Files included: {included_files}")
|
|
275
378
|
typer.echo(f"[INFO] Files skipped: {skipped_files}")
|
|
276
379
|
typer.echo(f"[INFO] Total findings: {len(all_findings)}")
|
|
@@ -13,12 +13,28 @@ def main() -> int:
|
|
|
13
13
|
parser.add_argument("--input", required=True, help="Input folder containing report files")
|
|
14
14
|
parser.add_argument("--output", required=True, help="Output folder for generated HTML")
|
|
15
15
|
parser.add_argument("--target", default="consolidated-scan", help="Target label used in HTML report")
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"--modified-since",
|
|
18
|
+
help="Only include files modified on or after this time. Accepts ISO date/datetime or: today, yesterday, last-week, last-7-days",
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument(
|
|
21
|
+
"--modified-until",
|
|
22
|
+
help="Only include files modified on or before this time. Accepts ISO date/datetime, today, or yesterday. Combine with --modified-since for a date range.",
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"--limit",
|
|
26
|
+
type=int,
|
|
27
|
+
help="Maximum number of most recently modified report files to include after filtering",
|
|
28
|
+
)
|
|
16
29
|
args = parser.parse_args()
|
|
17
30
|
|
|
18
31
|
render_consolidated(
|
|
19
32
|
input=Path(args.input),
|
|
20
33
|
output=Path(args.output),
|
|
21
34
|
target=args.target,
|
|
35
|
+
modified_since=args.modified_since,
|
|
36
|
+
modified_until=args.modified_until,
|
|
37
|
+
limit=args.limit,
|
|
22
38
|
)
|
|
23
39
|
return 0
|
|
24
40
|
|