- Inicio
- Plugins
- Seguridad y permisos
- dsh-push-privacy-guard
dsh-push-privacy-guard
lizhijie429/dsh-push-privacy-guard
Privacy guard for git workflows: before git commit, git push or gh repo sync it scans the content that would enter git (local paths, user info, API keys, private keys, connection strings) and blocks anything not approved in the DSH approval UI; approved items go into a manageable, masked whitelist. Native DSH Config schema with live settings, first-push full-repository scan, fail-closed checks, zero npm runtime dependencies.
Instalar
dsh plugin --profile web add github:lizhijie429/dsh-push-privacy-guardREADME
dsh-push-privacy-guard
简体中文 | English
DSH(DeepSeek Harness)Host 插件:在 Agent 执行 git commit、git push(以及 gh repo sync)之前检查将要进入 git 的内容,发现本地绝对路径、用户信息、API Key、私钥、连接串等敏感信息时,通过 DSH 原生审批面板请求用户一次性授权;拒绝则阻止命令,批准则放行并把本次授权的信息写入可管理的白名单,之后同样的信息不再重复询问。
定位:内容泄露护栏,不是安全边界。它只覆盖 DSH 工具层(
pwsh/bash一次性命令,以及 PTC 内部 bash 调用);持久终端(terminal_send)的 commit/push 默认直接拒绝;不覆盖人工终端推送、脚本内部自行发起的推送,也不能发现规则库之外的泄露形式。
能力
- 提交前检查:扫描
git commit将记录的暂存区内容;同一命令里先git add、commit 带 pathspec /-i/--include、commit -a时按git diff HEAD覆盖工作区改动并补扫未跟踪文件;同时检查-m/-F/--trailer提交信息。-F -、命令替换等无法预读的信息按“扫描不完整”处理并请求授权。 - 推送前检查:只读计算本次
git push真正要上传的范围(支持git -C、多个/通配 refspec、remote、--force、--all、--mirror、--delete、gh repo sync),按提交逐个扫描(git log -p,含“先加后删”的中间提交)+ 待推送提交信息 + tag 对象消息。 - dry-run 放行:
git push --dry-run/git push -n不上传任何内容,直接放行、不打扰。 - 首次仓库全仓扫描:某个仓库第一次通过 DSH 推送时询问一次「是否先全仓库扫描」;全仓扫描用
--full-tree覆盖整个HEAD的 git 已跟踪文件,.gitignore忽略的内容天然不参与。之后该仓库只检查本次提交/推送内容。 - 用户授权:命中未白名单项时调用
ctx.approval.request(),在 Web UI 审批面板展示脱敏后的命中清单;批准 = 本次放行 + 入白名单,拒绝/取消 = 阻止命令。 - 白名单管理:
/privacy-guard斜杠命令(用户专属,不产生模型消息),底层state/whitelist.json可手改、即时生效。 - 失败关闭:一旦识别为 commit/push,扫描失败/超时/git 查询失败/无法获得授权都会阻止命令,而不是放行;
git commit/git push无法定位仓库时默认拒绝(unresolvedRepo)。 - 原生配置 schema:
index.mjs导出 CordisConfig(Schemastery),加载时由 DSH 校验;开关、模式、上限与路径字段标记为.volatile(),可在 DSH 设置页直接修改并热生效(loader 提交后插件原地刷新配置,不重启)。 - 零运行时依赖(仅
node:*内置模块;Schemastery 按 MIT 许可内嵌在vendor/),可按绝对路径挂载,也可作为 bundle 安装。
工作原理
工具调用(pwsh / bash / terminal_send / PTC 内部 bash)
└─ tools/pre-execute(本插件,异步,prepend)
├─ lib/detect.mjs 解析命令:git commit / git push / gh repo sync;workdir、cd、git -C
├─ lib/scan.mjs 只读 git:暂存区 / 推送范围 / 全仓 tracked 文件 / 提交信息
├─ lib/rules.mjs 规则匹配、占位符过滤、掩码、稳定指纹
├─ lib/whitelist.mjs 白名单(只存掩码,不存明文)
├─ lib/repo-state.mjs 每仓库是否已问过全仓扫描
└─ ctx.approval.request() → 用户允许 / 拒绝
└─ 放行 → 工具执行;拒绝 → 返回 {kind:'deny', reason}
/privacy-guard …(ctx.inject(['commands']) 可选注册,仅用户可见)
所有 git 调用都是只读子命令(rev-parse / rev-list / diff / log / for-each-ref / ls-tree / cat-file / remote),不会修改仓库、index 或远端;全仓扫描通过一次 git cat-file --batch 流式读取所有 blob。
内置规则(V1)
| 规则 | 说明 | 级别 |
|---|---|---|
private-key-block | -----BEGIN … PRIVATE KEY----- / PGP 私钥块 | 高 |
aws-access-key | AKIA / ASIA + 16 位 | 高 |
github-token | ghp_ / gho_ / ghu_ / ghs_ / ghr_ | 高 |
github-fine-grained-token | github_pat_… | 高 |
gitlab-token | glpat- / gldt- / glrt- | 高 |
npm-token | npm_… | 高 |
openai-key | sk- / sk-proj- 长串 | 高 |
slack-token | xox[baprs]-… | 高 |
google-api-key | AIza + 35 位 | 高 |
jwt | 三段 JWT | 高 |
bearer-token | Bearer <token> | 高 |
assigned-secret | password/secret/token/api_key/... = 值 | 高 |
assigned-secret-zh | 密码/密钥/令牌/凭证:值 | 高 |
connection-string | mongodb/mysql/postgres/redis/amqp/jdbc URI | 高 |
local-abs-path-win | Windows 绝对路径(C:\Users\…) | 中 |
local-abs-path-unc | UNC 共享路径(双反斜杠开头的网络共享路径) | 中 |
local-home-path-posix | /Users/…、/home/… | 中 |
ssh-home-path | ~/.ssh/<文件>、$HOME/.ssh/<文件>、%USERPROFILE%\.ssh\<文件> | 中 |
email | 邮箱(过滤 example / noreply / git@github.com 等占位) | 中 |
cn-mobile | 中国大陆手机号 | 中 |
cn-id-card | 18 位身份证(校验位通过才报) | 高 |
internal-url | 内网 IP / .local、.internal、.corp 地址 | 中 |
过滤:${…}、{{…}}、<…>、your_*、changeme、process.env.*、os.environ[...]、示例域名等占位值不报;ignorePaths 默认忽略锁文件、*.min.js、*.map、node_modules、dist、build 等。
白名单
state/whitelist.json:
{
"version": 1,
"entries": [
{
"id": "a1b2c3d4e5f60718",
"rule": "openai-key",
"label": "OpenAI API Key",
"masked": "sk-a…34",
"firstFile": "src/config.ts",
"addedAt": "2026-11-03T02:00:00.000Z",
"source": "approval"
}
]
}
- 身份 =
sha256(规则 id + 命中值)截断 16 位:同一个敏感值跨文件、跨仓库只需授权一次。 - 只存掩码,不落明文;手改后下一次检查立即生效;文件损坏时按空白名单处理并写日志。
- 仓库初始化状态在
state/repos.json。
/privacy-guard 命令
| 命令 | 行为 |
|---|---|
/privacy-guard list | 列出白名单条目(id / 规则 / 掩码 / 首次文件 / 时间) |
/privacy-guard remove <id前缀> | 删除单条(前缀需唯一) |
/privacy-guard clear confirm | 清空白名单(必须带 confirm) |
/privacy-guard status | 开关、文件路径、规则数、白名单数、已初始化仓库数、当前仓库状态 |
/privacy-guard repos | 列出已初始化仓库 |
/privacy-guard reset <路径子串|all> | 清除仓库初始化记录,下次推送重新询问全仓扫描 |
/privacy-guard scan | 立即扫描当前会话仓库(全仓 tracked + 暂存区)并报告,不推送、不写白名单 |
/privacy-guard help | 帮助 |
命令在 Web UI 的命令面板执行,不会变成模型消息,模型无法借此修改白名单或自我授权(但能直接写 state/whitelist.json 的主体是信任边界,见“已知限制”)。
配置(profile cordis.patch.yml 的 config:)
配置由 lib/schema.mjs 导出的 Cordis Config(Schemastery)校验:非法枚举/类型会在加载时报错,不再静默回退。带 .volatile() 的字段会出现在 DSH 设置页表单中(设置页只投影 volatile 字段);编辑后 loader 直接提交新值并触发 loader/volatile-update,插件原地刷新配置,无需重启。数组/对象类字段(disableRules、extraRules、ignorePaths)仍通过 cordis.patch.yml 修改,由 profile 重载生效。
| 字段 | 默认 | 说明 |
|---|---|---|
enabled | true | 总开关 |
interceptCommit | true | 检查 git commit |
interceptPush | true | 检查 git push / gh repo sync |
fullScanOnFirstPush | ask | ask / always / never |
unresolvedRepo | deny | 识别出 commit/push 但仓库定位失败(变量路径、非仓库、GIT_DIR 覆盖等)时:deny / allow |
persistentShellCommits | deny | terminal_send 等持久终端的 commit/push(无法获知其真实 cwd):deny / allow |
whitelistOnApprove | true | 授权后自动写白名单 |
requireApprovalOnIncompleteScan | true | 扫描不完整(超时/超限/大文件跳过/动态提交信息)时是否要求授权 |
disableRules | [] | 关闭的内置规则 id |
extraRules | [] | 自定义规则 {id,label,pattern,flags,severity,mask,capture} |
ignorePaths | 锁文件/构建产物 | 追加到默认忽略 glob |
whitelistFile | state/whitelist.json | 相对插件目录或绝对路径 |
repoStateFile | state/repos.json | 同上 |
logFile | state/push-privacy-guard.log | 同上;挂载时 >5MB 轮转一次 |
maxTotalBytes | 20 MiB | 单次差异/扫描总字节上限 |
maxFileBytes | 1 MiB | 全仓/未跟踪单文件上限;超限跳过会把扫描标记为不完整(默认要求授权) |
maxFiles | 5000 | 全仓文件数上限 |
maxCommits | 100 | 多分支/镜像逐提交扫描与提交信息上限 |
maxFindings | 200 | 单次扫描命中上限 |
maxApprovalItems | 20 | 审批文案最多列举条数 |
gitTimeoutMs | 20000 | 单条 git 命令超时 |
非法值回退默认并写 config.warning 日志,不会静默失效。
社区收录 / 插件市场
可通过 DSH「插件 → 发现」添加本插件自带的市场索引(格式 1,由 @deepseek-ai/dsh-plugin-market-index 的 parseMarketIndex 校验):
https://raw.githubusercontent.com/lizhijie429/dsh-push-privacy-guard/main/market/index.json
步骤:先启用实验性的 自定义插件市场(插件 → 实验性插件 → 更多 → 自定义插件市场),再在 插件 → 发现 → 索引源 中粘贴上面的 URL,搜索 “Push Privacy Guard” 安装即可。
也可以直接用 Git 源安装(无需 npm 发布):
dsh plugin --profile desktop add https://github.com/lizhijie429/dsh-push-privacy-guard
已提交的社区收录:
- Open Plugin Market(社区插件索引)收录申请 #216(pinned Git commit
756cc68,v0.2.1)。 - awesome-dsh-plugin 精选列表 PR #11727(
data/plugins/lizhijie429__dsh-push-privacy-guard.yml)。 - GitHub Release v0.2.1(变更说明与安装方式)。
npm 包尚未发布(需要维护者 npm token);当前以固定 Git commit 作为市场安装源。索引条目只声明安装参数,实际安装内容以仓库
package.json与cordis.patch.yml为准。
安装
桌面端(desktop profile)
在 %USERPROFILE%\.dsh\profiles\desktop\cordis.patch.yml 末尾追加(把 <用户> 换成实际 Windows 用户名):
- insert:
- id: push-privacy-guard
name: 'C:\Users\<用户>\.dsh\plugins\dsh-push-privacy-guard\index.mjs'
config:
fullScanOnFirstPush: ask
whitelistOnApprove: true
desktop profile 的 patchReload 为 live,保存后热加载;state/push-privacy-guard.log 出现 plugin.mounted 即生效。代码改动后需重启 DeepSeek Harness(Node ESM 模块缓存)。
其他 profile(bundle 方式)
dsh plugin --profile web add "file:$env:USERPROFILE\.dsh\plugins\dsh-push-privacy-guard"
package.json 的 dsh.bundle.patch 会加载 cordis.patch.yml 默认配置。
验证
cd "$env:USERPROFILE\.dsh\plugins\dsh-push-privacy-guard"
npm test
Get-Content state\push-privacy-guard.log -Tail 20
CI:.github/workflows/test.yml 在 ubuntu-latest / windows-latest(Node 22)上执行 npm test(含真实 git 集成用例)。
端到端(需要会话审批策略为 ask,即有审批面板可点):
- 在临时仓库
git add一个包含sk-<长串>的文件,执行git commit→ UI 弹审批;批准 → 提交成功且state/whitelist.json增加条目;再次提交同类内容不再询问。 - 换一个新的假密钥 → 拒绝 → 命令被阻止。
- 首次
git push→ 弹「是否全仓扫描」;拒绝后只检查本次推送,state/repos.json记录该仓库。
若会话审批策略为
never(关闭审批),本插件一律拒绝命中项——这是 fail-closed 设计,不是故障。需要弹窗授权时把策略切回ask。
已知限制
- 不覆盖 DSH 之外的操作:人工终端推送、脚本内部自行执行
git push、其他机器上的推送都不经过本插件。 - 只检查将要进入 git 的内容:未暂存/未跟踪文件不会被提交或推送,因此不检查;
git push只按本地 git 数据估算上传范围(不联网)。 - 仅识别命令文本:
bash -c/pwsh -Command会递归解析一层;变量拼接、别名、node deploy.mjs之类间接执行无法识别。 - 持久终端默认拒绝:
terminal_send等持久终端的真实 cwd 无法获知,commit/push 默认直接拒绝;需要时把persistentShellCommits设为allow(风险自担),或改用一次性的pwsh/bash+workdir。 - 仓库定位失败默认拒绝:
cd $repo、GIT_DIR=…、非仓库目录等无法定位仓库时默认拒绝;可用git -C <绝对路径>/workdir,或把unresolvedRepo设为allow。 - force push / mirror:已覆盖多个/通配 refspec 与 tag 对象;但被强制覆盖的远端旧历史、
--mirror删除的远端 ref 不重扫。 - 首次全仓扫描只看
HEAD的已跟踪文件:历史提交中被删除的敏感信息不会被重新发现;大文件(>maxFileBytes)跳过时标记不完整(默认要求授权)。 git commit -C/-c/--fixup复用的旧提交信息在 commit 阶段不重扫(push 阶段通常兜底;interceptPush:false时属残余风险)。- 规则库不是万能:高熵字符串、自定义内部格式、二进制内容可能漏报;规则可配置但与任何正则方案一样存在误报/漏报。
- 白名单文件即信任边界:能写
state/whitelist.json的主体(Full access 会话中的模型、其他插件、把 state 指到 workspace 的配置)可以预置白名单实现“自我授权”;请把 state 放在用户目录并限制写权限。 - 多进程并发写白名单只在单进程内串行;同时运行多个 DSH 进程时可能相互覆盖。
- 不清理仓库:插件只负责阻止/放行,不会自动删除已提交的敏感信息或改写历史。
License
MIT,见 LICENSE。
vendor/schemastery 与 vendor/cosmokit 内嵌自 DeepSeek Harness 运行时的 @deepseek-ai/schemastery / @deepseek-ai/cosmokit(MIT,许可证随目录保留),用于让按绝对路径挂载的外部插件也能声明 DSH 原生 Config schema。