From 06f93297a53d76911388f694e28e9d89c17bb290 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Fri, 13 Feb 2026 08:48:30 +0100 Subject: [PATCH] feat(streamlit): Add ACL rules and mesh distribution to emancipate - Added _emancipate_acl() to create HAProxy ACL routing rules - Added _emancipate_mesh() to distribute emancipated services to P2P peers - Added cmd_emancipate_all() for bulk emancipation of all instances - Emancipate now: DNS + Vortex + HAProxy + ACL + SSL + Mesh + Reload Co-Authored-By: Claude Opus 4.5 --- .../files/usr/sbin/streamlitctl | 131 +++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) diff --git a/package/secubox/secubox-app-streamlit/files/usr/sbin/streamlitctl b/package/secubox/secubox-app-streamlit/files/usr/sbin/streamlitctl index 7aceb856..6b8b1977 100644 --- a/package/secubox/secubox-app-streamlit/files/usr/sbin/streamlitctl +++ b/package/secubox/secubox-app-streamlit/files/usr/sbin/streamlitctl @@ -1362,6 +1362,126 @@ _emancipate_reload() { [ -x /usr/bin/gk2hub-generate ] && /usr/bin/gk2hub-generate >/dev/null 2>&1 & } +_emancipate_acl() { + local name="$1" + local domain="$2" + local port="$3" + + log_info "[ACL] Creating routing rules for $name" + + # Create ACL rule for Streamlit WebSocket paths + local acl_name="streamlit_${name}_acl" + local vhost_name=$(echo "$domain" | tr '.-' '_') + local backend_name="streamlit_${name}" + + # ACL for Streamlit-specific paths (WebSocket + static) + uci set haproxy.${acl_name}=acl + uci set haproxy.${acl_name}.name="path_streamlit_${name}" + uci set haproxy.${acl_name}.criterion="path_beg" + uci set haproxy.${acl_name}.pattern="/_stcore /static /component /media /health" + uci set haproxy.${acl_name}.backend="$backend_name" + uci set haproxy.${acl_name}.vhost="$vhost_name" + uci set haproxy.${acl_name}.enabled="1" + + uci commit haproxy + log_info "[ACL] Rule $acl_name created for vhost $vhost_name" +} + +_emancipate_mesh() { + local name="$1" + local domain="$2" + local port="$3" + + log_info "[MESH] Publishing $name to P2P mesh" + + # Register in secubox-p2p shared services + if command -v ubus >/dev/null 2>&1; then + ubus call luci.secubox-p2p share_service "{\"name\":\"streamlit_${name}\",\"port\":$port,\"domain\":\"$domain\",\"type\":\"streamlit\"}" 2>/dev/null && \ + log_info "[MESH] Service published to local mesh registry" + fi + + # Sync to peers if P2P is enabled + local p2p_enabled=$(uci -q get secubox-p2p.main.enabled) + if [ "$p2p_enabled" = "1" ]; then + # Get peer list and sync + local peers=$(uci -q get secubox-p2p.main.peers 2>/dev/null) + for peer in $peers; do + local peer_addr=$(uci -q get secubox-p2p.${peer}.address 2>/dev/null) + if [ -n "$peer_addr" ]; then + log_info "[MESH] Syncing to peer: $peer_addr" + # Use dbclient to sync emancipation state + dbclient -y -i /root/.ssh/id_dropbear "root@$peer_addr" \ + "uci set streamlit.${name}_remote=remote_instance; \ + uci set streamlit.${name}_remote.origin_host='$(uci -q get system.@system[0].hostname)'; \ + uci set streamlit.${name}_remote.domain='$domain'; \ + uci set streamlit.${name}_remote.port='$port'; \ + uci commit streamlit" 2>/dev/null && \ + log_info "[MESH] Peer $peer_addr updated" || \ + log_warn "[MESH] Failed to sync to $peer_addr" + fi + done + fi +} + +cmd_emancipate_all() { + require_root + load_config + + echo "" + echo "==============================================" + echo " BULK EMANCIPATION: All Streamlit Instances" + echo "==============================================" + echo "" + + # Get all enabled instances + local instances=$(uci show ${CONFIG} 2>/dev/null | grep "=instance$" | cut -d'.' -f2 | cut -d'=' -f1) + local count=0 + local success=0 + local failed=0 + + for inst in $instances; do + local enabled=$(uci -q get ${CONFIG}.${inst}.enabled) + local port=$(uci -q get ${CONFIG}.${inst}.port) + local app=$(uci -q get ${CONFIG}.${inst}.app) + + if [ "$enabled" = "1" ] && [ -n "$port" ]; then + count=$((count + 1)) + echo "[$count] Emancipating: $inst (app: $app, port: $port)" + + # Check if already emancipated + local already=$(uci -q get ${CONFIG}.${inst}.emancipated) + if [ "$already" = "1" ]; then + local existing_domain=$(uci -q get ${CONFIG}.${inst}.domain) + echo " Already emancipated: $existing_domain" + success=$((success + 1)) + continue + fi + + # Run emancipation + if cmd_emancipate "$inst" 2>/dev/null; then + success=$((success + 1)) + echo " ✓ Success" + else + failed=$((failed + 1)) + echo " ✗ Failed" + fi + fi + done + + echo "" + echo "==============================================" + echo " BULK EMANCIPATION COMPLETE" + echo "==============================================" + echo "" + echo " Total: $count instances" + echo " Success: $success" + echo " Failed: $failed" + echo "" + + # Final reload + _emancipate_reload +} + cmd_emancipate() { require_root load_config @@ -1419,10 +1539,16 @@ cmd_emancipate() { # Step 3: HAProxy vhost + backend _emancipate_haproxy "$name" "$domain" "$port" - # Step 4: SSL Certificate + # Step 4: HAProxy ACL rules for routing + _emancipate_acl "$name" "$domain" "$port" + + # Step 5: SSL Certificate _emancipate_ssl "$domain" - # Step 5: Reload HAProxy + # Step 6: Mesh P2P distribution to peers + _emancipate_mesh "$name" "$domain" "$port" + + # Step 7: Reload HAProxy _emancipate_reload # Mark app as emancipated @@ -1640,6 +1766,7 @@ case "${1:-}" in service-stop) shift; cmd_service_stop "$@" ;; emancipate) shift; cmd_emancipate "$@" ;; + emancipate-all) cmd_emancipate_all ;; *) usage ;; esac