kekkai-cli 1.0.3__py3-none-any.whl → 1.0.4__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
@@ -16,11 +16,10 @@ from .output import (
16
16
  VERSION,
17
17
  ScanSummaryRow,
18
18
  console,
19
- print_quick_start,
19
+ print_dashboard,
20
20
  print_scan_summary,
21
21
  sanitize_error,
22
22
  sanitize_for_terminal,
23
- splash,
24
23
  )
25
24
  from .paths import app_base_dir, config_path, ensure_dir, is_within_base, safe_join
26
25
  from .policy import (
@@ -259,10 +258,7 @@ def _handle_no_args() -> int:
259
258
  cfg_path = config_path()
260
259
  if not cfg_path.exists():
261
260
  return _command_init(None, False)
262
- console.print(splash())
263
- console.print("Config exists. Run one of:")
264
- console.print(" [green]kekkai scan[/green]")
265
- console.print(" [green]kekkai init --force[/green]")
261
+ print_dashboard()
266
262
  return 0
267
263
 
268
264
 
@@ -278,9 +274,8 @@ def _command_init(config_override: str | None, force: bool) -> int:
278
274
  ensure_dir(cfg_path.parent)
279
275
 
280
276
  cfg_path.write_text(load_config_text(base_dir))
281
- console.print(splash())
282
- console.print(f"Initialized config at [cyan]{cfg_path}[/cyan]")
283
- console.print(print_quick_start())
277
+ print_dashboard()
278
+ console.print(f"\n[success]Initialized config at[/success] [cyan]{cfg_path}[/cyan]\n")
284
279
  return 0
285
280
 
286
281
 
kekkai/output.py CHANGED
@@ -11,9 +11,9 @@ from dataclasses import dataclass
11
11
  from typing import TYPE_CHECKING
12
12
 
13
13
  from rich import box
14
- from rich.align import Align
15
- from rich.console import Console
16
- from rich.panel import Panel
14
+ from rich.console import Console, Group
15
+ from rich.padding import Padding
16
+ from rich.rule import Rule
17
17
  from rich.table import Table
18
18
  from rich.text import Text
19
19
  from rich.theme import Theme
@@ -23,12 +23,13 @@ if TYPE_CHECKING:
23
23
 
24
24
  __all__ = [
25
25
  "console",
26
- "splash",
27
- "print_splash",
26
+ "print_dashboard",
28
27
  "print_scan_summary",
29
28
  "sanitize_for_terminal",
30
29
  "sanitize_error",
31
30
  "ScanSummaryRow",
31
+ "VERSION",
32
+ "splash",
32
33
  ]
33
34
 
34
35
  ANSI_ESCAPE_PATTERN = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]")
@@ -36,114 +37,88 @@ ANSI_ESCAPE_PATTERN = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]")
36
37
  KEKKAI_THEME = Theme(
37
38
  {
38
39
  "info": "dim cyan",
39
- "warning": "magenta",
40
+ "warning": "yellow",
40
41
  "danger": "bold red",
41
42
  "success": "bold green",
42
43
  "header": "bold white",
43
- "title": "bold cyan",
44
- "text": "white",
45
44
  "muted": "dim white",
46
45
  "brand": "bold cyan",
46
+ "command": "bold white",
47
+ "desc": "dim white",
47
48
  }
48
49
  )
49
50
 
50
51
  console = Console(theme=KEKKAI_THEME)
51
52
 
52
53
  BANNER_ASCII = r"""
53
- ██ ▄█▀▓█████ ██ ▄█▀ ██ ▄█▀▄▄▄ ██▓
54
- ██▄█▒ ▓█ ▀ ██▄█▒ ██▄█▒▒████▄ ▓██▒
55
- ▓███▄░ ▒███ ▓███▄░ ▓███▄░▒██ ▀█▄ ▒██▒
56
- ▓██ █▄ ▒▓█ ▄ ▓██ █▄ ▓██ █▄░██▄▄▄▄██ ░██░
57
- ▒██▒ █▄░▒████▒▒██▒ █▄▒██▒ █▄▓█ ▓██▒░██░
58
- ▒ ▒▒ ▓▒░░ ▒░ ░▒ ▒▒ ▓▒▒ ▒▒ ▓▒▒▒ ▓▒█░░▓
59
- ░ ░▒ ▒░ ░ ░ ░░ ░▒ ▒░░ ░▒ ▒░ ▒ ▒▒ ░ ▒ ░
60
- ░ ░░ ░ ░ ░ ░░ ░ ░ ░░ ░ ░ ▒
54
+ __ __ __ _
55
+ / /_____ / /__/ /_____ _(_)
56
+ / '_/ _ \/ '_/ '_/ _ `/ /
57
+ /_/\_\\___/_/\_/_/\_\\_,_/_/
61
58
  """
62
59
 
63
- VERSION = "1.0.3"
64
-
60
+ VERSION = "1.0.4"
65
61
 
66
- def print_splash() -> None:
67
- """Print the Kekkai splash screen with menu and tips."""
68
- header_text = Text(BANNER_ASCII, style="header")
69
- subtitle = Text("Local-first AppSec Orchestrator", style="info")
70
- subtitle.justify = "center"
71
-
72
- header_panel = Panel(
73
- Align.center(Text.assemble(header_text, "\n", subtitle)),
74
- box=box.HEAVY,
75
- style="info",
76
- padding=(1, 2),
77
- )
78
62
 
79
- menu_table = Table(box=box.SIMPLE, show_header=False, padding=(0, 2), expand=True)
80
- menu_table.add_column("Command", style="title", ratio=1)
81
- menu_table.add_column("Description", style="text", ratio=3)
63
+ def print_dashboard() -> None:
64
+ """Render the professional Kekkai dashboard."""
65
+ if not console.is_terminal:
66
+ print(f"Kekkai v{VERSION} - Local-First AppSec Orchestrator")
67
+ return
82
68
 
83
- menu_table.add_row("kekkai scan", "Run a comprehensive security scan in the current directory.")
84
- menu_table.add_row("kekkai dojo", "Interact with your DefectDojo instance (import/export).")
85
- menu_table.add_row("kekkai report", "Generate compliance and audit reports.")
86
- menu_table.add_row("kekkai config", "Configure local settings and API keys.")
69
+ header_table = Table.grid(padding=(0, 2), expand=False)
87
70
 
88
- menu_panel = Panel(
89
- menu_table,
90
- title="[header]COMMAND MENU[/]",
91
- border_style="dim cyan",
92
- padding=(1, 2),
93
- )
71
+ logo = Text(BANNER_ASCII.strip("\n"), style="brand")
94
72
 
95
- tips_content = Text()
96
- tips_content.append("Best Practices:\n", style="warning")
97
- tips_content.append(" - Run scans locally before pushing to CI to save time.\n", style="text")
98
- tips_content.append(" - Use .kekkaiignore to filter out known false positives.\n", style="text")
99
- tips_content.append(
100
- " - Keep your CLI updated to catch the latest CVE signatures.\n\n", style="text"
101
- )
73
+ meta = Text()
74
+ meta.append(f"\nv{VERSION}", style="muted")
75
+ meta.append("\nLocal-First AppSec Orchestrator", style="bold white")
76
+ meta.append("\nhttps://github.com/kademoslabs/kekkai", style="blue link")
102
77
 
103
- tips_content.append("Open Source:\n", style="success")
104
- tips_content.append(
105
- " We are looking for collaborators! Star us on GitHub or submit a PR.\n\n", style="text"
106
- )
78
+ header_table.add_row(logo, meta)
107
79
 
108
- tips_content.append("Enterprise Features:\n", style="danger")
109
- tips_content.append(
110
- " ThreatFlow visualization and RBAC require an active Enterprise license.", style="text"
80
+ menu_table = Table(
81
+ box=None,
82
+ padding=(0, 2),
83
+ show_header=True,
84
+ header_style="dim cyan",
85
+ expand=True,
111
86
  )
112
-
113
- tips_panel = Panel(
114
- tips_content,
115
- title="[header]QUICK TIPS & INFO[/]",
116
- border_style="dim cyan",
117
- padding=(1, 2),
87
+ menu_table.add_column("Command", style="command", ratio=1)
88
+ menu_table.add_column("Description", style="desc", ratio=3)
89
+
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
+ menu_table.add_row("kekkai triage", "Interactive finding review (TUI)")
94
+ menu_table.add_row("kekkai report", "Generate compliance reports")
95
+ menu_table.add_row("kekkai config", "Manage settings and keys")
96
+
97
+ tips_grid = Table.grid(padding=(0, 1))
98
+ tips_grid.add_row("⚡", "[dim]Run scans locally before pushing to CI to save time.[/dim]")
99
+ tips_grid.add_row("🔒", "[dim]ThreatFlow requires an API key for remote models.[/dim]")
100
+ tips_grid.add_row("🤝", "[dim]Star us on GitHub to support open source development.[/dim]")
101
+
102
+ dashboard = Group(
103
+ Padding(header_table, (1, 1, 1, 1)),
104
+ Rule(style="dim cyan"),
105
+ Padding(menu_table, (1, 2)),
106
+ Rule(style="dim cyan"),
107
+ Padding(tips_grid, (1, 2, 1, 2)),
108
+ Text("\n"),
118
109
  )
119
110
 
120
- console.print(header_panel)
121
- console.print(menu_panel)
122
- console.print(tips_panel)
123
- console.print()
111
+ console.print(dashboard)
124
112
 
125
113
 
126
114
  def splash(*, force_plain: bool = False) -> str:
127
- """Render the Kekkai splash banner.
128
-
129
- Args:
130
- force_plain: If True, return plain text regardless of TTY.
131
-
132
- Returns:
133
- Banner string for display.
134
- """
135
- if force_plain or not console.is_terminal:
136
- return f"Kekkai v{VERSION} - Local-First AppSec Orchestrator"
137
-
138
- with console.capture() as capture:
139
- print_splash()
140
- result: str = capture.get()
141
- return result
115
+ """Deprecated: Use print_dashboard() instead."""
116
+ return f"Kekkai v{VERSION} - Local-First AppSec Orchestrator"
142
117
 
143
118
 
144
- def splash_minimal() -> str:
145
- """Return minimal splash for non-TTY environments."""
146
- return f"Kekkai v{VERSION} - Local-First AppSec Orchestrator"
119
+ def print_quick_start() -> str:
120
+ """Deprecated: Content moved to print_dashboard()."""
121
+ return ""
147
122
 
148
123
 
149
124
  @dataclass
@@ -161,15 +136,7 @@ def print_scan_summary(
161
136
  *,
162
137
  force_plain: bool = False,
163
138
  ) -> str:
164
- """Render scan results as a formatted table.
165
-
166
- Args:
167
- rows: Scan result rows to display.
168
- force_plain: If True, return plain text regardless of TTY.
169
-
170
- Returns:
171
- Formatted table string.
172
- """
139
+ """Render scan results as a formatted table."""
173
140
  if force_plain or not console.is_terminal:
174
141
  lines = ["Scan Summary:"]
175
142
  for row in rows:
@@ -180,7 +147,7 @@ def print_scan_summary(
180
147
  )
181
148
  return "\n".join(lines)
182
149
 
183
- table = Table(title="Scan Summary", show_header=True, header_style="bold")
150
+ table = Table(title="Scan Summary", show_header=True, header_style="bold", box=box.SIMPLE)
184
151
  table.add_column("Scanner", style="cyan")
185
152
  table.add_column("Status", style="green")
186
153
  table.add_column("Findings", justify="right")
@@ -202,33 +169,12 @@ def print_scan_summary(
202
169
 
203
170
 
204
171
  def sanitize_for_terminal(text: str) -> str:
205
- """Strip ANSI escape sequences from untrusted content.
206
-
207
- Prevents terminal escape injection attacks where malicious content
208
- could manipulate terminal display or hide warnings.
209
-
210
- Args:
211
- text: Potentially untrusted text to sanitize.
212
-
213
- Returns:
214
- Text with all ANSI escape sequences removed.
215
- """
172
+ """Strip ANSI escape sequences from untrusted content."""
216
173
  return ANSI_ESCAPE_PATTERN.sub("", text)
217
174
 
218
175
 
219
176
  def sanitize_error(error: str | Exception, *, max_length: int = 200) -> str:
220
- """Sanitize error messages for user display.
221
-
222
- Removes sensitive information like full paths and stack traces
223
- to prevent information disclosure.
224
-
225
- Args:
226
- error: Error message or exception to sanitize.
227
- max_length: Maximum length of returned message.
228
-
229
- Returns:
230
- Sanitized, truncated error message.
231
- """
177
+ """Sanitize error messages for user display."""
232
178
  message = str(error) if isinstance(error, Exception) else error
233
179
  message = ANSI_ESCAPE_PATTERN.sub("", message)
234
180
  message = re.sub(r"/[^\s:]+", "[path]", message)
@@ -239,41 +185,3 @@ def sanitize_error(error: str | Exception, *, max_length: int = 200) -> str:
239
185
  message = message[:max_length] + "..."
240
186
 
241
187
  return message
242
-
243
-
244
- def print_quick_start() -> str:
245
- """Render Quick Start guide panel.
246
-
247
- Returns:
248
- Formatted Quick Start panel string.
249
- """
250
- if not console.is_terminal:
251
- return (
252
- "Quick Start:\n"
253
- " 1. kekkai scan --repo . # Scan current directory\n"
254
- " 2. kekkai threatflow # Generate threat model\n"
255
- " 3. kekkai dojo up # Start DefectDojo\n"
256
- )
257
-
258
- content = Text()
259
- content.append("1. ", style="bold cyan")
260
- content.append("kekkai scan --repo .", style="green")
261
- content.append(" # Scan current directory\n")
262
- content.append("2. ", style="bold cyan")
263
- content.append("kekkai threatflow", style="green")
264
- content.append(" # Generate threat model\n")
265
- content.append("3. ", style="bold cyan")
266
- content.append("kekkai dojo up", style="green")
267
- content.append(" # Start DefectDojo")
268
-
269
- panel = Panel(
270
- content,
271
- title="[bold]Quick Start[/bold]",
272
- border_style="green",
273
- padding=(1, 2),
274
- )
275
-
276
- with console.capture() as capture:
277
- console.print(panel)
278
- result: str = capture.get()
279
- return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kekkai-cli
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Kekkai monorepo (local-first AppSec orchestration + compliance checker)
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -1,10 +1,10 @@
1
1
  kekkai/__init__.py,sha256=_VrBvJRyqHiXs31S8HOhATk_O2iy-ac0_9X7rHH75j8,143
2
- kekkai/cli.py,sha256=u-5GHXUT9G8Np-5SOLbSTtebQDv8yFYYCFZAjiDAAWU,35903
2
+ kekkai/cli.py,sha256=f_IsxjlmzYKwl_x_BNIlVYBnBnSNfKskwclJdGwhWAo,35705
3
3
  kekkai/config.py,sha256=LE7bKsmv5dim5KnZya0V7_LtviNQ1V0pMN_6FyAsMpc,13084
4
4
  kekkai/dojo.py,sha256=DchLaTnDBwX0D14lTRdCtwql_II8aDEZ0JEq9F-n4MI,15887
5
5
  kekkai/dojo_import.py,sha256=oI-vwpLITA7-U2_MxhaTp_PYfr5HqvcFy3VzKsWA6IY,6911
6
6
  kekkai/manifest.py,sha256=Ph5xGDKuVxMW1GVIisRhxUelaiVZQe-W5sZWsq4lHqs,1887
7
- kekkai/output.py,sha256=1YdWLzyRtdaH6cn24JB8S0JadyDCqcZTu91zRlOmAFw,8731
7
+ kekkai/output.py,sha256=IJUZJK_Txhs7WPtSjtAR1eLes5Oqv2X7M8E3wmTO35M,5572
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
@@ -83,8 +83,8 @@ portal/ops/monitoring.py,sha256=xhLbKjVaob709K4x0dEsOo4lh7Ddm2A4UE2ZmhfmMtI,1790
83
83
  portal/ops/restore.py,sha256=rgzKoBIilgoPPv5gZhSSBuLKG1skKw5ryoCRR3d7CPQ,17058
84
84
  portal/ops/secrets.py,sha256=wu2bUfJGctbGjyuGUgvUc_Y6IH1SCW16dExtqcKu_kg,14338
85
85
  portal/ops/upgrade.py,sha256=fXsIXCJYYABdWDECDXkt7F2PidzNtO6Zr-g0Y5PLlVU,20106
86
- kekkai_cli-1.0.3.dist-info/METADATA,sha256=kX8rUv9yPg47h93pkmuzwrakY2UXJUvTAG0kUP27ASM,3652
87
- kekkai_cli-1.0.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
88
- kekkai_cli-1.0.3.dist-info/entry_points.txt,sha256=WUEX6IISnRcwlQAdhisPfIIV3Us2MYCwtJoyPpLJO44,75
89
- kekkai_cli-1.0.3.dist-info/top_level.txt,sha256=u0J4T-Rnb0cgs0LfzZAUNt6nx1d5l7wKn8vOuo9FBEY,26
90
- kekkai_cli-1.0.3.dist-info/RECORD,,
86
+ kekkai_cli-1.0.4.dist-info/METADATA,sha256=1pSlurcZ2U9rmTL-lu0cZwDrr8v0eWJZwQKlBXxIW7s,3652
87
+ kekkai_cli-1.0.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
88
+ kekkai_cli-1.0.4.dist-info/entry_points.txt,sha256=WUEX6IISnRcwlQAdhisPfIIV3Us2MYCwtJoyPpLJO44,75
89
+ kekkai_cli-1.0.4.dist-info/top_level.txt,sha256=u0J4T-Rnb0cgs0LfzZAUNt6nx1d5l7wKn8vOuo9FBEY,26
90
+ kekkai_cli-1.0.4.dist-info/RECORD,,