kekkai-cli 1.1.1__py3-none-any.whl → 2.0.1__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.
kekkai/cli.py CHANGED
@@ -58,6 +58,11 @@ def main(argv: Sequence[str] | None = None) -> int:
58
58
  init_parser = subparsers.add_parser("init", help="initialize config and directories")
59
59
  init_parser.add_argument("--config", type=str, help="Path to config file")
60
60
  init_parser.add_argument("--force", action="store_true", help="Overwrite existing config")
61
+ init_parser.add_argument(
62
+ "--ci",
63
+ action="store_true",
64
+ help="Auto-generate GitHub Actions workflow for CI/CD integration",
65
+ )
61
66
 
62
67
  scan_parser = subparsers.add_parser("scan", help="run a scan pipeline")
63
68
  scan_parser.add_argument("--config", type=str, help="Path to config file")
@@ -147,7 +152,7 @@ def main(argv: Sequence[str] | None = None) -> int:
147
152
  help="Minimum severity for PR comments (default: medium)",
148
153
  )
149
154
 
150
- dojo_parser = subparsers.add_parser("dojo", help="manage local DefectDojo stack")
155
+ dojo_parser = subparsers.add_parser("dojo", help=argparse.SUPPRESS)
151
156
  dojo_subparsers = dojo_parser.add_subparsers(dest="dojo_command")
152
157
 
153
158
  dojo_up = dojo_subparsers.add_parser("up", help="start the local DefectDojo stack")
@@ -378,7 +383,7 @@ def main(argv: Sequence[str] | None = None) -> int:
378
383
 
379
384
  parsed = parser.parse_args(args)
380
385
  if parsed.command == "init":
381
- return _command_init(parsed.config, parsed.force)
386
+ return _command_init(parsed.config, parsed.force, parsed.ci)
382
387
  if parsed.command == "scan":
383
388
  return _command_scan(
384
389
  parsed.config,
@@ -427,7 +432,7 @@ def _handle_no_args() -> int:
427
432
  return 0
428
433
 
429
434
 
430
- def _command_init(config_override: str | None, force: bool) -> int:
435
+ def _command_init(config_override: str | None, force: bool, ci: bool = False) -> int:
431
436
  cfg_path = _resolve_config_path(config_override)
432
437
  if cfg_path.exists() and not force:
433
438
  print(f"Config already exists at {cfg_path}. Use --force to overwrite.")
@@ -441,6 +446,27 @@ def _command_init(config_override: str | None, force: bool) -> int:
441
446
  cfg_path.write_text(load_config_text(base_dir))
442
447
  print_dashboard()
443
448
  console.print(f"\n[success]Initialized config at[/success] [cyan]{cfg_path}[/cyan]\n")
449
+
450
+ # Auto-generate GitHub Actions workflow if --ci flag is set
451
+ if ci:
452
+ workflow_created = _generate_github_workflow()
453
+ if workflow_created:
454
+ console.print(
455
+ "[success]✓[/success] Created GitHub Actions workflow: "
456
+ "[cyan].github/workflows/kekkai-security.yml[/cyan]"
457
+ )
458
+ console.print(
459
+ "\n[info]Next steps:[/info]\n"
460
+ " 1. Commit the workflow file:\n"
461
+ " [dim]git add .github/workflows/kekkai-security.yml[/dim]\n"
462
+ " 2. Push to GitHub\n"
463
+ " 3. Security scans will run automatically on pull requests\n"
464
+ )
465
+ else:
466
+ console.print(
467
+ "[warning]⚠[/warning] Not a Git repository or .github/workflows/ cannot be created"
468
+ )
469
+
444
470
  return 0
445
471
 
446
472
 
@@ -1752,6 +1778,91 @@ def _resolve_dojo_open_port(parsed: argparse.Namespace, compose_root: Path) -> i
1752
1778
  return dojo.DEFAULT_PORT
1753
1779
 
1754
1780
 
1781
+ def _generate_github_workflow() -> bool:
1782
+ """Generate GitHub Actions workflow file for security scanning.
1783
+
1784
+ Returns:
1785
+ True if workflow was created successfully, False otherwise.
1786
+ """
1787
+ # Check if we're in a git repository
1788
+ cwd = Path.cwd()
1789
+ git_dir = cwd / ".git"
1790
+ if not git_dir.exists():
1791
+ return False
1792
+
1793
+ # Create .github/workflows directory
1794
+ workflows_dir = cwd / ".github" / "workflows"
1795
+ try:
1796
+ workflows_dir.mkdir(parents=True, exist_ok=True)
1797
+ except (OSError, PermissionError):
1798
+ return False
1799
+
1800
+ # Generate workflow file
1801
+ workflow_path = workflows_dir / "kekkai-security.yml"
1802
+ if workflow_path.exists():
1803
+ # Don't overwrite existing workflow
1804
+ return False
1805
+
1806
+ workflow_content = """name: Kekkai Security Scan
1807
+
1808
+ on:
1809
+ pull_request:
1810
+ types: [opened, synchronize, reopened]
1811
+ push:
1812
+ branches:
1813
+ - main
1814
+ - develop
1815
+
1816
+ permissions:
1817
+ contents: read
1818
+ pull-requests: write
1819
+
1820
+ jobs:
1821
+ security-scan:
1822
+ runs-on: ubuntu-latest
1823
+ steps:
1824
+ - name: Checkout code
1825
+ uses: actions/checkout@v4
1826
+
1827
+ - name: Set up Python
1828
+ uses: actions/setup-python@v5
1829
+ with:
1830
+ python-version: '3.12'
1831
+
1832
+ - name: Install Kekkai
1833
+ run: |
1834
+ python -m pip install --upgrade pip
1835
+ pip install kekkai-cli
1836
+
1837
+ - name: Run Security Scan
1838
+ run: |
1839
+ kekkai scan --ci --fail-on high
1840
+ continue-on-error: true
1841
+
1842
+ - name: Post PR Comments (if PR)
1843
+ if: github.event_name == 'pull_request'
1844
+ run: |
1845
+ kekkai scan --pr-comment --max-comments 50
1846
+ env:
1847
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1848
+ continue-on-error: true
1849
+
1850
+ - name: Upload Results
1851
+ uses: actions/upload-artifact@v4
1852
+ if: always()
1853
+ with:
1854
+ name: kekkai-scan-results
1855
+ path: ~/.kekkai/runs/*/
1856
+ retention-days: 30
1857
+ """
1858
+
1859
+ try:
1860
+ workflow_path.write_text(workflow_content, encoding="utf-8")
1861
+ return True
1862
+ except (OSError, PermissionError):
1863
+ return False
1864
+
1865
+
1755
1866
  def _resolve_config_path(config_override: str | None) -> Path:
1756
1867
  if config_override:
1757
1868
  return Path(config_override).expanduser().resolve()
kekkai/output.py CHANGED
@@ -57,7 +57,7 @@ BANNER_ASCII = r"""
57
57
  /_/\_\\___/_/\_/_/\_\\_,_/_/
58
58
  """
59
59
 
60
- VERSION = "1.1.1"
60
+ VERSION = "2.0.1"
61
61
 
62
62
 
63
63
  def print_dashboard() -> None:
@@ -88,9 +88,8 @@ def print_dashboard() -> None:
88
88
  menu_table.add_column("Description", style="desc", ratio=3)
89
89
 
90
90
  menu_table.add_row("kekkai scan", "Run security scan in current directory")
91
- menu_table.add_row("kekkai threatflow", "Generate AI-powered threat model")
92
- menu_table.add_row("kekkai dojo", "Manage local DefectDojo instance")
93
91
  menu_table.add_row("kekkai triage", "Interactive finding review (TUI)")
92
+ menu_table.add_row("kekkai threatflow", "Generate AI-powered threat model")
94
93
  menu_table.add_row("kekkai report", "Generate compliance reports")
95
94
  menu_table.add_row("kekkai config", "Manage settings and keys")
96
95
 
@@ -0,0 +1,232 @@
1
+ """Fix generation screen for AI-powered code fixes.
2
+
3
+ Provides a modal screen that shows fix generation progress
4
+ and preview of AI-generated patches.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from collections.abc import Callable
11
+ from typing import TYPE_CHECKING
12
+
13
+ from rich.text import Text
14
+ from textual.app import ComposeResult
15
+ from textual.binding import Binding
16
+ from textual.containers import Vertical, VerticalScroll
17
+ from textual.screen import ModalScreen
18
+ from textual.widgets import Footer, Label, Static
19
+
20
+ if TYPE_CHECKING:
21
+ from .models import FindingEntry
22
+
23
+ __all__ = ["FixGenerationScreen"]
24
+
25
+
26
+ class FixGenerationScreen(ModalScreen[bool]):
27
+ """Modal screen for generating AI-powered fixes.
28
+
29
+ Shows progress, model configuration, and fix preview.
30
+
31
+ Bindings:
32
+ escape: Cancel and go back
33
+ enter: Accept fix (if generated)
34
+ """
35
+
36
+ BINDINGS = [
37
+ Binding("escape", "cancel", "Cancel"),
38
+ Binding("enter", "accept", "Accept Fix", show=False),
39
+ ]
40
+
41
+ DEFAULT_CSS = """
42
+ FixGenerationScreen {
43
+ align: center middle;
44
+ }
45
+ #fix-dialog {
46
+ width: 80;
47
+ height: 30;
48
+ border: thick $primary;
49
+ background: $surface;
50
+ padding: 1;
51
+ }
52
+ #fix-title {
53
+ dock: top;
54
+ height: 3;
55
+ content-align: center middle;
56
+ background: $primary;
57
+ color: $text;
58
+ }
59
+ #fix-content {
60
+ height: 1fr;
61
+ padding: 1;
62
+ }
63
+ #fix-preview {
64
+ height: 1fr;
65
+ border: solid $accent;
66
+ padding: 1;
67
+ background: $panel;
68
+ }
69
+ #fix-status {
70
+ dock: bottom;
71
+ height: 3;
72
+ padding: 1;
73
+ background: $surface;
74
+ }
75
+ .fix-button {
76
+ margin: 1;
77
+ }
78
+ """
79
+
80
+ def __init__(
81
+ self,
82
+ finding: FindingEntry,
83
+ on_fix_generated: Callable[[bool, str], None] | None = None,
84
+ name: str | None = None,
85
+ id: str | None = None,
86
+ ) -> None:
87
+ super().__init__(name=name, id=id)
88
+ self.finding = finding
89
+ self.on_fix_generated = on_fix_generated
90
+ self.fix_preview: str | None = None
91
+ self.fix_generated = False
92
+
93
+ def compose(self) -> ComposeResult:
94
+ with Vertical(id="fix-dialog"):
95
+ yield Label("🤖 AI-Powered Fix Generation", id="fix-title")
96
+ with VerticalScroll(id="fix-content"):
97
+ yield Label(self._get_finding_summary())
98
+ yield Label(self._get_model_info())
99
+ yield Static("", id="fix-preview")
100
+ yield Static(self._get_initial_status(), id="fix-status")
101
+ yield Footer()
102
+
103
+ def _get_finding_summary(self) -> Text:
104
+ """Generate summary of finding to fix."""
105
+ text = Text()
106
+ text.append("Finding:\n", style="bold")
107
+ text.append(f" {self.finding.scanner}: ", style="cyan")
108
+ text.append(f"{self.finding.title}\n")
109
+ if self.finding.file_path:
110
+ text.append(f" File: {self.finding.file_path}", style="dim")
111
+ if self.finding.line:
112
+ text.append(f":{self.finding.line}", style="dim")
113
+ text.append("\n")
114
+ return text
115
+
116
+ def _get_model_info(self) -> Text:
117
+ """Display model configuration info."""
118
+ text = Text()
119
+ text.append("\nModel Configuration:\n", style="bold")
120
+
121
+ # Check for Ollama
122
+ if self._is_ollama_available():
123
+ text.append(" ✓ Ollama detected (local-first AI)\n", style="green")
124
+ text.append(" No API keys needed - runs on your machine\n", style="dim")
125
+ # Check for API keys
126
+ elif os.environ.get("KEKKAI_FIX_API_KEY"):
127
+ text.append(" ⚠ Using remote API (OpenAI/Anthropic)\n", style="yellow")
128
+ text.append(" Code will be sent to external service\n", style="dim")
129
+ else:
130
+ text.append(" ✗ No AI backend configured\n", style="red")
131
+ text.append(" Install Ollama or set KEKKAI_FIX_API_KEY\n", style="dim")
132
+
133
+ return text
134
+
135
+ def _get_initial_status(self) -> Text:
136
+ """Initial status message."""
137
+ if self._is_ollama_available() or os.environ.get("KEKKAI_FIX_API_KEY"):
138
+ return Text("Press Enter to generate fix, or Escape to cancel", style="italic")
139
+ else:
140
+ return Text(
141
+ "❌ Cannot generate fix: No AI backend configured\n"
142
+ "Install Ollama (recommended) or set KEKKAI_FIX_API_KEY",
143
+ style="red",
144
+ )
145
+
146
+ def _is_ollama_available(self) -> bool:
147
+ """Check if Ollama is available on the system."""
148
+ import shutil
149
+
150
+ return shutil.which("ollama") is not None
151
+
152
+ def on_mount(self) -> None:
153
+ """Auto-generate fix if backend is available."""
154
+ if self._is_ollama_available() or os.environ.get("KEKKAI_FIX_API_KEY"):
155
+ # Auto-start fix generation
156
+ self.set_timer(0.5, self._generate_fix)
157
+
158
+ def _generate_fix(self) -> None:
159
+ """Generate AI-powered fix."""
160
+ status = self.query_one("#fix-status", Static)
161
+ status.update(Text("⏳ Generating fix with AI...", style="yellow italic"))
162
+
163
+ try:
164
+ # Import fix engine
165
+ from ..fix import FixConfig
166
+
167
+ # Determine model mode
168
+ if self._is_ollama_available():
169
+ model_mode = "ollama"
170
+ model_name = os.environ.get("KEKKAI_FIX_MODEL_NAME", "mistral")
171
+ else:
172
+ model_mode = "openai"
173
+ model_name = None
174
+
175
+ # Create fix config (for future integration)
176
+ _config = FixConfig(
177
+ model_mode=model_mode,
178
+ model_name=model_name,
179
+ api_key=os.environ.get("KEKKAI_FIX_API_KEY"),
180
+ max_fixes=1,
181
+ timeout_seconds=60,
182
+ dry_run=True,
183
+ )
184
+
185
+ # Note: This is a simplified mock - actual implementation would:
186
+ # 1. Convert FindingEntry to proper format for FixEngine
187
+ # 2. Call fix engine with proper error handling
188
+ # 3. Display actual fix preview
189
+
190
+ # For now, show a placeholder
191
+ self.fix_preview = (
192
+ "# AI-Powered Fix (Preview)\n"
193
+ f"# Finding: {self.finding.title}\n"
194
+ f"# Scanner: {self.finding.scanner}\n\n"
195
+ "# Fix would be generated here using:\n"
196
+ f"# - Model: {model_name or 'gpt-4'}\n"
197
+ f"# - Mode: {model_mode}\n"
198
+ "# - Context from source file\n\n"
199
+ "# Press Enter to apply (dry-run mode)\n"
200
+ "# Press Escape to cancel"
201
+ )
202
+
203
+ preview = self.query_one("#fix-preview", Static)
204
+ preview.update(Text(self.fix_preview, style="green"))
205
+
206
+ status.update(
207
+ Text("✓ Fix generated! Press Enter to apply or Escape to cancel", style="green")
208
+ )
209
+ self.fix_generated = True
210
+
211
+ except Exception as e:
212
+ status.update(Text(f"✗ Fix generation failed: {e}", style="red"))
213
+ self.fix_generated = False
214
+
215
+ def action_accept(self) -> None:
216
+ """Accept and apply the generated fix."""
217
+ if not self.fix_generated:
218
+ return
219
+
220
+ if self.on_fix_generated:
221
+ self.on_fix_generated(
222
+ True, "Fix generated successfully (dry-run mode - review before applying)"
223
+ )
224
+
225
+ self.dismiss(True)
226
+
227
+ def action_cancel(self) -> None:
228
+ """Cancel fix generation."""
229
+ if self.on_fix_generated:
230
+ self.on_fix_generated(False, "Fix generation cancelled")
231
+
232
+ self.dismiss(False)
kekkai/triage/screens.py CHANGED
@@ -49,6 +49,7 @@ class FindingListScreen(Screen[None]):
49
49
  Binding("down", "cursor_down", "Next", show=False),
50
50
  Binding("up", "cursor_up", "Previous", show=False),
51
51
  Binding("enter", "view_detail", "View"),
52
+ Binding("x", "fix_with_ai", "🤖 Fix with AI"),
52
53
  Binding("f", "mark_false_positive", "False Positive"),
53
54
  Binding("c", "mark_confirmed", "Confirmed"),
54
55
  Binding("d", "mark_deferred", "Deferred"),
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: kekkai-cli
3
+ Version: 2.0.1
4
+ Summary: Terminal UI for Trivy/Semgrep/Gitleaks. Local-first security triage.
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
+ Requires-Dist: jinja2>=3.1.6
12
+
13
+ <p align="center">
14
+ <img src="https://raw.githubusercontent.com/kademoslabs/assets/main/logos/kekkai-slim.png" alt="Kekkai CLI Logo" width="250"/>
15
+ </p>
16
+
17
+ <p align="center"><strong>Stop parsing JSON. Security triage in your terminal.</strong></p>
18
+
19
+ <p align="center">
20
+ <img src="https://img.shields.io/github/actions/workflow/status/kademoslabs/kekkai/docker-publish.yml?logo=github"/>
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?pypiBaseUrl=https%3A%2F%2Fpypi.org&logo=pypi"/>
23
+ </p>
24
+
25
+ ---
26
+
27
+ # Kekkai
28
+
29
+ **Interactive security triage in the terminal.**
30
+
31
+ 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
+ Running scanners is easy. Interpreting noisy output, dealing with false positives, and making CI usable is not. Kekkai exists to make that part tolerable..
34
+
35
+ ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai.gif)
36
+
37
+ ---
38
+
39
+ ## What it does
40
+
41
+ - Runs Trivy (dependencies), Semgrep (code), and Gitleaks (secrets)
42
+ - Normalizes their outputs into a single report format
43
+ - Provides an interactive terminal UI for reviewing findings
44
+ - Lets you mark findings as false positives and persist decisions locally
45
+ - Supports CI mode with severity-based failure thresholds
46
+
47
+ Kekkai does not replace scanners or introduce proprietary detection logic. It sits on top of existing tools and focuses on workflow and UX.
48
+
49
+ ---
50
+
51
+ ## Quick Start
52
+
53
+ > Requires Docker and Python 3.12
54
+
55
+ ### 1. Install
56
+
57
+ ```bash
58
+ pipx install kekkai-cli
59
+ ```
60
+
61
+ ### 2. Scan
62
+
63
+ ```bash
64
+ kekkai scan
65
+ # Runs Trivy (CVEs), Semgrep (code), Gitleaks (secrets)
66
+ # Outputs unified kekkai-report.json
67
+ ```
68
+
69
+ ### 3. Triage
70
+
71
+ ```bash
72
+ kekkai triage
73
+ # Interactive TUI to review findings with keyboard navigation
74
+ ```
75
+
76
+ No signup, no cloud service required.
77
+
78
+ ---
79
+
80
+ ## Why Kekkai?
81
+
82
+ | Problem | Kekkai Solution |
83
+ |---------|-----------------|
84
+ | **Juggling 3+ tools** | One CLI for Trivy, Semgrep, Gitleaks |
85
+ | **Reading JSON logs** | Interactive terminal UI |
86
+ | **Installing scanners** | Auto-pulls Docker containers |
87
+ | **Parsing different formats** | Unified `kekkai-report.json` |
88
+ | **False positives** | Mark and ignore with `.kekkaiignore` |
89
+ | **CI/CD integration** | `kekkai scan --ci --fail-on high` |
90
+
91
+ ---
92
+
93
+ ## Features
94
+
95
+ ### Interactive Triage TUI
96
+
97
+ Stop reading JSON. Use keyboard navigation to review findings, mark false positives, and generate ignore files.
98
+
99
+ ```bash
100
+ kekkai triage
101
+ ```
102
+
103
+ **Controls:**
104
+ - `j/k` or `↑/↓`: Navigate findings
105
+ - `f`: Mark as false positive
106
+ - `c`: Confirm finding
107
+ - `d`: Defer/ignore
108
+ - `Ctrl+S`: Save decisions
109
+ - `q`: Quit
110
+
111
+ ![Triage TUI](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-triage.png)
112
+
113
+ [Full Triage Documentation →](docs/triage/README.md)
114
+
115
+ ---
116
+
117
+ ### CI/CD Policy Gate
118
+
119
+ Break builds on severity thresholds.
120
+
121
+ Kekkai can be used as a CI gate based on severity thresholds.
122
+
123
+ ```bash
124
+ # Fail on any critical or high findings
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
145
+ ```
146
+
147
+ [Full CI Documentation →](docs/ci/ci-mode.md)
148
+
149
+ ---
150
+
151
+ ### GitHub PR Comments
152
+
153
+ Get security feedback directly in pull requests.
154
+
155
+ ```bash
156
+ export GITHUB_TOKEN="ghp_..."
157
+ kekkai scan --pr-comment
158
+ ```
159
+ ---
160
+
161
+ ### Unified Scanning
162
+
163
+ Run industry-standard scanners without installing them individually. Each scanner runs in an isolated Docker container.
164
+
165
+ ```bash
166
+ kekkai scan # Scan current directory
167
+ kekkai scan --repo /path/to/project # Scan specific path
168
+ kekkai scan --output results.json # Custom output path
169
+ ```
170
+
171
+ **Scanners Included:**
172
+ | Scanner | Finds | Image |
173
+ |---------|-------|-------|
174
+ | Trivy | CVEs in dependencies | `aquasec/trivy:latest` |
175
+ | Semgrep | Code vulnerabilities | `semgrep/semgrep:latest` |
176
+ | Gitleaks | Hardcoded secrets | `zricethezav/gitleaks:latest` |
177
+
178
+ **Container Security:**
179
+ - Read-only filesystem
180
+ - No network access
181
+ - Memory limited (2GB)
182
+ - No privilege escalation
183
+
184
+ ---
185
+
186
+ #### Design choices
187
+
188
+ - Local-first: no SaaS required, runs entirely on your machine or CI
189
+ - No network access for scanner containers
190
+ - Read-only filesystems, memory-limited containers
191
+ - Uses existing tools instead of reimplementing scanners
192
+ - Terminal-first UX instead of dashboards
193
+
194
+ ---
195
+
196
+ ## Optional features
197
+
198
+ These are opt-in and not required for basic use:
199
+
200
+ ### Local-First AI Threat Modeling
201
+
202
+ Generate STRIDE threat models with AI that runs on **your machine**. No API keys. No cloud.
203
+
204
+ ```bash
205
+ # Ollama (recommended - easy setup, privacy-preserving)
206
+ ollama pull mistral
207
+ kekkai threatflow --repo . --model-mode ollama --model-name mistral
208
+
209
+ # Output: THREATS.md with attack surface analysis and Mermaid.js diagrams
210
+ ```
211
+
212
+ **Supports:**
213
+ - Ollama (recommended)
214
+ - Local GGUF models (llama.cpp)
215
+ - OpenAI/Anthropic (if you trust them with your code)
216
+
217
+ [Full Local-First AI Threat Modeling Documentation →](docs/threatflow/README.md)
218
+
219
+ ---
220
+
221
+ ### DefectDojo Integration
222
+
223
+ Spin up a vulnerability management dashboard locally if you need it.
224
+
225
+ ```bash
226
+ kekkai dojo up --wait # Start DefectDojo
227
+ kekkai upload # Import scan results
228
+ ```
229
+
230
+ **What You Get:**
231
+ - DefectDojo web UI at `http://localhost:8080`
232
+ - Automatic credential generation
233
+ - Pre-configured for Kekkai imports
234
+
235
+ [DefectDojo Quick Start →](docs/dojo/dojo-quickstart.md)
236
+
237
+ ---
238
+
239
+ ### AI-Powered Fix Engine
240
+
241
+ Generate code patches for findings (experimental).
242
+
243
+ ```bash
244
+ kekkai fix --input scan-results.json --apply
245
+ ```
246
+
247
+ ---
248
+
249
+ ### Compliance Reporting
250
+
251
+ Map findings to PCI-DSS, OWASP, HIPAA, SOC 2.
252
+
253
+ ```bash
254
+ kekkai report --input scan-results.json --format pdf --frameworks PCI-DSS,OWASP
255
+ ```
256
+
257
+ ---
258
+
259
+ ## What this is not
260
+
261
+ - Not a replacement for commercial AppSec platforms
262
+ - Not a new scanner or detection engine
263
+ - Not optimized for large enterprises (yet)
264
+ - Not a hosted service
265
+
266
+ Right now, Kekkai is aimed at individual developers and small teams who already run scanners but want better triage and less noise.
267
+
268
+ ---
269
+
270
+ ## Security
271
+
272
+ Kekkai is designed with security as a core principle:
273
+
274
+ - **Container Isolation**: Scanners run in hardened Docker containers
275
+ - **No Network Access**: Containers cannot reach external networks
276
+ - **Local-First AI**: run entirely on your machine
277
+ - **SLSA Level 3**: Release artifacts include provenance attestations
278
+ - **Signed Images**: Docker images are Cosign-signed
279
+
280
+ For vulnerability reports, see [SECURITY.md](SECURITY.md).
281
+
282
+ ---
283
+
284
+ ## Documentation
285
+
286
+ | Guide | Description |
287
+ |-------|-------------|
288
+ | [Installation](docs/README.md#installation-methods) | All installation methods |
289
+ | [ThreatFlow](docs/threatflow/README.md) | AI threat modeling setup |
290
+ | [Triage TUI](docs/triage/README.md) | Interactive finding review |
291
+ | [CI Mode](docs/ci/ci-mode.md) | Pipeline integration |
292
+ | [DefectDojo](docs/dojo/dojo-quickstart.md) | Optional vulnerability management |
293
+ | [Security](docs/security/slsa-provenance.md) | SLSA provenance verification |
294
+
295
+ ---
296
+
297
+ ## Roadmap (short-term)
298
+
299
+ 1. Persistent triage state across runs (baselines)
300
+ 2. “New findings only” diffs
301
+ 3. Better PR-level workflows
302
+ 4. Cleaner reporting for small teams
303
+
304
+ ---
305
+
306
+ ## Contributing
307
+
308
+ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
309
+
310
+ ---
311
+
312
+ ## License
313
+
314
+ Apache-2.0 — See [LICENSE](LICENSE) for details.
315
+
316
+ ---
317
+
318
+ <p align="center"><i>Built by <a href="https://kademos.org">Kademos Labs</a></i></p>
@@ -1,10 +1,10 @@
1
1
  kekkai/__init__.py,sha256=_VrBvJRyqHiXs31S8HOhATk_O2iy-ac0_9X7rHH75j8,143
2
- kekkai/cli.py,sha256=-Kix3HMEsroCgtOLu-QCtPwi7OqOSi3YzXzboT5tGvU,63529
2
+ kekkai/cli.py,sha256=Y99dHzSRLV4sqbFiSe81nJRtvx2dQWmRDPyOVdghIIQ,66616
3
3
  kekkai/config.py,sha256=LE7bKsmv5dim5KnZya0V7_LtviNQ1V0pMN_6FyAsMpc,13084
4
4
  kekkai/dojo.py,sha256=erLdTMOioTyzVhXYW8xgdbU5Ro-KQx1OcTQN7_zemmY,18634
5
5
  kekkai/dojo_import.py,sha256=D0ZQM_0JYHqUqJA3l4nKD-RkpvcOcgj-4zv59HRcQ6k,7274
6
6
  kekkai/manifest.py,sha256=Ph5xGDKuVxMW1GVIisRhxUelaiVZQe-W5sZWsq4lHqs,1887
7
- kekkai/output.py,sha256=nPKsf3FjWtWf_nHj4HVpgqeZtLpPOtZoLJElVLSyPK4,5500
7
+ kekkai/output.py,sha256=IJrO36C79WTxCqYp9LEVn5OI4GtPVBWUWH6I-TttfmQ,5426
8
8
  kekkai/paths.py,sha256=EcyG3CEOQFQygowu7O5Mp85dKkXWWvnm1h0j_BetGxY,1190
9
9
  kekkai/policy.py,sha256=0XCUH-SbnO1PsM-exjSFHYHRnLkiNa50QfkyPakwNko,9792
10
10
  kekkai/runner.py,sha256=MBFUiJ4sSVEGNbJ6cv-8p1WHaHqjio6yWEfr_K4GuTs,2037
@@ -61,10 +61,11 @@ kekkai/threatflow/sanitizer.py,sha256=uQsxYZ5VDXutZoj-WMl7fo5T07uHuQZqgVzoVMoaKe
61
61
  kekkai/triage/__init__.py,sha256=gYf4XPIYZTthU0Q0kaptbgMKulkjLxWQWG0HQvtlu-o,2182
62
62
  kekkai/triage/app.py,sha256=MU2tBI50d8sOdDKESGNrWYiREG9bBtrSccaMoiMv5gM,5027
63
63
  kekkai/triage/audit.py,sha256=UVaSKKC6tZkHxEoMcnIZkMOT_ngj7QzHWYuDAHas_sc,5842
64
+ kekkai/triage/fix_screen.py,sha256=mj_waXwKPCrT01bVSSu5Ohi-3JvN2lT18Yy44xICItY,7667
64
65
  kekkai/triage/ignore.py,sha256=uBKM7zKyzORj9LJ5AAnoYWZQTRy57P0ZofSapiDWcfI,7305
65
66
  kekkai/triage/loader.py,sha256=vywhS8fcre7PiBX3H2CpKXFxzvO7LcDnIHIB0kzG3R4,5850
66
67
  kekkai/triage/models.py,sha256=nRmWtELMqHWHX1NqZ2upH2ZAJVeBxa3Wh8f3kkB9WYo,5384
67
- kekkai/triage/screens.py,sha256=6eEiHvuuS_gGESS_K3NjPiQx8G7CR18-j9upU1p5nRg,11004
68
+ kekkai/triage/screens.py,sha256=MbudQkdQ4JFt5c80V3LtqCeXxAIu7nIfZpm7G5wRXT0,11061
68
69
  kekkai/triage/widgets.py,sha256=eOF6Qoo5uBqjxiEkbpgcO1tbIOGBQBKn75wP9Jw_AaE,4733
69
70
  kekkai_core/__init__.py,sha256=gREN4oarM0azTkSTWTnlDnPZGgv1msai2Deq9Frj3gc,122
70
71
  kekkai_core/redaction.py,sha256=EeWYPjAs2hIXlLKGmGn_PRdK08G4KcOBmbRCoFklbHc,2893
@@ -84,8 +85,8 @@ kekkai_core/windows/chocolatey.py,sha256=tF5S5eN-HeENRt6yQ4TZgwng0oRMX_ScskQ3-eb
84
85
  kekkai_core/windows/installer.py,sha256=MePAywHH3JTIAENv52XtkUMOGqmYqZqkH77VW5PST8o,6945
85
86
  kekkai_core/windows/scoop.py,sha256=lvothICrAoB3lGfkvhqVeNTB50eMmVGA0BE7JNCfHdI,5284
86
87
  kekkai_core/windows/validators.py,sha256=45xUuAbHcKc0WLIZ-0rByPeDD88MAV8KvopngyYBHpQ,6525
87
- kekkai_cli-1.1.1.dist-info/METADATA,sha256=_Wt5_uAwnvnEK-Hmc7RxwZozkiwU_6JpLFD_xTpgDTM,11667
88
- kekkai_cli-1.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
89
- kekkai_cli-1.1.1.dist-info/entry_points.txt,sha256=MBV1OIfxJmT2oJvzeeFKIH1eh8M9kKAn7JqFBeuMfWA,43
90
- kekkai_cli-1.1.1.dist-info/top_level.txt,sha256=wWwh7GGPaUjcaCRmt70ueL3WQoQbeGa5L0T0hgOh-MY,19
91
- kekkai_cli-1.1.1.dist-info/RECORD,,
88
+ kekkai_cli-2.0.1.dist-info/METADATA,sha256=WNYk460xPTeXtMnwDW2Z6zDhHysNhltYOS726u-i2q4,8118
89
+ kekkai_cli-2.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
90
+ kekkai_cli-2.0.1.dist-info/entry_points.txt,sha256=MBV1OIfxJmT2oJvzeeFKIH1eh8M9kKAn7JqFBeuMfWA,43
91
+ kekkai_cli-2.0.1.dist-info/top_level.txt,sha256=wWwh7GGPaUjcaCRmt70ueL3WQoQbeGa5L0T0hgOh-MY,19
92
+ kekkai_cli-2.0.1.dist-info/RECORD,,
@@ -1,379 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: kekkai-cli
3
- Version: 1.1.1
4
- Summary: Kekkai 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
-
16
- <p align="center"><strong>Security orchestration at developer speed.</strong></p>
17
- <p align="center"><i>One tool for the entire AppSec lifecycle: Predict, Detect, Triage, Manage.</i></p>
18
-
19
- <p align="center">
20
- <img src="https://img.shields.io/github/actions/workflow/status/kademoslabs/kekkai/docker-publish.yml?logo=github"/>
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?pypiBaseUrl=https%3A%2F%2Fpypi.org&logo=pypi"/>
23
- </p>
24
-
25
- ---
26
-
27
- # Kekkai
28
-
29
- Stop juggling security tools. **Kekkai orchestrates your entire AppSec lifecycle** — from AI-powered threat modeling to vulnerability management — in a single CLI.
30
-
31
- ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-start.gif)
32
-
33
- ---
34
-
35
- ## The Five Pillars
36
-
37
- | Pillar | Feature | Command | Description |
38
- |--------|---------|---------|-------------|
39
- | 🔮 **Predict** | AI Threat Modeling | `kekkai threatflow` | Generate STRIDE threat models before writing code |
40
- | 🔍 **Detect** | Unified Scanning | `kekkai scan` | Run Trivy, Semgrep, Gitleaks in isolated containers |
41
- | ✅ **Triage** | Interactive Review | `kekkai triage` | Review findings in a terminal UI, mark false positives |
42
- | 🚦 **Gate** | CI/CD Policy | `kekkai scan --ci` | Break builds on severity thresholds |
43
- | 📊 **Manage** | DefectDojo | `kekkai dojo up` | Spin up vulnerability management in 60 seconds |
44
-
45
- ---
46
-
47
- ## Quick Start (60 Seconds)
48
-
49
- ### 1. Install
50
-
51
- ```bash
52
- pipx install kekkai-cli
53
- ```
54
-
55
- ### 2. Predict (Threat Model)
56
-
57
- ```bash
58
- kekkai threatflow --repo . --model-mode local
59
- # Generates THREATS.md with STRIDE analysis and Data Flow Diagram
60
- ```
61
-
62
- ### 3. Detect (Scan)
63
-
64
- ```bash
65
- kekkai scan
66
- # Runs Trivy (CVEs), Semgrep (code), Gitleaks (secrets)
67
- # Outputs unified kekkai-report.json
68
- ```
69
-
70
- ### 4. Triage (Review)
71
-
72
- ```bash
73
- kekkai triage
74
- # Interactive TUI to accept, reject, or ignore findings
75
- ```
76
-
77
- ### 5. Manage (DefectDojo)
78
-
79
- ```bash
80
- kekkai dojo up --wait
81
- kekkai upload
82
- # Full vulnerability management platform + automated import
83
- ```
84
-
85
- ---
86
-
87
- ## Why Kekkai?
88
-
89
- | Capability | Manual Approach | Kekkai |
90
- |------------|-----------------|--------|
91
- | **Tooling** | Install/update 5+ tools individually | One binary, auto-pulls scanner containers |
92
- | **Output** | Parse 5 different JSON formats | Unified `kekkai-report.json` |
93
- | **Threat Modeling** | Expensive consultants or whiteboarding | AI-generated `THREATS.md` locally |
94
- | **DefectDojo** | 200-line docker-compose + debugging | `kekkai dojo up` (one command) |
95
- | **Triage** | Read JSON files manually | Interactive terminal UI |
96
- | **CI/CD** | Complex bash scripts | `kekkai scan --ci --fail-on high` |
97
- | **PR Feedback** | Manual security review comments | Auto-comments on GitHub PRs |
98
-
99
- ---
100
-
101
- ## Feature Deep Dives
102
-
103
- ### 🔮 ThreatFlow — AI-Powered Threat Modeling
104
-
105
- Generate STRIDE-aligned threat models and Mermaid.js Data Flow Diagrams from your codebase.
106
-
107
- ![Hero GIF](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/kekkai-threatflow.gif)
108
-
109
- ```bash
110
- # Ollama (recommended - easy setup, privacy-preserving)
111
- ollama pull mistral
112
- kekkai threatflow --repo . --model-mode ollama --model-name mistral
113
-
114
- # Local GGUF model (requires llama-cpp-python)
115
- kekkai threatflow --repo . --model-mode local --model-path ./mistral-7b.gguf
116
-
117
- # Remote API (faster, requires API key)
118
- export KEKKAI_THREATFLOW_API_KEY="sk-..."
119
- kekkai threatflow --repo . --model-mode openai
120
- ```
121
-
122
- **Output:** `THREATS.md` containing:
123
- - Attack surface analysis
124
- - STRIDE threat classification
125
- - Mermaid.js architecture diagram
126
- - Recommended mitigations
127
-
128
- [Full ThreatFlow Documentation →](docs/threatflow/README.md)
129
-
130
- ---
131
-
132
- ### 🔍 Unified Scanning
133
-
134
- Run industry-standard scanners without installing them individually. Each scanner runs in an isolated Docker container with security hardening.
135
-
136
- ```bash
137
- kekkai scan # Scan current directory
138
- kekkai scan --repo /path/to/project # Scan specific path
139
- kekkai scan --output results.json # Custom output path
140
- ```
141
-
142
- **Scanners Included:**
143
- | Scanner | Finds | Image |
144
- |---------|-------|-------|
145
- | Trivy | CVEs in dependencies | `aquasec/trivy:latest` |
146
- | Semgrep | Code vulnerabilities | `semgrep/semgrep:latest` |
147
- | Gitleaks | Hardcoded secrets | `zricethezav/gitleaks:latest` |
148
-
149
- **Container Security:**
150
- - Read-only filesystem
151
- - No network access
152
- - Memory limited (2GB)
153
- - No privilege escalation
154
-
155
- ---
156
-
157
- ### ✅ Interactive Triage TUI
158
-
159
- Stop reading JSON. Review security findings in your terminal.
160
-
161
- ```bash
162
- kekkai triage
163
- ```
164
-
165
- **Features:**
166
- - Navigate findings with keyboard
167
- - Mark as: Accept, Reject, False Positive, Ignore
168
- - Filter by severity, scanner, or status
169
- - Persist decisions in `.kekkai-ignore`
170
- - Export triaged results
171
-
172
- <!-- Screenshot placeholder: ![Triage TUI](https://raw.githubusercontent.com/kademoslabs/assets/main/screenshots/triage-tui.png) -->
173
-
174
- [Full Triage Documentation →](docs/triage/README.md)
175
-
176
- ---
177
-
178
- ### 🚦 CI/CD Policy Gate
179
-
180
- Automate security enforcement in your pipelines.
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
-
186
- ```bash
187
- # Fail on any critical or high findings
188
- kekkai scan --ci --fail-on high
189
-
190
- # Fail only on critical
191
- kekkai scan --ci --fail-on critical
192
-
193
- # Custom threshold: fail on 5+ medium findings
194
- kekkai scan --ci --fail-on medium --max-findings 5
195
- ```
196
-
197
- **Exit Codes:**
198
- | Code | Meaning |
199
- |------|---------|
200
- | 0 | No findings above threshold |
201
- | 1 | Findings exceed threshold |
202
- | 2 | Scanner error |
203
-
204
- **GitHub Actions Example:**
205
-
206
- ```yaml
207
- - name: Security Scan
208
- run: |
209
- pipx install kekkai-cli
210
- kekkai scan --ci --fail-on high
211
- ```
212
-
213
- [Full CI Documentation →](docs/ci/ci-mode.md)
214
-
215
- ---
216
-
217
- ### 📊 DefectDojo Integration
218
-
219
- Spin up a complete vulnerability management platform locally.
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
-
225
- ```bash
226
- kekkai dojo up --wait # Start DefectDojo (Nginx, Postgres, Redis, Celery)
227
- kekkai dojo status # Check service health
228
- kekkai upload # Import scan results
229
- kekkai dojo down # Stop and clean up (removes volumes)
230
- ```
231
-
232
- **What You Get:**
233
- - DefectDojo web UI at `http://localhost:8080`
234
- - Automatic credential generation
235
- - Pre-configured for Kekkai imports
236
- - Clean teardown (no orphaned volumes)
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
-
246
- [Full Dojo Documentation →](docs/dojo/dojo.md)
247
-
248
- ---
249
-
250
- ### 🔔 GitHub PR Comments
251
-
252
- Get security feedback directly in pull requests.
253
-
254
- ```bash
255
- export GITHUB_TOKEN="ghp_..."
256
- kekkai scan --github-comment
257
- ```
258
-
259
- Kekkai will:
260
- 1. Run all scanners
261
- 2. Post findings as PR review comments
262
- 3. Annotate specific lines with inline comments
263
-
264
- ---
265
-
266
- ## Installation
267
-
268
- ### pipx (Recommended)
269
-
270
- Isolated environment, no conflicts with system Python.
271
-
272
- ```bash
273
- pipx install kekkai-cli
274
- ```
275
-
276
- ### Homebrew (macOS/Linux)
277
-
278
- ```bash
279
- brew install kademoslabs/tap/kekkai
280
- ```
281
-
282
- ### Scoop (Windows)
283
-
284
- ```bash
285
- scoop bucket add kademoslabs https://github.com/kademoslabs/scoop-bucket
286
- scoop install kekkai
287
- ```
288
-
289
- ### Docker (No Python Required)
290
-
291
- ```bash
292
- docker pull kademoslabs/kekkai:latest
293
- alias kekkai='docker run --rm -v "$(pwd):/repo" kademoslabs/kekkai:latest'
294
- ```
295
-
296
- ### pip (Traditional)
297
-
298
- ```bash
299
- pip install kekkai-cli
300
- ```
301
-
302
- ---
303
-
304
- ## Enterprise Features
305
-
306
- For organizations that need advanced capabilities, **Kekkai Enterprise** provides:
307
-
308
- | Feature | Description |
309
- |---------|-------------|
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 |
315
- | **Audit Logging** | Cryptographically signed compliance trails |
316
-
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
322
-
323
- [Contact us for enterprise access →](mailto:sales@kademos.org)
324
-
325
- ---
326
-
327
- ## Security
328
-
329
- Kekkai is designed with security as a core principle:
330
-
331
- - **Container Isolation**: Scanners run in hardened Docker containers
332
- - **No Network Access**: Containers cannot reach external networks
333
- - **Local-First AI**: ThreatFlow can run entirely on your machine
334
- - **SLSA Level 3**: Release artifacts include provenance attestations
335
- - **Signed Images**: Docker images are Cosign-signed
336
-
337
- For vulnerability reports, see [SECURITY.md](SECURITY.md).
338
-
339
- ---
340
-
341
- ## Documentation
342
-
343
- | Guide | Description |
344
- |-------|-------------|
345
- | [Installation](docs/README.md#installation-methods) | All installation methods |
346
- | [ThreatFlow](docs/threatflow/README.md) | AI threat modeling setup |
347
- | [Dojo Quick Start](docs/dojo/dojo-quickstart.md) | DefectDojo in 5 minutes |
348
- | [CI Mode](docs/ci/ci-mode.md) | Pipeline integration |
349
- | [Portal](docs/portal/README.md) | Enterprise features overview |
350
- | [Portal SSO](docs/portal/saml-setup.md) | SAML 2.0 SSO configuration |
351
- | [Portal RBAC](docs/portal/rbac.md) | Role-based access control |
352
- | [Portal Deployment](docs/portal/deployment.md) | Self-hosted deployment |
353
- | [Security](docs/security/slsa-provenance.md) | SLSA provenance verification |
354
-
355
- ---
356
-
357
- ## CI/CD Status
358
-
359
- [![Kekkai Security Scan](https://github.com/kademoslabs/kekkai/actions/workflows/kekkai-pr-scan.yml/badge.svg)](https://github.com/kademoslabs/kekkai/actions/workflows/kekkai-pr-scan.yml)
360
- [![Docker Image Publish](https://github.com/kademoslabs/kekkai/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/kademoslabs/kekkai/actions/workflows/docker-publish.yml)
361
- [![Docker Security Scan](https://github.com/kademoslabs/kekkai/actions/workflows/docker-security-scan.yml/badge.svg)](https://github.com/kademoslabs/kekkai/actions/workflows/docker-security-scan.yml)
362
- [![Cross-Platform Tests](https://github.com/kademoslabs/kekkai/actions/workflows/test-cross-platform.yml/badge.svg)](https://github.com/kademoslabs/kekkai/actions/workflows/test-cross-platform.yml)
363
- [![Release with SLSA Provenance](https://github.com/kademoslabs/kekkai/actions/workflows/release-slsa.yml/badge.svg)](https://github.com/kademoslabs/kekkai/actions/workflows/release-slsa.yml)
364
-
365
- ---
366
-
367
- ## Contributing
368
-
369
- We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
370
-
371
- ---
372
-
373
- ## License
374
-
375
- Apache-2.0 — See [LICENSE](LICENSE) for details.
376
-
377
- ---
378
-
379
- <p align="center"><i>Built by <a href="https://kademos.org">Kademos Labs</a></i></p>