fix: command injection in watch_serve.sh, SSH host key verification, log permissions, input validation
ober
9618aa593c587b2845bd41da6ca546d89df23331
--- a/jerboa_proxy.py +++ b/jerboa_proxy.py @@ -13,7 +13,7 @@ Why this exists (proven this session): Run: python3 jerboa_proxy.py [UPSTREAM_BASE] [PORT] """ -import json, sys, urllib.request, urllib.error, http.server, socketserver, time +import json, os, sys, urllib.request, urllib.error, http.server, socketserver, time UPSTREAM = (sys.argv[1] if len(sys.argv) > 1 else "https://x8d9bjmhior1nx-8000.proxy.runpod.net").rstrip("/") @@ -25,10 +25,13 @@ GROUNDING = ("You are an expert in Jerboa Scheme, a Chez-Scheme-based dialect wi "Gerbil-flavored prelude. Provide accurate, idiomatic Jerboa code with correct " "imports. Module paths use (jerboa ...) and (std ...) — never :std/foo (Gerbil) " "or (srfi :NN) (R7).") -LOG = "/tmp/jerboa_proxy.log" +LOG_DIR = os.path.join(os.path.expanduser("~"), ".jerboa") +LOG = os.path.join(LOG_DIR, "proxy.log") +os.makedirs(LOG_DIR, exist_ok=True) def log(m): - with open(LOG, "a") as f: + fd = os.open(LOG, os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600) + with os.fdopen(fd, "a") as f: f.write(f"{time.strftime('%H:%M:%S')} {m}\n") def ground(raw): @@ -70,11 +73,17 @@ def ground(raw): class H(http.server.BaseHTTPRequestHandler): protocol_version = "HTTP/1.0" # close-delimited: simplest correct SSE passthrough def _do(self, method): - n = int(self.headers.get("Content-Length", 0) or 0) + try: + n = int(self.headers.get("Content-Length", 0) or 0) + except (ValueError, TypeError): + self.send_response(400); self.end_headers() + self.wfile.write(b"Invalid Content-Length"); return raw = self.rfile.read(n) if n else b"" if self.path.endswith("/chat/completions") and raw: raw, note = ground(raw) log(f"POST {self.path} {note} stream={b'stream' in raw}") + # Intentional: forward the client's Authorization header to the upstream + # RunPod proxy, which requires it for authentication. req = urllib.request.Request( UPSTREAM + self.path, data=raw or None, method=method, headers={"Content-Type": "application/json", "User-Agent": UA, --- a/upload_hf.sh +++ b/upload_hf.sh @@ -1,5 +1,5 @@ #!/bin/bash -cd /Users/user/mine/jerboa-lora +cd "$(dirname "$0")" source .venv-mlx/bin/activate export HF_HUB_DISABLE_XET=1 --- a/v6_runpod.py +++ b/v6_runpod.py @@ -149,9 +149,7 @@ def ssh_base(state: dict[str, Any]) -> list[str]: "-p", str(port), "-o", - "StrictHostKeyChecking=no", - "-o", - "UserKnownHostsFile=/dev/null", + "StrictHostKeyChecking=accept-new", "-o", "LogLevel=ERROR", "-o", @@ -191,9 +189,7 @@ def run_scp(state: dict[str, Any], local: Path, remote: str, *, recursive: bool "-P", str(port), "-o", - "StrictHostKeyChecking=no", - "-o", - "UserKnownHostsFile=/dev/null", + "StrictHostKeyChecking=accept-new", "-o", "LogLevel=ERROR", "-o", @@ -218,9 +214,7 @@ def scp_back(state: dict[str, Any], remote: str, local: Path, *, recursive: bool "-P", str(port), "-o", - "StrictHostKeyChecking=no", - "-o", - "UserKnownHostsFile=/dev/null", + "StrictHostKeyChecking=accept-new", "-o", "LogLevel=ERROR", "-o", --- a/watch_serve.sh +++ b/watch_serve.sh @@ -1,8 +1,10 @@ #!/bin/bash # watch_serve.sh <ip> <port> — watchdog for 70GB pull + vLLM load on the pod -IP=$1; PORT=$2 -CP=/tmp/rp_cm_$PORT -SSH="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPath=$CP -o ControlPersist=120 -i $HOME/.ssh/runpod_v5 -p $PORT root@$IP" +IP="$1"; PORT="$2" +case "$IP" in *[!0-9.]*|"") echo "Invalid IP" >&2; exit 1;; esac +case "$PORT" in *[!0-9]*|"") echo "Invalid PORT" >&2; exit 1;; esac +CP="/tmp/rp_cm_${PORT}" +SSH="ssh -o StrictHostKeyChecking=accept-new -o ControlMaster=auto -o ControlPath=${CP} -o ControlPersist=120 -i ${HOME}/.ssh/runpod_v5 -p ${PORT} root@${IP}" prev=""; stall=0 for i in $(seq 1 90); do ts=$(date +%H:%M:%S)