kekkai-cli 2.0.1__tar.gz → 2.2.1__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.
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/PKG-INFO +19 -30
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/README.md +18 -29
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/pyproject.toml +2 -2
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/cli.py +49 -1
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/output.py +1 -1
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/__init__.py +6 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/app.py +12 -0
- kekkai_cli-2.2.1/src/kekkai/triage/code_context.py +369 -0
- kekkai_cli-2.2.1/src/kekkai/triage/editor_support.py +166 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/fix_screen.py +34 -4
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/screens.py +240 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_cli.egg-info/PKG-INFO +19 -30
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_cli.egg-info/SOURCES.txt +6 -0
- kekkai_cli-2.2.1/tests/test_editor_support.py +172 -0
- kekkai_cli-2.2.1/tests/test_triage_code_context.py +333 -0
- kekkai_cli-2.2.1/tests/test_triage_editor.py +408 -0
- kekkai_cli-2.2.1/tests/test_triage_security.py +194 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/setup.cfg +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/compliance/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/compliance/hipaa.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/compliance/mappings.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/compliance/owasp.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/compliance/owasp_agentic.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/compliance/pci_dss.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/compliance/soc2.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/config.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/dojo.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/dojo_import.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/fix/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/fix/audit.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/fix/differ.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/fix/engine.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/fix/prompts.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/github/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/github/commenter.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/github/models.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/github/sanitizer.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/installer/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/installer/errors.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/installer/extract.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/installer/manager.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/installer/manifest.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/installer/verify.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/manifest.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/paths.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/policy.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/report/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/report/compliance_matrix.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/report/generator.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/report/html.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/report/pdf.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/report/unified.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/runner.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/backends/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/backends/base.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/backends/docker.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/backends/native.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/base.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/container.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/falco.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/gitleaks.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/semgrep.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/trivy.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/url_policy.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/scanners/zap.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/artifacts.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/chunking.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/core.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/mermaid.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/model_adapter.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/prompts.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/redaction.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/threatflow/sanitizer.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/audit.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/ignore.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/loader.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/models.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai/triage/widgets.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_cli.egg-info/dependency_links.txt +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_cli.egg-info/entry_points.txt +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_cli.egg-info/requires.txt +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_cli.egg-info/top_level.txt +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/ci/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/ci/benchmarks.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/ci/metadata.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/ci/validators.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/docker/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/docker/metadata.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/docker/sbom.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/docker/security.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/docker/signing.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/redaction.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/slsa/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/slsa/verify.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/windows/__init__.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/windows/chocolatey.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/windows/installer.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/windows/scoop.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/src/kekkai_core/windows/validators.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_cli_output.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_compliance.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_dojo_import.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_fix_engine.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_github_commenter_filter.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_github_commenter_format.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_github_commenter_limit.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_github_commenter_sanitize.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_installer_checksum.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_installer_extract.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_installer_manager.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_installer_manifest.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_installer_platform.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_kekkai_cli.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_kekkai_config.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_kekkai_dojo.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_kekkai_dojo_cli.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_kekkai_manifest.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_kekkai_paths.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_kekkai_runner.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_mermaid.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_policy.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_redaction.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_report.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_backends.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_base.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_container.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_digest_defaults.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_falco.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_gitleaks.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_native.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_semgrep.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_trivy.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_scanner_zap.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_slsa_provenance.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_threatflow_chunking.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_threatflow_model_adapter.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_threatflow_prompts.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_threatflow_redaction.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_threatflow_sanitizer.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_triage_audit.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_triage_ignore.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_triage_loader.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_triage_models.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_unified_report.py +0 -0
- {kekkai_cli-2.0.1 → kekkai_cli-2.2.1}/tests/test_url_policy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kekkai-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Terminal UI for Trivy/Semgrep/Gitleaks. Local-first security triage.
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -14,19 +14,20 @@ Requires-Dist: jinja2>=3.1.6
|
|
|
14
14
|
<img src="https://raw.githubusercontent.com/kademoslabs/assets/main/logos/kekkai-slim.png" alt="Kekkai CLI Logo" width="250"/>
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
|
-
<p align="center"><strong>
|
|
17
|
+
<p align="center"><strong>Interactive security triage in the terminal.</strong></p>
|
|
18
18
|
|
|
19
19
|
<p align="center">
|
|
20
20
|
<img src="https://img.shields.io/github/actions/workflow/status/kademoslabs/kekkai/docker-publish.yml?logo=github"/>
|
|
21
21
|
<img src="https://img.shields.io/circleci/build/github/kademoslabs/kekkai?logo=circleci"/>
|
|
22
|
-
<img src="https://img.shields.io/pypi/v/kekkai-cli
|
|
22
|
+
<img alt="PyPI - Version" src="https://img.shields.io/pypi/v/kekkai-cli">
|
|
23
|
+
|
|
23
24
|
</p>
|
|
24
25
|
|
|
25
26
|
---
|
|
26
27
|
|
|
27
28
|
# Kekkai
|
|
28
29
|
|
|
29
|
-
**
|
|
30
|
+
**Stop parsing JSON.**
|
|
30
31
|
|
|
31
32
|
Kekkai is a small open-source CLI that wraps existing security scanners (Trivy, Semgrep, Gitleaks) and focuses on the part that tends to be slow and frustrating: reviewing and triaging results.
|
|
32
33
|
|
|
@@ -73,6 +74,17 @@ kekkai triage
|
|
|
73
74
|
# Interactive TUI to review findings with keyboard navigation
|
|
74
75
|
```
|
|
75
76
|
|
|
77
|
+
### ⚡️ Auto-Install (Pre-commit)
|
|
78
|
+
|
|
79
|
+
Add this to your `.pre-commit-config.yaml` to scan on every commit:
|
|
80
|
+
|
|
81
|
+
```yaml
|
|
82
|
+
- repo: [https://github.com/kademoslabs/kekkai](https://github.com/kademoslabs/kekkai)
|
|
83
|
+
rev: v2.0.1
|
|
84
|
+
hooks:
|
|
85
|
+
- id: kekkai-scan
|
|
86
|
+
```
|
|
87
|
+
|
|
76
88
|
No signup, no cloud service required.
|
|
77
89
|
|
|
78
90
|
---
|
|
@@ -114,34 +126,11 @@ kekkai triage
|
|
|
114
126
|
|
|
115
127
|
---
|
|
116
128
|
|
|
117
|
-
### CI/CD
|
|
118
|
-
|
|
119
|
-
Break builds on severity thresholds.
|
|
120
|
-
|
|
121
|
-
Kekkai can be used as a CI gate based on severity thresholds.
|
|
129
|
+
### 🚦 CI/CD in 1 Second
|
|
122
130
|
|
|
131
|
+
Don't write YAML. Run this in your repo:
|
|
123
132
|
```bash
|
|
124
|
-
|
|
125
|
-
kekkai scan --ci --fail-on high
|
|
126
|
-
|
|
127
|
-
# Fail only on critical
|
|
128
|
-
kekkai scan --ci --fail-on critical
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**Exit Codes:**
|
|
132
|
-
| Code | Meaning |
|
|
133
|
-
|------|---------|
|
|
134
|
-
| 0 | No findings above threshold |
|
|
135
|
-
| 1 | Findings exceed threshold |
|
|
136
|
-
| 2 | Scanner error |
|
|
137
|
-
|
|
138
|
-
**GitHub Actions Example:**
|
|
139
|
-
|
|
140
|
-
```yaml
|
|
141
|
-
- name: Security Scan
|
|
142
|
-
run: |
|
|
143
|
-
pipx install kekkai-cli
|
|
144
|
-
kekkai scan --ci --fail-on high
|
|
133
|
+
kekkai init --ci
|
|
145
134
|
```
|
|
146
135
|
|
|
147
136
|
[Full CI Documentation →](docs/ci/ci-mode.md)
|
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
<img src="https://raw.githubusercontent.com/kademoslabs/assets/main/logos/kekkai-slim.png" alt="Kekkai CLI Logo" width="250"/>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<p align="center"><strong>
|
|
5
|
+
<p align="center"><strong>Interactive security triage in the terminal.</strong></p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<img src="https://img.shields.io/github/actions/workflow/status/kademoslabs/kekkai/docker-publish.yml?logo=github"/>
|
|
9
9
|
<img src="https://img.shields.io/circleci/build/github/kademoslabs/kekkai?logo=circleci"/>
|
|
10
|
-
<img src="https://img.shields.io/pypi/v/kekkai-cli
|
|
10
|
+
<img alt="PyPI - Version" src="https://img.shields.io/pypi/v/kekkai-cli">
|
|
11
|
+
|
|
11
12
|
</p>
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
15
16
|
# Kekkai
|
|
16
17
|
|
|
17
|
-
**
|
|
18
|
+
**Stop parsing JSON.**
|
|
18
19
|
|
|
19
20
|
Kekkai is a small open-source CLI that wraps existing security scanners (Trivy, Semgrep, Gitleaks) and focuses on the part that tends to be slow and frustrating: reviewing and triaging results.
|
|
20
21
|
|
|
@@ -61,6 +62,17 @@ kekkai triage
|
|
|
61
62
|
# Interactive TUI to review findings with keyboard navigation
|
|
62
63
|
```
|
|
63
64
|
|
|
65
|
+
### ⚡️ Auto-Install (Pre-commit)
|
|
66
|
+
|
|
67
|
+
Add this to your `.pre-commit-config.yaml` to scan on every commit:
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
- repo: [https://github.com/kademoslabs/kekkai](https://github.com/kademoslabs/kekkai)
|
|
71
|
+
rev: v2.0.1
|
|
72
|
+
hooks:
|
|
73
|
+
- id: kekkai-scan
|
|
74
|
+
```
|
|
75
|
+
|
|
64
76
|
No signup, no cloud service required.
|
|
65
77
|
|
|
66
78
|
---
|
|
@@ -102,34 +114,11 @@ kekkai triage
|
|
|
102
114
|
|
|
103
115
|
---
|
|
104
116
|
|
|
105
|
-
### CI/CD
|
|
106
|
-
|
|
107
|
-
Break builds on severity thresholds.
|
|
108
|
-
|
|
109
|
-
Kekkai can be used as a CI gate based on severity thresholds.
|
|
117
|
+
### 🚦 CI/CD in 1 Second
|
|
110
118
|
|
|
119
|
+
Don't write YAML. Run this in your repo:
|
|
111
120
|
```bash
|
|
112
|
-
|
|
113
|
-
kekkai scan --ci --fail-on high
|
|
114
|
-
|
|
115
|
-
# Fail only on critical
|
|
116
|
-
kekkai scan --ci --fail-on critical
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
**Exit Codes:**
|
|
120
|
-
| Code | Meaning |
|
|
121
|
-
|------|---------|
|
|
122
|
-
| 0 | No findings above threshold |
|
|
123
|
-
| 1 | Findings exceed threshold |
|
|
124
|
-
| 2 | Scanner error |
|
|
125
|
-
|
|
126
|
-
**GitHub Actions Example:**
|
|
127
|
-
|
|
128
|
-
```yaml
|
|
129
|
-
- name: Security Scan
|
|
130
|
-
run: |
|
|
131
|
-
pipx install kekkai-cli
|
|
132
|
-
kekkai scan --ci --fail-on high
|
|
121
|
+
kekkai init --ci
|
|
133
122
|
```
|
|
134
123
|
|
|
135
124
|
[Full CI Documentation →](docs/ci/ci-mode.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "kekkai-cli"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.2.1"
|
|
4
4
|
description = "Terminal UI for Trivy/Semgrep/Gitleaks. Local-first security triage."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -21,7 +21,7 @@ line-length = 100
|
|
|
21
21
|
extend-exclude = ["dist", "build", ".venv"]
|
|
22
22
|
lint.select = ["E", "F", "I", "B", "UP", "S", "SIM"]
|
|
23
23
|
lint.ignore = ["S101"] # allow asserts in tests
|
|
24
|
-
lint.per-file-ignores = { "tests/**" = ["S"], "src/kekkai_core/docker/**" = ["S603"], "src/kekkai_core/slsa/**" = ["S603", "S607"], "src/kekkai/github/**" = ["S105"] }
|
|
24
|
+
lint.per-file-ignores = { "tests/**" = ["S", "SIM117"], "src/kekkai_core/docker/**" = ["S603"], "src/kekkai_core/slsa/**" = ["S603", "S607"], "src/kekkai/github/**" = ["S105"] }
|
|
25
25
|
|
|
26
26
|
[tool.mypy]
|
|
27
27
|
python_version = "3.12"
|
|
@@ -221,6 +221,17 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
221
221
|
type=str,
|
|
222
222
|
help="Path for .kekkaiignore output (default: .kekkaiignore)",
|
|
223
223
|
)
|
|
224
|
+
triage_parser.add_argument(
|
|
225
|
+
"--repo",
|
|
226
|
+
type=str,
|
|
227
|
+
help="Repository root path (default: auto-detect from run.json)",
|
|
228
|
+
)
|
|
229
|
+
triage_parser.add_argument(
|
|
230
|
+
"--context-lines",
|
|
231
|
+
type=int,
|
|
232
|
+
default=10,
|
|
233
|
+
help="Context lines before/after line (default: 10, range: 5-100)",
|
|
234
|
+
)
|
|
224
235
|
|
|
225
236
|
# Fix subcommand - AI-powered remediation
|
|
226
237
|
fix_parser = subparsers.add_parser("fix", help="generate AI-powered code fixes for findings")
|
|
@@ -1186,6 +1197,11 @@ def _command_triage(parsed: argparse.Namespace) -> int:
|
|
|
1186
1197
|
|
|
1187
1198
|
input_path_str = cast(str | None, getattr(parsed, "input", None))
|
|
1188
1199
|
output_path_str = cast(str | None, getattr(parsed, "output", None))
|
|
1200
|
+
repo_path_str = cast(str | None, getattr(parsed, "repo", None))
|
|
1201
|
+
context_lines = cast(int, getattr(parsed, "context_lines", 10))
|
|
1202
|
+
|
|
1203
|
+
# Validate context_lines range
|
|
1204
|
+
context_lines = max(5, min(100, context_lines))
|
|
1189
1205
|
|
|
1190
1206
|
# Default to latest run if no input specified
|
|
1191
1207
|
if not input_path_str:
|
|
@@ -1232,7 +1248,39 @@ def _command_triage(parsed: argparse.Namespace) -> int:
|
|
|
1232
1248
|
|
|
1233
1249
|
console.print(f"[info]Loaded {len(findings)} finding(s)[/info]\n")
|
|
1234
1250
|
|
|
1235
|
-
|
|
1251
|
+
# Auto-detect repo_path from run.json if not explicitly provided
|
|
1252
|
+
repo_path: Path | None = None
|
|
1253
|
+
if repo_path_str:
|
|
1254
|
+
repo_path = Path(repo_path_str).expanduser().resolve()
|
|
1255
|
+
elif input_path.is_dir():
|
|
1256
|
+
# Try to read repo_path from run.json
|
|
1257
|
+
manifest_path = input_path / "run.json"
|
|
1258
|
+
if manifest_path.exists():
|
|
1259
|
+
try:
|
|
1260
|
+
import json
|
|
1261
|
+
|
|
1262
|
+
with manifest_path.open() as f:
|
|
1263
|
+
manifest_data = json.load(f)
|
|
1264
|
+
stored_repo = manifest_data.get("repo_path")
|
|
1265
|
+
if stored_repo:
|
|
1266
|
+
repo_path = Path(stored_repo).expanduser().resolve()
|
|
1267
|
+
console.print(f"[dim]Using repo path from run metadata: {repo_path}[/dim]\n")
|
|
1268
|
+
except (OSError, json.JSONDecodeError, KeyError):
|
|
1269
|
+
pass
|
|
1270
|
+
|
|
1271
|
+
# Fall back to current directory if still not set (with warning)
|
|
1272
|
+
if repo_path is None:
|
|
1273
|
+
repo_path = Path.cwd()
|
|
1274
|
+
console.print("[warning]⚠ Repo path not detected. Using current directory.[/warning]")
|
|
1275
|
+
console.print("[dim]Tip: Use --repo to specify repository root explicitly.[/dim]")
|
|
1276
|
+
console.print(f"[dim]Current directory: {repo_path}[/dim]\n")
|
|
1277
|
+
|
|
1278
|
+
return run_triage(
|
|
1279
|
+
findings=findings,
|
|
1280
|
+
output_path=output_path,
|
|
1281
|
+
repo_path=repo_path,
|
|
1282
|
+
context_lines=context_lines,
|
|
1283
|
+
)
|
|
1236
1284
|
|
|
1237
1285
|
|
|
1238
1286
|
def _command_fix(parsed: argparse.Namespace) -> int:
|
|
@@ -29,6 +29,8 @@ def run_triage(
|
|
|
29
29
|
input_path: Path | None = None,
|
|
30
30
|
output_path: Path | None = None,
|
|
31
31
|
findings: Sequence[FindingEntry] | None = None,
|
|
32
|
+
repo_path: Path | None = None,
|
|
33
|
+
context_lines: int = 10,
|
|
32
34
|
) -> int:
|
|
33
35
|
"""Run the triage TUI (lazy import).
|
|
34
36
|
|
|
@@ -36,6 +38,8 @@ def run_triage(
|
|
|
36
38
|
input_path: Path to findings JSON file.
|
|
37
39
|
output_path: Path for .kekkaiignore output.
|
|
38
40
|
findings: Pre-loaded findings (alternative to input_path).
|
|
41
|
+
repo_path: Repository root path for code context display.
|
|
42
|
+
context_lines: Number of lines to show before/after vulnerable line.
|
|
39
43
|
|
|
40
44
|
Returns:
|
|
41
45
|
Exit code (0 for success).
|
|
@@ -50,6 +54,8 @@ def run_triage(
|
|
|
50
54
|
input_path=input_path,
|
|
51
55
|
output_path=output_path,
|
|
52
56
|
findings=findings,
|
|
57
|
+
repo_path=repo_path,
|
|
58
|
+
context_lines=context_lines,
|
|
53
59
|
)
|
|
54
60
|
except ImportError as e:
|
|
55
61
|
raise RuntimeError(
|
|
@@ -51,6 +51,8 @@ class TriageApp(App[None]):
|
|
|
51
51
|
input_path: Path | None = None,
|
|
52
52
|
output_path: Path | None = None,
|
|
53
53
|
audit_path: Path | None = None,
|
|
54
|
+
repo_path: Path | None = None,
|
|
55
|
+
context_lines: int = 10,
|
|
54
56
|
) -> None:
|
|
55
57
|
"""Initialize triage application.
|
|
56
58
|
|
|
@@ -59,6 +61,8 @@ class TriageApp(App[None]):
|
|
|
59
61
|
input_path: Path to findings JSON file.
|
|
60
62
|
output_path: Path for .kekkaiignore output.
|
|
61
63
|
audit_path: Path for audit log.
|
|
64
|
+
repo_path: Repository root path for code context display.
|
|
65
|
+
context_lines: Number of lines to show before/after vulnerable line.
|
|
62
66
|
"""
|
|
63
67
|
super().__init__()
|
|
64
68
|
self._input_path = input_path
|
|
@@ -66,6 +70,8 @@ class TriageApp(App[None]):
|
|
|
66
70
|
self.ignore_file = IgnoreFile(output_path)
|
|
67
71
|
self.audit_log = TriageAuditLog(audit_path)
|
|
68
72
|
self._decisions: dict[str, TriageDecision] = {}
|
|
73
|
+
self.repo_path = repo_path or Path.cwd()
|
|
74
|
+
self.context_lines = context_lines
|
|
69
75
|
|
|
70
76
|
@property
|
|
71
77
|
def findings(self) -> list[FindingEntry]:
|
|
@@ -148,6 +154,8 @@ def run_triage(
|
|
|
148
154
|
input_path: Path | None = None,
|
|
149
155
|
output_path: Path | None = None,
|
|
150
156
|
findings: Sequence[FindingEntry] | None = None,
|
|
157
|
+
repo_path: Path | None = None,
|
|
158
|
+
context_lines: int = 10,
|
|
151
159
|
) -> int:
|
|
152
160
|
"""Run the triage TUI.
|
|
153
161
|
|
|
@@ -155,6 +163,8 @@ def run_triage(
|
|
|
155
163
|
input_path: Path to findings JSON file.
|
|
156
164
|
output_path: Path for .kekkaiignore output.
|
|
157
165
|
findings: Pre-loaded findings (alternative to input_path).
|
|
166
|
+
repo_path: Repository root path for code context display.
|
|
167
|
+
context_lines: Number of lines to show before/after vulnerable line.
|
|
158
168
|
|
|
159
169
|
Returns:
|
|
160
170
|
Exit code (0 for success).
|
|
@@ -163,6 +173,8 @@ def run_triage(
|
|
|
163
173
|
findings=findings,
|
|
164
174
|
input_path=input_path,
|
|
165
175
|
output_path=output_path,
|
|
176
|
+
repo_path=repo_path,
|
|
177
|
+
context_lines=context_lines,
|
|
166
178
|
)
|
|
167
179
|
app.run()
|
|
168
180
|
return 0
|