kekkai-cli 1.1.0__tar.gz → 1.1.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.
Files changed (176) hide show
  1. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/PKG-INFO +33 -13
  2. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/README.md +32 -12
  3. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/pyproject.toml +2 -3
  4. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/cli.py +124 -33
  5. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/dojo_import.py +9 -1
  6. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/output.py +1 -1
  7. kekkai_cli-1.1.1/src/kekkai/report/unified.py +226 -0
  8. kekkai_cli-1.1.1/src/kekkai/triage/__init__.py +86 -0
  9. kekkai_cli-1.1.1/src/kekkai/triage/loader.py +196 -0
  10. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_cli.egg-info/PKG-INFO +33 -13
  11. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_cli.egg-info/SOURCES.txt +4 -33
  12. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_cli.egg-info/entry_points.txt +0 -1
  13. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_cli.egg-info/top_level.txt +0 -1
  14. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_dojo_import.py +30 -0
  15. kekkai_cli-1.1.1/tests/test_triage_loader.py +283 -0
  16. kekkai_cli-1.1.1/tests/test_unified_report.py +529 -0
  17. kekkai_cli-1.1.0/src/kekkai/triage/__init__.py +0 -33
  18. kekkai_cli-1.1.0/src/portal/__init__.py +0 -19
  19. kekkai_cli-1.1.0/src/portal/api.py +0 -155
  20. kekkai_cli-1.1.0/src/portal/auth.py +0 -103
  21. kekkai_cli-1.1.0/src/portal/enterprise/__init__.py +0 -45
  22. kekkai_cli-1.1.0/src/portal/enterprise/audit.py +0 -435
  23. kekkai_cli-1.1.0/src/portal/enterprise/licensing.py +0 -408
  24. kekkai_cli-1.1.0/src/portal/enterprise/rbac.py +0 -276
  25. kekkai_cli-1.1.0/src/portal/enterprise/saml.py +0 -595
  26. kekkai_cli-1.1.0/src/portal/ops/__init__.py +0 -53
  27. kekkai_cli-1.1.0/src/portal/ops/backup.py +0 -553
  28. kekkai_cli-1.1.0/src/portal/ops/log_shipper.py +0 -469
  29. kekkai_cli-1.1.0/src/portal/ops/monitoring.py +0 -517
  30. kekkai_cli-1.1.0/src/portal/ops/restore.py +0 -469
  31. kekkai_cli-1.1.0/src/portal/ops/secrets.py +0 -408
  32. kekkai_cli-1.1.0/src/portal/ops/upgrade.py +0 -591
  33. kekkai_cli-1.1.0/src/portal/tenants.py +0 -340
  34. kekkai_cli-1.1.0/src/portal/uploads.py +0 -259
  35. kekkai_cli-1.1.0/src/portal/web.py +0 -393
  36. kekkai_cli-1.1.0/tests/test_enterprise_audit.py +0 -288
  37. kekkai_cli-1.1.0/tests/test_enterprise_licensing.py +0 -367
  38. kekkai_cli-1.1.0/tests/test_enterprise_rbac.py +0 -224
  39. kekkai_cli-1.1.0/tests/test_enterprise_saml.py +0 -326
  40. kekkai_cli-1.1.0/tests/test_ops_backup.py +0 -318
  41. kekkai_cli-1.1.0/tests/test_ops_log_shipper.py +0 -366
  42. kekkai_cli-1.1.0/tests/test_ops_monitoring.py +0 -379
  43. kekkai_cli-1.1.0/tests/test_ops_restore.py +0 -299
  44. kekkai_cli-1.1.0/tests/test_ops_secrets.py +0 -331
  45. kekkai_cli-1.1.0/tests/test_ops_upgrade.py +0 -418
  46. kekkai_cli-1.1.0/tests/test_portal_api.py +0 -157
  47. kekkai_cli-1.1.0/tests/test_portal_auth.py +0 -226
  48. kekkai_cli-1.1.0/tests/test_portal_tenants.py +0 -347
  49. kekkai_cli-1.1.0/tests/test_portal_uploads.py +0 -378
  50. kekkai_cli-1.1.0/tests/test_portal_web.py +0 -386
  51. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/setup.cfg +0 -0
  52. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/__init__.py +0 -0
  53. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/compliance/__init__.py +0 -0
  54. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/compliance/hipaa.py +0 -0
  55. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/compliance/mappings.py +0 -0
  56. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/compliance/owasp.py +0 -0
  57. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/compliance/owasp_agentic.py +0 -0
  58. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/compliance/pci_dss.py +0 -0
  59. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/compliance/soc2.py +0 -0
  60. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/config.py +0 -0
  61. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/dojo.py +0 -0
  62. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/fix/__init__.py +0 -0
  63. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/fix/audit.py +0 -0
  64. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/fix/differ.py +0 -0
  65. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/fix/engine.py +0 -0
  66. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/fix/prompts.py +0 -0
  67. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/github/__init__.py +0 -0
  68. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/github/commenter.py +0 -0
  69. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/github/models.py +0 -0
  70. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/github/sanitizer.py +0 -0
  71. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/installer/__init__.py +0 -0
  72. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/installer/errors.py +0 -0
  73. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/installer/extract.py +0 -0
  74. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/installer/manager.py +0 -0
  75. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/installer/manifest.py +0 -0
  76. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/installer/verify.py +0 -0
  77. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/manifest.py +0 -0
  78. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/paths.py +0 -0
  79. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/policy.py +0 -0
  80. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/report/__init__.py +0 -0
  81. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/report/compliance_matrix.py +0 -0
  82. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/report/generator.py +0 -0
  83. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/report/html.py +0 -0
  84. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/report/pdf.py +0 -0
  85. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/runner.py +0 -0
  86. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/__init__.py +0 -0
  87. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/backends/__init__.py +0 -0
  88. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/backends/base.py +0 -0
  89. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/backends/docker.py +0 -0
  90. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/backends/native.py +0 -0
  91. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/base.py +0 -0
  92. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/container.py +0 -0
  93. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/falco.py +0 -0
  94. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/gitleaks.py +0 -0
  95. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/semgrep.py +0 -0
  96. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/trivy.py +0 -0
  97. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/url_policy.py +0 -0
  98. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/scanners/zap.py +0 -0
  99. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/__init__.py +0 -0
  100. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/artifacts.py +0 -0
  101. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/chunking.py +0 -0
  102. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/core.py +0 -0
  103. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/mermaid.py +0 -0
  104. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/model_adapter.py +0 -0
  105. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/prompts.py +0 -0
  106. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/redaction.py +0 -0
  107. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/threatflow/sanitizer.py +0 -0
  108. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/triage/app.py +0 -0
  109. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/triage/audit.py +0 -0
  110. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/triage/ignore.py +0 -0
  111. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/triage/models.py +0 -0
  112. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/triage/screens.py +0 -0
  113. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai/triage/widgets.py +0 -0
  114. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_cli.egg-info/dependency_links.txt +0 -0
  115. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_cli.egg-info/requires.txt +0 -0
  116. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/__init__.py +0 -0
  117. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/ci/__init__.py +0 -0
  118. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/ci/benchmarks.py +0 -0
  119. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/ci/metadata.py +0 -0
  120. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/ci/validators.py +0 -0
  121. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/docker/__init__.py +0 -0
  122. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/docker/metadata.py +0 -0
  123. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/docker/sbom.py +0 -0
  124. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/docker/security.py +0 -0
  125. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/docker/signing.py +0 -0
  126. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/redaction.py +0 -0
  127. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/slsa/__init__.py +0 -0
  128. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/slsa/verify.py +0 -0
  129. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/windows/__init__.py +0 -0
  130. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/windows/chocolatey.py +0 -0
  131. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/windows/installer.py +0 -0
  132. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/windows/scoop.py +0 -0
  133. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/src/kekkai_core/windows/validators.py +0 -0
  134. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_cli_output.py +0 -0
  135. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_compliance.py +0 -0
  136. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_fix_engine.py +0 -0
  137. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_github_commenter_filter.py +0 -0
  138. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_github_commenter_format.py +0 -0
  139. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_github_commenter_limit.py +0 -0
  140. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_github_commenter_sanitize.py +0 -0
  141. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_installer_checksum.py +0 -0
  142. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_installer_extract.py +0 -0
  143. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_installer_manager.py +0 -0
  144. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_installer_manifest.py +0 -0
  145. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_installer_platform.py +0 -0
  146. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_kekkai_cli.py +0 -0
  147. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_kekkai_config.py +0 -0
  148. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_kekkai_dojo.py +0 -0
  149. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_kekkai_dojo_cli.py +0 -0
  150. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_kekkai_manifest.py +0 -0
  151. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_kekkai_paths.py +0 -0
  152. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_kekkai_runner.py +0 -0
  153. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_mermaid.py +0 -0
  154. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_policy.py +0 -0
  155. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_redaction.py +0 -0
  156. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_report.py +0 -0
  157. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_backends.py +0 -0
  158. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_base.py +0 -0
  159. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_container.py +0 -0
  160. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_digest_defaults.py +0 -0
  161. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_falco.py +0 -0
  162. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_gitleaks.py +0 -0
  163. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_native.py +0 -0
  164. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_semgrep.py +0 -0
  165. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_trivy.py +0 -0
  166. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_scanner_zap.py +0 -0
  167. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_slsa_provenance.py +0 -0
  168. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_threatflow_chunking.py +0 -0
  169. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_threatflow_model_adapter.py +0 -0
  170. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_threatflow_prompts.py +0 -0
  171. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_threatflow_redaction.py +0 -0
  172. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_threatflow_sanitizer.py +0 -0
  173. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_triage_audit.py +0 -0
  174. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_triage_ignore.py +0 -0
  175. {kekkai_cli-1.1.0 → kekkai_cli-1.1.1}/tests/test_triage_models.py +0 -0
  176. {kekkai_cli-1.1.0 → kekkai_cli-1.1.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: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Kekkai monorepo (local-first AppSec orchestration + compliance checker)
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -28,7 +28,7 @@ Requires-Dist: httpx>=0.24.0
28
28
 
29
29
  Stop juggling security tools. **Kekkai orchestrates your entire AppSec lifecycle** — from AI-powered threat modeling to vulnerability management — in a single CLI.
30
30
 
31
- ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-demo.gif)
31
+ ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-start.gif)
32
32
 
33
33
  ---
34
34
 
@@ -104,6 +104,8 @@ kekkai upload
104
104
 
105
105
  Generate STRIDE-aligned threat models and Mermaid.js Data Flow Diagrams from your codebase.
106
106
 
107
+ ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-threatflow.gif)
108
+
107
109
  ```bash
108
110
  # Ollama (recommended - easy setup, privacy-preserving)
109
111
  ollama pull mistral
@@ -177,6 +179,10 @@ kekkai triage
177
179
 
178
180
  Automate security enforcement in your pipelines.
179
181
 
182
+ <p align="center">
183
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-scan.png" alt="Kekkai Scanning" width="650"/>
184
+ </p>
185
+
180
186
  ```bash
181
187
  # Fail on any critical or high findings
182
188
  kekkai scan --ci --fail-on high
@@ -212,6 +218,10 @@ kekkai scan --ci --fail-on medium --max-findings 5
212
218
 
213
219
  Spin up a complete vulnerability management platform locally.
214
220
 
221
+ <p align="center">
222
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-dojo.png" alt="Kekkai Dojo" width="650"/>
223
+ </p>
224
+
215
225
  ```bash
216
226
  kekkai dojo up --wait # Start DefectDojo (Nginx, Postgres, Redis, Celery)
217
227
  kekkai dojo status # Check service health
@@ -225,6 +235,14 @@ kekkai dojo down # Stop and clean up (removes volumes)
225
235
  - Pre-configured for Kekkai imports
226
236
  - Clean teardown (no orphaned volumes)
227
237
 
238
+ <p align="center">
239
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/Active-Engagements-kekkai-dojo.png" alt="Kekkai Dojo" width="850"/>
240
+ </p>
241
+
242
+ <p align="center">
243
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-dojo-dashboard-findings.png" alt="Kekkai Dojo" width="850"/>
244
+ </p
245
+
228
246
  [Full Dojo Documentation →](docs/dojo/dojo.md)
229
247
 
230
248
  ---
@@ -283,24 +301,26 @@ pip install kekkai-cli
283
301
 
284
302
  ---
285
303
 
286
- ## Enterprise Features — Kekkai Portal
304
+ ## Enterprise Features
287
305
 
288
- For teams that need centralized management, **Kekkai Portal** provides:
306
+ For organizations that need advanced capabilities, **Kekkai Enterprise** provides:
289
307
 
290
308
  | Feature | Description |
291
309
  |---------|-------------|
292
- | **SAML 2.0 SSO** | Integrate with Okta, Azure AD, Google Workspace ([Setup Guide](docs/portal/saml-setup.md)) |
293
- | **Role-Based Access Control** | Fine-grained permissions per team/project ([RBAC Guide](docs/portal/rbac.md)) |
294
- | **Multi-Tenant Architecture** | Isolated environments per organization ([Architecture](docs/portal/multi-tenant.md)) |
295
- | **Aggregated Dashboards** | Centralized view of all CLI scan results |
310
+ | **Multi-Tenant Portal** | Web dashboard for managing multiple teams/projects ([Learn More](docs/portal/README.md)) |
311
+ | **SAML 2.0 SSO** | Integrate with Okta, Azure AD, Google Workspace |
312
+ | **Role-Based Access Control** | Fine-grained permissions per team/project |
313
+ | **Advanced Operations** | Automated backup/restore, monitoring, zero-downtime upgrades ([Learn More](docs/ops/README.md)) |
314
+ | **Compliance Reporting** | Map findings to OWASP, PCI-DSS, HIPAA, SOC 2 |
296
315
  | **Audit Logging** | Cryptographically signed compliance trails |
297
316
 
298
- **Upgrade Path:**
299
- - CLI users can sync results to Portal: `kekkai upload` ([Sync Guide](docs/portal/cli-sync.md))
300
- - Portal provides dashboards for security managers
301
- - Self-hosted or Kademos-managed options ([Deployment Guide](docs/portal/deployment.md))
317
+ **Architecture:**
318
+ - Open-source CLI remains fully functional standalone
319
+ - Enterprise features available in separate private repository for licensed customers
320
+ - Optional integration: CLI can sync results to enterprise portal
321
+ - Self-hosted or Kademos-managed deployment options
302
322
 
303
- [Contact us for Portal access →](mailto:sales@kademos.org)
323
+ [Contact us for enterprise access →](mailto:sales@kademos.org)
304
324
 
305
325
  ---
306
326
 
@@ -17,7 +17,7 @@
17
17
 
18
18
  Stop juggling security tools. **Kekkai orchestrates your entire AppSec lifecycle** — from AI-powered threat modeling to vulnerability management — in a single CLI.
19
19
 
20
- ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-demo.gif)
20
+ ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-start.gif)
21
21
 
22
22
  ---
23
23
 
@@ -93,6 +93,8 @@ kekkai upload
93
93
 
94
94
  Generate STRIDE-aligned threat models and Mermaid.js Data Flow Diagrams from your codebase.
95
95
 
96
+ ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-threatflow.gif)
97
+
96
98
  ```bash
97
99
  # Ollama (recommended - easy setup, privacy-preserving)
98
100
  ollama pull mistral
@@ -166,6 +168,10 @@ kekkai triage
166
168
 
167
169
  Automate security enforcement in your pipelines.
168
170
 
171
+ <p align="center">
172
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-scan.png" alt="Kekkai Scanning" width="650"/>
173
+ </p>
174
+
169
175
  ```bash
170
176
  # Fail on any critical or high findings
171
177
  kekkai scan --ci --fail-on high
@@ -201,6 +207,10 @@ kekkai scan --ci --fail-on medium --max-findings 5
201
207
 
202
208
  Spin up a complete vulnerability management platform locally.
203
209
 
210
+ <p align="center">
211
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-dojo.png" alt="Kekkai Dojo" width="650"/>
212
+ </p>
213
+
204
214
  ```bash
205
215
  kekkai dojo up --wait # Start DefectDojo (Nginx, Postgres, Redis, Celery)
206
216
  kekkai dojo status # Check service health
@@ -214,6 +224,14 @@ kekkai dojo down # Stop and clean up (removes volumes)
214
224
  - Pre-configured for Kekkai imports
215
225
  - Clean teardown (no orphaned volumes)
216
226
 
227
+ <p align="center">
228
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/Active-Engagements-kekkai-dojo.png" alt="Kekkai Dojo" width="850"/>
229
+ </p>
230
+
231
+ <p align="center">
232
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-dojo-dashboard-findings.png" alt="Kekkai Dojo" width="850"/>
233
+ </p
234
+
217
235
  [Full Dojo Documentation →](docs/dojo/dojo.md)
218
236
 
219
237
  ---
@@ -272,24 +290,26 @@ pip install kekkai-cli
272
290
 
273
291
  ---
274
292
 
275
- ## Enterprise Features — Kekkai Portal
293
+ ## Enterprise Features
276
294
 
277
- For teams that need centralized management, **Kekkai Portal** provides:
295
+ For organizations that need advanced capabilities, **Kekkai Enterprise** provides:
278
296
 
279
297
  | Feature | Description |
280
298
  |---------|-------------|
281
- | **SAML 2.0 SSO** | Integrate with Okta, Azure AD, Google Workspace ([Setup Guide](docs/portal/saml-setup.md)) |
282
- | **Role-Based Access Control** | Fine-grained permissions per team/project ([RBAC Guide](docs/portal/rbac.md)) |
283
- | **Multi-Tenant Architecture** | Isolated environments per organization ([Architecture](docs/portal/multi-tenant.md)) |
284
- | **Aggregated Dashboards** | Centralized view of all CLI scan results |
299
+ | **Multi-Tenant Portal** | Web dashboard for managing multiple teams/projects ([Learn More](docs/portal/README.md)) |
300
+ | **SAML 2.0 SSO** | Integrate with Okta, Azure AD, Google Workspace |
301
+ | **Role-Based Access Control** | Fine-grained permissions per team/project |
302
+ | **Advanced Operations** | Automated backup/restore, monitoring, zero-downtime upgrades ([Learn More](docs/ops/README.md)) |
303
+ | **Compliance Reporting** | Map findings to OWASP, PCI-DSS, HIPAA, SOC 2 |
285
304
  | **Audit Logging** | Cryptographically signed compliance trails |
286
305
 
287
- **Upgrade Path:**
288
- - CLI users can sync results to Portal: `kekkai upload` ([Sync Guide](docs/portal/cli-sync.md))
289
- - Portal provides dashboards for security managers
290
- - Self-hosted or Kademos-managed options ([Deployment Guide](docs/portal/deployment.md))
306
+ **Architecture:**
307
+ - Open-source CLI remains fully functional standalone
308
+ - Enterprise features available in separate private repository for licensed customers
309
+ - Optional integration: CLI can sync results to enterprise portal
310
+ - Self-hosted or Kademos-managed deployment options
291
311
 
292
- [Contact us for Portal access →](mailto:sales@kademos.org)
312
+ [Contact us for enterprise access →](mailto:sales@kademos.org)
293
313
 
294
314
  ---
295
315
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kekkai-cli"
3
- version = "1.1.0"
3
+ version = "1.1.1"
4
4
  description = "Kekkai monorepo (local-first AppSec orchestration + compliance checker)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -13,7 +13,6 @@ dependencies = [
13
13
 
14
14
  [project.scripts]
15
15
  kekkai = "kekkai.cli:main"
16
- kekkai-portal = "portal.web:main"
17
16
 
18
17
  [tool.ruff]
19
18
  target-version = "py312"
@@ -56,7 +55,7 @@ source = ["src"]
56
55
  [tool.coverage.report]
57
56
  show_missing = true
58
57
  skip_covered = false
59
- fail_under = 69
58
+ fail_under = 68
60
59
  exclude_lines = [
61
60
  "pragma: no cover",
62
61
  "if TYPE_CHECKING:",
@@ -604,6 +604,36 @@ def _command_scan(
604
604
  )
605
605
  manifest.write_manifest(run_dir / "run.json", run_manifest)
606
606
 
607
+ # Generate unified report (aggregates all scanner findings)
608
+ if scan_results:
609
+ from .report.unified import UnifiedReportError, generate_unified_report
610
+
611
+ # Determine output path for unified report
612
+ if output_path:
613
+ # --output flag provided: use it for unified report
614
+ unified_report_path = Path(output_path).expanduser().resolve()
615
+ # Security: Validate path (ASVS V5.3.3)
616
+ if not is_within_base(base_dir, unified_report_path):
617
+ # Allow explicit paths outside base_dir, but warn
618
+ console.print(
619
+ f"[warning]Writing outside kekkai home: {unified_report_path}[/warning]"
620
+ )
621
+ else:
622
+ # Default: save in run directory
623
+ unified_report_path = run_dir / "kekkai-report.json"
624
+
625
+ try:
626
+ generate_unified_report(
627
+ scan_results=scan_results,
628
+ output_path=unified_report_path,
629
+ run_id=run_id,
630
+ commit_sha=commit_sha,
631
+ )
632
+ console.print(f"[success]Unified report:[/success] {unified_report_path}")
633
+ except UnifiedReportError as e:
634
+ err_msg = sanitize_error(str(e))
635
+ console.print(f"[warning]Failed to generate unified report: {err_msg}[/warning]")
636
+
607
637
  # Collect all findings for policy evaluation
608
638
  all_findings: list[Finding] = []
609
639
  scan_errors: list[str] = []
@@ -822,6 +852,26 @@ def _resolve_github_repo(override: str | None) -> tuple[str | None, str | None]:
822
852
  return None, None
823
853
 
824
854
 
855
+ def _normalize_scanner_name(stem: str) -> str:
856
+ """Normalize filename stem to scanner name.
857
+
858
+ Strips the "-results" suffix from scanner output filenames.
859
+
860
+ Examples:
861
+ gitleaks-results -> gitleaks
862
+ trivy-results -> trivy
863
+ semgrep-results -> semgrep
864
+ custom-scanner -> custom-scanner
865
+
866
+ Args:
867
+ stem: File stem (name without extension).
868
+
869
+ Returns:
870
+ Normalized scanner name.
871
+ """
872
+ return stem.removesuffix("-results")
873
+
874
+
825
875
  def _create_scanner(
826
876
  name: str,
827
877
  zap_target_url: str | None = None,
@@ -1106,22 +1156,57 @@ def _threatflow_banner() -> str:
1106
1156
  def _command_triage(parsed: argparse.Namespace) -> int:
1107
1157
  """Run interactive triage TUI."""
1108
1158
  from .triage import run_triage
1159
+ from .triage.loader import load_findings_from_path
1109
1160
 
1110
1161
  input_path_str = cast(str | None, getattr(parsed, "input", None))
1111
1162
  output_path_str = cast(str | None, getattr(parsed, "output", None))
1112
1163
 
1113
- input_path = Path(input_path_str).expanduser().resolve() if input_path_str else None
1114
- output_path = Path(output_path_str).expanduser().resolve() if output_path_str else None
1164
+ # Default to latest run if no input specified
1165
+ if not input_path_str:
1166
+ runs_dir = app_base_dir() / "runs"
1167
+ if runs_dir.exists():
1168
+ run_dirs = sorted(
1169
+ [d for d in runs_dir.iterdir() if d.is_dir()],
1170
+ key=lambda d: d.stat().st_mtime,
1171
+ )
1172
+ if run_dirs:
1173
+ input_path = run_dirs[-1]
1174
+ console.print(f"[info]Using latest run: {input_path.name}[/info]\n")
1175
+ else:
1176
+ console.print("[danger]No scan runs found. Run 'kekkai scan' first.[/danger]")
1177
+ return 1
1178
+ else:
1179
+ console.print("[danger]No scan runs found. Run 'kekkai scan' first.[/danger]")
1180
+ return 1
1181
+ else:
1182
+ input_path = Path(input_path_str).expanduser().resolve()
1115
1183
 
1116
- if input_path and not input_path.exists():
1117
- console.print(f"[danger]Error:[/danger] Input file not found: {input_path}")
1184
+ if not input_path.exists():
1185
+ console.print(f"[danger]Error:[/danger] Input not found: {input_path}")
1118
1186
  return 1
1119
1187
 
1188
+ output_path = Path(output_path_str).expanduser().resolve() if output_path_str else None
1189
+
1120
1190
  console.print("[bold cyan]Kekkai Triage[/bold cyan] - Interactive Finding Review")
1121
1191
  console.print("Use j/k to navigate, f=false positive, c=confirmed, d=deferred")
1122
1192
  console.print("Press Ctrl+S to save, q to quit\n")
1123
1193
 
1124
- return run_triage(input_path=input_path, output_path=output_path)
1194
+ # Use new loader that supports raw scanner outputs
1195
+ findings, errors = load_findings_from_path(input_path)
1196
+
1197
+ if errors:
1198
+ console.print("[warning]Warnings:[/warning]")
1199
+ for err in errors[:5]: # Limit to first 5
1200
+ console.print(f" - {err}")
1201
+ console.print()
1202
+
1203
+ if not findings:
1204
+ console.print("[warning]No findings to triage.[/warning]")
1205
+ return 0
1206
+
1207
+ console.print(f"[info]Loaded {len(findings)} finding(s)[/info]\n")
1208
+
1209
+ return run_triage(findings=findings, output_path=output_path)
1125
1210
 
1126
1211
 
1127
1212
  def _command_fix(parsed: argparse.Namespace) -> int:
@@ -1414,9 +1499,13 @@ def _command_upload(parsed: argparse.Namespace) -> int:
1414
1499
  console.print(f"Product: {product_name}")
1415
1500
  console.print(f"Engagement: {engagement_name}")
1416
1501
 
1417
- # Find and load scan results
1418
- scan_files = list(run_dir.glob("*.json"))
1419
- scan_files = [f for f in scan_files if f.name not in ("run.json", "policy-result.json")]
1502
+ # Find and load scan results - prefer *-results.json first
1503
+ scan_files = sorted(run_dir.glob("*-results.json"))
1504
+ if not scan_files:
1505
+ # Fallback to all JSON (excluding metadata files)
1506
+ scan_files = sorted(
1507
+ [f for f in run_dir.glob("*.json") if f.name not in ("run.json", "policy-result.json")]
1508
+ )
1420
1509
 
1421
1510
  if not scan_files:
1422
1511
  console.print(f"[danger]Error:[/danger] No scan results found in {run_dir}")
@@ -1429,35 +1518,39 @@ def _command_upload(parsed: argparse.Namespace) -> int:
1429
1518
  scanners_map: dict[str, Scanner] = {}
1430
1519
 
1431
1520
  for scan_file in scan_files:
1432
- scanner_name = scan_file.stem # e.g., "trivy", "semgrep", "gitleaks"
1521
+ # Normalize scanner name: "gitleaks-results" -> "gitleaks"
1522
+ scanner_name = _normalize_scanner_name(scan_file.stem)
1433
1523
  console.print(f" Loading {scanner_name}...")
1434
1524
 
1525
+ # Load raw JSON
1435
1526
  try:
1436
- with scan_file.open() as f:
1437
- data = _json.load(f)
1438
- except _json.JSONDecodeError as e:
1527
+ raw_text = scan_file.read_text(encoding="utf-8")
1528
+ _json.loads(raw_text) # Validate JSON syntax
1529
+ except (OSError, _json.JSONDecodeError) as e:
1439
1530
  console.print(f" [warning]Skipped (invalid JSON): {e}[/warning]")
1440
1531
  continue
1441
1532
 
1442
- # Parse findings based on format
1443
- findings = _parse_findings_from_json(data)
1444
-
1445
- if findings:
1446
- scan_results.append(
1447
- ScanResult(
1448
- scanner=scanner_name,
1449
- success=True,
1450
- findings=findings,
1451
- raw_output_path=scan_file,
1452
- duration_ms=0,
1453
- )
1533
+ # Create scanner and use canonical parser
1534
+ scanner = _create_scanner(scanner_name)
1535
+ if not scanner:
1536
+ console.print(" [warning]Skipped (unknown scanner)[/warning]")
1537
+ continue
1538
+
1539
+ # Use canonical scanner parser (reuses validated logic)
1540
+ findings = scanner.parse(raw_text)
1541
+
1542
+ scan_results.append(
1543
+ ScanResult(
1544
+ scanner=scanner.name, # Use canonical scanner name
1545
+ success=True,
1546
+ findings=findings,
1547
+ raw_output_path=scan_file,
1548
+ duration_ms=0,
1454
1549
  )
1455
- # Create scanner instance for import
1456
- scanner = _create_scanner(scanner_name)
1457
- if scanner:
1458
- scanners_map[scanner_name] = scanner
1550
+ )
1551
+ scanners_map[scanner.name] = scanner
1459
1552
 
1460
- console.print(f" {len(findings)} findings")
1553
+ console.print(f" {len(findings)} finding(s)")
1461
1554
 
1462
1555
  if not scan_results:
1463
1556
  console.print("[danger]Error:[/danger] No valid scan results to upload")
@@ -1493,11 +1586,9 @@ def _command_upload(parsed: argparse.Namespace) -> int:
1493
1586
  )
1494
1587
 
1495
1588
  success_count = 0
1496
- scanner_names_list = list(scanners_map.keys())
1497
1589
  for idx, ir in enumerate(import_results):
1498
- scanner_label = (
1499
- scanner_names_list[idx] if idx < len(scanner_names_list) else f"scanner-{idx}"
1500
- )
1590
+ # Label based on actual scan_results order (not scanners_map keys)
1591
+ scanner_label = scan_results[idx].scanner if idx < len(scan_results) else f"scanner-{idx}"
1501
1592
  if ir.success:
1502
1593
  success_count += 1
1503
1594
  console.print(
@@ -61,7 +61,15 @@ class DojoClient:
61
61
 
62
62
  try:
63
63
  with urlopen(req, timeout=self._timeout) as resp: # noqa: S310 # nosec B310
64
- return json.loads(resp.read().decode()) if resp.read else {}
64
+ raw_bytes = resp.read() # Call once and store result
65
+ if not raw_bytes: # Check bytes, not method
66
+ return {}
67
+ try:
68
+ result: dict[str, Any] = json.loads(raw_bytes.decode())
69
+ return result
70
+ except json.JSONDecodeError:
71
+ # Empty or invalid JSON response - return empty dict
72
+ return {}
65
73
  except HTTPError as exc:
66
74
  error_body = exc.read().decode() if exc.fp else str(exc)
67
75
  raise RuntimeError(f"Dojo API error {exc.code}: {error_body}") from exc
@@ -57,7 +57,7 @@ BANNER_ASCII = r"""
57
57
  /_/\_\\___/_/\_/_/\_\\_,_/_/
58
58
  """
59
59
 
60
- VERSION = "1.1.0"
60
+ VERSION = "1.1.1"
61
61
 
62
62
 
63
63
  def print_dashboard() -> None: