kbve 0.1.0__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.
kbve-0.1.0/.flake8 ADDED
@@ -0,0 +1,14 @@
1
+ [flake8]
2
+ exclude =
3
+ .git,
4
+ __pycache__,
5
+ build,
6
+ dist,
7
+ .tox,
8
+ venv,
9
+ .venv,
10
+ .pytest_cache
11
+ max-line-length = 120
12
+ extend-ignore = E203, E221
13
+ per-file-ignores =
14
+ kbve/proto/*_pb2*.py: E501, E303, F401, E261, W504, E302, W291, E271, E211, E111, E225, E231, F541, E114, E128
@@ -0,0 +1 @@
1
+ 3.12
kbve-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,57 @@
1
+ Metadata-Version: 2.4
2
+ Name: kbve
3
+ Version: 0.1.0
4
+ Summary: KBVE - API layer and complexity handler for async HTTP, WebSocket, gRPC, and broadcasting
5
+ License-Expression: LicenseRef-Proprietary
6
+ Requires-Python: <3.14,>=3.12
7
+ Requires-Dist: aiohappyeyeballs==2.6.1
8
+ Requires-Dist: aiohttp==3.13.3
9
+ Requires-Dist: aiosignal==1.4.0
10
+ Requires-Dist: annotated-doc==0.0.4
11
+ Requires-Dist: annotated-types==0.7.0
12
+ Requires-Dist: anyio==4.12.1
13
+ Requires-Dist: attrs==25.4.0
14
+ Requires-Dist: click==8.3.1
15
+ Requires-Dist: colorama==0.4.6; sys_platform == 'win32'
16
+ Requires-Dist: fastapi==0.128.7
17
+ Requires-Dist: frozenlist==1.8.0
18
+ Requires-Dist: grpcio==1.78.0
19
+ Requires-Dist: h11==0.16.0
20
+ Requires-Dist: httptools==0.7.1
21
+ Requires-Dist: idna==3.11
22
+ Requires-Dist: multidict==6.7.1
23
+ Requires-Dist: propcache==0.4.1
24
+ Requires-Dist: protobuf==5.29.6
25
+ Requires-Dist: pydantic-core==2.41.5
26
+ Requires-Dist: pydantic==2.12.5
27
+ Requires-Dist: python-dotenv==1.2.1
28
+ Requires-Dist: pyyaml==6.0.3
29
+ Requires-Dist: starlette==0.52.1
30
+ Requires-Dist: typing-extensions==4.15.0
31
+ Requires-Dist: typing-inspection==0.4.2
32
+ Requires-Dist: uvicorn==0.40.0
33
+ Requires-Dist: uvloop==0.22.1; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'
34
+ Requires-Dist: watchfiles==1.1.1
35
+ Requires-Dist: websockets==16.0
36
+ Requires-Dist: yarl==1.22.0
37
+ Description-Content-Type: text/markdown
38
+
39
+ # kbve
40
+
41
+ API layer and complexity handler for async HTTP, WebSocket, gRPC, and broadcasting.
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ pip install kbve
47
+ ```
48
+
49
+ ## Development
50
+
51
+ This package is part of the [KBVE](https://github.com/kbve/kbve) monorepo, managed with Nx and Poetry.
52
+
53
+ ```bash
54
+ pnpm nx test python-kbve
55
+ pnpm nx lint python-kbve
56
+ pnpm nx build python-kbve
57
+ ```
kbve-0.1.0/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # kbve
2
+
3
+ API layer and complexity handler for async HTTP, WebSocket, gRPC, and broadcasting.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install kbve
9
+ ```
10
+
11
+ ## Development
12
+
13
+ This package is part of the [KBVE](https://github.com/kbve/kbve) monorepo, managed with Nx and Poetry.
14
+
15
+ ```bash
16
+ pnpm nx test python-kbve
17
+ pnpm nx lint python-kbve
18
+ pnpm nx build python-kbve
19
+ ```
@@ -0,0 +1,10 @@
1
+ """KBVE - Core library for async servers, Nx workspace tooling, and MDX rendering."""
2
+
3
+ from .models.server_models import ServerConfig # noqa: F401
4
+ from .server.app_server import AppServer # noqa: F401
5
+ from .server.grpc_server import GrpcServer # noqa: F401
6
+ from .server.http_server import HttpServer # noqa: F401
7
+ from .server.services.health_service import HealthServicer # noqa: F401
8
+ from .server.services.echo_service import EchoServicer # noqa: F401
9
+
10
+ __version__ = "0.1.0"
@@ -0,0 +1 @@
1
+ """KBVE API utilities."""
@@ -0,0 +1 @@
1
+ """KBVE API clients."""
@@ -0,0 +1 @@
1
+ """KBVE API utilities."""
@@ -0,0 +1,4 @@
1
+ """KBVE MDX/Starlight rendering primitives."""
2
+
3
+ from .escape import escape_mdx # noqa: F401
4
+ from .renderer import MdxWriter # noqa: F401
@@ -0,0 +1,14 @@
1
+ """MDX/JSX text escaping utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ def escape_mdx(text: str) -> str:
7
+ """Escape characters that MDX/JSX would interpret as markup."""
8
+ return (text
9
+ .replace("&", "&amp;")
10
+ .replace("<", "&lt;")
11
+ .replace(">", "&gt;")
12
+ .replace("{", "&#123;")
13
+ .replace("}", "&#125;")
14
+ .replace("|", "\\|"))
@@ -0,0 +1,220 @@
1
+ """Starlight MDX rendering primitives.
2
+
3
+ Provides ``MdxWriter``, a composable builder for generating Astro Starlight
4
+ MDX pages with frontmatter, cards, tabs, mermaid diagrams, tables, and
5
+ admonitions.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import io
11
+ from typing import Any
12
+
13
+
14
+ class MdxWriter:
15
+ """Composable builder for Starlight MDX content.
16
+
17
+ Usage::
18
+
19
+ w = MdxWriter()
20
+ w.frontmatter(title="My Page", description="A page.")
21
+ w.imports("Card", "CardGrid", source="@astrojs/starlight/components")
22
+ w.heading("Hello", level=2)
23
+ w.admonition("note", "Auto-generated", "Some body text.")
24
+ w.card_grid_start()
25
+ w.card("3 Apps", icon="rocket", body="app1, app2, app3")
26
+ w.card_grid_end()
27
+ w.mermaid_pie("Title", {"Apps": 3, "Libs": 5})
28
+ w.table(["Col A", "Col B"], [["a", "b"]])
29
+ content = w.render()
30
+ """
31
+
32
+ def __init__(self) -> None:
33
+ self._buf = io.StringIO()
34
+
35
+ # ── Frontmatter ──────────────────────────────────────────────
36
+
37
+ def frontmatter(self, **kwargs: Any) -> "MdxWriter":
38
+ """Write YAML frontmatter block.
39
+
40
+ Supports flat keys and one level of nesting via dict values::
41
+
42
+ w.frontmatter(
43
+ title="Page",
44
+ sidebar={"label": "Nav", "order": 1},
45
+ )
46
+ """
47
+ colon = ":"
48
+ self._buf.write("---\n")
49
+ for key, val in kwargs.items():
50
+ if isinstance(val, dict):
51
+ self._buf.write(f"{key}{colon}\n")
52
+ for k, v in val.items():
53
+ if isinstance(v, str) and "\n" in v:
54
+ self._buf.write(f" {k}{colon} |\n")
55
+ for line in v.splitlines():
56
+ self._buf.write(f" {line}\n")
57
+ else:
58
+ self._buf.write(f" {k}{colon} {v}\n")
59
+ elif isinstance(val, bool):
60
+ bval = "true" if val else "false"
61
+ self._buf.write(f"{key}{colon} {bval}\n")
62
+ else:
63
+ self._buf.write(f"{key}{colon} {val}\n")
64
+ self._buf.write("---\n\n")
65
+ return self
66
+
67
+ # ── Imports ──────────────────────────────────────────────────
68
+
69
+ def imports(self, *components: str, source: str) -> "MdxWriter":
70
+ """Write an ESM import statement."""
71
+ names = ", ".join(components)
72
+ lbrace = "{"
73
+ rbrace = "}"
74
+ semi = ";"
75
+ self._buf.write(
76
+ f"import {lbrace} {names} {rbrace} from '{source}'{semi}\n\n"
77
+ )
78
+ return self
79
+
80
+ # ── Headings & text ──────────────────────────────────────────
81
+
82
+ def heading(self, text: str, level: int = 2) -> "MdxWriter":
83
+ prefix = "#" * level
84
+ self._buf.write(f"{prefix} {text}\n\n")
85
+ return self
86
+
87
+ def text(self, content: str) -> "MdxWriter":
88
+ self._buf.write(f"{content}\n\n")
89
+ return self
90
+
91
+ def raw(self, content: str) -> "MdxWriter":
92
+ """Write raw content without trailing newlines."""
93
+ self._buf.write(content)
94
+ return self
95
+
96
+ # ── Admonitions ──────────────────────────────────────────────
97
+
98
+ def admonition(
99
+ self, kind: str, title: str, body: str,
100
+ ) -> "MdxWriter":
101
+ """Write a Starlight admonition (note, tip, caution, danger)."""
102
+ prefix = ":" * 3
103
+ self._buf.write(
104
+ f"{prefix}{kind}[{title}]\n{body}\n{prefix}\n\n"
105
+ )
106
+ return self
107
+
108
+ # ── Cards ────────────────────────────────────────────────────
109
+
110
+ def card_grid_start(self) -> "MdxWriter":
111
+ self._buf.write("<CardGrid>\n")
112
+ return self
113
+
114
+ def card_grid_end(self) -> "MdxWriter":
115
+ self._buf.write("</CardGrid>\n\n")
116
+ return self
117
+
118
+ def card(
119
+ self, title: str, icon: str, body: str,
120
+ ) -> "MdxWriter":
121
+ line1 = f' <Card title="{title}" icon="{icon}">'
122
+ line2 = f" {body}"
123
+ self._buf.write(f"{line1}\n{line2}\n </Card>\n")
124
+ return self
125
+
126
+ # ── Tabs ─────────────────────────────────────────────────────
127
+
128
+ def tabs_start(self) -> "MdxWriter":
129
+ self._buf.write("<Tabs>\n")
130
+ return self
131
+
132
+ def tabs_end(self) -> "MdxWriter":
133
+ self._buf.write("</Tabs>\n\n")
134
+ return self
135
+
136
+ def tab_start(self, label: str) -> "MdxWriter":
137
+ tag = f' <TabItem label="{label}">'
138
+ self._buf.write(f"{tag}\n\n")
139
+ return self
140
+
141
+ def tab_end(self) -> "MdxWriter":
142
+ self._buf.write(" </TabItem>\n")
143
+ return self
144
+
145
+ # ── Mermaid ──────────────────────────────────────────────────
146
+
147
+ def mermaid_pie(
148
+ self, title: str, data: dict[str, int | float],
149
+ ) -> "MdxWriter":
150
+ """Write a Mermaid pie chart."""
151
+ self._buf.write("```mermaid\npie showData\n")
152
+ self._buf.write(f" title {title}\n")
153
+ for label, value in data.items():
154
+ if value > 0:
155
+ self._buf.write(
156
+ ' "' + label + '" : ' + str(value) + '\n'
157
+ )
158
+ self._buf.write("```\n\n")
159
+ return self
160
+
161
+ def mermaid_graph(self, lines: list[str]) -> "MdxWriter":
162
+ """Write a raw Mermaid graph block."""
163
+ self._buf.write("```mermaid\n")
164
+ self._buf.write("\n".join(lines))
165
+ self._buf.write("\n```\n\n")
166
+ return self
167
+
168
+ # ── Tables ───────────────────────────────────────────────────
169
+
170
+ def table(
171
+ self,
172
+ headers: list[str],
173
+ rows: list[list[str]],
174
+ alignments: list[str] | None = None,
175
+ ) -> "MdxWriter":
176
+ """Write a Markdown table.
177
+
178
+ ``alignments`` can contain ``"left"``, ``"center"``, or ``"right"``
179
+ per column. Defaults to left-aligned.
180
+ """
181
+ if alignments is None:
182
+ alignments = ["left"] * len(headers)
183
+
184
+ sep_map = {
185
+ "left": "---",
186
+ "center": ":---:",
187
+ "right": "---:",
188
+ }
189
+ header_line = "| " + " | ".join(headers) + " |"
190
+ sep_line = "| " + " | ".join(
191
+ sep_map.get(a, "---") for a in alignments
192
+ ) + " |"
193
+
194
+ self._buf.write(header_line + "\n")
195
+ self._buf.write(sep_line + "\n")
196
+ for row in rows:
197
+ self._buf.write("| " + " | ".join(row) + " |\n")
198
+ self._buf.write("\n")
199
+ return self
200
+
201
+ # ── Details / collapsible ────────────────────────────────────
202
+
203
+ def details_start(self, summary: str) -> "MdxWriter":
204
+ self._buf.write(f"<details>\n<summary>{summary}</summary>\n\n")
205
+ return self
206
+
207
+ def details_end(self) -> "MdxWriter":
208
+ self._buf.write("\n</details>\n\n")
209
+ return self
210
+
211
+ # ── Render ───────────────────────────────────────────────────
212
+
213
+ def render(self) -> str:
214
+ """Return the accumulated MDX content as a string."""
215
+ return self._buf.getvalue()
216
+
217
+ def write_to(self, path: str) -> None:
218
+ """Write the accumulated MDX content to a file."""
219
+ with open(path, "w") as f:
220
+ f.write(self.render())
@@ -0,0 +1,3 @@
1
+ """KBVE models."""
2
+
3
+ from .server_models import ServerConfig # noqa: F401
@@ -0,0 +1,13 @@
1
+ """Server configuration models."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class ServerConfig(BaseModel):
7
+ """Configuration for the unified HTTP + gRPC server."""
8
+
9
+ http_host: str = "0.0.0.0"
10
+ http_port: int = 8000
11
+ grpc_host: str = "0.0.0.0"
12
+ grpc_port: int = 50051
13
+ log_level: str = "info"
@@ -0,0 +1,20 @@
1
+ """KBVE Nx workspace integrations — graph analysis and security auditing."""
2
+
3
+ from .graph import ( # noqa: F401
4
+ parse_graph,
5
+ group_projects_by_type,
6
+ collect_edges,
7
+ top_hubs,
8
+ ProjectRow,
9
+ )
10
+ from .security import ( # noqa: F401
11
+ normalize_severity,
12
+ parse_npm,
13
+ parse_cargo,
14
+ parse_python,
15
+ parse_codeql,
16
+ parse_dependabot,
17
+ build_summary,
18
+ parse_all_ecosystems,
19
+ SEVERITY_ORDER,
20
+ )
@@ -0,0 +1,131 @@
1
+ """Nx project graph parsing and analysis.
2
+
3
+ Parses Nx graph JSON into structured data for downstream rendering
4
+ (MDX, JSON reports, API responses, etc.).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import re
11
+ from dataclasses import dataclass
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+
16
+ @dataclass
17
+ class ProjectRow:
18
+ """A single project extracted from the Nx graph."""
19
+
20
+ name: str
21
+ project_type: str
22
+ root: str
23
+ dep_count: int
24
+ dependent_count: int
25
+
26
+
27
+ @dataclass
28
+ class GraphData:
29
+ """Parsed and analysed Nx project graph."""
30
+
31
+ nodes: dict[str, Any]
32
+ deps: dict[str, list[dict[str, str]]]
33
+ rows: list[ProjectRow]
34
+ by_type: dict[str, list[str]]
35
+ edges: set[tuple[str, str]]
36
+ edges_by_source: dict[str, list[str]]
37
+
38
+
39
+ def mermaid_id(name: str) -> str:
40
+ """Sanitize a project name into a valid Mermaid node ID."""
41
+ return re.sub(r"[^a-zA-Z0-9_]", "_", name)
42
+
43
+
44
+ def parse_graph(source: str | Path | dict) -> GraphData:
45
+ """Parse an Nx graph from a file path, JSON string, or dict.
46
+
47
+ Returns a fully analysed ``GraphData`` with rows, groupings, and edges
48
+ ready for rendering.
49
+ """
50
+ if isinstance(source, dict):
51
+ data = source
52
+ elif isinstance(source, Path) or (
53
+ isinstance(source, str) and not source.lstrip().startswith("{")
54
+ ):
55
+ with open(source) as f:
56
+ data = json.load(f)
57
+ else:
58
+ data = json.loads(source)
59
+
60
+ nodes: dict[str, Any] = data["graph"]["nodes"]
61
+ deps: dict[str, list[dict[str, str]]] = data["graph"]["dependencies"]
62
+
63
+ by_type = group_projects_by_type(nodes)
64
+ rows = _build_rows(nodes, deps)
65
+ edges, edges_by_source = collect_edges(deps)
66
+
67
+ return GraphData(
68
+ nodes=nodes,
69
+ deps=deps,
70
+ rows=rows,
71
+ by_type=by_type,
72
+ edges=edges,
73
+ edges_by_source=edges_by_source,
74
+ )
75
+
76
+
77
+ def group_projects_by_type(
78
+ nodes: dict[str, Any],
79
+ ) -> dict[str, list[str]]:
80
+ """Group project names by their Nx project type."""
81
+ by_type: dict[str, list[str]] = {}
82
+ for name, node in sorted(nodes.items()):
83
+ ptype = node.get("type", "unknown")
84
+ by_type.setdefault(ptype, []).append(name)
85
+ return by_type
86
+
87
+
88
+ def collect_edges(
89
+ deps: dict[str, list[dict[str, str]]],
90
+ ) -> tuple[set[tuple[str, str]], dict[str, list[str]]]:
91
+ """Collect unique directed edges from Nx dependency data.
92
+
93
+ Returns ``(edge_set, edges_by_source)``.
94
+ """
95
+ seen: set[tuple[str, str]] = set()
96
+ by_source: dict[str, list[str]] = {}
97
+ for dep_list in deps.values():
98
+ for d in dep_list:
99
+ edge = (d["source"], d["target"])
100
+ if edge not in seen:
101
+ seen.add(edge)
102
+ by_source.setdefault(d["source"], []).append(d["target"])
103
+ return seen, by_source
104
+
105
+
106
+ def top_hubs(rows: list[ProjectRow], n: int = 5) -> list[ProjectRow]:
107
+ """Return the *n* most-depended-on projects."""
108
+ return sorted(rows, key=lambda r: r.dependent_count, reverse=True)[:n]
109
+
110
+
111
+ def _build_rows(
112
+ nodes: dict[str, Any],
113
+ deps: dict[str, list[dict[str, str]]],
114
+ ) -> list[ProjectRow]:
115
+ """Build a sorted list of ``ProjectRow`` from raw graph data."""
116
+ rows: list[ProjectRow] = []
117
+ for name in sorted(nodes):
118
+ node = nodes[name]
119
+ dep_count = len(deps.get(name, []))
120
+ dependents = sum(
121
+ 1 for d_list in deps.values() for d in d_list
122
+ if d["target"] == name
123
+ )
124
+ rows.append(ProjectRow(
125
+ name=name,
126
+ project_type=node.get("type", "unknown"),
127
+ root=node.get("data", {}).get("root", ""),
128
+ dep_count=dep_count,
129
+ dependent_count=dependents,
130
+ ))
131
+ return rows