DSH 插件:把工作区备份到 S3 兼容对象存储RustFS / 阿里云 OSS / AWS…
29.3/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add KAIROSLLL/dsh-plugin-oss-backup该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · other
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 22 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 21 处,展示前 21 条)
- 发起网络请求src/client/api.ts:617
const response = await fetch(STATE_PATH, { - 发起网络请求src/client/api.ts:652
const response = await fetch(path, { - 执行外部命令来自配置/变量src/credential-store.ts:75
const child = execFile( - 删除本地文件src/credential-store.ts:130
await rm(file, { force: true }) - 读取本地文件src/credential-store.ts:139
raw = await readFile(file, 'utf8') - 写入本地文件src/credential-store.ts:164
await mkdir(dirname(file), { recursive: true }) - 写入本地文件src/credential-store.ts:165
await writeFile(file, JSON.stringify({ v: 1, kind: 'dpapi', data: cipher }), { - 执行外部命令来自配置/变量src/env-source.ts:38
const child = execFile( - 读取本地文件src/index.ts:443
uploadIndex = UploadIndex.parse(await readFile(uploadIndexPath(), 'utf8')) - 写入本地文件src/index.ts:458
await mkdir(dirname(target), { recursive: true }) - 写入本地文件src/index.ts:460
await writeFile(temp, uploadIndex.serialize(), 'utf8') - 写入本地文件src/index.ts:461
await rename(temp, target) - 读取本地文件src/index.ts:1142
const bytes = await readFile(file) - 读取本地文件src/manual-backup.ts:113
const list = deps.readdir ?? ((path: string) => readdir(path, { withFileTypes: true })) - 读取本地文件src/manual-backup.ts:114
const statOf = deps.stat ?? ((path: string) => stat(path)) - 读取本地文件src/settings.ts:174
const text = await readFile(settingsFilePath(home), 'utf8') - 写入本地文件src/settings.ts:194
await mkdir(dirname(file), { recursive: true }) - 写入本地文件src/settings.ts:195
await writeFile(file, `${JSON.stringify(safe, null, 2)}\n`, 'utf8') - 读取本地文件src/upload.ts:158
const statFile = deps.statFile ?? ((path: string) => stat(path)) - 读取本地文件src/upload.ts:175
const read = deps.readFile ?? ((path: string) => readFile(path)) - 读取本地文件src/upload.ts:194
const openStream = deps.openStream ?? ((path: string) => createReadStream(path))
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 递归备份工作区文件夹
- 备份至S3兼容对象存储
- 凭证仅从环境变量读取
展开完整介绍(75 字)↓
DSH 插件:把工作区备份到 S3 兼容对象存储(RustFS / 阿里云 OSS / AWS S3)。凭证只从环境变量读,不落盘、不回显、不进日志。
README
由 DeepSeek 最新模型翻译生成dsh-plugin-oss-backup
把文件备份到对象存储的 DeepSeek Harness 插件。支持 RustFS / MinIO 等自建 S3 兼容服务、阿里云 OSS、AWS S3 —— 一次配置,之后在设置界面点几下就能把整个文件夹传上云。
⚠️ 安全须知(先读这一段)
1. 优先用密钥管理器把凭证注入环境变量。 1Password CLI(op run -- dsh web)、HashiCorp Vault、AWS Secrets Manager、Azure Key Vault、Doppler、direnv 都行 —— 插件只读 process.env,所以让密钥留在它该待的地方,远比复制粘贴到某个文件里安全。具体接法见 凭证接入指南。
2. 不要用主账号密钥。 请新建一个只能读写指定桶的子账号,只给它 PutObject 权限。本文「第 2 步」有现成的配置可抄。
3. 别把密钥写进会被提交的文件 —— README、issue、脚本、截图、Dockerfile 都算。本插件支持 .env(启动时自动读、只读不写),但它只适合本地临时使用;用之前务必确认 .env 在 .gitignore 里(本仓库已挡 .env / .env. / .key / .pem)。
展开完整文档(README 剩余 1 节)
dsh-plugin-oss-backup
把文件备份到对象存储的 DeepSeek Harness 插件。支持 RustFS / MinIO 等自建 S3 兼容服务、阿里云 OSS、AWS S3 —— 一次配置,之后在设置界面点几下就能把整个文件夹传上云。
⚠️ 安全须知(先读这一段)
1. 优先用密钥管理器把凭证注入环境变量。 1Password CLI(op run -- dsh web)、HashiCorp Vault、AWS Secrets Manager、Azure Key Vault、Doppler、direnv 都行 —— 插件只读 process.env,所以让密钥留在它该待的地方,远比复制粘贴到某个文件里安全。具体接法见 凭证接入指南。
2. 不要用主账号密钥。 请新建一个只能读写指定桶的子账号,只给它 PutObject 权限。本文「第 2 步」有现成的配置可抄。
3. 别把密钥写进会被提交的文件 —— README、issue、脚本、截图、Dockerfile 都算。本插件支持 .env(启动时自动读、只读不写),但它只适合本地临时使用;用之前务必确认 .env 在 .gitignore 里(本仓库已挡 .env / .env. / .key / .pem)。
4. 密钥一旦出现在聊天记录、日志或提交历史里,就当它已经泄漏 —— 立刻去服务商后台轮换掉。
5. 本插件自己不会把密钥写到磁盘上。 密钥只在内存里流转,界面永远只显示「已设置 / 未设置」,日志里也只会出现变量名,不会出现变量值。(.env 是你写的、插件只读 —— 落不落盘由你决定。)
6. 想确认这一点,可以在配好之后自己检查:~/.dsh/oss-backup/config.json 里只会有开关、目录、桶名这类非机密信息,不会有任何密钥。
一、它能做什么
四个用法
| 用法 | 说明 |
| 手动备份整个文件夹 | 在设置界面填一个目录,点「立即备份」,它就会把该目录(含所有子目录)递归传上去 |
| 定期全量备份 | 按时间表(每 N 分钟 / 小时 / 天,或每天、每月固定时刻)自动把整个目录完整传一遍 |
| 文件改动自动备份 | 打开开关后,每次保存文件(模型用 write / edit 改文件)都会在 2 秒后自动上传 |
| 让模型上传单个文件 | 模型可以直接调用 oss_backup 工具,把一个本地文件传到指定的对象路径 |
| 《接数据》(趣味) | 点「立即备份」时先在「上传状态」框里玩一局节奏小游戏,通关才真的开始备份。不想要可以在设置里关掉 |
支持的对象存储
| provider | 适用 | 寻址方式 |
| rustfs(默认) | RustFS、MinIO 等自建 S3 兼容服务 | path-style |
| aliyun | 阿里云 OSS | 虚拟主机风格 |
| aws | AWS S3(也可指向其它 S3 兼容服务) | 虚拟主机风格 |
已实测通过:RustFS 真实上传(本机)、阿里云连通性。AWS 与阿里云的完整上传流程依赖你自己的账号环境,仓库里的配置示例可直接照抄。
界面上有什么
- 设置 → 对象存储备份(与主面板内容一致):
- 顶部两张卡片:存储端点、环境状态(是否配好、密钥是否已设置);
- 上传状态:进度条 + 最近几次上传的大小;;
- 云端备份按钮:打开当前 provider 的网页控制台,方便核对桶里的内容;
- 设置:自动备份开关、备份目录、「跳过依赖 / 缓存目录」开关,以及折叠的「高级设置」;
- 凭证:在界面里临时填写密钥(见第四节);
- 手动备份:「立即备份」按钮 + 进度条 + 上次结果;
- 环境自检:provider / 端点 / 桶 / 区域 / 密钥是否已设置;
- 最近上传:时间、对象路径、大小。
- 左侧栏:一栏状态提示(已就绪 / 上传中 / 缺配置 / 未连接)。
二、安装
cd <你的插件目录>
pnpm add dsh-plugin-oss-backup # 或把打好的 .tgz 装进 DSH profile
装完后重启 dsh web,设置页里就会出现「对象存储备份」。
本地开发时安装的坑(点开看)
不要用 link: 安装本地包。 症状是启动时报 dsh-plugin-oss-backup: failed to import: link: 会在 profile 里建一个指向源码目录的软链接,而 Node 解析模块时会先取真实路径,于是解析起点跳出了 ~/.dsh/profiles 目录树,插件依赖的宿主模块就找不到了。
正确做法是先打包再安装:
pnpm pack # 产出 dsh-plugin-oss-backup-x.y.z.tgz
pnpm add file:<绝对路径>/dsh-plugin-oss-backup-x.y.z.tgz
三、配置(照着做就行)
第 1 步:决定用哪个 provider
选一个就好:
OSS_PROVIDER=rustfs # 默认值,自建服务(RustFS / MinIO)
OSS_PROVIDER=aliyun # 阿里云 OSS
OSS_PROVIDER=aws # AWS S3
不设置 OSS_PROVIDER 时按 rustfs 处理。
第 2 步:创建最小权限子账号(必做)
不要跳过这一步。 用主账号密钥意味着一旦泄漏,整个云账号都危险。
阿里云 OSS(RAM 子账号)
1. 控制台 → RAM 访问控制 → 用户 → 创建用户,勾选「OpenAPI 调用访问」(只拿 AccessKey,不要开控制台登录);
2. 创建自定义权限策略(不要用 AliyunOSSFullAccess 这类系统策略),把 dsh-backup 换成你自己的桶名:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": ["oss:PutObject", "oss:GetObject", "oss:HeadObject"],
"Resource": ["acs:oss:::dsh-backup/"]
},
{
"Effect": "Allow",
"Action": ["oss:ListObjects", "oss:GetBucketInfo"],
"Resource": ["acs:oss:::dsh-backup"]
}
]
}
3. 把这个策略授权给刚建的用户;
4. 记下它的 AccessKey ID 与 Secret,下一步要用。
AWS S3(IAM 用户)
把上面的策略换成 IAM 语法即可(Resource 形如 arn:aws:s3:::dsh-backup/):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowBackupObjectsOnly",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::dsh-backup/"]
},
{
"Sid": "AllowListOwnBucket",
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetBucketLocation"],
"Resource": ["arn:aws:s3:::dsh-backup"]
}
]
}
RustFS / MinIO
mc admin user add <alias> dsh-backup-bot '<一个强随机密码>' mc admin policy create <alias> dsh-backup-rw ./dsh-backup-rw.json # 内容即上面的通用策略 mc admin policy attach <alias> dsh-backup-rw --user dsh-backup-bot
第 3 步:设置环境变量
挑你自己那一档,把值换成上面拿到的密钥。
强烈建议优先用密钥管理器接入。 下面的 setx 示例只是「最不依赖任何工具」的写法;更好的做法是让 1Password / Vault / AWS Secrets Manager 这类工具在启动 dsh web 时把凭证注入环境变量 —— 密钥就不用出现在 shell 历史、脚本或任何磁盘文件里。
完整的接入清单(1Password / Bitwarden / Vault / AWS / Azure / Doppler / direnv / Docker / systemd)见 凭证接入指南。
先说清一件事:值从哪来都行。 插件只关心「这个键在你的进程环境里存不存在」,不关心它怎么来的。下面这些完全等价,用你顺手的那个:
| 来源 | 怎么做 |
| 密钥管理器(推荐) | op run -- dsh web(1Password)、doppler run -- dsh web、Vault / AWS Secrets Manager 等 —— 见接入指南 |
| 系统环境变量 | Windows setx、macOS / Linux export(下面就是这一种) |
| .env 文件 | 复制 .env.example 改成 .env,放到 <DSH home>/oss-backup/.env 或当前工作目录 —— 插件启动时自动读(只适合本地临时用,务必确认它被 gitignore) |
| Docker | docker run -e RUSTFS_ACCESS_KEY=... |
| CI | GitHub Actions Secrets / GitLab CI Variables 之类 |
.env 的几条规则(只读,插件永不写入):
- 优先级:.env > 系统环境变量。.env 是你显式写下来的那份,比机器上残留的旧 export 更权威 —— 否则「我在 .env 里改了却毫无效果」会非常难查。
被覆盖的键名会进日志与界面(只有名字,没有值);
- 只采用第一个能读到的文件(先看 <DSH home>/oss-backup/.env,再看当前工作目录),不做多层合并 —— 否则出问题时没法解释某个值来自哪份文件;
- 解析规则就那几条:KEY=value、KEY="value"、export KEY=value、# 注释。
不支持行内注释、多行值、变量展开 —— 支持它们只会让「值被悄悄改掉」成为可能的解释;
- 改了 .env 要重启 dsh web 才生效(和系统环境变量一样)。
① RustFS / MinIO
setx OSS_PROVIDER "rustfs"
setx RUSTFS_ENDPOINT "http://127.0.0.1:9000"
setx RUSTFS_BUCKET "dsh-backup"
setx RUSTFS_ACCESS_KEY "<子账号 AK>" setx RUSTFS_SECRET_KEY "<子账号 SK>"
② 阿里云 OSS
setx OSS_PROVIDER "aliyun"
setx OSS_BUCKET "dsh-backup"
setx OSS_REGION "oss-cn-hangzhou" # 默认就是这个 OSS_ENDPOINT 可以留空:会自动拼成 https://oss-cn-hangzhou.aliyuncs.com setx OSS_ACCESS_KEY_ID "<RAM 子账号 AccessKey ID>" setx OSS_ACCESS_KEY_SECRET "<RAM 子账号 AccessKey Secret>"
如果你显式设 OSS_ENDPOINT,一定要带上 https://。不带协议头时会被当成 http:// 处理,连接必然失败。
③ AWS S3
setx OSS_PROVIDER "aws"
setx AWS_BUCKET "my-backup-bucket"
setx AWS_REGION "us-east-1" # 必填 setx AWS_ACCESS_KEY_ID "<IAM 用户 AccessKey ID>" setx AWS_SECRET_ACCESS_KEY "<IAM 用户 Secret Access Key>" AWS_ENDPOINT 一般留空,表示用 AWS 官方端点
macOS / Linux 把 setx X "v" 换成 export X="v",并写进你的 shell 配置文件。
第 4 步:重启 dsh web
这一步不能省。 环境变量是进程启动时读取的,正在运行的 dsh web 不会自动感知新变量。
第 5 步:确认配置成功
重启后打开 设置 → 对象存储备份,看「环境自检」:
- 状态应显示「就绪」;
- provider 一行会写明当前用的是哪一档(例如 RustFS / MinIO 等自建 S3 兼容端点 · path-style);
- 密钥两行应显示「已设置(值不显示)」。
⚠️ 「就绪」不只看变量配没配齐:插件会真的对存储桶发一次 HeadBucket 去确认服务能连上(结果缓存 30 秒)。所以还有第三种状态:
| 状态 | 含义 | 怎么办 |
| 就绪 | 变量齐了,服务也连得上 | 可以直接用 |
| 变量齐了,但服务连不上 | 端点/桶/密钥有一处不对,或者服务根本没启动 | 看下方红字里的具体原因 |
| 缺少 N 个变量 | 环境变量没配齐 | 那一行会列出缺哪个变量名 |
「服务连不上」这一条是专门为下面这种情况加的:变量都填好了、但 RustFS 没开 ——以前会显示成"就绪",看着一切正常,实际上每次上传都在连接被拒。
小贴士:setx 设了但插件说"未配置"?
setx 写入的是用户级环境变量,而已启动的进程(尤其是从快捷方式、启动器拉起来的
dsh web)不一定继承得到它。所以插件每次启动都会主动去读一遍系统里的环境变量
(先看进程已有的,再看用户级,最后看系统级),缺什么补什么 —— 不会覆盖你已经设好的值。
界面上会标注「当前来自系统环境变量(启动时自动补读:…)」,看到它就说明补读成功了。
你只需要保证设过值 + 重启过一次。
四、使用
手动备份一个文件夹
1. 打开 设置 → 对象存储备份 → 设置;
2. 在「备份目录」里填要备份的目录(例如 D:\projects\my-project);
3. 点「保存」;
4. 回到「手动备份」块,点「立即备份」。
它会递归备份整个文件夹,完成后显示:共多少个文件 → 成功几个 / 失败几个 · 总大小。
没变化的文件会自动跳过。 插件在 ~/.dsh/oss-backup/uploaded.json 里记着每个对象键对应的 (文件大小, 修改时间),下次备份时一致的直接跳过 —— 所以重复点「立即备份」只会传真正改过的那几个,不会再把你几千个没动过的文件重传一遍。界面会显示「跳过 N 个未变化的」。
判定依据是大小 + 修改时间。改了内容一般也就会改修改时间,所以会被正确重传;只有"内容变了但大小和修改时间都没变"这种刻意为之的情况才会漏判。
换机器或删掉那个索引文件也不影响正确性 —— 只是会重传一次,之后恢复正常。
上传后的对象路径规则是 前缀 + 被备份目录自己的名字 + 相对路径。例如备份 D:\projects\projects\yy(里面是 11、22 两个子文件夹),桶里会出现:
workspace-backup/yy/11/...
workspace-backup/yy/22/...
yy 这一层会保留,这样在桶里一眼就能看出这批文件属于哪个目录。
会自动跳过的目录:node_modules、.git、.hg、.svn、.pnpm-store、.npm-cache、 __pycache__、.venv。这些要么体积巨大,要么是可再生的产物。
想让备份"一个文件都不少",把设置里的「跳过依赖 / 缓存目录」开关关掉即可。
限额:最多 2000 个文件、单个文件最大 5 GB、总量 50 GB。触发上限时界面会提示「已触到文件数上限」。
超过 8 MB 的文件走分片上传(@aws-sdk/lib-storage,每片 8 MB、4 片并发),内存占用恒定、与文件大小无关 —— 所以单文件上限敢放到 5 GB(S3 单次 PUT 的上限;分片协议本身允许到 5 TB)。这几个数只是防呆,用来拦住"误选了整个磁盘"。
误选了也没关系:备份途中可以点「强行打断」。 它会立刻停下 —— 正在传的那个文件被掐断(在途的分片请求一并中止),已经传完的不受影响,也不会被记成"失败"。
下次备份会从没传完的地方继续(查重会跳过已成功的那部分)。
《接数据》(备份前的小游戏)
点「立即备份」时,如果游戏开关是开着的,会先在「上传状态」那一格里来一局节奏小游戏《接数据》—— 通关了才真的开始备份。
不想玩的话,把设置里的开关关掉,之后点按钮直接开始。
怎么玩
- 四条轨道,方块从右往左滑;键盘 D F J K 对应四条轨道(键位标在判定线左侧,一直在),也可以直接用鼠标点那条轨道;
- 左侧有一条判定线,方块经过它的一瞬间点掉它;
- 判定分三级,窗口挺严的:
| 判定 | 条件 | 扣分 |
| PERFECT | ±0.09 秒内点中 | 不扣分 |
| GOOD | ±0.175 秒内(不够准) | 扣 0.5 个 |
| LOST | 过了 0.175 秒都没点 | 扣 1 个 |
命中时判定线会亮起、对应轨道扫过一层光、判定处扩散一圈光环 —— PERFECT 是品牌色、GOOD 是灰色,一眼就能看出自己准不准。
四档难度
| 难度 | 一局时长 | 特点 |
| 杂鱼 | 约 22 秒 |
| 简单 | 约 29 秒 |
| 中等 | 约 36 秒 |
| 齁哦哦哦 | 约 45 秒 |
难度会记住,下次打开还是这一档。
计分规则
满分 100 分,扣分按总方块数分摊:
扣分 = (GOOD × 0.5 + LOST × 1) ÷ 总方块数 × 100
也就是 PERFECT 完全不扣分,GOOD 扣半个,LOST 扣一个。参考:
- 全部 PERFECT → 100 分;
- 全部 GOOD → 50 分(这也会失败);
- 全部 LOST → 0 分。
结果为:
- 扣分 < 30 → 通过,备份自动开始;
- 扣分 ≥ 30 → 失败,备份不会触发
用「按总数分摊」而不是「每个失败固定扣几分」,是为了让四档难度的容错率一致 ——高难度方块多得多,固定扣分会让它直接变成不可能完成。
文件改动自动备份
在设置里把「自动备份」开关打开(点一下立即生效)。
之后每次模型保存文件,该文件会在停止改动 2 秒后自动上传;上传失败会自动重试 3 次(间隔 1 秒 / 2 秒 / 4 秒),仍失败就只记一条日志,不会影响你正常的写文件操作。
开关关闭时完全不生效,这是默认状态。
连不上时直接不提供上传
- 确认连不上之后,所有上传入口一起停:模型调 oss_backup 会被直接拒绝、「立即备份」按钮变灰并说明原因、自动备份与定期备份都不再排期;
- 连接 / 凭证 / 桶名这类错误不重试 —— 它们不会因为多等 4 秒就变好,直接失败;
- 连续失败 3 次也会熔断,暂停 60 秒,期间的文件改动直接跳过、不排队;
- 界面上写明原因(例如 ECONNREFUSED),服务恢复后自动重新可用,不用重启。
注意:这个开关监听的是模型的文件写入操作。如果你用命令行工具(例如 git、脚本)直接改文件,不会触发自动备份 —— 那种情况请用手动备份。
定期全量备份
在设置界面的「定期全量备份」一行选模式(改完点「保存」生效),宿主会按时间表把整个备份目录完整传一遍 —— 与上面「文件改动自动备份」是两套独立的机制,可以只开一个,也可以都开。
| 模式 | 说明 | 例子 |
| 关闭 | 默认,不排期 | — |
| 按间隔 | 每 N 分钟 / 小时 / 天 | 每 6 小时 |
| 每天 | 每天固定时刻 | 每天 03:00 |
| 每月 | 每月固定几号的固定时刻 | 每月 1 日 03:00 |
设置那一行下面会显示下次实际触发时间,方便确认排期对不对。
几个刻意的设计,避免你踩坑:
- 固定节拍:「按间隔」对齐到排定时刻,不是「从现在往后加一段」。每 30 分钟就是 :00 和 :30,每 6 小时就是 00/06/12/18,「每 N 天」对齐到当地零点 ——一次备份跑多久都不会把后续时间点往后推;
- 内部用的是「跑完再排下一次」的链式定时器(不是 setInterval),所以也不会堆叠出好几次备份;
- 上一次还在跑就跳过这一轮(不排队),日志里会记一条「跳过」;
- 每月只支持 1-28 号:这样每个月都一定存在,不会遇到「2 月没有 30 号」那种要么跳过一个月、要么被顺延到 3 月 1 号的情况;
- 还没设置备份目录时不会排期,只记一条日志提醒你;
- 时间点用的是本机时区。
备份范围、排除规则(node_modules / __pycache__ 等)和文件数 / 体积限额,与「手动备份」完全一致 —— 它俩共用同一套逻辑。
凭证(在设置界面里临时填写密钥)
如果你不想用 setx,也可以在设置界面的「凭证」块里直接填 AK/SK,点「应用到本次进程」:
- 填完立刻生效,可以马上试一次手动备份;
- 只对本次运行有效 —— 重启 dsh web 后需要重新填;
- 提交后输入框会立即清空,界面上永远不会回显你填过的值;
- 想让配置永久有效、以后都不用填,还是用 setx(见第三节)。
高级设置
展开「高级设置」,可以改这些非机密项(会保存下来,重启后仍在):
| 项 | 说明 |
| 对象键前缀 | 桶里的目录层级,默认 workspace-backup/ |
| Provider | 覆盖 OSS_PROVIDER(留空则用环境变量) |
| 端点 | 覆盖端点(留空则用环境变量或按区域自动推导) |
| 存储桶 | 覆盖桶名(留空则用环境变量) |
| 区域 | 覆盖区域(留空则用环境变量或默认值) |
优先级:Provider 以设置页为准(这是你在界面上明确选的),端点 / 桶 / 区域以环境变量为准(已经设过的不会被悄悄改掉)。
让模型上传单个文件
模型可以直接调用 oss_backup 工具,传一个本地文件和目标对象路径,例如:
把 D:\backup\report.tar.gz 上传到对象存储,objectKey 用 backups/report.tar.gz
这是单文件上传;要备份整个文件夹请用上面的「手动备份」。
云端备份按钮
「云端备份」按钮会打开当前 provider 对应的网页控制台,方便你在网页里核对桶里的内容。
地址由插件按你的配置推导,换 provider 之后按钮自己就指对了:
| provider | 打开哪里 |
| rustfs(自建 / MinIO) | 本机网页控制台 —— 由端点端口 +1 推出来(http://127.0.0.1:9000 → http://127.0.0.1:9001/) |
| aliyun | 阿里云 OSS 控制台,直达当前这个桶的对象列表 |
| aws | AWS S3 控制台,直达当前这个桶(带上你配的 region) |
按钮旁边会显示完整地址,并做成真链接 —— 万一浏览器拦下了新窗口,点链接照样能打开。
端点或桶还没配好时,这一块会直说「地址推导不出来」,而不是给一个打不开的链接。
五、常见问题
Q:环境自检显示「缺少 N 个变量」怎么办? 那一行会列出具体缺哪个变量名。按第三节补上,然后重启 dsh web。
Q:明明 setx 过了,为什么还说未配置? 两个常见原因:① 设完没有重启 dsh web;② 变量设到了别的账户下(例如你在管理员终端里 setx,但 dsh web 跑在普通用户下)。
插件启动时会主动补读系统环境变量,所以只要「设过 + 重启过」就会生效。
Q:上传失败,怎么排查? 界面的「手动备份」块会显示失败条数,以及最多 5 条失败原因;「最近上传」里也有记录。
常见原因:密钥没有目标桶的写权限、桶名写错、端点地址不对、网络不通。
Q:备份目录里文件太多,会不会传很久? 会。手动备份是逐个文件上传的,且带上面说的限额。建议备份项目目录,而不是整个磁盘根目录。
Q:重启后设置还在吗? 在。「开关 / 备份目录 / 前缀 / 跳过缓存 / provider / 端点 / 桶 / 区域」都保存在 ~/.dsh/oss-backup/config.json,重启后自动恢复。
只有密钥在「界面临时填写」那种方式下需要重填 —— 用 setx 就没这个问题。
Q:界面上会显示我的密钥吗? 不会,任何时候都不会。界面只显示「已设置」或「未设置」。
Q:备份上去的文件怎么恢复? 直接用你对象存储服务商的控制台或命令行下载即可(对象路径见上面的规则)。
本插件只负责上传。
Q:能同时配多个桶 / 多套账号吗? 不能。插件一次只对一个存储目标生效,切换需要改环境变量或「高级设置」里的覆盖值。
六、安全说明
你的密钥是怎么被处理的
这个插件按四条原则设计,每一条都由代码结构保证,而不是靠「记得别打印」:
| 原则 | 具体做法 |
| 代码里没有明文密钥 | 整个仓库里只有变量名(如 RUSTFS_ACCESS_KEY),没有任何真实值;.env.example 里全是空占位 |
| 日志和错误里不出现密钥 | 加载日志只报变量名;报错只说缺哪个变量;所有对外文本在出口还会再走一遍脱敏,抹掉密钥字面量以及签名形态(X-Amz-Signature、Signature=、Credential=、URL 里的用户名密码等) |
| 密钥不写入本地文件 | 插件不读 .env;config.json 只保存非机密项;界面上临时填写的密钥只存在于进程内存里 |
| 前端拿不到密钥 | 界面跑在浏览器沙箱里,没有读取环境变量的能力。它唯一的数据来源是一条只读的脱敏状态接口,密钥部分只有「是 / 否」。界面填写的密钥是单向送进宿主的,宿主永远不回传 |
你应该注意什么
-一定一定优先用密钥管理器接入!!!本插件不自带密钥管理器功能。
- 务必用最小权限子账号,并且只授权你真正需要的那个桶;
- 不要在共享电脑、共享屏幕上操作「凭证」块,也不要在填完后让别人看你的浏览器;
- 定期在服务商后台轮换密钥;
- 如果怀疑泄漏,先吊销再排查,不要抱侥幸心理;
- 本插件只能保护「它自己不泄露密钥」,无法保护你把它贴到聊天窗口或提交进 Git。
仓库自带的检查
如果你要参与开发或二次分发,仓库里有两道自动检查:
pnpm run check:secrets # 扫描仓库里有没有明文密钥(会与环境里真实的凭证值比对)
pnpm run check:load # 构建产物能否正常加载
CI(GitHub Actions)里还跑 Gitleaks,会扫描提交历史,一旦发现疑似密钥就让构建失败。
七、开发者信息
pnpm install
pnpm run build # 编译 host(tsc)+ 打包 client(esbuild)
pnpm test # 258 个单元测试
pnpm run typecheck:client
pnpm run check:secrets
pnpm run check:load
项目结构
src/
index.ts host 入口:注册工具 + 四条 HTTP 路由(状态 / 设置 / 凭证 / 手动备份) env.ts provider 档案(rustfs / aliyun / aws)与环境变量校验 env-source.ts 启动时补读系统环境变量(Windows) dotenv.ts 启动时补读 .env(只读,永不写入;优先级高于系统环境) settings.ts 设置读写(只存非机密项) auto-backup.ts 自动备份:防抖 + 指数退避重试 + 对象键净化 manual-backup.ts 批量备份:目录遍历、排除名单、限额、查重、逐个上传 upload-index.ts 已上传文件索引(只存大小与修改时间,用于跳过没变化的文件) upload.ts S3 客户端构造 + PutObject redact.ts 出口脱敏 client/ 界面(设置页 / 侧边栏 / 主面板) assets/ code-uploading.jpg 上传中弹出的那张图 scripts/ 构建、真实上传冒烟、密钥自检、加载自检 tests/ vitest
发布
pnpm run build && pnpm test && pnpm run check:secrets && pnpm run check:load
npm pack --dry-run # 确认包里有 lib/、assets/、cordis.patch.yml、README.md、LICENSE
npm publish
设计上的两个注意点
- webServer 必须是硬依赖(inject 里列上)。用软取(ctx.get)时,apply 阶段该服务可能还没就绪,会导致路由静默不注册,症状是设置页永远显示「未连接」。
- client bundle 的模块 id 必须是包名。client-modules 按最近归属的 package.json 判定浏览器模块 id,写错会报 loaded without registering,并让界面半边失效。
License
MIT —— 见仓库根目录的 LICENSE 文件。
形象来源与许可
「接数据」小游戏与界面中出现的鲸鱼娘等形象取自 @ZipZipPipe,基于 @上善无形 原创角色二创,依 CC BY-NC-SA 4.0 协议非商业使用。
这些形象不在本项目的 MIT 许可范围内 —— MIT 只覆盖代码。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
KAIROSLLL/dsh-plugin-oss-backup
DSH 插件:把工作区备份到 S3 兼容对象存储RustFS / 阿里云 OSS / AWS…
相关插件 · 其他
模型破甲清洗HunYiSage/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,993已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,269已汉化DSH
70.8
这是你的仓库?认领条目