deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
[!NOTE] 本文档由 AI 生成,可能存在错误或遗漏,使用前请 review 并实测。
DSH 单实例多租户插件 —— 配套 Caddy + Authelia 认证前端使用。
所有用户共享全局模型 API_KEY 与插件运行环境,适用于成员间信任度较高的内部团队、
小型工作组或亲友共享场景,不适用于需要严格资源隔离的环境。
本 README 同时是整套认证前端的部署手册。
浏览器 ── TLS ──▶ nginx :443
│ dsh.example.com ──▶ Caddy 127.0.0.1:9443(HTTP)
│ /auth/* ─────────▶ Authelia 127.0.0.1:9091(门户)
▼
Caddy:forward_auth 问 Authelia → 注入 Remote-User/Groups
普通路径: Host 固定为公网域名
特权方法路径(/api/settings.* 等15个): Host→localhost + 剥 Origin
▼
dsh 127.0.0.1:3088 + 本插件(exact 影子路由做会话级 owner/access ACL)
sudo bash install.sh --domain dsh.example.com
# 可选: --admin-user <name> --admin-password <pass> --github-proxy https://ghproxy.net/
脚本自动完成全部步骤:下载二进制、生成密钥、创建管理员账号并保存凭据至
/root/dsh-p0-credentials/admin.txt。
| 项 | 要求 |
|---|---|
| 已有 | nginx 占 443 且有可用证书的站点 |
| 端口空闲 | 127.0.0.1:9091(Authelia)、127.0.0.1:9443(Caddy),均只绑回环 |
| DNS/证书 | 不需要新增,复用现有域名与证书 |
版本参考:Authelia v4.39.20、Caddy v2.11.4。
install.sh 会自动完成以下全部步骤。手动部署时参照 examples/ 目录:
/opt/authelia/,Caddy → /usr/local/bin/,
创建各自服务账号configuration.yml
和 users.yml 到 /etc/authelia/,
填入随机密钥和口令哈希Caddyfile 到 /etc/caddy/,
生成共享密钥 DSH_TENANCY_SECRETdsh.example.com.conf
修改 vhostRemote-User / Remote-Groups;
SSH 隧道直连按本地管理员处理owner/access 判定可见性;
session.list/search/workspace.list 响应自动过滤/tenancy/* 提供 whoami / sessions / claim / acl / invites 接口~/dsh(可配)内;
浏览越界静默钳制到根,写入越界 403/register 自助注册$DSH_HOME/tenancy/audit.log(JSONL,5MB 轮转)记录门控拒绝、
ACL 变更等pub.example.com)
经 nginx/Caddy 转发到 127.0.0.1:3089,则
pub.example.com/<user>/<projectName> 直接公开个人工作区里构建好的项目
(~/dsh/<user>/<projectName>/dist,构建输出目录名可配)。无鉴权、只读,
只服务构建产物,不暴露源码/隐藏文件;详见 docs/architecture.md 与
handbooks/operations.mdctx.skills 注册 publish-web-app skill
(skills/publish-web-app.md):DSH agent 编写/构建 Web 应用时自动遵循
「产物放 <项目>/dist/、资源相对引用」的约定,含最简单免构建单
index.html 的写法;该文件也可直接拷入 ~/.dsh/skills/ 使用nologin shell + 无密码(shadow 固有锁定)+ 不进任何管理组 ⇒ 不可登录服务器;
其唯一文件权限是个人工作区 ~/dsh/<user>(dsh 以 root 运行时即
/root/dsh/<user>):递归 chown + 目录 0700。幂等可重放;同名既有系统账号
不符时判 conflict 不接管;存量成员可经 POST /tenancy/sysuser 补建/tenancy/workspaces/<id>/share + UI 对话框):共享用户在侧栏可见该工作区、
可在其中新建会话(agent 真实读写同一份文件),并可在共享工作区浏览文件树/
建目录(P13 放开,非共享路径仍钳回个人根)。共享工作区内新建的会话默认
对参与者(owner+共享用户)可读——共享前已建的会话保持私有、不追溯,owner
可随时把任意会话改回私有;写仍仅限 owner同时跑多个 dsh 实例时,每个启用 tenancy 的 profile 必须配置独立的 dbPath /
auditPath / invitesPath,否则后写者会清掉前者的 ACL/邀请码记录。
拿不准就只在生产 profile 启用 tenancy。
# 安装
dsh plugin --profile web add github:choi-peng/dsh-tenancy
# 应用全部补丁(dsh 升级后重跑)
bash scripts/apply-patches.sh && pm2 restart dsh-web
sharedSecret必须与/etc/caddy/dsh.env的DSH_TENANCY_SECRET一致。配好后, 未携带X-Dsh-Tenancy-Key的请求会被直接 401(不再回落为 local 管理员); 留空则任何能直连127.0.0.1:3088的进程都是 admin,不得用于生产。 核对:dsh --profile web --dump-config | less
# 生成密码哈希
/opt/authelia/authelia crypto hash generate argon2 --password '新成员密码'
# → $argon2id$v=19$m=65536,t=3,p=4$...
# 加成员:编辑 /etc/authelia/users.yml 追加用户(password: "$argon2id$...";groups: dsh-team;管理员额外加 dsh-admins)
systemctl restart authelia
install.sh 生成至 /root/dsh-p0-credentials/(chmod 700),
登录后尽快改密注册成功时自动 useradd -M -s /usr/sbin/nologin 建同名账号(无密码、不进管理组
⇒ 不可登录),并把 ~/dsh/<user> 递归 chown 给它、目录 0700。相关操作:
# 查看某成员的系统账号(home 应为 /root/dsh/<user>,shell 应为 nologin)
getent passwd alice
# 为存量成员(功能启用前注册)补建账号与目录归属(SSH 隧道直连 3088 即 local admin)
curl -s -X POST http://127.0.0.1:3088/tenancy/sysuser \
-H 'content-type: application/json' -d '{"username":"alice"}'
/root 常为 0750,系统用户无法穿越抵达个人目录——插件会在日志提示一次;
确需真实可访问时自行决策:chmod o+x /root(仅允许穿越、不可列目录)
或 setfacl -m u:<user>:x /root。插件不会擅改 /root 权限| 症状 | 原因与解法 |
|---|---|
forward_auth 全 400,Authelia 报 insecure scheme |
Caddyfile 加 servers { trusted_proxies static private_ranges },让 nginx 的 X-Forwarded-Proto 生效 |
wrong argument count ... after '-Remote-Name' |
header_up -X 一行只能删一个字段,多字段拆成多行 |
Authelia 报 missing host value |
forward_auth uri 忘了子路径前缀:应为 /auth/api/authz/forward-auth |
| 非管理员也能调 settings.* | 缺少显式 deny 规则;检查规则顺序 |
新用户登录失败 does not exist |
systemctl restart authelia |
成员建工作区报 path outside workspace root |
目标目录不在围栏根内,预期行为 |
/register 打不开(302 跳门户) |
Caddyfile 未放行 /register 公开路由 |
| 登录页没有「邀请码注册」按钮 | nginx /auth/ location 未加 sub_filter |
注册报 server-error |
检查 dsh 进程对 autheliaUsersPath 可写、autheliaBin 存在可执行 |
| 注册成功但没有系统账号 | systemUserEnabled 未开/进程非 root/找不到 nologin shell → 看启动 WARN;存量成员经 POST /tenancy/sysuser 补建 |
审计出现 sysuser.conflict |
同名既有系统账号 home/shell 与约定不符,插件不接管不动文件;人工裁决 |
审计出现 sysuser.chown-partial |
个人目录部分条目 chown 失败(见审计 detail);重放 POST /tenancy/sysuser |
| GitHub 下载超时 | 用镜像前缀 https://ghproxy.net/ |
选模型/新建会话报 agent-presets: refusing to compose an unscoped context; the scope key is what joins an agent to its preset(resume failed for session ...) |
profile 的 node_modules/@deepseek-ai 里被装进了与 dsh 内置同名的核心包副本(dsh-scope/dsh-agent-presets/dsh-session 等)——进程内同一份代码加载两遍,私有 Symbol 作用域标记跨副本不可见,AgentPresets.mount 把已作用域的 agent 上下文判成 unscoped。解法:删除 profile overlay 里与内置树重复的 @deepseek-ai/*(保留仅 overlay 独有的包,如 dsh-client-ui-primitives/dsh-client-ui-slots,以及作为第三方插件正式依赖的 dsh-settings/schemastery 等):cd ~/.dsh/profiles/<name> && pnpm remove @deepseek-ai/<dups…> && pm2 restart dsh-web。核对:ls ~/.dsh/profiles/<name>/node_modules/@deepseek-ai/ 里不应出现 dsh-scope/dsh-agent-presets/dsh-session/dsh-client-connection 等内置核心。若重装后复发,检查是否用 pnpm add @deepseek-ai/*@<版本> 手工补齐过内置依赖 |
清理重复后跑 pnpm install/peers check 报 Issues with peer dependencies found(第三方插件把 @deepseek-ai/* 声明为 peer,运行时由外层 base 树 ~/.dsh/profiles/node_modules 提供,pnpm 看不到) |
让 pnpm 不再自动补装/告警这些 peer(否则 auto-install-peers 会把核心包又装回 overlay,复发改 bug):profile 的 pnpm-workspace.yaml 顶层加 autoInstallPeers: false 与 peerDependencyRules.ignoreMissing: ['@deepseek-ai/*'](pnpm ≥10 设置读 pnpm-workspace.yaml,不再读 package.json 的 pnpm 字段;.npmrc 里不要留 auto-install-peers=true)。改完 pnpm install && pnpm peers check 应输出 No peer dependency issues found |
| 文件 | 说明 |
|---|---|
examples/Caddyfile |
含 @adminapi 特权路径重写 |
examples/authelia/configuration.yml |
密钥已脱敏 |
examples/authelia/users.yml |
用户库模板 |
examples/nginx/dsh.example.com.conf |
nginx vhost |
examples/systemd/ |
Authelia / Caddy systemd 单元 |
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。