dsh-plugin-approval-alert
doncelee229-cmyk
DeepSeek Harness 审批/选择方案系统级通知提醒,显示工作区名、点击跳转、多语言。Approval & decision alerts with native notifications for DeepSeek Harnes…
JUANWANG-BUAA/dsh-full-remote
DeepSeek Harness plugin for remote access: a token-gated reverse proxy keeps settings, credentials, and file access working over public tunnels and on other devices instead of returning 403. Per-device sessions. 支持通过公网隧道或局域网,在手机等设备上远程使用 DeepSeek Harness,设置、凭据与文件访问等功能保持可用。
PROJECT TOPICS
PROJECT README
Listed in awesome-dsh-plugin · DeepSeek Harness plugin
English | 中文
dsh-full-remote is a plugin for
DeepSeek Harness. It
places an authenticated reverse proxy in front of the Harness Web server,
so the Web UI can be used through a public tunnel or from a device on the
local network while privileged APIs such as settings, credentials, and
directory browsing remain available.
| Desktop control panel | Mobile workspace |
|---|---|
![]() |
![]() |
DeepSeek Harness binds its Web server to a loopback address and only
accepts privileged requests when the Host and Origin headers refer to
a loopback address. When the UI is reached through a generic tunnel, these
headers carry the public hostname and the trust check fails. The page
loads, but the following methods return 403:
settings.*credentials.*host.listDirectory| Approach | Result |
|---|---|
Generic tunnel (SSH port forward, Caddy, binding 0.0.0.0) |
Page loads; settings.* / credentials.* / host.listDirectory return 403 |
| LAN-only plugin without authentication | Usable on the local network; not suitable for public exposure |
| Password prompt without header rewriting | Requests are authenticated, but the privileged APIs remain blocked |
The plugin inserts a reverse proxy between the tunnel and the Harness Web server. The proxy:
Host and Origin to 127.0.0.1 before forwarding, so the
privileged APIs pass Harness's trust check;Because the rewrite disables Harness's original trust check for remote clients, the plugin provides its own access-control layer in its place. This layer is described under Security model.
The plugin does not manage tunnels. Any tunnel (cloudflared, ngrok, frp, SSH, Tailscale) can be pointed at the local endpoint the plugin publishes.
flowchart LR
A[Phone or remote browser] --> B[Public tunnel<br>cloudflared / ngrok / frp / SSH]
B --> C[dsh-full-remote<br>127.0.0.1:3081<br>authentication + header rewrite]
C --> D[DeepSeek Harness Web<br>127.0.0.1:3080]
127.0.0.1:3081 by default).Host/Origin to loopback, removes untrusted
headers, and forwards the request to the Harness Web server at
127.0.0.1:3080.settings.describe / update / replace / mutatecredentials.describe / set / unsethost.listDirectory / pickDirectory / openPathagentPreset.*, llm.discoverModels0600; reveal and
rotation are performed from the local paneltrustForwardedFor to use real client IPs from a trusted local
tunnel in CIDR / rate-limit / audit, preferring CF-Connecting-IP and
otherwise using the rightmost X-Forwarded-For valuesettings.describe with the same Host/Origin
rewrite the proxy usestlsCertFile / tlsKeyFile)/_dsh_reverse_proxy/healthzset-cookie is removed^22.19.0 || >=24webServer
and is not intended for headless profiles.dsh plugin --profile web add dsh-full-remote
dsh --profile web
http://127.0.0.1:3080.# Examples only. The plugin does not execute these commands.
cloudflared tunnel --url http://127.0.0.1:3081
ngrok http 3081
For devices on the same network, set the listen address to a LAN IP instead of using a tunnel.
The package was previously published as dsh-reverse-proxy.
On the settings page, press Start proxy to start the listener and Stop proxy to stop it.
| Bind | Purpose |
|---|---|
127.0.0.1 (default) |
The tunnel runs on the same machine |
192.168.x.x |
A device on the same network, without a tunnel |
0.0.0.0 / :: |
Bind every interface. This is not an address to open; the panel reports a separate reachable address. |
The listen address can be changed at runtime and persists across restarts. If a new address fails to bind, the proxy rolls back to the previous working address.
The copyable tunnel target (and any extra reachable URL the panel
lists) is what a remote client should open. Binding 0.0.0.0 only
listens; it is not a URL.
backendHost is the address the proxy connects to, not the address it
listens on. Keep it at 127.0.0.1.
The QR encodes a one-time login URL. Public / reachable Origin is the
host the scanning device will request: the tunnel's https://…, or the
LAN URL from the panel. Leave it empty only when the tunnel target above
is already that address.
Do not put 127.0.0.1 in Origin. That address is the Harness machine; a
phone would open its own loopback and never reach the proxy.
Then press Generate invite. After a scan (or opening the link) the login page submits once. The invite expires in 15 minutes, works once, and does not contain the standing token.
dsh plugin forwards to pnpm. If you installed with an exact pin such as
add dsh-full-remote@0.2.4, a bare update dsh-full-remote reports
Already up to date and stays on the old version. To jump to the latest npm
release:
dsh plugin --profile web update --latest dsh-full-remote
Then restart dsh web. --latest ignores the current range, installs the
newest version, and rewrites package.json. For a specific version use
dsh plugin --profile web update dsh-full-remote@0.2.5.
| Control panel | Fence self-check |
|---|---|
![]() |
![]() |
| Phone invite (QR) | Access token | Listen address |
|---|---|---|
![]() |
![]() |
![]() |
| Login page (phone) | Add workspace on phone | Mobile control panel |
|---|---|---|
![]() |
![]() |
![]() |
Common options:
- id: reverse-proxy
name: dsh-full-remote
config:
listenHost: 127.0.0.1
listenPort: 3081
approvalMode: false # true: approve each new device locally
allowedCidrs: [] # e.g. ["192.168.1.0/24"]; empty: any IP after login
trustForwardedFor: false # true: trust CF-Connecting-IP / rightmost X-Forwarded-For from a trusted local tunnel
upgradeMaxAttempts: 10 # failed WebSocket upgrades before lockout
upgradeLockoutSeconds: 300 # lockout for repeated failed WebSocket upgrades
headersTimeoutMs: 15000 # timeout for request headers
requestTimeoutMs: 120000 # timeout for the complete request; effective value is >= headersTimeoutMs
sessionIdleSeconds: 0 # 0: off; otherwise idle timeout in seconds
auditLog: true
allowTokenRead: true # false: token only returned on rotation
tlsCertFile: "" # optional local HTTPS
tlsKeyFile: ""
The complete option list, with defaults and validation, is defined in the
package Config schema (src/index.ts).
Two points to note:
directory-picker row in
the same profile.backendHost must remain a loopback address. A wildcard or non-loopback
value is rejected at load time.The Host/Origin rewrite restores the privileged APIs and, at the same time, disables Harness's original protection for remote clients. The access-control layer provided by this plugin consists of:
0600;HttpOnly, SameSite=Strict session cookie per device, carrying a
per-device secret of which only a hash is stored;429 lockout on failed logins;/dsh-reverse-proxy/*), which require a
control header and are never forwarded through the public proxy;trustForwardedFor: when enabled, only a loopback peer's
forwarding headers are trusted for CIDR / rate-limit / audit, so a local
tunnel can see real client IPs. It prefers CF-Connecting-IP and
otherwise uses the rightmost X-Forwarded-For value to avoid client-side
spoofing. Keep it disabled for direct LAN access.The access token must be treated as a secret. Terminate TLS on the public
side of the tunnel. For LAN use without a tunnel, set
tlsCertFile / tlsKeyFile (for example with
mkcert).
allowTokenRead: true (the default), GET /token is served over
loopback HTTP, so any local process that sends the control header can
read the token. Set allowTokenRead: false to receive the token only
when rotating.127.0.0.1 to the proxy. allowedCidrs and per-IP
login lockout therefore apply to the tunnel as a whole unless
trustForwardedFor: true is set behind a trusted local edge.pnpm pack
dsh plugin --profile web add ./dsh-full-remote-0.2.5.tgz
Git installs run the prepare build. On pnpm ≥ 10 allow it:
allowBuilds:
dsh-full-remote: true
pnpm install
pnpm run check:ci
check:ci runs lint, typecheck, unit and client tests, and a build. CI
adds a real dsh plugin add smoke test against a live Harness
composition. .github/workflows/canary.yml runs a weekly smoke test
against the harness default-branch tip.
The loopback control API lives at /dsh-reverse-proxy/* and is never
forwarded through the public proxy. The settings page is the intended
interface; the raw routes are rarely needed. For example, recent audit
events can be read with GET /dsh-reverse-proxy/audit?limit=50&event=login.ok
from the local control surface.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。