diff --git a/docs/wasm-runtime-architecture.md b/docs/wasm-runtime-architecture.md index 8e8eacf..a701b69 100644 --- a/docs/wasm-runtime-architecture.md +++ b/docs/wasm-runtime-architecture.md @@ -1,8 +1,8 @@ # UCE WASM Runtime Architecture -Status: current as of the W7e native-pipeline removal (June 2026). This document -describes the **runtime architecture as built** — the process topology, the -wasm membrane, the unified request dispatch, and the central WebSocket broker. +Status: current as of the worker-role isolation and bounded serializer changes +(July 2026). This document describes the **runtime architecture as built**. It +covers the process topology, wasm membrane, request dispatch, and WebSocket broker. Native `.so` unit execution/dlopen fallback has been removed; the parser and preprocessor remain only as the front-end that emits C++ for wasm side-module compilation. @@ -26,8 +26,8 @@ gets invoked*. ``` ┌────────────────────────────┐ - nginx ──FastCGI──► worker pool (N processes) │ $FCGI_SOCKET_PATH (example `/run/uce/fastcgi.sock`) - (port 80 etc.) │ uniform unit renderers │ (FastCGI + CLI) + nginx ──FastCGI──► public workers (N processes)│ $FCGI_SOCKET_PATH (example `/run/uce/fastcgi.sock`) + (port 80 etc.) │ public unit renderers │ └─────────────▲──────────────┘ │ forward render (FastCGI, FCGI_SOCKET_PATH) │ @@ -42,6 +42,11 @@ gets invoked*. │ dispatcher(s) │ bind addr; forwards to pool └──────────────────┘ + trusted CLI/test calls ──► ┌──────────────────┐ + (CLI socket) │ CLI workers │ isolated module and + │ (M processes) │ connector caches + └──────────────────┘ + parent process: spawns/respawns all of the above + the proactive compiler. ``` diff --git a/site/doc/pages/http_request.txt b/site/doc/pages/http_request.txt index 0fb52d4..2dd7186 100644 --- a/site/doc/pages/http_request.txt +++ b/site/doc/pages/http_request.txt @@ -24,16 +24,8 @@ DValue resp = http_request(req); print("HTTP ", resp["status"].to_u64(), ", ", resp["body"].to_string().length(), " bytes returned\n"); :example -// GitHub token exchange: client_secret stays in stdin body, not argv. -DValue token; token["method"]="POST"; token["url"]="https://github.com/login/oauth/access_token"; -token["headers"]["Accept"]="application/json"; token["headers"]["Content-Type"]="application/x-www-form-urlencoded"; -token["body"]="client_id="+uri_encode(client_id)+"&client_secret="+uri_encode(client_secret)+"&code="+uri_encode(code); -for(String key:{"https_only","public_dns_only","pin_dns","isolated_curl","no_redirects"}) token["security"][key].set_bool(true); -DValue token_response=http_request(token); - -:example -// ATProto metadata discovery uses the same generic policy; no provider operation name. -DValue meta; meta["method"]="GET"; meta["url"]="https://"+issuer_host+"/.well-known/oauth-authorization-server"; -meta["headers"]["Accept"]="application/json"; -for(String key:{"https_only","public_dns_only","pin_dns","isolated_curl","no_redirects"}) meta["security"][key].set_bool(true); -DValue metadata=http_request(meta); +// Hardened requests reject IP-literal hosts before they start curl. +DValue hardened; hardened["method"]="GET"; hardened["url"]="https://127.0.0.1/"; +for(String key:{"https_only","public_dns_only","pin_dns","isolated_curl","no_redirects"}) hardened["security"][key].set_bool(true); +DValue rejected=http_request(hardened); +print(rejected["error"].to_string(), "\n"); diff --git a/site/tests/units.uce b/site/tests/units.uce index ff38a80..c42e355 100644 --- a/site/tests/units.uce +++ b/site/tests/units.uce @@ -22,6 +22,12 @@ RENDER(Request& context) file_put_contents(outside_unit, "RENDER(Request& context) {}"); DValue outside_info = unit_info(outside_unit); file_unlink(outside_unit); + String generated_dir = path_join(context.params["UCE_BIN_DIRECTORY"], "site-tests-generated"); + mkdir(generated_dir); + String generated_unit = path_join(generated_dir, "generated.uce"); + file_put_contents(generated_unit, "RENDER(Request& context) {}"); + DValue generated_info = unit_info(generated_unit); + file_unlink(generated_unit); ob_start(); unit_call("call_helpers.uce", "emit_marker"); @@ -37,6 +43,7 @@ RENDER(Request& context) check("unit_info()", info["path"].to_string() != "", json_encode(info)); check("compiler canonicalizes relative unit paths", relative_info["path"].to_string().find("/../") == String::npos && str_ends_with(relative_info["path"].to_string(), "/site/tests/relative-child.uce"), json_encode(relative_info)); check("compiler rejects units outside document root", outside_info["path"].to_string() == "", json_encode(outside_info)); + check("compiler accepts generated units in BIN_DIRECTORY", generated_info["path"].to_string() == generated_unit, json_encode(generated_info)); check("unit_compile()", unit_compile("call_helpers.uce"), "call_helpers.uce"); check("unit_call()", call_output.find("UNIT_CALL_EXPORT_OK") != String::npos, call_output); check("unit_render()", render_output.find("data-unit-render=\"ok\"") != String::npos, render_output); diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp index c9a2317..13b6c18 100644 --- a/src/lib/compiler.cpp +++ b/src/lib/compiler.cpp @@ -752,22 +752,29 @@ String compiler_normalize_unit_path(Request* context, String file_name) if(error || canonical == "") return(""); } - String allowed_root = trim(first( + StringList allowed_roots = { context->params["DOCUMENT_ROOT"], context->server->config["PRECOMPILE_FILES_IN"], context->server->config["HTTP_DOCUMENT_ROOT"], - path_join(context->server->config["COMPILER_SYS_PATH"], context->server->config["SITE_DIRECTORY"]) - )); - if(allowed_root == "") - return(""); - if(allowed_root[0] != '/') - allowed_root = expand_path(allowed_root, context->server->config["COMPILER_SYS_PATH"]); - allowed_root = path_real(allowed_root); - if(allowed_root == "") - return(""); - if(allowed_root[allowed_root.length() - 1] != '/') - allowed_root += "/"; - return(canonical + "/" == allowed_root || str_starts_with(canonical, allowed_root) ? canonical : ""); + path_join(context->server->config["COMPILER_SYS_PATH"], context->server->config["SITE_DIRECTORY"]), + context->server->config["BIN_DIRECTORY"] + }; + for(String allowed_root : allowed_roots) + { + allowed_root = trim(allowed_root); + if(allowed_root == "") + continue; + if(allowed_root[0] != '/') + allowed_root = expand_path(allowed_root, context->server->config["COMPILER_SYS_PATH"]); + allowed_root = path_real(allowed_root); + if(allowed_root == "") + continue; + if(allowed_root[allowed_root.length() - 1] != '/') + allowed_root += "/"; + if(canonical + "/" == allowed_root || str_starts_with(canonical, allowed_root)) + return(canonical); + } + return(""); } bool compiler_is_known_unit_file(String file_name)