fix(fn-run): propagar stdout/stderr de bash functions library-style #1

Open
dataforge wants to merge 537 commits from auto/0077-fn-run-bash-mudo into master
8 changed files with 426 additions and 0 deletions
Showing only changes of commit 4d6ea9a910 - Show all commits
@@ -0,0 +1,52 @@
---
name: win_firewall_add_rule
kind: function
lang: ps
domain: infra
version: "1.0.0"
purity: impure
signature: "win_firewall_add_rule -Name <string> -Port <int> [-Protocol <string>]"
description: "Añade una regla de entrada al firewall de Windows para permitir tráfico en un puerto TCP/UDP. Si ya existe una regla con el mismo nombre, la elimina y la recrea. Requiere privilegios de Administrador."
tags: [firewall, windows, netsh, network, infra, security, port, wsl2]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "powershell/functions/infra/win_firewall_add_rule.ps1"
---
## Uso
```powershell
# Desde PowerShell (como Administrador)
.\win_firewall_add_rule.ps1 -Name "CDP-9222" -Port 9222
# Con protocolo explícito
.\win_firewall_add_rule.ps1 -Name "MyApp-UDP-5000" -Port 5000 -Protocol UDP
```
```bash
# Desde WSL2
powershell.exe -ExecutionPolicy Bypass -File win_firewall_add_rule.ps1 -Name "CDP-9222" -Port 9222
```
## Parametros
| Parametro | Tipo | Obligatorio | Default | Descripcion |
|------------|--------|-------------|---------|--------------------------------------|
| `-Name` | string | si | — | Nombre de la regla en el firewall |
| `-Port` | int | si | — | Puerto local (1-65535) |
| `-Protocol`| string | no | TCP | Protocolo: TCP o UDP |
## Notas
- Requiere ejecutarse como **Administrador** en Windows. Si se llama desde WSL2, usar `powershell.exe` (que corre en Windows) o `pwsh.exe`.
- Si ya existe una regla con el mismo nombre, la elimina primero y la recrea (idempotente respecto al nombre).
- La regla creada es `dir=in action=allow` — solo aplica para tráfico entrante.
- Caso de uso principal: permitir que WSL2 alcance Chrome CDP en el host Windows cuando Chrome escucha en `127.0.0.1:9222`.
- Retorna exit code 0 si tuvo éxito, 1 si hubo error (falta de privilegios, puerto inválido, fallo de netsh).
@@ -0,0 +1,56 @@
# win_firewall_add_rule.ps1 - Adds a Windows Firewall inbound rule for a TCP/UDP port.
# Requires: Administrator privileges
# Usage: powershell.exe -ExecutionPolicy Bypass -File win_firewall_add_rule.ps1 -Name "CDP-9222" -Port 9222
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(Mandatory = $true)]
[int]$Port,
[Parameter(Mandatory = $false)]
[string]$Protocol = "TCP"
)
# Verify administrator privileges
$currentPrincipal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Error "ERROR: This script requires Administrator privileges. Run PowerShell as Administrator."
exit 1
}
# Validate protocol
$validProtocols = @("TCP", "UDP")
if ($validProtocols -notcontains $Protocol.ToUpper()) {
Write-Error "ERROR: Protocol must be TCP or UDP, got '$Protocol'."
exit 1
}
# Validate port range
if ($Port -lt 1 -or $Port -gt 65535) {
Write-Error "ERROR: Port must be between 1 and 65535, got '$Port'."
exit 1
}
# Remove existing rule with the same name if it exists
$existingRule = netsh advfirewall firewall show rule name="$Name" 2>&1
if ($LASTEXITCODE -eq 0) {
Write-Host "Removing existing rule '$Name'..."
netsh advfirewall firewall delete rule name="$Name" | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Error "ERROR: Failed to remove existing rule '$Name'."
exit 1
}
}
# Add the new inbound rule
Write-Host "Adding firewall rule '$Name' for $Protocol port $Port..."
netsh advfirewall firewall add rule name="$Name" dir=in action=allow protocol=$Protocol localport=$Port
if ($LASTEXITCODE -ne 0) {
Write-Error "ERROR: Failed to add firewall rule '$Name'."
exit 1
}
Write-Host "OK: Firewall rule '$Name' added - $Protocol inbound on port $Port."
@@ -0,0 +1,46 @@
---
name: win_firewall_remove_rule
kind: function
lang: ps
domain: infra
version: "1.0.0"
purity: impure
signature: "win_firewall_remove_rule -Name <string>"
description: "Elimina una regla del firewall de Windows por nombre. Si la regla no existe, termina con éxito sin hacer nada (idempotente). Requiere privilegios de Administrador."
tags: [firewall, windows, netsh, network, infra, security, cleanup, wsl2]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "powershell/functions/infra/win_firewall_remove_rule.ps1"
---
## Uso
```powershell
# Desde PowerShell (como Administrador)
.\win_firewall_remove_rule.ps1 -Name "CDP-9222"
```
```bash
# Desde WSL2
powershell.exe -ExecutionPolicy Bypass -File win_firewall_remove_rule.ps1 -Name "CDP-9222"
```
## Parametros
| Parametro | Tipo | Obligatorio | Descripcion |
|-----------|--------|-------------|-----------------------------------|
| `-Name` | string | si | Nombre exacto de la regla a eliminar |
## Notas
- Requiere ejecutarse como **Administrador** en Windows.
- Idempotente: si la regla no existe, sale con exit code 0 y mensaje informativo.
- Complementa `win_firewall_add_rule` para teardown limpio de reglas temporales.
- Retorna exit code 0 si tuvo éxito (o la regla no existía), 1 si hubo error.
@@ -0,0 +1,33 @@
# win_firewall_remove_rule.ps1 - Removes a Windows Firewall rule by name.
# Requires: Administrator privileges
# Usage: powershell.exe -ExecutionPolicy Bypass -File win_firewall_remove_rule.ps1 -Name "CDP-9222"
param(
[Parameter(Mandatory = $true)]
[string]$Name
)
# Verify administrator privileges
$currentPrincipal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Error "ERROR: This script requires Administrator privileges. Run PowerShell as Administrator."
exit 1
}
# Check if the rule exists
$existingRule = netsh advfirewall firewall show rule name="$Name" 2>&1
if ($LASTEXITCODE -ne 0) {
Write-Host "INFO: Firewall rule '$Name' does not exist - nothing to remove."
exit 0
}
# Remove the rule
Write-Host "Removing firewall rule '$Name'..."
netsh advfirewall firewall delete rule name="$Name"
if ($LASTEXITCODE -ne 0) {
Write-Error "ERROR: Failed to remove firewall rule '$Name'."
exit 1
}
Write-Host "OK: Firewall rule '$Name' removed."
@@ -0,0 +1,73 @@
---
name: win_portproxy_add
kind: function
lang: ps
domain: infra
version: "1.0.0"
purity: impure
signature: "win_portproxy_add -ListenPort <int> [-ConnectPort <int>] [-ListenAddr <string>] [-ConnectAddr <string>]"
description: "Añade una regla de port proxy v4tov4 con netsh para redirigir tráfico desde ListenAddr:ListenPort hacia ConnectAddr:ConnectPort. Si ya existe una regla para el mismo listenaddress:listenport, la elimina y la recrea. Requiere privilegios de Administrador."
tags: [portproxy, netsh, windows, network, infra, wsl2, cdp, redirect, proxy]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "powershell/functions/infra/win_portproxy_add.ps1"
---
## Uso
```powershell
# Caso típico WSL2 → Chrome CDP: redirigir 0.0.0.0:9222 → 127.0.0.1:9222
.\win_portproxy_add.ps1 -ListenPort 9222
# Con todos los parámetros explícitos
.\win_portproxy_add.ps1 -ListenPort 9222 -ConnectPort 9222 -ListenAddr 0.0.0.0 -ConnectAddr 127.0.0.1
# Redirigir a un puerto diferente
.\win_portproxy_add.ps1 -ListenPort 8080 -ConnectPort 3000
```
```bash
# Desde WSL2 — habilitar acceso a Chrome CDP en el host Windows
powershell.exe -ExecutionPolicy Bypass -File win_portproxy_add.ps1 -ListenPort 9222
```
## Parametros
| Parametro | Tipo | Obligatorio | Default | Descripcion |
|----------------|--------|-------------|---------------|--------------------------------------------------|
| `-ListenPort` | int | si | — | Puerto en el que escucha el proxy (1-65535) |
| `-ConnectPort` | int | no | =ListenPort | Puerto de destino al que conectar (1-65535) |
| `-ListenAddr` | string | no | `0.0.0.0` | Dirección IP en la que escucha el proxy |
| `-ConnectAddr` | string | no | `127.0.0.1` | Dirección IP de destino |
## Notas
- Requiere ejecutarse como **Administrador** en Windows.
- Caso de uso principal: WSL2 no puede alcanzar `127.0.0.1` del host Windows directamente. Esta regla hace que el host escuche en `0.0.0.0:PORT` y reenvíe al loopback donde Chrome (u otro proceso) está escuchando.
- Idempotente respecto a listenaddress:listenport: si ya existe una regla para esa combinación, la elimina y la recrea.
- Combinar con `win_firewall_add_rule` para que el firewall también permita el tráfico entrante.
- Retorna exit code 0 si tuvo éxito, 1 si hubo error.
## Flujo completo WSL2 → Chrome CDP
```bash
# 1. Abrir Puerto en firewall
powershell.exe -ExecutionPolicy Bypass -File win_firewall_add_rule.ps1 -Name "CDP-9222" -Port 9222
# 2. Redirigir tráfico de red al loopback
powershell.exe -ExecutionPolicy Bypass -File win_portproxy_add.ps1 -ListenPort 9222
# 3. Arrancar Chrome con CDP en Windows
# chrome.exe --remote-debugging-port=9222 --headless
# 4. Desde WSL2 conectar al host Windows
# WSL2_HOST=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')
# curl http://$WSL2_HOST:9222/json
```
@@ -0,0 +1,62 @@
# win_portproxy_add.ps1 - Adds a netsh portproxy rule (v4tov4) to forward traffic.
# Requires: Administrator privileges
# Usage: powershell.exe -ExecutionPolicy Bypass -File win_portproxy_add.ps1 -ListenPort 9222
# powershell.exe -ExecutionPolicy Bypass -File win_portproxy_add.ps1 -ListenPort 9222 -ConnectPort 9222 -ListenAddr 0.0.0.0 -ConnectAddr 127.0.0.1
param(
[Parameter(Mandatory = $true)]
[int]$ListenPort,
[Parameter(Mandatory = $false)]
[int]$ConnectPort = 0, # 0 means use ListenPort
[Parameter(Mandatory = $false)]
[string]$ListenAddr = "0.0.0.0",
[Parameter(Mandatory = $false)]
[string]$ConnectAddr = "127.0.0.1"
)
# Verify administrator privileges
$currentPrincipal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Error "ERROR: This script requires Administrator privileges. Run PowerShell as Administrator."
exit 1
}
# Default ConnectPort to ListenPort if not specified
if ($ConnectPort -eq 0) {
$ConnectPort = $ListenPort
}
# Validate ports
if ($ListenPort -lt 1 -or $ListenPort -gt 65535) {
Write-Error "ERROR: ListenPort must be between 1 and 65535, got '$ListenPort'."
exit 1
}
if ($ConnectPort -lt 1 -or $ConnectPort -gt 65535) {
Write-Error "ERROR: ConnectPort must be between 1 and 65535, got '$ConnectPort'."
exit 1
}
# Remove existing portproxy for the same listenaddress:listenport if it exists
$existing = netsh interface portproxy show v4tov4 2>&1 | Select-String "$ListenAddr\s+$ListenPort"
if ($existing) {
Write-Host "Removing existing portproxy for ${ListenAddr}:${ListenPort}..."
netsh interface portproxy delete v4tov4 listenaddress=$ListenAddr listenport=$ListenPort | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Error "ERROR: Failed to remove existing portproxy for ${ListenAddr}:${ListenPort}."
exit 1
}
}
# Add the portproxy rule
Write-Host "Adding portproxy: ${ListenAddr}:${ListenPort} -> ${ConnectAddr}:${ConnectPort}..."
netsh interface portproxy add v4tov4 listenaddress=$ListenAddr listenport=$ListenPort connectaddress=$ConnectAddr connectport=$ConnectPort
if ($LASTEXITCODE -ne 0) {
Write-Error "ERROR: Failed to add portproxy ${ListenAddr}:${ListenPort} -> ${ConnectAddr}:${ConnectPort}."
exit 1
}
Write-Host "OK: Portproxy added - ${ListenAddr}:${ListenPort} -> ${ConnectAddr}:${ConnectPort}."
@@ -0,0 +1,61 @@
---
name: win_portproxy_remove
kind: function
lang: ps
domain: infra
version: "1.0.0"
purity: impure
signature: "win_portproxy_remove -ListenPort <int> [-ListenAddr <string>]"
description: "Elimina una regla de port proxy v4tov4 de netsh identificada por ListenAddr:ListenPort. Si la regla no existe, termina con éxito sin hacer nada (idempotente). Requiere privilegios de Administrador."
tags: [portproxy, netsh, windows, network, infra, wsl2, cleanup, proxy]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "powershell/functions/infra/win_portproxy_remove.ps1"
---
## Uso
```powershell
# Eliminar portproxy en puerto 9222 (listenaddr por defecto: 0.0.0.0)
.\win_portproxy_remove.ps1 -ListenPort 9222
# Con listenaddr explícito
.\win_portproxy_remove.ps1 -ListenAddr 0.0.0.0 -ListenPort 9222
```
```bash
# Desde WSL2
powershell.exe -ExecutionPolicy Bypass -File win_portproxy_remove.ps1 -ListenPort 9222
```
## Parametros
| Parametro | Tipo | Obligatorio | Default | Descripcion |
|---------------|--------|-------------|-------------|------------------------------------------------------|
| `-ListenPort` | int | si | — | Puerto de escucha de la regla a eliminar (1-65535) |
| `-ListenAddr` | string | no | `0.0.0.0` | Dirección IP de escucha de la regla a eliminar |
## Notas
- Requiere ejecutarse como **Administrador** en Windows.
- Idempotente: si la regla no existe, sale con exit code 0 y mensaje informativo.
- Complementa `win_portproxy_add` para teardown limpio.
- La regla se identifica por la combinación `listenaddress:listenport` — debe coincidir exactamente con la usada en `win_portproxy_add`.
- Retorna exit code 0 si tuvo éxito (o la regla no existía), 1 si hubo error.
## Teardown completo WSL2 → Chrome CDP
```bash
# 1. Eliminar portproxy
powershell.exe -ExecutionPolicy Bypass -File win_portproxy_remove.ps1 -ListenPort 9222
# 2. Eliminar regla de firewall
powershell.exe -ExecutionPolicy Bypass -File win_firewall_remove_rule.ps1 -Name "CDP-9222"
```
@@ -0,0 +1,43 @@
# win_portproxy_remove.ps1 - Removes a netsh portproxy v4tov4 rule.
# Requires: Administrator privileges
# Usage: powershell.exe -ExecutionPolicy Bypass -File win_portproxy_remove.ps1 -ListenPort 9222
# powershell.exe -ExecutionPolicy Bypass -File win_portproxy_remove.ps1 -ListenAddr 0.0.0.0 -ListenPort 9222
param(
[Parameter(Mandatory = $true)]
[int]$ListenPort,
[Parameter(Mandatory = $false)]
[string]$ListenAddr = "0.0.0.0"
)
# Verify administrator privileges
$currentPrincipal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Error "ERROR: This script requires Administrator privileges. Run PowerShell as Administrator."
exit 1
}
# Validate port
if ($ListenPort -lt 1 -or $ListenPort -gt 65535) {
Write-Error "ERROR: ListenPort must be between 1 and 65535, got '$ListenPort'."
exit 1
}
# Check if the portproxy rule exists
$existing = netsh interface portproxy show v4tov4 2>&1 | Select-String "$ListenAddr\s+$ListenPort"
if (-not $existing) {
Write-Host "INFO: Portproxy for ${ListenAddr}:${ListenPort} does not exist - nothing to remove."
exit 0
}
# Remove the portproxy rule
Write-Host "Removing portproxy for ${ListenAddr}:${ListenPort}..."
netsh interface portproxy delete v4tov4 listenaddress=$ListenAddr listenport=$ListenPort
if ($LASTEXITCODE -ne 0) {
Write-Error "ERROR: Failed to remove portproxy for ${ListenAddr}:${ListenPort}."
exit 1
}
Write-Host "OK: Portproxy for ${ListenAddr}:${ListenPort} removed."