fix(bootstrap): self-heal stale /aiui/api/web-search proxy to the gated daemon
Live on archi-dev-box: the node still proxied web-search straight to
SearXNG :8888 unauthenticated — the repo conf was fixed in d0c9ea6e but
existing nodes' /etc/nginx/sites-enabled never gets rewritten by a source
edit. Added to the nginx self-heal battery: stale 8888/search proxy_pass →
session-gated 5678 with the Cookie forwarded (heal_stale_web_search_block,
pure + idempotent + tested). Fresh ISOs already ship the gated block.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1055,6 +1055,22 @@ async fn run_nginx() -> Result<bool> {
|
||||
/// rejected. Stripped during nginx bootstrap so the backend solely owns CORS.
|
||||
const NGINX_LND_DUP_CORS: &str = " add_header Access-Control-Allow-Origin $http_origin always;\n add_header Access-Control-Allow-Credentials \"true\" always;\n";
|
||||
|
||||
/// S4 follow-up (2026-08-07): pre-fix nodes proxy /aiui/api/web-search
|
||||
/// STRAIGHT to SearXNG (127.0.0.1:8888) with no session check — anyone on the
|
||||
/// LAN can run searches attributed to the node's IP. The canonical conf routes
|
||||
/// it through the session-gated daemon (5678) and forwards the Cookie. The
|
||||
/// stale target string is unique to that block, so a plain replace is safe.
|
||||
/// Pure and testable; `None` when the stale shape is absent.
|
||||
fn heal_stale_web_search_block(content: &str) -> Option<String> {
|
||||
if !content.contains("proxy_pass http://127.0.0.1:8888/search;") {
|
||||
return None;
|
||||
}
|
||||
Some(content.replace(
|
||||
"proxy_pass http://127.0.0.1:8888/search;\n proxy_http_version 1.1;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;",
|
||||
"proxy_pass http://127.0.0.1:5678;\n proxy_http_version 1.1;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header Cookie $http_cookie;",
|
||||
))
|
||||
}
|
||||
|
||||
async fn patch_nginx_conf(path: &str) -> Result<bool> {
|
||||
let content = fs::read_to_string(path)
|
||||
.await
|
||||
@@ -1084,6 +1100,7 @@ async fn patch_nginx_conf(path: &str) -> Result<bool> {
|
||||
content.contains("listen 80 default_server;") && !content.contains("listen [::]:80");
|
||||
let missing_v6_https =
|
||||
content.contains("listen 443 ssl default_server;") && !content.contains("listen [::]:443");
|
||||
let stale_web_search = heal_stale_web_search_block(&content).is_some();
|
||||
if !missing_app_catalog
|
||||
&& !missing_bitcoin_status
|
||||
&& !missing_lnd_proxy
|
||||
@@ -1093,12 +1110,18 @@ async fn patch_nginx_conf(path: &str) -> Result<bool> {
|
||||
&& !needs_fedimint_css
|
||||
&& !missing_v6_http
|
||||
&& !missing_v6_https
|
||||
&& !stale_web_search
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let mut patched = content.clone();
|
||||
|
||||
if let Some(p) = heal_stale_web_search_block(&patched) {
|
||||
patched = p;
|
||||
}
|
||||
|
||||
|
||||
if missing_v6_http {
|
||||
patched = patched.replace(
|
||||
"listen 80 default_server;",
|
||||
@@ -1270,6 +1293,19 @@ mod tests {
|
||||
let outcome = PodmanHealOutcome::Unhealthy;
|
||||
assert_ne!(outcome, PodmanHealOutcome::Healthy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stale_web_search_block_is_gated_and_idempotent() {
|
||||
let stale = " location /aiui/api/web-search {\n proxy_pass http://127.0.0.1:8888/search;\n proxy_http_version 1.1;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_connect_timeout 30s;\n }";
|
||||
let healed = heal_stale_web_search_block(stale).expect("stale block must heal");
|
||||
assert!(healed.contains("proxy_pass http://127.0.0.1:5678;"));
|
||||
assert!(healed.contains("proxy_set_header Cookie $http_cookie;"));
|
||||
assert!(!healed.contains("8888"));
|
||||
// Second pass is a no-op (idempotent self-heal).
|
||||
assert!(heal_stale_web_search_block(&healed).is_none());
|
||||
// A config without the block is untouched.
|
||||
assert!(heal_stale_web_search_block("location / { try_files $uri /index.html; }").is_none());
|
||||
}
|
||||
}
|
||||
|
||||
/// Repair this node's own systemd restart policy.
|
||||
|
||||
Reference in New Issue
Block a user