kekkai-cli 1.0.0__py3-none-any.whl

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 (90) hide show
  1. kekkai/__init__.py +7 -0
  2. kekkai/cli.py +1038 -0
  3. kekkai/config.py +403 -0
  4. kekkai/dojo.py +419 -0
  5. kekkai/dojo_import.py +213 -0
  6. kekkai/github/__init__.py +16 -0
  7. kekkai/github/commenter.py +198 -0
  8. kekkai/github/models.py +56 -0
  9. kekkai/github/sanitizer.py +112 -0
  10. kekkai/installer/__init__.py +39 -0
  11. kekkai/installer/errors.py +23 -0
  12. kekkai/installer/extract.py +161 -0
  13. kekkai/installer/manager.py +252 -0
  14. kekkai/installer/manifest.py +189 -0
  15. kekkai/installer/verify.py +86 -0
  16. kekkai/manifest.py +77 -0
  17. kekkai/output.py +218 -0
  18. kekkai/paths.py +46 -0
  19. kekkai/policy.py +326 -0
  20. kekkai/runner.py +70 -0
  21. kekkai/scanners/__init__.py +67 -0
  22. kekkai/scanners/backends/__init__.py +14 -0
  23. kekkai/scanners/backends/base.py +73 -0
  24. kekkai/scanners/backends/docker.py +178 -0
  25. kekkai/scanners/backends/native.py +240 -0
  26. kekkai/scanners/base.py +110 -0
  27. kekkai/scanners/container.py +144 -0
  28. kekkai/scanners/falco.py +237 -0
  29. kekkai/scanners/gitleaks.py +237 -0
  30. kekkai/scanners/semgrep.py +227 -0
  31. kekkai/scanners/trivy.py +246 -0
  32. kekkai/scanners/url_policy.py +163 -0
  33. kekkai/scanners/zap.py +340 -0
  34. kekkai/threatflow/__init__.py +94 -0
  35. kekkai/threatflow/artifacts.py +476 -0
  36. kekkai/threatflow/chunking.py +361 -0
  37. kekkai/threatflow/core.py +438 -0
  38. kekkai/threatflow/mermaid.py +374 -0
  39. kekkai/threatflow/model_adapter.py +491 -0
  40. kekkai/threatflow/prompts.py +277 -0
  41. kekkai/threatflow/redaction.py +228 -0
  42. kekkai/threatflow/sanitizer.py +643 -0
  43. kekkai/triage/__init__.py +33 -0
  44. kekkai/triage/app.py +168 -0
  45. kekkai/triage/audit.py +203 -0
  46. kekkai/triage/ignore.py +269 -0
  47. kekkai/triage/models.py +185 -0
  48. kekkai/triage/screens.py +341 -0
  49. kekkai/triage/widgets.py +169 -0
  50. kekkai_cli-1.0.0.dist-info/METADATA +135 -0
  51. kekkai_cli-1.0.0.dist-info/RECORD +90 -0
  52. kekkai_cli-1.0.0.dist-info/WHEEL +5 -0
  53. kekkai_cli-1.0.0.dist-info/entry_points.txt +3 -0
  54. kekkai_cli-1.0.0.dist-info/top_level.txt +3 -0
  55. kekkai_core/__init__.py +3 -0
  56. kekkai_core/ci/__init__.py +11 -0
  57. kekkai_core/ci/benchmarks.py +354 -0
  58. kekkai_core/ci/metadata.py +104 -0
  59. kekkai_core/ci/validators.py +92 -0
  60. kekkai_core/docker/__init__.py +17 -0
  61. kekkai_core/docker/metadata.py +153 -0
  62. kekkai_core/docker/sbom.py +173 -0
  63. kekkai_core/docker/security.py +158 -0
  64. kekkai_core/docker/signing.py +135 -0
  65. kekkai_core/redaction.py +84 -0
  66. kekkai_core/slsa/__init__.py +13 -0
  67. kekkai_core/slsa/verify.py +121 -0
  68. kekkai_core/windows/__init__.py +29 -0
  69. kekkai_core/windows/chocolatey.py +335 -0
  70. kekkai_core/windows/installer.py +256 -0
  71. kekkai_core/windows/scoop.py +165 -0
  72. kekkai_core/windows/validators.py +220 -0
  73. portal/__init__.py +19 -0
  74. portal/api.py +155 -0
  75. portal/auth.py +103 -0
  76. portal/enterprise/__init__.py +32 -0
  77. portal/enterprise/audit.py +435 -0
  78. portal/enterprise/licensing.py +342 -0
  79. portal/enterprise/rbac.py +276 -0
  80. portal/enterprise/saml.py +595 -0
  81. portal/ops/__init__.py +53 -0
  82. portal/ops/backup.py +553 -0
  83. portal/ops/log_shipper.py +469 -0
  84. portal/ops/monitoring.py +517 -0
  85. portal/ops/restore.py +469 -0
  86. portal/ops/secrets.py +408 -0
  87. portal/ops/upgrade.py +591 -0
  88. portal/tenants.py +340 -0
  89. portal/uploads.py +259 -0
  90. portal/web.py +384 -0
@@ -0,0 +1,135 @@
1
+ Metadata-Version: 2.4
2
+ Name: kekkai-cli
3
+ Version: 1.0.0
4
+ Summary: Kekkai/Regulon monorepo (local-first AppSec orchestration + compliance checker)
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: rich>=13.0.0
8
+ Requires-Dist: jsonschema>=4.20.0
9
+ Requires-Dist: textual>=0.50.0
10
+ Requires-Dist: httpx>=0.24.0
11
+
12
+ <p align="center">
13
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/logos/kekkai-slim.png" alt="Kekkai CLI Logo" width="250"/>
14
+ </p>
15
+ <p align="center"><i>One command. Clean AppSec reports.</i></p>
16
+ <p align="center">
17
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg"/>
18
+ <img src="https://img.shields.io/badge/status-active-brightgreen"/>
19
+ </p>
20
+
21
+ # Kekkai 🛡️
22
+
23
+ **Security that moves at developer speed.**
24
+ *Local-first orchestration for Trivy, Semgrep, and DefectDojo.*
25
+
26
+ ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-recording.gif)
27
+
28
+ ---
29
+
30
+ ## ⚡ Quick Start
31
+
32
+ Stop fighting with Docker Compose. Start scanning in 30 seconds.
33
+
34
+ ### Installation
35
+
36
+ **Option 1: pipx (Recommended - Isolated Environment)**
37
+
38
+ ```bash
39
+ pipx install kekkai-cli
40
+ ```
41
+
42
+ **Option 2: Homebrew (macOS/Linux)**
43
+
44
+ ```bash
45
+ brew tap kademoslabs/tap
46
+ brew install kekkai
47
+ ```
48
+
49
+ **Option 3: Docker (No Python Required)**
50
+
51
+ ```bash
52
+ # Build image
53
+ docker build -t kademoslabs/kekkai:latest -f apps/kekkai/Dockerfile .
54
+
55
+ # Run via wrapper script
56
+ ./scripts/kekkai-docker --help
57
+
58
+ # Or set up alias
59
+ alias kekkai="$(pwd)/scripts/kekkai-docker"
60
+ ```
61
+
62
+ **Option 4: Scoop (Windows)**
63
+
64
+ ```powershell
65
+ scoop bucket add kademoslabs https://github.com/kademoslabs/scoop-bucket
66
+ scoop install kekkai
67
+ ```
68
+
69
+ **Option 5: pip (Traditional)**
70
+
71
+ ```bash
72
+ pip install kekkai-cli
73
+ ```
74
+
75
+
76
+
77
+ ### 1. Scan your project (Local)
78
+
79
+ Run industry-standard scanners (Trivy, Semgrep, Gitleaks) in unified Docker containers without installing them individually.
80
+
81
+ ```bash
82
+ cd your-repo
83
+ kekkai scan
84
+
85
+ ```
86
+
87
+ ### 2. Spin up DefectDojo
88
+
89
+ Launch a full local vulnerability management platform (Nginx, Postgres, Redis, Celery) with one command.
90
+
91
+ ```bash
92
+ kekkai dojo up --wait --open
93
+
94
+ ```
95
+
96
+ ### 3. Generate a Threat Model (AI)
97
+
98
+ Generate a STRIDE threat model and Data Flow Diagram using your local LLM.
99
+
100
+ ```bash
101
+ kekkai threatflow --repo . --model-mode local
102
+
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 🛑 The Problem vs. Kekkai
108
+
109
+ | Feature | The Old Way | The Kekkai Way |
110
+ | --- | --- | --- |
111
+ | **Tooling** | Manually install/update 5+ tools (Trivy, Semgrep, etc.) | **One Binary.** `kekkai scan` auto-pulls and runs the latest scanner containers. |
112
+ | **Reporting** | Parse 5 different JSON formats manually. | **Unified Output.** One deduplicated `kekkai-report.json` for all findings. |
113
+ | **DefectDojo** | Write a 200-line `docker-compose.yml` and debug networking. | **One Command.** `kekkai dojo up` automates the entire stack setup. |
114
+ | **Threat Modeling** | Expensive consultants or manual whiteboarding. | **AI Agent.** `kekkai threatflow` generates `THREATS.md` locally. |
115
+ | **CI/CD** | Write complex bash scripts to break builds. | **Policy Engine.** `kekkai scan --ci --fail-on high`. |
116
+
117
+ ---
118
+
119
+ ## 🔒 Enterprise Features (Portal)
120
+
121
+ For teams that need centralized management, **Kekkai Portal** offers:
122
+
123
+ * **SAML 2.0 SSO** with Replay Protection
124
+ * **Role-Based Access Control (RBAC)**
125
+ * **Cryptographically Signed Audit Logs**
126
+
127
+ *Built by Kademos Labs.*
128
+
129
+ ---
130
+
131
+ ## 📚 Documentation
132
+
133
+ - **[Automated Distribution Updates](docs/ci/automated-distributions.md)** - CI/CD distribution triggers
134
+ - **[CI Architecture](/.docs/development/ci-architecture.md)** - Developer guide for distribution automation
135
+ - **[Homebrew Maintenance](docs/ci/homebrew-maintenance.md)** - Homebrew tap management
@@ -0,0 +1,90 @@
1
+ kekkai/__init__.py,sha256=_VrBvJRyqHiXs31S8HOhATk_O2iy-ac0_9X7rHH75j8,143
2
+ kekkai/cli.py,sha256=u-5GHXUT9G8Np-5SOLbSTtebQDv8yFYYCFZAjiDAAWU,35903
3
+ kekkai/config.py,sha256=LE7bKsmv5dim5KnZya0V7_LtviNQ1V0pMN_6FyAsMpc,13084
4
+ kekkai/dojo.py,sha256=DchLaTnDBwX0D14lTRdCtwql_II8aDEZ0JEq9F-n4MI,15887
5
+ kekkai/dojo_import.py,sha256=oI-vwpLITA7-U2_MxhaTp_PYfr5HqvcFy3VzKsWA6IY,6911
6
+ kekkai/manifest.py,sha256=Ph5xGDKuVxMW1GVIisRhxUelaiVZQe-W5sZWsq4lHqs,1887
7
+ kekkai/output.py,sha256=oEt-T49wXUvmhyAwnsdxPGrw3Ql5jUWApdXpzhlKRN8,6008
8
+ kekkai/paths.py,sha256=EcyG3CEOQFQygowu7O5Mp85dKkXWWvnm1h0j_BetGxY,1190
9
+ kekkai/policy.py,sha256=0XCUH-SbnO1PsM-exjSFHYHRnLkiNa50QfkyPakwNko,9792
10
+ kekkai/runner.py,sha256=MBFUiJ4sSVEGNbJ6cv-8p1WHaHqjio6yWEfr_K4GuTs,2037
11
+ kekkai/github/__init__.py,sha256=3EQ7LkRqgQwr5uTt7hNvVXLiKTpzE47woc8lZQjy5cE,386
12
+ kekkai/github/commenter.py,sha256=v19pEctYJvUvA7e-t6eOA5dZaNIt16ocCxC92IUxQeM,5906
13
+ kekkai/github/models.py,sha256=baW5prDEVncKrfC8aLoKjaTpPKYtRzZOBOg4Zje3qug,1340
14
+ kekkai/github/sanitizer.py,sha256=GWvVRHH_EGdhnHZi4rLWQDWTOrxw_U74Fi9fT5qUfBs,3239
15
+ kekkai/installer/__init__.py,sha256=pgUELK_2JzSGtzQuRzclF7M5FK9EulKmgFH5Xr8kxZI,858
16
+ kekkai/installer/errors.py,sha256=4SsTmcjIiQUmXDZVfeS2H2GCtpcMqEskN-9EyzFbBJc,561
17
+ kekkai/installer/extract.py,sha256=r4wYGCZ7zV2lIki5kns7t9bFRV1fahqOral8Jl7LZcQ,5232
18
+ kekkai/installer/manager.py,sha256=FqHTmHvTc2YkWWISvdS1uW7IZV6bHqyEg33TDb4Ldtc,7881
19
+ kekkai/installer/manifest.py,sha256=oZFquI9pUtgtB4ZXontQND5D7m4WzjjJuybhlePk3k4,5544
20
+ kekkai/installer/verify.py,sha256=ThtWfKnjrdx90_XBJclBGiw4yzTFs5HKoFJ0IyVPsMM,2186
21
+ kekkai/scanners/__init__.py,sha256=uKJqnBgcf47eJlDB3mvHpLsobR6M6N6uO2L0Dor1MaE,1552
22
+ kekkai/scanners/base.py,sha256=uy7HgOaQxNcp6-X1gfXAecSYpKXaEsuVeluf6SwkbwM,2678
23
+ kekkai/scanners/container.py,sha256=OhD0Meld_Zm4YcTuON91kx08Cj5h4R1FR0ABGbx7kQI,4197
24
+ kekkai/scanners/falco.py,sha256=Y0kjg9QArIZnXw8Q-EEZv8o7iUOehOY3jTKh3AMR1yU,7384
25
+ kekkai/scanners/gitleaks.py,sha256=8hRWXsH_EMhkqGcP2AtJdaMWHmQa91XdG2oVnq8g-kI,7159
26
+ kekkai/scanners/semgrep.py,sha256=v4RDV_mHv1UXqdhV7FSyQUCu0EUCOoERGzDVowqwgVA,6758
27
+ kekkai/scanners/trivy.py,sha256=E0B31eomyNF0k3ULnDkqfFoQM54UtrIIFPm3jqgE9VA,7788
28
+ kekkai/scanners/url_policy.py,sha256=0V4ESDd2R1MSyI1bs_WtFZxZpKX33O154qFIrD6uk5U,5209
29
+ kekkai/scanners/zap.py,sha256=64NHzM-GF3oOV4UZ_W9N2v55mz91FPPg_k6hgcwlX1I,10932
30
+ kekkai/scanners/backends/__init__.py,sha256=Rdo17FeCPGTI-1QeKtBSkg4NrW26RnvX9vgzdsxY5fg,372
31
+ kekkai/scanners/backends/base.py,sha256=bFvY0qLvawTKOSgmGyEfTm7OlFJwfivzNMUexPZD2Z0,1698
32
+ kekkai/scanners/backends/docker.py,sha256=mLrYL8MxM7cbhX_-po00hTLV6DtSi1bP9c6RfE3tStQ,5867
33
+ kekkai/scanners/backends/native.py,sha256=3kwmwHMkB1AY57ZWOYpw8CtxuK2yMET49MgH9OV1ns8,7409
34
+ kekkai/threatflow/__init__.py,sha256=J07MqRdIYMIIBq3TevZk6gQ43y-kJetDPItgafB2pe4,2113
35
+ kekkai/threatflow/artifacts.py,sha256=8h3IGk798U4Wkco4x0uKgzUsZCh7VfTOufwrxs7rTTo,17119
36
+ kekkai/threatflow/chunking.py,sha256=0FNVnaQoU3FEmtjYHVaiLsKBSzHx6Vo4oozVwwWkOHM,9981
37
+ kekkai/threatflow/core.py,sha256=CYLUI38n30zEq3DbUNI_H9mqBwwlPoL7TtFOiiwC3wI,15421
38
+ kekkai/threatflow/mermaid.py,sha256=Brp-x-LUHMRjC7OBh4Vxzlk3NeCcdmWfWXlv7WL1ZdE,11579
39
+ kekkai/threatflow/model_adapter.py,sha256=xqVPYc0rDys5RgvqJwR2VULJyzx8eToLQsOtKO1fKRE,15394
40
+ kekkai/threatflow/prompts.py,sha256=lgbj7FJ1c3UYj4ofGnlLoRmywYBfdAKY0QEHmIB_JFw,8525
41
+ kekkai/threatflow/redaction.py,sha256=mGUcNQB6YPVKArtMrEYcXCWslgUiCkloiowY9IlZ1iY,7622
42
+ kekkai/threatflow/sanitizer.py,sha256=uQsxYZ5VDXutZoj-WMl7fo5T07uHuQZqgVzoVMoaKec,22688
43
+ kekkai/triage/__init__.py,sha256=5La5HUnO6ehoUoRbOfZ_QvRj0U4ud4W2o79oraBhpCg,798
44
+ kekkai/triage/app.py,sha256=MU2tBI50d8sOdDKESGNrWYiREG9bBtrSccaMoiMv5gM,5027
45
+ kekkai/triage/audit.py,sha256=UVaSKKC6tZkHxEoMcnIZkMOT_ngj7QzHWYuDAHas_sc,5842
46
+ kekkai/triage/ignore.py,sha256=uBKM7zKyzORj9LJ5AAnoYWZQTRy57P0ZofSapiDWcfI,7305
47
+ kekkai/triage/models.py,sha256=nRmWtELMqHWHX1NqZ2upH2ZAJVeBxa3Wh8f3kkB9WYo,5384
48
+ kekkai/triage/screens.py,sha256=6eEiHvuuS_gGESS_K3NjPiQx8G7CR18-j9upU1p5nRg,11004
49
+ kekkai/triage/widgets.py,sha256=eOF6Qoo5uBqjxiEkbpgcO1tbIOGBQBKn75wP9Jw_AaE,4733
50
+ kekkai_core/__init__.py,sha256=gREN4oarM0azTkSTWTnlDnPZGgv1msai2Deq9Frj3gc,122
51
+ kekkai_core/redaction.py,sha256=EeWYPjAs2hIXlLKGmGn_PRdK08G4KcOBmbRCoFklbHc,2893
52
+ kekkai_core/ci/__init__.py,sha256=uldVoVW4HNdAOq0X5k4NAMOUxbue73zqOvd1BbiywGQ,328
53
+ kekkai_core/ci/benchmarks.py,sha256=9sVVObk3tqKKukH3i2g9voPKN1NFIuzOEUmjoiW6Q0o,11013
54
+ kekkai_core/ci/metadata.py,sha256=7NACmqzQQzSsfjDLR5cl6m7R2T3i-8frUihs8rkitic,2801
55
+ kekkai_core/ci/validators.py,sha256=j9KMsAauGWVArXFeWouACTjFgn7PlUTFUuAqIhI8DNo,2330
56
+ kekkai_core/docker/__init__.py,sha256=WnuDHW7JP0dPdV95a8L5SxAI6OJHh9umzVgRE-ZkaGQ,585
57
+ kekkai_core/docker/metadata.py,sha256=OE7C0NYSHZqpciyoRqCvdb2YcbiW4Y7KR8weC5FrsOE,4103
58
+ kekkai_core/docker/sbom.py,sha256=hAJtHqYRNSsjes9lrE7cHPYnX3elOdXhX7tXyo9kf7c,4644
59
+ kekkai_core/docker/security.py,sha256=EpjAUUp5kf-wy-sRbRosR4RerJKkKQcUIFYAxM7x02A,4439
60
+ kekkai_core/docker/signing.py,sha256=kH2F4ibXAqbPGJ483cSP1kh_cNiJM6rUHImMrfqOV1k,3362
61
+ kekkai_core/slsa/__init__.py,sha256=_MrP7YX10UYbYclD9qCqisIYdG5h1yzKZQQZoqtUIpQ,260
62
+ kekkai_core/slsa/verify.py,sha256=jOqROy6Q57Xwv9yj31_cgZ51dePxA9NRAsELuj0WtiY,3579
63
+ kekkai_core/windows/__init__.py,sha256=taJXYcLYTPucwhJw0rR4NJbNQIrDbIN6cheRPBMkOA4,770
64
+ kekkai_core/windows/chocolatey.py,sha256=tF5S5eN-HeENRt6yQ4TZgwng0oRMX_ScskQ3-ebEIUg,10187
65
+ kekkai_core/windows/installer.py,sha256=MePAywHH3JTIAENv52XtkUMOGqmYqZqkH77VW5PST8o,6945
66
+ kekkai_core/windows/scoop.py,sha256=lvothICrAoB3lGfkvhqVeNTB50eMmVGA0BE7JNCfHdI,5284
67
+ kekkai_core/windows/validators.py,sha256=45xUuAbHcKc0WLIZ-0rByPeDD88MAV8KvopngyYBHpQ,6525
68
+ portal/__init__.py,sha256=vLjCqUgIqzHbT-oIMMWuWQ-lDA5jvuOOEa9qdBRLcIY,507
69
+ portal/api.py,sha256=4_hQwkUnP8P3EjCdB5Tb7uRcuH3H7M6GxTvwTTmhLv4,4066
70
+ portal/auth.py,sha256=4K_Ya9W_2sZl2MF0FNVr9QASjTOKAO3CMdgGUuYbb9s,3102
71
+ portal/tenants.py,sha256=91SOqzjGefcHXodfN8LIHER8boeSB-Jb-WoHPTWI5GI,11394
72
+ portal/uploads.py,sha256=WhosreaTKFYHNKXW9F4jOmB_OwUl1YGtT5DeaXnRMqk,7352
73
+ portal/web.py,sha256=nW9ShBI18TitVFxaN0OmGgqtMdUnv5UPZcBMT12VuvM,14173
74
+ portal/enterprise/__init__.py,sha256=djxFlSUZ5-YwhT9SXJsAOaD1rRHDL14BXigh6l4WDC4,763
75
+ portal/enterprise/audit.py,sha256=VTm-M4gVKOxcBREqIJBs4r5wyqqqf1eCOsHi3FFiDcI,13772
76
+ portal/enterprise/licensing.py,sha256=M8PFfE_v73UJL6Lfr4qhqfAGrvtJyPwDPb4SMRMGfV0,11002
77
+ portal/enterprise/rbac.py,sha256=vrZoyIVmWM0C90CIgZaprwqhiDbAM-ggNNg36Zu-5lU,8548
78
+ portal/enterprise/saml.py,sha256=TXHBbILI7qMe0ertcFPnuSUSPbJzEeBiHmZzhY9-Ix8,20367
79
+ portal/ops/__init__.py,sha256=ZyEYmFM_4LFWfQfgp9Kh2vqmolSjVKFdk1vX1vkhjqc,1391
80
+ portal/ops/backup.py,sha256=eLUnZcUtS0svEoagb0jQQmT7TcAGjBA3fUlM2YoCfLg,20102
81
+ portal/ops/log_shipper.py,sha256=Age3YfvsJ5YWrPQYdHELr4Qa9jJCATHiwv3Q-rMJwJs,15237
82
+ portal/ops/monitoring.py,sha256=xhLbKjVaob709K4x0dEsOo4lh7Ddm2A4UE2ZmhfmMtI,17908
83
+ portal/ops/restore.py,sha256=rgzKoBIilgoPPv5gZhSSBuLKG1skKw5ryoCRR3d7CPQ,17058
84
+ portal/ops/secrets.py,sha256=wu2bUfJGctbGjyuGUgvUc_Y6IH1SCW16dExtqcKu_kg,14338
85
+ portal/ops/upgrade.py,sha256=fXsIXCJYYABdWDECDXkt7F2PidzNtO6Zr-g0Y5PLlVU,20106
86
+ kekkai_cli-1.0.0.dist-info/METADATA,sha256=htJH1nyVjsze_4rHWPSQ4_AVSDbZJzZYltPh-krm0pY,3660
87
+ kekkai_cli-1.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
88
+ kekkai_cli-1.0.0.dist-info/entry_points.txt,sha256=WUEX6IISnRcwlQAdhisPfIIV3Us2MYCwtJoyPpLJO44,75
89
+ kekkai_cli-1.0.0.dist-info/top_level.txt,sha256=u0J4T-Rnb0cgs0LfzZAUNt6nx1d5l7wKn8vOuo9FBEY,26
90
+ kekkai_cli-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ kekkai = kekkai.cli:main
3
+ kekkai-portal = portal.web:main
@@ -0,0 +1,3 @@
1
+ kekkai
2
+ kekkai_core
3
+ portal
@@ -0,0 +1,3 @@
1
+ __all__ = ["redact", "redact_extended", "detect_secrets"]
2
+
3
+ from .redaction import detect_secrets, redact, redact_extended
@@ -0,0 +1,11 @@
1
+ """CI/CD automation utilities for distribution triggers."""
2
+
3
+ from kekkai_core.ci.metadata import calculate_sha256, extract_version_from_tag
4
+ from kekkai_core.ci.validators import validate_semver, verify_checksum
5
+
6
+ __all__ = [
7
+ "extract_version_from_tag",
8
+ "calculate_sha256",
9
+ "validate_semver",
10
+ "verify_checksum",
11
+ ]
@@ -0,0 +1,354 @@
1
+ """Performance benchmarking utilities for cross-platform testing."""
2
+
3
+ import json
4
+ import platform
5
+ import sys
6
+ import time
7
+ from collections.abc import Callable
8
+ from dataclasses import dataclass, field
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ try:
13
+ import psutil # type: ignore[import-untyped]
14
+
15
+ PSUTIL_AVAILABLE = True
16
+ except ImportError:
17
+ PSUTIL_AVAILABLE = False
18
+
19
+
20
+ @dataclass
21
+ class BenchmarkResult:
22
+ """Results from a performance benchmark."""
23
+
24
+ name: str
25
+ duration_seconds: float
26
+ memory_peak_mb: float | None = None
27
+ memory_start_mb: float | None = None
28
+ memory_end_mb: float | None = None
29
+ platform: str = field(default_factory=lambda: sys.platform)
30
+ python_version: str = field(default_factory=lambda: platform.python_version())
31
+ metadata: dict[str, Any] = field(default_factory=dict)
32
+
33
+ def to_dict(self) -> dict[str, Any]:
34
+ """Convert to dictionary for serialization."""
35
+ return {
36
+ "name": self.name,
37
+ "duration_seconds": self.duration_seconds,
38
+ "memory_peak_mb": self.memory_peak_mb,
39
+ "memory_start_mb": self.memory_start_mb,
40
+ "memory_end_mb": self.memory_end_mb,
41
+ "platform": self.platform,
42
+ "python_version": self.python_version,
43
+ "metadata": self.metadata,
44
+ }
45
+
46
+
47
+ class PerformanceBenchmark:
48
+ """Context manager for performance benchmarking."""
49
+
50
+ def __init__(self, name: str, metadata: dict[str, Any] | None = None):
51
+ """Initialize benchmark.
52
+
53
+ Args:
54
+ name: Name of the benchmark
55
+ metadata: Additional metadata to include
56
+ """
57
+ self.name = name
58
+ self.metadata = metadata or {}
59
+ self.start_time: float | None = None
60
+ self.end_time: float | None = None
61
+ self.memory_start: float | None = None
62
+ self.memory_end: float | None = None
63
+ self.memory_peak: float | None = None
64
+
65
+ def __enter__(self) -> "PerformanceBenchmark":
66
+ """Start benchmarking."""
67
+ self.start_time = time.perf_counter()
68
+
69
+ if PSUTIL_AVAILABLE:
70
+ process = psutil.Process()
71
+ self.memory_start = process.memory_info().rss / (1024 * 1024) # MB
72
+
73
+ return self
74
+
75
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
76
+ """End benchmarking."""
77
+ self.end_time = time.perf_counter()
78
+
79
+ if PSUTIL_AVAILABLE:
80
+ process = psutil.Process()
81
+ self.memory_end = process.memory_info().rss / (1024 * 1024) # MB
82
+ self.memory_peak = self.memory_end # Simplified; real peak tracking needs monitoring
83
+
84
+ def get_result(self) -> BenchmarkResult:
85
+ """Get benchmark result."""
86
+ if self.start_time is None or self.end_time is None:
87
+ raise RuntimeError("Benchmark not completed")
88
+
89
+ duration = self.end_time - self.start_time
90
+
91
+ return BenchmarkResult(
92
+ name=self.name,
93
+ duration_seconds=duration,
94
+ memory_peak_mb=self.memory_peak,
95
+ memory_start_mb=self.memory_start,
96
+ memory_end_mb=self.memory_end,
97
+ metadata=self.metadata,
98
+ )
99
+
100
+
101
+ def benchmark_function(
102
+ func: Callable[..., Any],
103
+ name: str | None = None,
104
+ iterations: int = 1,
105
+ warmup: int = 0,
106
+ metadata: dict[str, Any] | None = None,
107
+ ) -> BenchmarkResult:
108
+ """Benchmark a function.
109
+
110
+ Args:
111
+ func: Function to benchmark
112
+ name: Name for the benchmark (defaults to function name)
113
+ iterations: Number of times to run the function
114
+ warmup: Number of warmup iterations (not measured)
115
+ metadata: Additional metadata
116
+
117
+ Returns:
118
+ Benchmark result
119
+ """
120
+ benchmark_name = name or func.__name__
121
+
122
+ # Warmup
123
+ for _ in range(warmup):
124
+ func()
125
+
126
+ # Measure
127
+ with PerformanceBenchmark(benchmark_name, metadata=metadata) as bench:
128
+ for _ in range(iterations):
129
+ func()
130
+
131
+ result = bench.get_result()
132
+
133
+ # Adjust for iterations
134
+ if iterations > 1:
135
+ result.duration_seconds /= iterations
136
+ result.metadata["iterations"] = iterations
137
+
138
+ return result
139
+
140
+
141
+ class BenchmarkRunner:
142
+ """Runner for multiple benchmarks."""
143
+
144
+ def __init__(self, output_dir: Path | None = None):
145
+ """Initialize benchmark runner.
146
+
147
+ Args:
148
+ output_dir: Directory to store benchmark results
149
+ """
150
+ self.output_dir = output_dir or Path(".benchmarks")
151
+ self.results: list[BenchmarkResult] = []
152
+
153
+ def run_benchmark(
154
+ self,
155
+ func: Callable[..., Any],
156
+ name: str | None = None,
157
+ iterations: int = 1,
158
+ metadata: dict[str, Any] | None = None,
159
+ ) -> BenchmarkResult:
160
+ """Run a benchmark and store result.
161
+
162
+ Args:
163
+ func: Function to benchmark
164
+ name: Benchmark name
165
+ iterations: Number of iterations
166
+ metadata: Additional metadata
167
+
168
+ Returns:
169
+ Benchmark result
170
+ """
171
+ result = benchmark_function(func, name=name, iterations=iterations, metadata=metadata)
172
+ self.results.append(result)
173
+ return result
174
+
175
+ def save_results(self, filename: str | None = None) -> Path:
176
+ """Save benchmark results to file.
177
+
178
+ Args:
179
+ filename: Output filename (default: benchmark_{timestamp}.json)
180
+
181
+ Returns:
182
+ Path to saved file
183
+ """
184
+ self.output_dir.mkdir(parents=True, exist_ok=True)
185
+
186
+ if filename is None:
187
+ timestamp = time.strftime("%Y%m%d_%H%M%S")
188
+ filename = f"benchmark_{timestamp}.json"
189
+
190
+ output_path = self.output_dir / filename
191
+
192
+ results_data = {
193
+ "timestamp": time.time(),
194
+ "platform": {
195
+ "system": platform.system(),
196
+ "release": platform.release(),
197
+ "machine": platform.machine(),
198
+ "python_version": platform.python_version(),
199
+ },
200
+ "results": [r.to_dict() for r in self.results],
201
+ }
202
+
203
+ output_path.write_text(json.dumps(results_data, indent=2))
204
+
205
+ return output_path
206
+
207
+ def load_results(self, filepath: Path) -> list[BenchmarkResult]:
208
+ """Load benchmark results from file.
209
+
210
+ Args:
211
+ filepath: Path to results file
212
+
213
+ Returns:
214
+ List of benchmark results
215
+ """
216
+ data = json.loads(filepath.read_text())
217
+
218
+ loaded_results = []
219
+ for result_dict in data.get("results", []):
220
+ result = BenchmarkResult(
221
+ name=result_dict["name"],
222
+ duration_seconds=result_dict["duration_seconds"],
223
+ memory_peak_mb=result_dict.get("memory_peak_mb"),
224
+ memory_start_mb=result_dict.get("memory_start_mb"),
225
+ memory_end_mb=result_dict.get("memory_end_mb"),
226
+ platform=result_dict.get("platform", "unknown"),
227
+ python_version=result_dict.get("python_version", "unknown"),
228
+ metadata=result_dict.get("metadata", {}),
229
+ )
230
+ loaded_results.append(result)
231
+
232
+ return loaded_results
233
+
234
+ def compare_with_baseline(
235
+ self, baseline_file: Path, threshold_percent: float = 20.0
236
+ ) -> dict[str, Any]:
237
+ """Compare current results with baseline.
238
+
239
+ Args:
240
+ baseline_file: Path to baseline results file
241
+ threshold_percent: Threshold for regression detection (e.g., 20.0 = 20%)
242
+
243
+ Returns:
244
+ Comparison report
245
+ """
246
+ baseline_results = self.load_results(baseline_file)
247
+
248
+ # Create lookup by name
249
+ baseline_by_name = {r.name: r for r in baseline_results}
250
+
251
+ regressions: list[dict[str, Any]] = []
252
+ improvements: list[dict[str, Any]] = []
253
+
254
+ for current in self.results:
255
+ if current.name not in baseline_by_name:
256
+ continue
257
+
258
+ baseline = baseline_by_name[current.name]
259
+
260
+ # Calculate percentage change
261
+ percent_change = (
262
+ (current.duration_seconds - baseline.duration_seconds)
263
+ / baseline.duration_seconds
264
+ * 100.0
265
+ )
266
+
267
+ comparison = {
268
+ "name": current.name,
269
+ "baseline_duration": baseline.duration_seconds,
270
+ "current_duration": current.duration_seconds,
271
+ "percent_change": percent_change,
272
+ }
273
+
274
+ if percent_change > threshold_percent:
275
+ regressions.append(comparison)
276
+ elif percent_change < -threshold_percent:
277
+ improvements.append(comparison)
278
+
279
+ return {
280
+ "threshold_percent": threshold_percent,
281
+ "regressions": regressions,
282
+ "improvements": improvements,
283
+ "total_benchmarks": len(self.results),
284
+ }
285
+
286
+
287
+ def get_system_info() -> dict[str, Any]:
288
+ """Get system information for benchmarking context.
289
+
290
+ Returns:
291
+ Dictionary with system information
292
+ """
293
+ info = {
294
+ "platform": {
295
+ "system": platform.system(),
296
+ "release": platform.release(),
297
+ "version": platform.version(),
298
+ "machine": platform.machine(),
299
+ "processor": platform.processor(),
300
+ },
301
+ "python": {
302
+ "version": platform.python_version(),
303
+ "implementation": platform.python_implementation(),
304
+ "compiler": platform.python_compiler(),
305
+ },
306
+ }
307
+
308
+ if PSUTIL_AVAILABLE:
309
+ info["memory"] = {
310
+ "total_gb": psutil.virtual_memory().total / (1024**3),
311
+ "available_gb": psutil.virtual_memory().available / (1024**3),
312
+ }
313
+ info["cpu"] = {
314
+ "physical_cores": psutil.cpu_count(logical=False),
315
+ "logical_cores": psutil.cpu_count(logical=True),
316
+ }
317
+
318
+ return info
319
+
320
+
321
+ def format_benchmark_report(results: list[BenchmarkResult]) -> str:
322
+ """Format benchmark results as human-readable report.
323
+
324
+ Args:
325
+ results: List of benchmark results
326
+
327
+ Returns:
328
+ Formatted report string
329
+ """
330
+ lines = ["# Performance Benchmark Report", ""]
331
+
332
+ # System info
333
+ sys_info = get_system_info()
334
+ lines.append("## System Information")
335
+ lines.append(f"- Platform: {sys_info['platform']['system']} {sys_info['platform']['release']}")
336
+ lines.append(f"- Machine: {sys_info['platform']['machine']}")
337
+ lines.append(
338
+ f"- Python: {sys_info['python']['version']} ({sys_info['python']['implementation']})"
339
+ )
340
+ lines.append("")
341
+
342
+ # Results table
343
+ lines.append("## Benchmark Results")
344
+ lines.append("")
345
+ lines.append("| Benchmark | Duration (s) | Memory Peak (MB) |")
346
+ lines.append("|-----------|--------------|------------------|")
347
+
348
+ for result in results:
349
+ memory_str = f"{result.memory_peak_mb:.2f}" if result.memory_peak_mb else "N/A"
350
+ lines.append(f"| {result.name} | {result.duration_seconds:.4f} | {memory_str} |")
351
+
352
+ lines.append("")
353
+
354
+ return "\n".join(lines)