Skip to content

Commit 89902c4

Browse files
committed
Disable NuvioDesktop runtime instrumentation
1 parent a7afa86 commit 89902c4

1 file changed

Lines changed: 8 additions & 98 deletions

File tree

scripts/instrument_native_desktop_evidence.py

Lines changed: 8 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,26 @@
11
#!/usr/bin/env python3
2-
"""Inject passive sanitized HTTP evidence into the accepted NuvioDesktop runtime.
2+
"""Compatibility shim: NuvioDesktop runtime instrumentation is disabled.
33
4-
Desktop test stdout is not a reliable evidence transport because Gradle may capture
5-
it. The injected bridge therefore appends only NiakVIO's sanitized FIELD_NATIVE_HTTP
6-
records to a dedicated workspace file consumed by the lab after the test.
4+
The native Desktop lab must observe the official runtime without patching
5+
PluginRuntime, FetchBridge or any repository/network loader. This historical entry
6+
point is retained only so old callers remain harmless and policy-compliant.
77
"""
88
from __future__ import annotations
99

1010
import argparse
1111
from pathlib import Path
1212

1313

14-
def replace_once(text: str, old: str, new: str, label: str) -> str:
15-
count = text.count(old)
16-
if count != 1:
17-
raise SystemExit(f"desktop evidence instrumentation anchor {label!r} count={count}")
18-
return text.replace(old, new, 1)
19-
20-
21-
def evidence_write(expression: str) -> str:
22-
return (
23-
'runCatching { java.io.File(System.getenv("GITHUB_WORKSPACE") ?: ".", '
24-
f'"desktop-native-http-evidence.log").appendText({expression} + "\\n") }}'
25-
)
26-
27-
2814
def main() -> int:
2915
parser = argparse.ArgumentParser()
3016
parser.add_argument("repo")
3117
args = parser.parse_args()
3218
repo = Path(args.repo).resolve()
33-
runtime = repo / "composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/runtime/PluginRuntime.kt"
34-
bridge = repo / "composeApp/src/fullCommonMain/kotlin/com/nuvio/app/features/plugins/runtime/network/FetchBridge.kt"
35-
runtime_text = runtime.read_text(encoding="utf-8")
36-
bridge_text = bridge.read_text(encoding="utf-8")
37-
if "FIELD_NATIVE_HTTP_REQUEST client=desktop" in bridge_text:
38-
print(f"FIELD_NATIVE_EVIDENCE_INSTRUMENTED client=desktop bridge={bridge}")
39-
return 0
40-
41-
runtime_text = replace_once(
42-
runtime_text,
43-
"addModule(FetchBridge())",
44-
"addModule(FetchBridge(scraperId, mediaType))",
45-
"bridge ownership",
46-
)
47-
48-
# Nuvio intentionally turns a thrown getStreams() into [] inside QuickJS. Keep
49-
# that production behavior unchanged, but surface the swallowed reason to the
50-
# lab in sanitized form so an empty provider result is diagnosable evidence.
51-
# This diagnostic is deliberately optional for minimal/synthetic runtimes used
52-
# by instrumentation contract tests. HTTP evidence remains mandatory. On the
53-
# accepted real NuvioDesktop runtime both anchors are present and the callback
54-
# is injected; a partial anchor match is treated as drift and fails closed.
55-
plugin_error_binding_anchor = ''' val callCode = """\n (async function() {\n'''
56-
plugin_error_callback_anchor = ''' console.error("getStreams error:", e && e.message ? e.message : e, e && e.stack ? e.stack : "");\n __capture_result(JSON.stringify([]));\n'''
57-
binding_count = runtime_text.count(plugin_error_binding_anchor)
58-
callback_count = runtime_text.count(plugin_error_callback_anchor)
59-
plugin_error_capture = False
60-
if binding_count == 1 and callback_count == 1:
61-
plugin_error_line = evidence_write(
62-
'"FIELD_NATIVE_PLUGIN_ERROR client=desktop provider=$scraperId request_type=${mediaType.lowercase()} error=$safePluginError"'
63-
)
64-
runtime_text = runtime_text.replace(
65-
plugin_error_binding_anchor,
66-
f''' function("__niakvio_capture_plugin_error") {{ args: Array<Any?> ->\n val rawPluginError = args.getOrNull(0)?.toString().orEmpty()\n val safePluginError = rawPluginError\n .replace(Regex("https?://\\\\S+", RegexOption.IGNORE_CASE), "<url>")\n .replace(Regex("(?i)(authorization|cookie|token|secret)\\\\s*[:=]\\\\s*\\\\S+"), "$1=<redacted>")\n .replace(Regex("\\\\s+"), "_")\n .take(360)\n {plugin_error_line}\n null\n }}\n\n val callCode = """\n (async function() {{\n''',
67-
1,
68-
)
69-
runtime_text = runtime_text.replace(
70-
plugin_error_callback_anchor,
71-
''' console.error("getStreams error:", e && e.message ? e.message : e, e && e.stack ? e.stack : "");\n __niakvio_capture_plugin_error(String(e && e.message ? e.message : e));\n __capture_result(JSON.stringify([]));\n''',
72-
1,
73-
)
74-
plugin_error_capture = True
75-
elif binding_count != 0 or callback_count != 0:
76-
raise SystemExit(
77-
"desktop evidence instrumentation partial plugin-error anchor drift "
78-
f"binding={binding_count} callback={callback_count}"
79-
)
80-
81-
bridge_text = replace_once(
82-
bridge_text,
83-
"internal class FetchBridge : HostModule {",
84-
"internal class FetchBridge(private val scraperId: String, private val mediaType: String) : HostModule {",
85-
"bridge constructor",
86-
)
87-
error_line = evidence_write('"FIELD_NATIVE_HTTP_ERROR client=desktop provider=$scraperId request_type=$requestType method=${method.uppercase()} endpoint=$endpoint error_class=$errorName"')
88-
bridge_text = replace_once(
89-
bridge_text,
90-
''' } catch (t: Throwable) {\n log.e(t) { "Fetch bridge error for $method $url" }\n''',
91-
f''' }} catch (t: Throwable) {{\n val endpoint = url.substringBefore('?').substringBefore('#').replace(Regex("\\\\s+"), "%20")\n val errorName = t::class.qualifiedName.orEmpty().replace(Regex("\\\\s+"), "_")\n val requestType = mediaType.lowercase().replace(Regex("[^a-z0-9_-]"), "_")\n {error_line}\n log.e(t) {{ "Fetch bridge error for $method <redacted-url>" }}\n''',
92-
"bridge error",
93-
)
94-
request_line = evidence_write('"FIELD_NATIVE_HTTP_REQUEST client=desktop provider=$scraperId request_type=$requestType method=${method.uppercase()} endpoint=$endpoint header_names=$headerNames body_chars=${body.length} follow_redirects=$followRedirects"')
95-
bridge_text = replace_once(
96-
bridge_text,
97-
''' val headers = parseHeaders(headersJson).toMutableMap()\n if (!headers.containsKey("User-Agent")) {\n headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"\n }\n\n val response = httpRequestRaw(\n''',
98-
f''' val headers = parseHeaders(headersJson).toMutableMap()\n if (!headers.containsKey("User-Agent")) {{\n headers["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"\n }}\n val evidenceStartedAt = kotlin.time.TimeSource.Monotonic.markNow()\n val endpoint = url.substringBefore('?').substringBefore('#').replace(Regex("\\\\s+"), "%20")\n val headerNames = headers.keys.map {{ it.lowercase() }}.distinct().sorted().joinToString(",")\n val requestType = mediaType.lowercase().replace(Regex("[^a-z0-9_-]"), "_")\n {request_line}\n\n val response = httpRequestRaw(\n''',
99-
"request evidence",
100-
)
101-
response_line = evidence_write('"FIELD_NATIVE_HTTP_RESPONSE client=desktop provider=$scraperId request_type=$requestType method=${method.uppercase()} endpoint=$endpoint final_endpoint=$finalEndpoint status=${response.status} duration_ms=${evidenceStartedAt.elapsedNow().inWholeMilliseconds} response_header_names=$responseHeaderNames body_chars=${response.body.length}"')
102-
bridge_text = replace_once(
103-
bridge_text,
104-
''' val responseHeaders = response.headers.mapKeys { (key, _) -> key.lowercase() }\n .mapValues { (_, value) -> truncateString(value, MAX_FETCH_HEADER_VALUE_CHARS) }\n val result = JsonObject(\n''',
105-
f''' val responseHeaders = response.headers.mapKeys {{ (key, _) -> key.lowercase() }}\n .mapValues {{ (_, value) -> truncateString(value, MAX_FETCH_HEADER_VALUE_CHARS) }}\n val finalEndpoint = response.url.substringBefore('?').substringBefore('#').replace(Regex("\\\\s+"), "%20")\n val responseHeaderNames = responseHeaders.keys.sorted().joinToString(",")\n {response_line}\n val result = JsonObject(\n''',
106-
"response evidence",
107-
)
108-
109-
runtime.write_text(runtime_text, encoding="utf-8")
110-
bridge.write_text(bridge_text, encoding="utf-8")
19+
if not (repo / ".git").exists():
20+
raise SystemExit(f"official NuvioDesktop checkout missing: {repo}")
11121
print(
112-
f"FIELD_NATIVE_EVIDENCE_INSTRUMENTED client=desktop runtime={runtime} bridge={bridge} "
113-
f"plugin_error_capture={str(plugin_error_capture).lower()}"
22+
"FIELD_NATIVE_RUNTIME_INSTRUMENTATION client=desktop "
23+
"status=disabled_by_human_ux_policy runtime_mutation=false"
11424
)
11525
return 0
11626

0 commit comments

Comments
 (0)