From b2a259fa235822e407d519feb1d9796ac39a9665 Mon Sep 17 00:00:00 2001 From: abiba-bot Date: Fri, 11 Sep 2026 14:56:57 +0000 Subject: [PATCH] fix: add dsh-web restart-persistent authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add capture-dsh-token.sh script that captures the dsh-web launch token - Add login endpoint (/dsh-web-login on :8081) that mints 30-day auth cookie - Document the authentication flow in zulip-health.prose.md (Platform B4) - Cookie is authority-bound to 127.0.0.1:3080 with 30-day expiry - After first login, subsequent requests use the cookie — no token required --- scripts/capture-dsh-token.sh | 77 ++++++++++++++++++++++++++++++++++++ zulip-health.prose.md | 37 +++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100755 scripts/capture-dsh-token.sh diff --git a/scripts/capture-dsh-token.sh b/scripts/capture-dsh-token.sh new file mode 100755 index 0000000..0f1f532 --- /dev/null +++ b/scripts/capture-dsh-token.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# capture-dsh-token.sh — start dsh-web, capture its token, update nginx +# Run on CT112 (tankodhs.sysloggh.net) +# This script: +# 1. Restarts the dsh-web service +# 2. Captures the token URL from the journal +# 3. Extracts the token value +# 4. Writes the token to /etc/dsh-web/launch-token +# 5. Creates an nginx config that exposes a /dsh-web-login endpoint +# 6. Reloads nginx + +set -euo pipefail + +# Kill any existing dsh-web instance first +systemctl stop dsh-web 2>/dev/null || true +sleep 2 + +# Record the time we started the service (for --since filter) +START_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + +# Start dsh-web +systemctl start dsh-web + +# Wait for the token to appear in the journal (up to 30 seconds) +TOKEN="" +for i in {1..30}; do + TOKEN=$(journalctl -u dsh-web.service --since "$START_TIME" --output=cat 2>/dev/null | grep -m1 "dsh web: http://" | grep -oP "(?<=dsh web: )(https?://[^ ]+)" | head -1 || true) + if [ -n "$TOKEN" ]; then + break + fi + sleep 1 +done + +if [ -z "$TOKEN" ]; then + echo "ERROR: token not captured within 30s" >&2 + exit 1 +fi + +# Extract the token value (everything after "?token=") +TOKEN_VALUE=$(echo "$TOKEN" | grep -oP "(?<=token=)[^ ]+") + +# Write the token to a file +mkdir -p /etc/dsh-web +echo "$TOKEN_VALUE" > /etc/dsh-web/launch-token +echo "Captured token: $TOKEN_VALUE" + +# Create the nginx config with the token (using printf to control expansion) +{ + printf "server {\n" + printf " listen 8081;\n" + printf " server_name _;\n" + printf " \n" + printf " location /dsh-web-login {\n" + printf " proxy_pass http://127.0.0.1:3080/?token=%s;\n" "$TOKEN_VALUE" + printf " proxy_http_version 1.1;\n" + printf " proxy_set_header Host 127.0.0.1:3080;\n" + printf " proxy_set_header X-Real-IP \$remote_addr;\n" + printf " proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;\n" + printf " }\n" + printf " \n" + printf " location / {\n" + printf " proxy_pass http://127.0.0.1:3080;\n" + printf " proxy_http_version 1.1;\n" + printf " proxy_set_header Host 127.0.0.1:3080;\n" + printf " proxy_set_header X-Real-IP \$remote_addr;\n" + printf " proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;\n" + printf " }\n" + printf "}\n" +} > /etc/nginx/sites-enabled/dsh.token + +# Reload nginx +nginx -t && /usr/sbin/nginx -s reload || { + echo "ERROR: failed to reload nginx" >&2 + exit 1 +} + +echo "Token captured and nginx reloaded" diff --git a/zulip-health.prose.md b/zulip-health.prose.md index 6ebafd4..cc47dcb 100644 --- a/zulip-health.prose.md +++ b/zulip-health.prose.md @@ -260,6 +260,43 @@ logged/reported as a warning — reported, never healed on. | `dsh-web` service not `active` | Restart Tanko via DSH service | | HTTP `:3080` connection refused/timeout (`000`) | Same as above | | HTTP status outside the expected set | Log/report as a warning — reported, never healed on | +**B4: dsh-web Authentication (Tanko — restart-persistent login)** + +The dsh-web UI is token-gated. Each dsh-web process generates a unique +launch token printed to the journal at startup. The token is used to mint +a 30-day authentication cookie. After the first authenticated login, +subsequent requests use the cookie — no token required. + +**Login endpoint**: `http://127.0.0.1:8081/dsh-web-login` (inside CT 112) + +**Token capture script**: `/opt/deepseek-harness/capture-dsh-token.sh` (CT 112) + +The script: +1. Restarts the dsh-web service +2. Captures the token URL from the journal +3. Extracts the token value +4. Writes the token to `/etc/dsh-web/launch-token` +5. Creates an nginx config that exposes the `/dsh-web-login` endpoint on port 8081 +6. Reloads nginx + +**Authentication flow**: +1. Access `http://127.0.0.1:8081/dsh-web-login` → 303 redirect +2. The redirect includes a `Set-Cookie` header with the `dsh-auth-*` cookie +3. The cookie has a 30-day expiry and is authority-bound to `127.0.0.1:3080` +4. Subsequent requests to `http://127.0.0.1:3080/` use the cookie for authentication +5. After 30 days, the cookie expires and a new token exchange is required + +**Verification**: +```bash +# Check if the login endpoint is working: +ssh root@192.168.68.15 "pct exec 112 -- curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8081/dsh-web-login" +# Expected: 303 + +# Check if the cookie works: +ssh root@192.168.68.15 "pct exec 112 -- curl -s -o /dev/null -w '%{http_code}' -b 'dsh-auth-*' http://127.0.0.1:3080/" +# Expected: 200 (after the cookie has been set) +``` + ### Step 4: Platform C — Agent Zero (kagentz, CT 105 via Docker host .14)