Repository navigation
Releases: suhui-organization/pod
Release list
v0.4.2 — 资产与发现按机器去重
v0.4.2 — 资产与发现按机器去重(修真实缺陷)
真机验证时暴露:一台机器接了三个 agent(codex / hermes / deepseek-harness),
而资产是机器级快照、云端一行 Agent = 一个绑定——于是同一份清单被复制三份,
Dashboard 上"48 个 server 绕过网关"实际是 16 × 3。看着精确、其实不对的数字
比没有数字更糟,所以这一版修掉。
- 端 A:inventory 增加
machine_id(sha256(hostname|username|platform)前 16 位,
哈希而非明文),并随X-Pod-Machine头用于发现上报;确定性派生,不写本机状态。 - 端 B:两张表新增
machine_id列(走 ADD COLUMN 迁移);Dashboard 的覆盖率与
Top 威胁按(machine_id, key)去重,并新增machines_with_unmanaged(涉及几台机器)。 - 老客户端没上报
machine_id时退回按agent_id计——宁可不合并,也不要错合并。 - 测试:
test_same_machine_with_multiple_bindings_is_counted_once与
test_two_machines_are_counted_separately一正一反守这条语义。
安装(钉在本发布版上):
curl -fsSL https://gitee.com/suhuisoftwares/pod/raw/v0.4.2/scripts/install.sh | sh
pod --version # → pod 0.4.2v0.4.1 — 端 A ↔ 端 B 的契约层;资产与发现也上云
v0.4.1 — 端 A ↔ 端 B 的契约层;资产与发现也上云了
一期分工是pod 干活、podcloud 收集·展示·持久化·备语料。这一版补的是两者之间的
管道:先让两端知道彼此的版本与状态,再把"这台机器上有什么、扫出了什么"送上云。
下面每一节都是这一版的一部分(原先散在"未发布"里,发版时归拢到版本号下)。
② 资产 + ③ 发现:pod 干的活的另一半也上云了
一期分工是"pod 干活、podcloud 收集展示持久化"。但此前只有行为那一半(工具调用判定)
真的流到了云端:资产(这台机器上有什么)与发现(扫出了什么)都留在本地,
于是云端资产表只能靠人手工维护,Dashboard 也只有"干了多少活",没有"还缺什么防护"。
② 资产清单(POST /api/v1/sync/inventory)
- 内容:harness 清单与纳管状态(identity / policy / audit)、MCP server 清单与
是否经过网关、覆盖率、当前规则版本; - 语义:快照替换——server 被删掉时云端跟着消失,不靠 diff;
- 落库:
pod_agent_assets(一行一个资产),控制台 Agent 卡片显示
"纳管 harness 2/4 · server 3 个,其中 1 个绕过网关"; - Dashboard 新增网关覆盖率卡片:跨机器统计"还有多少个 server 绕过网关、
涉及几台机器"——这才是运维每天要看的东西。
③ 发现(POST /api/v1/sync/findings)
- 内容:漏洞扫描(
guard,key = AG-xx)与控制平面姿态(posture,key = 类别)
的结果,按(威胁 × 级别 × harness)聚合成计数; - 语义:同样是快照——修好后下次上报即消失,不会在云端永远留一条红;
- 落库:
pod_agent_findings,Dashboard 新增扫描发现卡片(high / 全部 + Top 威胁)。
边界与兼容
- 隐私不变:只出标识、布尔与计数——没有路径、args、env 取值、配置原文与证据;
测试里有专门断言(摘要/资产/发现里都不出现本机路径与命令行)。 - 老服务端可用:两个新端点返回 404 时只提示一次、不算同步失败
(与/sync/quarantine同一口径);老客户端不带这些 payload,云端照常工作。 - 顺手修掉一个展示口径问题:Dashboard 近 7 天趋势此前按上传时间
synced_at分组,
离线机器补传会把历史事件全堆在"今天";现在按事件发生时间ts分组。
测试:apps/cli/test/sync-protocol.test.ts 9 项(新增资产/发现/404 容忍)、
cloud/server/tests/test_sync_protocol.py 8 项(新增落库、快照替换、鉴权、Dashboard 聚合)。
端 A ↔ 端 B 的契约层:协议版本 + 健康摘要
一期架构是两段式:端 A(本机安装的监控/执法程序)与 端 B(SaaS 或用户自部署的控制台)。
两端分开发布——端 A 按 tag 发、端 B 按镜像滚——所以"版本错配"不是异常,是常态。
这一版把这条契约补上:不改变任何安全流程,纯粹让两端知道彼此的状态。
1. 协议版本(两端可判定"能不能配合")
每个上云请求带 X-Pod-Protocol 与 X-Pod-Version;心跳 body 也带协议版本。
服务端据此回 client_outdated + 说明,客户端打印提示但继续同步(可用性优先)。
此前没有版本时,错配的表现是静默半失效:老客户端不认 /sync/quarantine(只打一行警告)、
新字段没人读。有了版本,"少了一半能力"才会被说出来。
2. 健康摘要(把"在线"和"真的在保护"分开)
心跳新增一份只含计数的摘要:审计链条数 / 断裂数 / 最近一次工具调用时间、
server 总数与绕过网关的数量、最近一次漏洞扫描的 high/medium/low。
为什么必须由机器上报:云端看不到本机文件。而"部署了但没生效"恰恰是最常见的形态——
网关没起(没有调用记录)、链被改过(broken > 0)、还有 server 绕过网关(unmanaged > 0)。
控制台现在把这三件事与"在线"分开显示;没上报就写"未上报",不用默认值冒充健康。
隐私边界不变:只出计数、布尔与时间戳,没有路径、主机名、配置原文,
也没有未纳管 server 的名字。
3. 契约写进一个文件
新增 docs/local-cloud-contract.md:两端职责边界、五条通道、
版本与健康字段、兼容矩阵(四种组合各自的行为)、出问题时看哪里。
两端的常量分别在 apps/cli/src/protocol.ts 与 cloud/server/app/protocol.py;
改契约要同时动这两处与本页。
测试:apps/cli/test/sync-protocol.test.ts(5 项,含"摘要里不出现本机路径"的隐私断言与
老服务端兼容)、cloud/server/tests/test_sync_protocol.py(3 项,含老客户端无 body 仍 200)。
安装(钉在本发布版上):
curl -fsSL https://gitee.com/suhuisoftwares/pod/raw/v0.4.1/scripts/install.sh | sh
# 镜像:https://raw.githubusercontent.com/suhui-organization/pod/v0.4.1/scripts/install.sh
pod --version # → pod 0.4.1v0.4.0 — 多 agent 漏洞扫描闭环 + 审计交付物
v0.4.0 — 多 agent 漏洞扫描 + 纳管/接管/切执法;审计交付物可被对方独立校验
这一版把"多 harness 的安全"从概念做成闭环:扫描(pod guard)→ 纳管/接管/切执法
(pod agents + 本地控制台)→ 可交付的审计物(pod harden,对方能用 --verify 独立校验)。
同时补上英文正文、pod --version 自查、以及按内容指纹打 tag 的服务器发布。
下面每一节都是这一版的一部分——它们原先散在"未发布"里,发版时归拢到版本号下。
构建一致性改按 commit 判断;发布脚本支持强制重发
上一版把镜像 tag 改成每镜像独立的内容指纹(fp-<hash>)之后,带出两个尾巴,这一版收掉。
1. "只滚了一半"的检测从 tag 改成 commit
旧口径靠"两个镜像共用一个 main-<commit> tag"来判断前后端是否同一次发布。tag 改成
每镜像独立的内容指纹后,server 与 web 天生不同,拿 tag 比只会变成假告警——
而假告警会让人开始忽略那一行,等于把检测废掉。
所以现在:
- 两个镜像都打进
BUILD_COMMIT(--build-arg,来自本次发布的 commit); - 后端
/api/v1/auth/config返回build_commit; - 前端拿自己的
BUILD_COMMIT与它对照,不一致才标红; - 没有 commit 的旧镜像 / 本地 dev 退回旧的 tag 规则(只在
main-<sha>形态下比对)。
一句话:tag 回答"是不是这份内容",commit 回答"是不是同一次发布"。
2. REPUBLISH=1:强制重发一次
内容未变时脚本幂等空跑——这通常是想要的,但偶尔需要真的重发一次(验证发布路径、
替换可疑镜像、节点镜像被清理)。REPUBLISH=1 bash install-server.sh 会强制重建并滚动。
这里有个容易踩的坑,一并修掉了:同 tag 重建时镜像引用没变,set image 是空操作,
必须走 rollout restart 才会真正拉到新镜像。现在脚本按"镜像引用是否变化"自动二选一
(引用变了 → set image;没变 → rollout restart)。
服务器发布按内容指纹打 tag:只改 CLI / 文档不再重启线上
install-server.sh 的镜像 tag 原来是 main-<commit>,于是只要 main 往前走一次
就会换 tag → 重建镜像 → set image 滚动。而 server 是 Recreate(SQLite 不能被两个
Pod 同时写),每次都是几十秒 API 不可用——哪怕这次合并只动了 pod CLI、文档或 k8s 脚本。
现在 tag 只跟真正进镜像的文件内容走:
| 之前 | 现在 | |
|---|---|---|
| tag | main-<commit> |
fp-<内容指纹>,且 server 与 web 各自独立 |
| 只改 CLI / 文档 | 重建 + 重启 server 与 web | 幂等空跑,零重启 |
| 只改前端 | 重建 + 重启两个 | 只滚 web(server 不动,连库备份都跳过) |
| 只改后端 | 重建 + 重启两个 | 只滚 server(仍先备份库),web 不动 |
| "线上是哪个 commit" | 看 tag | 看 Deployment 注解 podsec/build-commit |
两个实现细节:
- 指纹用 git blob 列表算(
git ls-tree -r --full-tree <rev> -- <镜像输入路径>),
在节点上直接对目标 commit 求值,不需要先 checkout;只有真正进镜像的路径参与
(server:Dockerfile + requirements.txt +app/+scripts/;web:整个cloud/web),
所以改deploy/k8s下的脚本不会误触发。 - 切换本身不重启:旧的
main-<sha>tag 会被识别为"同一个 sha 的内容指纹"并比对,
内容一致就空跑——采纳这个改动当天不会多挨一次重启,等cloud/真变了再自然换 tag。
顺带修掉一个隐患:原来"tag 相同就空跑"不看镜像是否还在 containerd;镜像被清理过时
空跑会让集群起不来。现在内容一致还要加一条"镜像确实在 containerd 里"才敢跳过。
英文正文补全:海外读者拿到的是一份全英文的报告
上一版把框架文案翻了,但缺一块要命的:报告正文(威胁目录的标题/摘要/处置建议、
判定层生成的 finding 文案、策略草稿的判定依据)。英文模式下会中英混排——对一份要交给
海外客户/审计方的报告来说,"这是给谁看的"这个判断会被直接削弱。这一版补齐。
覆盖范围(英文模式下不再出现中文)
- 威胁目录 115 条:18 条威胁的标题、现象描述、处置动作、处置理由、覆盖边界与已有防线;
- 判定层 31 条:
detect.ts生成的全部 finding 文案(含计数与枚举的分隔符); - 默认规则的原因文案:
hookRisk.riskPatterns[].why——命中内置默认值时翻译,
用户自己在rules.json里写的说明原样显示(t()查不到词条即回显原文); - 策略草稿 12 条:草稿标题、判定依据、策略 diff 的变更标签与汇总行;
- 报表排版:括号(全角/半角)、枚举分隔符、
1 finding/2 findings的单复数。
验收方式是三条端到端断言,而不是人工看一眼:
apps/cli/test/guard.test.ts:用带问题的 home 跑guard scan --lang en-US,
断言零 CJK(之前用的是空 home——不出 finding,断言是空转的);apps/cli/test/harden.test.ts:report.md/findings.json/harness-scan.md
三份交付物在英文模式下零 CJK;packages/guard/src/catalog-i18n.test.ts(新增):目录与默认规则的每条文案
都必须有英文词条。这是 CI 门禁,不是"记得就手动跑一下"的脚本。
一处工程机制
目录文案是数据,渲染时才按 t(entry.title) 查表,静态的 t('…') 抽取看不见调用点
(scripts/i18n-coverage.sh 会因此把它们算成僵尸键)。所以:
- 覆盖率脚本新增
DATA_SOURCES例外:在catalog.ts/rules.ts里作为完整字符串
字面量出现的词条不计入僵尸键;必须带引号匹配,否则 '代码执行' 这类短词会命中长句里的
子串、把真缺口一起吞掉; - "这些数据键有没有英文"改由 vitest 断言(能真的拿到目录对象,比在 shell 里猜字符串可靠)。
顺带:localizeThreat() 在渲染时求值而不是模块加载时——--lang 在 import 之后才生效,
模块级求值会把标题冻在默认语言上。
全量 pnpm test 572 项通过,typecheck 通过,i18n 覆盖 751/751(100%)。
扫描变成漏斗,审计交付物变成客户能自己验的东西
这一版改的是交付形态,不是判定能力:同样一份扫描结果,操作者要的是"我现在做什么",
客户要的是"这份结论能不能被复核"。两者需要两份不同的输出。
pod guard:清单 → 漏斗
- §0 新增「先做这三件事」:按"严重级别 → 能不能真的解决 → 影响面"排序,每条带
一条可直接复制的 pod 命令和一条确认命令。排序把"只是复核一遍"的动作
(如凭据搬家的pod scan)排在改变状态的动作(纳管 / 冻结 / 接管)后面。 - 命令带 harness:建议里给的是
pod agents enroll --harness claude-code,
而不是目录里的pod agents enroll --harness <id>模板;harness 名先过 id 形态
校验(^[a-z0-9][._-]*$),不合法就退回通用形态——建议是给用户照抄的,
不能是一段看起来像指令的任意 shell。 - 交付入口:同一节给出"本轮可根治 / 只能降险 / pod 看不到"的计数,
以及把同一批事实变成可交付报告的命令(pod harden --out …)。 pod guard watch的变化通知也用上同一套映射:报"新增 AG-03"时直接给出该跑哪条命令。
pod harden:报告目录 → 可交付审计物
- 接入 16 类 harness 扫描:原来只跑
pod scan的 6 类平台;现在交付物里包含
harness-scan.md/harness-findings.json,client 复核不用重跑。 - 报告重构成可交付结构:§0 执行摘要 / §1 范围与方法(含"没建基线时哪类判定不生效")/
§2 结论与待办(每条带可执行命令)/ §3 覆盖边界(看不到什么)/ §4–§8 子报告 /
§9 如何验证 / §10 产物清单与交付声明。 - 交付元信息:
--client/--auditor/--engagement写进封面、findings.json
与manifest.json,同一客户多次审计能对上工单号。 pod harden --verify <目录>:收到报告的一方逐文件重算 sha256 比对 manifest,
不需要重跑审计、也不需要信任出具方;被改动过的文件会被指出并按--strict语义退出 1。- 跨层去重:同一个钩子(posture + guard)、同一处明文凭据(scan + guard)
在交付物里只出现一次,保留 guard 那条(带 AG 编号与处置命令)。只按"级别 + 归一化
路径 + 威胁类别映射"合并,映射之外一律不合并——宁可多报一条,也不吞掉真问题。 - 计数口径修正:交付物 §0 的 MCP server 数改用 harness 扫描(覆盖面更大)的结果,
不再出现 §0 说 0 个、§5 说 2 个的自相矛盾。
测试:packages/guard 新增漏斗层 4 项(含 harness 名注入防护与排序),
apps/cli/test/harden.test.ts 新增 5 项(封面元信息、可交付结构、--verify 通过/失败/
非交付目录、跨层去重)。全量 pnpm test 565 项通过,i18n 覆盖 100%。
纳管/接管/切执法的事件改成"上得了云"的落点
一个用户最先发现的问题:pocloud 上看不到本地做的事。查下来是事件落点错了。
修复:控制平面事件写进被改动 agent 的链
纳管、接管、切执法、还原、移除纳管这五个动作,事件原来统一写机器级的
~/.pod/audit/_control/control.jsonl,而 pod sync 是按绑定里的 local_agent
过滤事件的(e.agent === local_agent)——于是这些事件一条都没上云。
线上实测:pod_control_events = 0(数据平面 58 条、同步记账 397 条),
云端「控制平面」页永远是空的,而本地界面还在说"已纳管"。
现在这些事件写进被改动的那个 agent 的链
(audit/<agent>/control.jsonl,agent 字段就是该 agent 名),沿用既有绑定即可上云。
判断口径写进了 docs/control-plane-hardening.md:
某个 agent 被改了 → 写那个 agent 的链;与具体 agent 无关的机器级事实 → _control。
真正的机器级事件(pod posture 的全局发现、LLM 调用留痕)仍留在 _control,
它们要上云需要一条 local_agent: "_control" 的绑定(文档 §5.3 第 4 条)。
顺带修掉两个被这次改动暴露出来的问题
- 语料计数把控制平面事件算进去了:
pod agents enforce的前置检查说"当前审计语料
N 条",而 N 会把 identity / config-change 数进去。那些不是工具调用——数进去会让人
以为"已经采到 N 条调用了",拿一张空表去切执法。现在只数数据平面。 changed.auditDir会误报 false:事件写进 agent 链时会顺手mkdir,
于是"审计目录是不是我建的"这个判定发生在它之后,明明是我们建的却报 false。
改成先判定并建目录,再写事件。
测试
- 新增
apps/cli/test/control-plane-sync.test.ts:证明纳管之后,
collectPendingEvents能把它捞出来(且只有该 agent 的绑定捞得到、游标不会重复推)。
这是这条链路唯一的自动化保险——线上那个"0 条"正是没有它才悄悄发生的。 - 控制台三个测试文件的断言从
_control改成 agent 链。
页面与 API 都能看出"这是哪次构建"
起因是一个很直接的问题:"从页面上怎么看出哪些是新功能?"——答案是看不出来:
两个控制台都没有构建标识,只能靠"找新元素"或翻运维命令判断版本。
后端:/api/v1/auth/config 新增 build
deploy/Dockerfile 的 ARG BUILD_TAG → PODCLOUD_BUILD_TAG → app/config.py →
接口返回。于是"新版本滚上去了没有"从"端点返回 401 还是 404(猜)"变成
"curl 一下看 build 是否等于本次 tag"(确定)。两个 install 脚本都会传这个参数。
云端控制台:侧栏显示「构建 」
同一个 tag 经 VITE_BUILD_TAG 打进前端产物;侧栏底部显示后端 tag,
并与前端自己的 tag 对照——不一致就标红并给出提示,因为那正是滚动发布
最容易漏掉的一种破法(新前端撞旧后端,见 docs/rolling-update.md §4.2)。
本地控制台:侧栏显示 build <commit>[+] · <构建时间>
commit 由 Vite 构建时注入;+ 表示构建时工作区有未提交改动——
本地控制台就是从工作区构建的,只写 commit 会让人以为页面等于某个干净的版本
(悬停能看到完整时间与说明)。
部署脚本
install-server.sh 新增 LOCAL_BUILD=1:代码还没 push 时在本机构建、
docker save | ssh ctr import 送进节点(tag 仍指向真实 commit,只是尚未推送)。
默认仍是"从节点的 origin/ 构建",保证镜像对应已推送的 commit。
发布验证也换成了核对构建标识,而不是拿 401/404 猜。
服务器集群发布固化成脚本(install-server.sh)
新增:cloud/server/deploy/k8s/install-server.sh
上线的服务器集群(192.168.66.8 / ns podcloud / podcloud.dlszjr.com)此前没有
发布脚本:镜像是手工在节点上构建、手工 ctr import、手工 set image 的,
而且节点的源码 clone 停在 #11(静默落后 9 个提交)。这次把它固化成一条命令:
KUBECONFIG=~/.kube/config-server.yaml PUBLIC_URL=https://podcloud.dlszjr.com \
bash cloud/server/deploy/k8s/install-server.sh它做六件事:预检(连得上集群 / ssh 得通构建节点 / 节点有 docker+ctr+git)→
解析目标 commit 并打印"相对运行版本改了什么"→ 备份数据库 → 在节点上
git checkout 到目标 commit 并构建镜像 → 导入 containerd → server 先滚完就绪
再滚 web → 验证(集群内自证 + 公开地址)。
三条硬约束写进了脚本与文档,因为它们各自都踩过坑:
- docker 里的镜像 kubelet 看不见,必须
docker save | ctr -n k8s.io images import -; - 备份必须用 sqlite 的在线备份 API:库在 WAL 模式,
cp podcloud.db会丢掉
-wal里已提交的事务(线上实测主文件 380 KB / WAL 4 MB,旧文档教的正是cp); - 只
set image、不 apply 清单:线上对象是手工调过的(nodeSelector→hadoop8、
hostPath PV、NodePort 30088、server 用Recreate),apply 会把调优冲掉。
幂等:已经在目标 tag 上就空跑退出。
新增:server-cluster-snapshot.yaml
线上清单的只读快照(去掉运行时字段,不含 Secret),从集群导出。
此前"服务器上到底跑的是什么"只存在于集群里,集群重建时无据可依。
已验证它 kubectl apply --dry-run=server 全部 configured(不是 create)。
修复:滚动更新手册的两处
- 备份命令是错的:
cp /app/data/podcloud.db在 WAL 模式下得到的是过期快照。
改为 sqlite 在线备份,并说明为什么。 - 只写了 kind 一条路:手册标题是"面向已上线的部署",但只教了
install-local.sh(本机 kind)。现在两条路并列,附一张区别表(tag 形式、
构建位置、镜像怎么进集群、清单来源、server 发布策略)。
本次发布(服务器集群)
main-4ba4f91 → main-fbf730b(web main-5007bd8 → main-fbf730b)。
cloud/server 自 4ba4f91 起零差异,cloud/web 只多了 deploy/overseas/*
(不进运行时镜像)——也就是说这次滚动对齐的是 tag 与可追溯性,不是新代码。
发布后验证:集群内 web→server 反代正常,公开地址 / /pricing /product 200、
/api/v1/rules/pack 与 /api/v1/harden/reports 401(401 = 端点在,404 = 旧版本)。
第三步:切执法(让网关真的拦)
接管只是让调用经过网关;这一步让网关真的判。
新增:控制台「切执法 / 回到只录不拦」+ pod agents enforce
卡片上在已接管之后出现第三个动作:
- 切执法:去掉包装命令里的
--record-only,并让它使用你编译好的策略; - 回到只录不拦:把
--record-only加回来(策略不变,只是不再阻断)——执法打断
正常干活时的快速退路。
这一步最危险的失败不是"改坏了"(有备份),而是**"看起来生效了、其实没有保护"**,
所以前置检查是硬性的,不满足直接拒绝执行:
| 检查 | 不满足时 |
|---|---|
| 有一份绑定该 agent 且含 server 规则的策略 | 拒绝,并给出要跑的命令与当前语料量 |
那份策略不是 allow:["*"] |
拒绝——record 模板拿去执法只会制造"已保护"的错觉 |
| server 确实处于只录不拦 | 拒绝,并说明先用「接管」 |
确认框里显示:用哪份策略执法(路径 + server/工具/allow·approve·deny 计数 +
编译时的语料量)、改前 → 改后、备份路径,以及切完会发生什么(命中 approve 的调用
挂起等审批;没跑 pod watch 就等到超时被拒——fail-closed)。
改进了「多份策略」这件常态
纳管写一份零权限策略、编译后又多一份 draft,于是"一个 agent 两份策略"成了常态。
卡片现在直接显示当前实际生效的策略文件(从包装命令的 --policy 读出来),
不用用户去猜哪一份在管自己。
「还原配置」变成逐步撤销
接管台账记了 history:接管 → 切执法 → 回到只录不拦 之后连点两次「还原配置」,
会先退到只录不拦、再退回到接管之前。历史空了才结束这次接管。
事实层
@podsec/guard 的 ServerFact 新增 recordOnly:进网关与真的在拦是两件事,
只看 behindGateway 会把"只录不拦"显示成"已保护"——那是这个产品最不该犯的错。
测试
@podsec/console:enforce.test.ts9 例(四种前置拒绝、计划只读、切执法、
回到只录不拦、重复切换被拒、逐步撤销);server.test.ts补 3 例。pod agents补 4 例(无策略拒绝、dry-run、切执法、退回)。合计新增 16 例。
第二步:接管(把 MCP server 包进网关)
纳管只把资产纳入管理;MCP server 仍然是直连的,策略与审计对它无效。这一版补上第二步:
新增:控制台「接管(包进网关)」+ `pod agents onboard...
v0.3.2 — 登录页排版修复
v0.3.2 — 登录页排版修复
控制台(cloud/web)
- 修掉登录页的排版回归:
LoginView.vue的<style scoped>在 i18n 批量改动(3eff333)里被提前闭合,
.login-logo的规则掉到了样式块外、从未生效——于是 logo 按 SVG 原始尺寸 256px 渲染且左对齐,
把登录卡撑到 739px 高(720px 视口下出现竖向滚动条)。现在这些规则回到样式块内。 - 品牌头居中:logo(原始尺寸的 60%,154px)、标题、副标题统一沿卡片中轴居中;表单字段保持左对齐。
卡片总高 637px,一屏放得下。
已知边界
控制台状态刷新仍是 5 秒轮询(没有 WebSocket),agent 列表一次性返回,规模大时应接分页。
v0.3.1 — 控制台修复 + 发布流程硬化
v0.3.1 — 控制台修复 + 发布流程硬化
这一版修掉一个"照着文档做也做不成"的控制台 bug,并把发布流程本身关进闸门。
控制台(cloud/web)
- 「添加 Agent」弹窗补回创建按钮:表单阶段底部两个按钮(
取消/我知道了)此前都只做关窗,
唯一能提交的路径是输入框里回车——界面上不写、按钮上也没有,用户点按钮就以为"添加失败"
(实测服务端只收到列表轮询,没有收到任何创建请求)。现在 footer 是取消+创建,
创建按钮带 loading 状态。 - 修掉回车重复建单:回车会同时触发
el-form的 submit 与输入框的@keyup.enter,
一次操作建出两个同名 agent(实测两个 agent 相隔 16ms 创建)。现在只保留表单 submit
一条提交路径,并加重入保护兜底。
仓库 / 发布
main分支保护落地:只走 PR、CI 四项(test/local-smoke/cloud-server/
cloud-web)必绿、禁止强推与删除,对管理员同样生效(enforce_admins)。- 新增
CONTRIBUTING.md与 PR 模板;docs/PUBLISHING.md写明维护者直推前也要留痕
(先开 issue 说明,事后立刻恢复保护)。 - 发布预检新增双远端镜像一致性检查(Gitee 是 GitHub 的只读镜像,漂移即报错),
并把四篇内容稿的安装命令 re-pin 到当前版本。
已知边界
控制台状态刷新仍是 5 秒轮询(没有 WebSocket),agent 列表一次性返回,规模大时应接分页。
v0.3.0 — 大模型安全服务 + 中英双语
这一版把"大模型"从一句口号做成了有闸门的功能,整个产品(CLI / 控制台 / 云端)都能中英切换。
本地(agent 机器上)
- 自动化红队
pod redteam:攻击场景由模型当数据提出(--llm,可选),判定走与网关同一条纯函数流水线(decideCall)——所以"挡住没有"可复现、可进 CI(高危绕过退出码 1)。出网的只有权限面(server/tool 名 + 三态位置),用--export-surface显式导出。 - 模型调用只有一处出网(
apps/cli/src/llm.ts):provider/model/base_url 统一解析,配置不静默回落;每次调用(含失败)写一条kind='llm-call'进本地哈希链——只记 provider/model/字符数/端点,不记 prompt 正文。 - 加固审计交付物
pod harden:一条命令跑完暴露面扫描 + 控制平面姿态 + 最小权限草稿 + 证据自检,产出一份可直接交给客户的报告目录(含逐文件 sha256)。全程本地,零上报。 - 订阅式规则包
pod rules:pack / verify / apply / pull 四个动作,Ed25519 签名;放宽已有规则的包默认拒绝应用(--allow-relax才放行)。 - 中英切换:
pod --lang en-US,或一次POD_LANG=en-US(也读LC_ALL/LANG)。覆盖 CLI 全部输出与报告;未翻译的串原样显示中文,不会出现 key 名或空白。
云端(可选控制平面)
- 规则包分发:控制台发布/撤回签名规则包,机器侧
pod rules pull拉取;公钥不与包同路(rules_public_key),放宽守卫在机器侧兜底。 - 熔断下发:控制台熔断/解除,机器下次
pod sync生效;人工在机器上加的熔断不会被云端误解除。 - 加固报告归档:
pod harden --upload只上传report.md与findings.json(已脱敏),原始审计链evidence.json永不出机器。 - 模型配置:provider 清单(DeepSeek / OpenAI / OpenAI 兼容 / 离线 mock)、连通性测试、AI 生成策略、告警摘要、AI 日报;出网面写着改(见下)。结构化 payload(能力清单、provider 说明)随
Accept-Language切换。 - 中英切换:登录页与用户菜单里的开关,选择记在浏览器本地;Element Plus 内置文案一并切换。
安全
- 告警出网收口:送进模型的告警只留白名单字段;
message里的文件路径打码成<path>(保留目录结构、去掉用户名/项目名),命中密钥模式整条不出网,剔除条数如实告知模型。密钥规则与服务端策略模板的deny_output_matching共用同一份(app/security.py::SECRET_PATTERNS),顺带补齐了sk-proj-…/gho_/glpat-三个漏网格式。 - 结构化 payload 的翻译出口:异常
detail有统一翻译出口,结构化返回值没有——设置页的能力清单与"为什么不可用"因此漏翻过,现已收口并有测试兜住。
仓库 / 发布
- 发布预检 30 项(
scripts/preflight-publish.sh):含干净环境安装 + 主路径冒烟、钉版本安装链接可达、赞助入口一致性。 - i18n 两把尺子:
scripts/i18n-coverage.sh管"词表齐不齐"(CLI/Web 差集 + 僵尸键 + 实体键陷阱);scripts/web-acceptance.sh管"界面上到底长什么样"(真机无头 Chrome 逐页断言"渲染出内容 + 无非数据中文")。 - GitHub Sponsors:
.github/FUNDING.yml+ README 入口;预检会校验两处账号一致。
已知边界
模型不参与判定、不执行动作:它只能产出数据(场景、策略草稿、摘要),改状态的入口都有它过不去的闸门(签名 + 放宽守卫 + 纯函数判定器)。注入检测目前是分级词表 + 工具描述摘除,模型分类器未做。其余边界见 docs/threat-model.md 与 docs/llm-security-services.md。
v0.2.0 — 首个完整开源版本
本地与云端第一次在同一个仓库发布:装一条命令拿到本地 CLI/网关,再一条命令起云端控制平面。
本地与云端第一次在同一个仓库里发布:装一条命令拿到本地 CLI/网关,再一条命令起云端控制平面。
本地(agent 机器上)
- 策略编译闭环:
pod record只录不拦 →pod policy draft从真实调用编译最小权限策略 →--diff输出收紧/放宽清单 →pod serve执法(deny > approve > allow,fail-closed)→pod verify-audit/export-evidence留证。 - 控制平面加固(G1–G16):生命周期钩子审计、配置冻结与漂移、记忆完整性、MCP 包来源固定、工具元数据验证、每 agent 独立密码学身份、签名委托链与能力收窄、JIT 令牌、熔断、信任传播异常、污染溯源。
- 判定规则归用户:所有阈值、正则、严重级别、可信来源都在
~/.pod/rules.json(--rules可覆盖);规则写错 fail-closed 报错,不静默退回默认值。 - 审计链可靠性:跨进程文件锁(
pod ingest、控制平面事件、网关写入)根治并发分叉;rules.auditHealth把"链断裂"和"静默停摆"变成可见告警。 - 能力图与毒性路径:
pod graph build/toxic/explain/apply/observe/diff/baseline,跨 agent 的 source→sink 组合风险。 - 本地控制台:
pod ui(只读,token 保护)。
云端(可选控制平面)
- 审计同步:数据平面(工具调用)与控制平面(钩子/配置/身份/委托/熔断)两套事件流,分别入表、分别展示;敏感内容只传 SHA-256 哈希。
- 一键接入:控制台注册 agent 后给一条
curl ... | bash,自动写~/.pod/cloud.json、清理失效绑定、验证同步。 - 控制平面页、时间线、策略中心、告警(含 webhook/邮件)、总览仪表盘(活跃度双口径:近 7 天 + 累计)、合规报告。
- 部署:
deploy/install.sh一条命令(Docker Compose),必填配置只有一项(JWT 密钥,脚本自动生成)。
仓库
- 原
podcloud-server/podcloud-web两个仓库已并入cloud/下并归档,历史链接会看到指向本仓库的告示。 - 清掉 FinHarness 遗留(3 个零引用模型、7 张死表迁移、配置回退、品牌与 CSS 令牌前缀),全仓库无
finharness字样。 - CI 四份门禁:本地测试、本地闭环冒烟、云端 pytest、前端构建。
已知边界
不做沙箱隔离、不实现 A2A/mTLS/SPIFFE 协议本体、不把行为漂移当主防线;详见 docs/threat-model.md 的"明确不防御"。
安装:curl -fsSL https://gitee.com/suhuisoftwares/pod/raw/v0.2.0/scripts/install.sh | sh
部署云端:git clone --branch v0.2.0 --depth 1 <repo> && cd pod && bash deploy/install.sh