feat(skill): 新增 verify-fast-ship 验证技能与功能验证地图(INT-58) #37
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
fjbobo/fast_ship!37
Loading…
Reference in a new issue
No description provided.
Delete branch "t3code/verify-fast-ship-skill"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
相关需求
INT-58 用 create-verification-skill 为 fast_ship 生成 verify-fast-ship 验证技能
改动内容
新增项目本地验证技能
.agents/skills/verify-fast-ship/(create-verification-skill的首次实战产物),并按其自身步骤真跑通过:make dev(4888/4999 与 vite proxy 写死无法双开,改为构建二进制 +FAST_SHIP_*环境覆盖直接运行);断言式 Doctor(PID 身份、端口归属、401 探活、bundle hash 逐项断言,失败即停);无头 Playwright 驱动约定(全部来自本仓库源码的真实选择器,含 Base UI combobox 的name=不可匹配陷阱);证据规则(凭据永不进 evidence);Cleanup 只杀已核对身份的自家 PID。register/login/shot/run四个命令 + scenario 注入 helper(api_get带 JWT、save_secret0600 落 scratch)。.gitignore补__pycache__/(驱动脚本为 Python)。技能位置:根目录
skills/是对外分发的技能(fast-shipAPI 技能被外部仓库导入),仓库内部技能归入.agents/skills/——除新增的verify-fast-ship外,version-release(驱动make release,不对外安装)也一并从skills/迁入;README 项目结构同步标注两个目录的分工。过程:首轮生成并跑通后,经独立审查发现 15 处问题(并发 RUN_ID 撞目录可能误杀他人实例、API Key 会落入证据、若干选择器与源码不符等),全部修复并重跑一轮验证通过。
修改范围
.agents/skills/(新增 verify-fast-ship、迁入 version-release)、skills/(迁出 version-release)、.gitignore、README.md
本地验证
make lintmake testgo test ./...全绿验证方式(命令 / 无头浏览器):无头 Python Playwright(技能自带
fsdrive.py,headless chromium)启动命令:技能 Launch 节的隔离实例——
go build至 scratch +FAST_SHIP_SERVER_PORT=5088/FAST_SHIP_DATABASE_PATH/FAST_SHIP_WEB_DIST_DIR等环境覆盖(本机 4888 已被其他工作树实例占用,验证全程未触碰)验证提交 SHA:
ee09e59应用可以启动(隔离实例 READY + doctor 断言通过),主要使用流程已验证:注册/登录、对话框创建项目(自动跳问题页)、项目网格/搜索、新建问题、问题筛选与搜索、API Key 创建/使用/删除
异常或空状态已验证(doctor 负路径 exit 1、端口被他人占用拒绝驱动、问题空态、搜索未命中、key 删除后 API 返回 401)
已修复的基线问题
无
端到端截图
无界面变化(仅新增
.agents/skills/文档与驱动脚本)。替代证据:技能实跑的采集截图(证据目录在工作树外,cleanup 后存活,共 42 个文件含 ARIA 快照、API 读回、sqlite 行核对):未验证范围与原因
feature map 首批覆盖 5 个用户面;版本与发货依赖 GitHub Release(超出本地可验证边界),documents/logs/board/settings 未入首批——后续按
maintain-verification-skill扩展。API 变更说明
无
创建 PR 前完成
审查意见处理
@CodeBot review$pr-review-loop自动等待并处理新意见,直到收敛@codex review
@CodeBot review
Codex Review Summary
This comment shows the latest Codex review activity on this pull request.
a6e7a11ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.
行内备注见下方;完整结论见 PR 会话顶层评论。
@ -0,0 +206,4 @@username, email, password = ns.argsfresh_auth_page("/register")fill_register(username, email, password)shot("register-form") # filled form, before submitP2 填好表单后的
shot()会把明文密码写进evidence/*.aria.txt。Playwright 的
aria_snapshot()对type=password也输出 value,不做掩码。我用同样的写法实测过:所以
register-form.aria.txt(以及下面第 197 行的login-form.aria.txt)会带上密码,和 SKILL.md「Credentials never enter evidence… not in.aria.txt」的规则冲突;如果login用的是真实账号,就是真实凭据落进了 cleanup 后仍保留的证据目录。建议提交前的这一张只截.png(密码框本身是圆点),或者在生成快照前把密码值替换掉 / 写入后对.aria.txt做脱敏。Code Bot 审查结论:
审查范围:HEAD
ee09e59(首审),新增skills/verify-fast-ship/(SKILL.md、features/ 5 个功能文件、scripts/fsdrive.py)及.gitignore。已对照server/internal/config/config.go、server/cmd/server/main.go、configs/config.yaml核对启动配方:CONFIG_PATH、FAST_SHIP_*覆盖(含单独绑定的FAST_SHIP_WEB_DIST_DIR)、服务启动日志行与release模式行为都与源码一致。register/login命令把明文密码写进证据目录 —fsdrive.py在提交前调用shot("register-form")/shot("login-form"),而 Playwright 的aria_snapshot()对type=password输入框照样输出 value(已实测得到- textbox "密码": VerifyPass1)。于是evidence/register-form.aria.txt、login-form.aria.txt里都有密码,违反 SKILL.md 自己定的「Credentials never enter evidence … not in.aria.txt」,且 evidence 在 cleanup 后保留;用真实账号login时泄漏的就是真实凭据。PR 描述的「证据零泄漏」只覆盖了 API Key。详见行内备注。ps -p PID -o comm=在 macOS 返回完整可执行路径,但在 Linux 只返回进程名(fast_ship,最多 15 字符),和$V/scratch/fast_ship永远不相等:Doctor 必然失败,Cleanup 则会走「leaving it alone」分支把服务留在后台。若技能只面向 macOS,建议在 SKILL.md 写明;否则可改用ps -o args=或/proc/$PID/exe比对。另外 Doctor 的fail()用exit 1,若 agent 在持久 shell 里直接粘贴执行会把整个会话退出,可考虑放进子 shell( … )运行。复审
如需复审,请单独在顶层评论回复
@CodeBot review行内备注见下方;完整结论见 PR 会话顶层评论。
@ -0,0 +206,4 @@username, email, password = ns.argsfresh_auth_page("/register")fill_register(username, email, password)shot("register-form") # filled form, before submitP2 填好表单后的
shot()会把明文密码写进evidence/register-form.aria.txt— Playwright 的aria_snapshot()把type=password当textbox,并把input.value原样输出成子节点(只跳过 checkbox/radio/file),所以快照里会出现- textbox "密码": VerifyPass1。这和 SKILL.md「凭据永不进 evidence,含.aria.txt」的规则直接冲突。建议提交前截图时跳过 aria 快照,或在shot()里先把密码框清空/掩码后再取快照。@ -0,0 +214,4 @@login, password = ns.argsfresh_auth_page("/login")fill_login(login, password)shot("login-form") # filled form, before submitP2 同上:
login-form.aria.txt也会带出明文密码。P2
ps -o comm=在 Linux 上只给可执行文件名(截断到 15 字符,即fast_ship),不是完整路径,所以这里在 Linux(云端 agent / CI)上永远不等于$V/scratch/fast_ship,Doctor 必然失败;Cleanup(第 183 行)用的是同一判断,会走「不是我们的进程」分支,把服务器留在后台。macOS 上comm恰好是完整路径才跑通。可改用ps -p "$PID" -o args=的首个字段,或在 Linux 上比对readlink /proc/$PID/exe。Code Bot 审查结论:
审查范围:HEAD
ee09e59(首轮,skills/verify-fast-ship/全部新增文件 +.gitignore)。register/login命令把明文密码写进 evidence —fsdrive.py在提交前对已填表单调用shot("register-form")/shot("login-form"),而 Playwrightaria_snapshot()会把type=password识别为textbox并原样输出input.value,所以register-form.aria.txt/login-form.aria.txt里会出现- textbox "密码": VerifyPass1。这违反了本技能自己「凭据永不进 evidence(含.aria.txt)」的硬规则;目前是一次性测试账号影响有限,但别人按技能换用真实密码时就会泄露。建议提交前的截图不取 aria 快照,或先清空/掩码密码框。ps -p "$PID" -o comm=去比对完整路径$V/scratch/fast_ship。Linux 上comm只返回截断到 15 字符的文件名(fast_ship),Doctor 会永远报「pid is not …」,Cleanup 会走「leaving it alone」分支把服务器留在后台。云端 agent / CI 多为 Linux,这条会让技能在那里不可用且泄漏进程。可改为比对ps -o args=首字段或/proc/$PID/exe。fail() { …; exit 1; }:如果 agent 在持久 shell 里直接粘贴执行(而不是bash -c/ 子 shell),失败时会把整个会话 shell 退出,$V/$PORT等变量随之丢失,后续 Cleanup 也找不到目录。可以把整块包在( … )里,或改成return/显式说明用子 shell 运行。复审
如需复审,请单独在顶层评论回复
@CodeBot review💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
ee09e59742ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
On Linux,
ps -o comm=returns only the executable basename, not its full path (the GNUpsmanual definescommas “only the executable name”), so this comparison offast_shipwith$V/scratch/fast_shipalways fails and Doctor aborts before every verification run. Cleanup repeats the same comparison at line 183, so a run that reaches teardown also leaves its own server running; use a path-aware identity check such as/proc/$PID/exeor compare against the basename.Useful? React with 👍 / 👎.
When the
registerorlogincommand callsshotafter filling the form, thisaria_snapshot()includes the password input's value, soregister-form.aria.txtandlogin-form.aria.txtcontain the plaintext password despite the skill's rule that credentials never enter evidence. Playwright's ARIA serialization exposes input values, including password fields (official issue); omit these pre-submit snapshots or redact password controls before writing them.Useful? React with 👍 / 👎.
两条都是真问题,已在
c47ca99修复并重验:P2 密码进证据:
fsdrive.py的shot()在写.aria.txt前,先eval_on_selector_all("input[type=password]")收集密码框的值并统一替换成•••。实跑验证:注册哨兵密码S3ntinel-Pw9后register-form.aria.txt输出textbox "密码": •••,全证据目录 grep 零命中。PNG 本来就只渲染掩码,无需处理。Note 可移植性:Doctor 与 Cleanup 的 PID 身份核对从
ps -o comm=改为ps -o args=首字段比对(comm在 Linux 只给截断进程名,macOS 才是完整路径),Linux/macOS 通用。Doctor 断言块整体包进( … )子 shell,fail的exit 1不再带走粘贴执行的会话。已在活实例上验证:DOCTOR OK、负路径 exit 1、cleanup 杀自己 PID 后端口释放。@CodeBot review
Code Bot 审查结论:
审查范围:HEAD
c47ca99(复审,上轮ee09e59),增量为fsdrive.py的shot()密码掩码与 SKILL.md 的 Doctor / Cleanup 进程识别改动。上轮问题处理情况:
P2 Doctor / Cleanup 用
ps -o comm=在 Linux 失效 — 已修复。已在 Linux 上按 Launch 的nohup "$V/scratch/fast_ship"方式实测,ps -p PID -o args= | awk '{print $1}'得到的就是完整路径,与$V/scratch/fast_ship相等。Note Doctor 的
exit 1会退掉持久 shell — 已修复,整块已包进( … )。Note SKILL.md description 声称覆盖 versions、documents、logs、settings,但 feature map 只有 5 个功能 — 仍未处理。
P2
register/login把明文密码写进 evidence — 部分修复,见下条。P2 密码掩码用原始值对快照文本做
str.replace,一部分密码仍会以明文落进.aria.txt—aria_snapshot()输出的不是input.value原文:它会合并空白(连续空格、Tab 变成单个空格,末尾空格被去掉),遇到:、#等需要 YAML 加引号的值时,会把"和\转义。这样快照里的文本和原值对不上,replace匹配不到。我用同版本的shot()写法实测:a b输出a b,end输出end,a"b: c输出"a\"b: c",x\y #z输出"x\\y #z",都没被掩码。普通测试密码(如VerifyPass1、p@ss"w0rd!)确实能掩掉,但用login跑真实账号时,带空格或符号的强密码仍可能泄漏,和「凭据永不进 evidence」的规则冲突。更稳的做法是不依赖文本匹配:取快照前先把密码框的 DOM value 临时换成占位符,快照后再恢复;或者提交前那一张只截.png,不写.aria.txt。Note 同一个
replace也会替换页面上其他与密码相同的文本。用短密码或常见词做测试时,快照里的正常文案可能被改成•••,影响证据可读性。改成上面不靠文本匹配的方案后,这个问题也会一起消失。复审
如需复审,请单独在顶层评论回复
@CodeBot reviewP2 掩码不可靠 — 已在
a6e7a11改为你建议的方案:shot()不再做文本匹配,序列化前用eval_on_selector_all把所有input[type=password]的 DOMvalue置为•••,拿到快照后在finally里按序恢复原值。实测验证:登录表单填入a b" c: end(连续空格+引号+冒号+尾随空格,正是文本匹配会漏的组合),login-tricky.aria.txt输出textbox "密码": •••,全证据目录 grep 无任何密码片段;恢复后字段值与原文一致(断言通过)。误伤相同文案的问题也随之消失。Note description 范围夸大 — 已修:frontmatter 的 surface 列表从 "auth, projects, issues, versions, documents, logs, settings" 收敛为 feature map 实际覆盖的 "auth, projects, issues, API keys"。
另:Codex 在
ee09e59上留的两条 P1(aria 明文密码、ps -o comm=Linux 不兼容)分别对应本 PR 的c47ca99与a6e7a11修复,均已闭环。@CodeBot review
@codex review
Code Bot 审查结论:
审查范围:HEAD
a6e7a11(复审,上轮c47ca99),增量为fsdrive.py中shot()的密码掩码改法和 SKILL.md frontmatter 的 description。上轮问题处理情况:
str.replace做文本匹配,带空白或需 YAML 转义的密码仍会明文进.aria.txt— 已修复。现在在调用aria_snapshot()前把所有input[type=password]的 DOMvalue临时改成•••,并在finally里按顺序恢复。我用同样写法在 Linux 无头 Chrome 上实测:两个密码框分别填a b" c: end(连续空格、引号、冒号、尾随空格)和x\y #z,快照输出都是textbox "密码": •••,恢复后的值与原值逐个相等。PNG 先于掩码截取,而浏览器本身只渲染圆点,没有泄漏。replace会误伤页面上与密码相同的文本 — 已修复,不再做文本匹配,这个问题随之消失。features/一致。本轮未发现需处理的问题。
复审
如需复审,请单独在顶层评论回复
@CodeBot review💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:
a6e7a1159fℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
@ -0,0 +49,4 @@FAST_SHIP_SERVER_MODE=release \FAST_SHIP_DATABASE_PATH="$V/scratch/data/fast_ship.db" \FAST_SHIP_UPLOAD_STORAGE_PATH="$V/scratch/data/uploads" \FAST_SHIP_WEB_DIST_DIR="$REPO/web/dist" \The launch command relies on
FAST_SHIP_SERVER_PORT,FAST_SHIP_DATABASE_PATH,FAST_SHIP_UPLOAD_STORAGE_PATH, andFAST_SHIP_ISSUES_AUTO_SYNC_ENABLEDto isolate each run, butconfig.Loadonly explicitly bindsserver.mode,database.log_sql,jwt.secret,encryption.key, andserver.web_dist_dir; Viper'sAutomaticEnvvalues are not populated byUnmarshalfor these unbound keys. As a result, the binary uses the YAML defaults (port 4888,./data/fast_ship.db, shared uploads, and auto-sync enabled), so the documented verification either collides with another instance or mutates the shared database and may contact GitHub.Useful? React with 👍 / 👎.
@ -0,0 +49,4 @@FAST_SHIP_SERVER_MODE=release \FAST_SHIP_DATABASE_PATH="$V/scratch/data/fast_ship.db" \FAST_SHIP_UPLOAD_STORAGE_PATH="$V/scratch/data/uploads" \FAST_SHIP_WEB_DIST_DIR="$REPO/web/dist" \这条对旧版本 Viper 成立,但本项目不适用——四个隔离键都经由
AutomaticEnv生效:config.Load(server/internal/config/config.go:54-56)设置了SetEnvPrefix("FAST_SHIP")+SetEnvKeyReplacer(".", "_")+AutomaticEnv(),go.mod 里 viper 是 v1.21.0——Unmarshal遍历AllKeys()时对每个键走Get,Get会查 AutomaticEnv 绑定的环境变量,配置文件里存在的键都能被 env 覆盖。server.port、database.path、upload.storage_path、issues.auto_sync_enabled)都真实存在于server/configs/config.yaml,所以都在AllKeys()里,不存在「未显式 BindEnv 所以 Unmarshal 读不到」的问题。实证:本 PR 的整轮验证就依赖这套覆盖——验证实例在
5088监听时本机4888正被另一个 fast_ship 实例占用,若 env 不生效会去撞4888直接启动失败;数据库读写落在$V/scratch/data/fast_ship.db(db-*.txt读回证据即来自该文件);Doctor 也断言「端口属主 PID +/api/auth/me401 + 启动日志」。假设哪天 env 真的失效,Doctor 的端口/属主断言会第一时间失败,不会静默用上共享实例。应要求把技能从
skills/verify-fast-ship/移到了.agents/skills/verify-fast-ship/(fa3f805):根目录skills/是对外分发的位置(fast-ship、version-release),verify-fast-ship 是仓库内部验证技能,属于.agents/。纯git mv,内容仅改两处驱动路径引用(SKILL.md$DRV、features/auth.md$DRV_NOAUTH)。@CodeBot review
Code Bot 审查结论:
审查范围:HEAD
fa3f805(复审,上轮a6e7a11),增量为把技能目录从skills/verify-fast-ship/整体移到.agents/skills/verify-fast-ship/。本轮核对:
8 个文件均为 rename,内容只改了 SKILL.md 的
$DRV和features/auth.md的$DRV_NOAUTH两处驱动路径,已确认两处都指向新位置$REPO/.agents/skills/verify-fast-ship/scripts/fsdrive.py。移动后技能目录内已没有残留的旧路径
skills/verify-fast-ship;fsdrive.py不依赖__file__或目录层级(scratch 由--evidence的父目录推出,$REPO由git rev-parse --show-toplevel得到),多嵌套一层不影响运行。AGENTS.md、CLAUDE.md、README.md、Makefile、CI workflow、.gitignore/.dockerignore都没有引用旧路径,也没有忽略.agents/;根目录skills/现在只剩对外分发的fast-ship和version-release。上轮已修复的问题(密码掩码改为临时替换 DOM value、PID 用
ps -o args=比对、Doctor 子 shell、description 覆盖面)在新位置的文件里保持不变。Note PR 描述还停留在旧位置 — 「改动内容」写的是
skills/verify-fast-ship/,「修改范围」写的是skills/、.gitignore,建议同步成.agents/skills/,免得合并后按描述找不到文件。本轮未发现需处理的问题。
复审
如需复审,请单独在顶层评论回复
@CodeBot review已修:
gh pr edit把描述里三处skills/verify-fast-ship/skills/更新为.agents/skills/(「改动内容」「修改范围」「替代证据」段),现在与fa3f805的实际文件位置一致。version-release 同样是仓库内部技能(只在仓库内驱动
make release,不被外部安装),已一并移入.agents/skills/version-release/(0d95776)。现在skills/只剩对外分发的fast-shipAPI 技能;README 项目结构补了一行标注两个目录的分工。version-release 的 SKILL.md 无自引用路径,纯 rename。@CodeBot review
Code Bot 审查结论:
审查范围:HEAD
0d95776(复审,上轮fa3f805),增量为把skills/version-release/移到.agents/skills/version-release/,以及 README 项目结构的两行说明。上轮问题处理情况:
.agents/skills/verify-fast-ship/。本轮核对:
version-release/SKILL.md是纯 rename(blob 不变),内容只引用make release/scripts/release.sh/VERSION,没有依赖自身目录的路径。在 HEAD 上全仓检索
version-release和skills/:Makefile、scripts/、两个 CI workflow、AGENTS.md、CLAUDE.md、.cursor/rules/、.gitignore/.dockerignore都没有引用旧路径;剩下的skills/引用全部指向skills/fast-ship(apidocgen输出路径和测试、make api-docs说明、README 链接),未受影响。README 新增的两行目录说明与实际结构一致:根目录
skills/只剩fast-ship,.agents/skills/下是verify-fast-ship和version-release。Note PR 描述和标题没覆盖这次的额外改动 — 「修改范围」仍写
.agents/skills/、.gitignore,没提README.md,也没提version-release从skills/迁出;标题只说新增 verify-fast-ship。建议在描述里补一句,方便以后按 PR 追溯这次目录调整。本轮未发现需处理的问题。
复审
如需复审,请单独在顶层评论回复
@CodeBot review已修:「改动内容」补了一段说明技能目录的分工(
skills/对外分发、.agents/skills/仓库内部)及version-release的迁入;「修改范围」更新为.agents/skills/(新增 verify-fast-ship、迁入 version-release)、skills/(迁出 version-release)、.gitignore、README.md。标题保持不动——本单主体仍是新增 verify-fast-ship,version-release 迁移是顺带的目录归位,描述里已可追溯。