v0.5.1-pre.008
This commit is contained in:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user