v0.5.1-pre.008

This commit is contained in:
2026-08-10 11:21:07 +02:00
parent a2820062eb
commit 0e05c660c6
90 changed files with 2490 additions and 1613 deletions

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# file: scripts/audit_khadhroony_workspace_rules.py
# version: 23
# version: 28
"""Audit mechanically verifiable rules specific to khadhroony-bot3."""
@@ -915,13 +915,13 @@ def audit_environment_namespaces(root: pathlib.Path) -> list[Violation]:
"config/store.config.json",
"config/wallet.config.json",
"config/execution.config.json",
"config/example.kb-app-demo-desktop.default.config.json",
"config/example.logging.config.json",
"config/example.transport.config.json",
"config/example.listeners.config.json",
"config/example.store.config.json",
"config/example.wallet.config.json",
"config/example.execution.config.json",
"config/exemples/example.kb-app-demo-desktop.default.config.json",
"config/exemples/example.logging.config.json",
"config/exemples/example.transport.config.json",
"config/exemples/example.listeners.config.json",
"config/exemples/example.store.config.json",
"config/exemples/example.wallet.config.json",
"config/exemples/example.execution.config.json",
]:
config = root / relative
if not config.is_file():
@@ -970,14 +970,15 @@ def audit_configuration_split(root: pathlib.Path) -> list[Violation]:
"config/store.config.json",
"config/wallet.config.json",
"config/execution.config.json",
"config/example.kb-app-demo-desktop.default.config.json",
"config/example.logging.config.json",
"config/example.transport.config.json",
"config/example.listeners.config.json",
"config/example.store.config.json",
"config/example.wallet.config.json",
"config/example.execution.config.json",
"config/exemples/example.kb-app-demo-desktop.default.config.json",
"config/exemples/example.logging.config.json",
"config/exemples/example.transport.config.json",
"config/exemples/example.listeners.config.json",
"config/exemples/example.store.config.json",
"config/exemples/example.wallet.config.json",
"config/exemples/example.execution.config.json",
"config/schemas/composition.config.schema.json",
"config/schemas/kb-app-demo-desktop.application.config.schema.json",
"config/schemas/logging.config.schema.json",
"config/schemas/transport.config.schema.json",
"config/schemas/listeners.config.schema.json",
@@ -1062,6 +1063,13 @@ def audit_configuration_split(root: pathlib.Path) -> list[Violation]:
"config/example.app.config.json",
"config/schemas/app.config.schema.json",
"config/example.config.json",
"config/example.kb-app-demo-desktop.default.config.json",
"config/example.logging.config.json",
"config/example.transport.config.json",
"config/example.listeners.config.json",
"config/example.store.config.json",
"config/example.wallet.config.json",
"config/example.execution.config.json",
"config/schema.config.json",
"config/ks-pipeline-demo-scenarios.default.config.json",
]
@@ -1069,9 +1077,238 @@ def audit_configuration_split(root: pathlib.Path) -> list[Violation]:
if not (root / relative).exists():
continue
violations.append(Violation("KH_CFG007", relative, 1, "legacy or unnecessary configuration composition file must be removed"))
protected_runtime_files = [
"ks-config/src/composition.rs",
"ks-config/src/execution.rs",
"ks-config/src/listeners.rs",
"ks-config/src/settings.rs",
"ks-config/src/store.rs",
"ks-config/src/transport.rs",
"ks-config/src/wallet.rs",
]
for relative in protected_runtime_files:
path = root / relative
if not path.is_file():
continue
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if "#[derive(" not in line:
continue
if "serde::Serialize" in line:
violations.append(Violation("KH_CFG013", relative, index, "resolved/source configuration contracts must not derive Serialize because they may contain resolved secrets"))
if re.search(r"\bDebug\b", line):
violations.append(Violation("KH_CFG014", relative, index, "resolved/source configuration contracts must not derive Debug because they may contain resolved secrets or internal values"))
return violations
def audit_ts_rs_boundaries(root: pathlib.Path) -> list[Violation]:
"""Keep TS-RS generation at explicit application boundaries."""
violations: list[Violation] = []
for cargo in sorted(root.glob("ks-*/Cargo.toml")):
crate = cargo.parent
data = tomllib.loads(cargo.read_text(encoding="utf-8"))
for section in ["dependencies", "dev-dependencies", "build-dependencies"]:
dependencies = data.get(section, {})
if "ts-rs" in dependencies:
violations.append(
Violation(
"KH_TS001",
cargo.relative_to(root).as_posix(),
1,
"generic ks-* crates must not depend on ts-rs without an explicit approved external TypeScript contract",
)
)
for path in sorted((crate / "src").rglob("*.rs")):
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if "ts_rs::" in line or "#[ts(" in line or re.search(r"#\[derive\([^]]*\bTS\b", line):
violations.append(
Violation(
"KH_TS002",
relative,
index,
"TS-RS derives/attributes belong to application DTO boundaries, not generic ks-* runtime types",
)
)
for generated in [crate / "frontend/ts/bindings", crate / "bindings"]:
if generated.exists():
violations.append(
Violation(
"KH_TS003",
generated.relative_to(root).as_posix(),
1,
"generic ks-* crates must not own generated TypeScript bindings",
)
)
desktop = root / "kb-app-demo-desktop/src"
if desktop.exists():
field_pattern = re.compile(r"^\s*pub\(crate\)\s+[A-Za-z0-9_]+:\s+ks_[a-z0-9_]+::")
for path in sorted(desktop.rglob("*.rs")):
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
if field_pattern.search(line):
violations.append(
Violation(
"KH_TS004",
relative,
index,
"desktop DTO/state fields that cross application boundaries must use application-owned wrappers rather than direct ks-* field types",
)
)
tauri_path = root / "kb-app-demo-desktop/src/tauri.rs"
if tauri_path.is_file():
lines = tauri_path.read_text(encoding="utf-8").splitlines()
for index, line in enumerate(lines):
if line.strip() != "#[tauri::command]":
continue
signature_lines: list[str] = []
for candidate in lines[index + 1 : index + 20]:
signature_lines.append(candidate)
if "{" in candidate:
break
signature = "\n".join(signature_lines)
if re.search(r"->[^\{]*\bks_[a-z0-9_]+::", signature, re.DOTALL):
violations.append(
Violation(
"KH_TS005",
"kb-app-demo-desktop/src/tauri.rs",
index + 1,
"Tauri command return types must use desktop-owned DTO wrappers instead of direct ks-* contracts",
)
)
return violations
def audit_sensitive_transport_surfaces(root: pathlib.Path) -> list[Violation]:
"""Keep resolved transport URLs and other internal paths away from public boundaries."""
violations: list[Violation] = []
protected = {
"ks-onchain-transport/src/http_client.rs": "HttpPoolClientSnapshot",
"ks-onchain-transport/src/ws_client.rs": "WsPoolClientSnapshot",
"ks-onchain-transport/src/ws_session.rs": "WsSessionSnapshot",
}
for relative, struct_name in protected.items():
path = root / relative
if not path.is_file():
continue
text = path.read_text(encoding="utf-8")
struct_match = re.search(
rf"pub struct {struct_name}\s*\{{(?P<body>.*?)\n\}}",
text,
re.DOTALL,
)
if struct_match is not None and re.search(r"\bendpoint_url\s*:", struct_match.group("body")):
violations.append(
Violation(
"KH_SEC001",
relative,
text[: struct_match.start()].count("\n") + 1,
f"backend snapshot `{struct_name}` must not retain a resolved endpoint URL",
)
)
derive_match = re.search(
rf"#\[derive\(([^)]*)\)\]\s*(?:#\[[^\]]+\]\s*)*pub struct {struct_name}\b",
text,
re.DOTALL,
)
if derive_match is not None and "serde::Serialize" in derive_match.group(1):
violations.append(
Violation(
"KH_SEC002",
relative,
text[: derive_match.start()].count("\n") + 1,
f"backend transport snapshot `{struct_name}` must not derive Serialize",
)
)
desktop_root = root / "kb-app-demo-desktop/src"
if desktop_root.is_dir():
forbidden_fields = {
"endpoint_url": "resolved endpoint URLs must not cross the Tauri boundary",
"fixture_path": "wallet-derived fixture paths must not cross functional Tauri payloads",
}
field_pattern = re.compile(r"pub\(crate\)\s+([a-z][a-z0-9_]*):")
for path in sorted(desktop_root.rglob("*.rs")):
relative = path.relative_to(root).as_posix()
for index, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
match = field_pattern.search(line)
if match is None or match.group(1) not in forbidden_fields:
continue
violations.append(
Violation(
"KH_SEC003",
relative,
index,
forbidden_fields[match.group(1)],
)
)
transport_root = root / "ks-onchain-transport/src"
if transport_root.is_dir():
forbidden_fragments = {
"rpc_error_message = %error_response.error.message": "remote JSON-RPC messages must not be copied into transport logs",
'.field("endpoint_url", &self.endpoint.url)': "transport Debug must not expose a resolved endpoint URL",
"pub fn endpoint_url(&self) -> &str": "resolved endpoint URL getters must remain crate-private",
}
for path in sorted(transport_root.rglob("*.rs")):
relative = path.relative_to(root).as_posix()
text = path.read_text(encoding="utf-8")
for fragment, message in forbidden_fragments.items():
start = 0
while True:
offset = text.find(fragment, start)
if offset < 0:
break
violations.append(
Violation(
"KH_SEC004",
relative,
text[:offset].count("\n") + 1,
message,
)
)
start = offset + len(fragment)
concrete_api_key = re.compile(r"api-key=([0-9a-fA-F]{8,}(?:-[0-9a-fA-F]+)*)")
secret_scan_roots = [root / "config", root / "ks-config", root / "ks-logging", root / "ks-onchain-transport", root / "kb-app-demo-desktop"]
for scan_root in secret_scan_roots:
if not scan_root.is_dir():
continue
for path in sorted(scan_root.rglob("*")):
if not path.is_file() or "frontend/ts/bindings" in path.as_posix():
continue
if path.suffix not in {".rs", ".json", ".md", ".ts", ".html"}:
continue
text = path.read_text(encoding="utf-8", errors="ignore")
match = concrete_api_key.search(text)
if match is None:
continue
violations.append(
Violation(
"KH_SEC006",
path.relative_to(root).as_posix(),
text[: match.start()].count("\n") + 1,
"concrete API-key material is forbidden in active source, configuration, documentation and tests",
)
)
http_client_path = root / "ks-onchain-transport/src/http_client.rs"
if http_client_path.is_file():
text = http_client_path.read_text(encoding="utf-8")
forbidden_http = [
"retry_index, text\n",
"error_response.error.message\n ))",
]
for fragment in forbidden_http:
offset = text.find(fragment)
if offset >= 0:
violations.append(
Violation(
"KH_SEC005",
"ks-onchain-transport/src/http_client.rs",
text[:offset].count("\n") + 1,
"HTTP transport errors must not copy remote response bodies or JSON-RPC messages",
)
)
return violations
def audit_wincode_resolution(root: pathlib.Path) -> list[Violation]:
"""Require the currently compatible Solana wincode dependency family."""
@@ -1155,7 +1392,9 @@ def main() -> int:
+audit_private_ks_lib_paths_in_active_docs(root)
+audit_solana_types(root)
+audit_environment_namespaces(root)
+audit_ts_rs_boundaries(root)
+audit_configuration_split(root)
+audit_sensitive_transport_surfaces(root)
+audit_wincode_resolution(root)
)
violations.sort(key=lambda item: (item.code, item.path, item.line, item.message))