Files
xas-test-library/docs/console-plan.md
T

53 lines
5.9 KiB
Markdown
Raw Normal View History

# 专用测试控制台实施方案
> 2026-10-13 目录展示已按用户后续确认改为“一项测试行为一个项目”,内部文件不平铺;清单与接口补充见 [ADR 0003](adr/0003-test-behavior-catalog.md)。本文其余存储和执行边界继续适用。
日期:2026-10-13。本文是当前维护入口,覆盖此前 Rundeck 方案的产品范围;历史验收记录继续保留。
## 已确认的行为
- 公司内网免登录;只读查看脚本代码,上传创建新脚本或不可变的新版本。
- 登记三个已知测试目录内的 Python/Shell 脚本,不批量复制源文件。原脚本保持原位置、参数与工作目录。危险的服务管理脚本仅登记待配置。
- 允许已登记测试按原逻辑写入原日志/结果目录;不修改源文件,不授权停止他人的模型服务。
- 每次运行有独立记录、实时标准输出/错误、退出状态、源文件摘要和结果文件。文件型日志需登记路径才会采集。历史结果有独立归档,不覆盖原文件。
- 数据库存元数据与状态,源文件/完整日志/报告存在文件系统,不把文件正文重复塞进数据库。
- 上传目录 runtime/library/<脚本ID>/versions/<版本>/;运行目录 runtime/runs/<运行ID>/。
- Git 管理控制台源码和部署配置,不在每次运行时拉取。没有提交、标签或推送授权。
## 架构与信任边界
FastAPI 提供网页/API,SQLite WAL 保存目录与队列;网页容器没有 Docker socket 或 GPU。独立宿主执行器处理单并发队列,启动有固定标签、限定资源、无 Docker socket 的临时容器。可配置的工作目录和输出路径必须位于已登记的来源目录,上传脚本只能写本次结果目录。源文件挂载只读,只有明确登记的输出目录可写。
所有内网用户共享权限,可上传和运行自己的代码,因此信任边界是允许访问的两个公司网段。执行容器限制宿主文件与设备,不能作为抵御恶意内网用户的完整安全平台。API 校验 Host、Origin、来源网段和专用请求头,拒绝跨站修改;不接收任意 shell 命令、环境变量、镜像或宿主挂载。
运行记录固定版本、配置快照与源码摘要;排队后原文件变动则拒绝执行。超时/取消只终止本次容器,不宣称远端模型推理已取消。执行器重启时只恢复/终止本项目标签容器,不自动补跑。日志、上传、结果大小与执行时长有上限。业务判定只在脚本提供明确报告时呈现;退出零只表示进程正常结束。
旧 smoke.sh 缺少当前服务要求的认证。为保留原代码,在其运行容器中放置仅服务本次进程的回环代理:凭据经 stdin 传递、只保留内存,固定上游地址、模型、1 次 models 与 3 次 completion,不重试。真实验收最多一轮,保留失败和截断输出。
## 实施和验收
1. 固定 API,先测试版本不可覆盖、目录边界、排队幂等与单并发、日志游标、归档和取消。
2. 实现目录/上传/代码只读、历史、实时日志、文件下载;快速样例验证成功、失败、取消和结果。
3. 只读扫描已知来源,配置一个轻量既有脚本。新端口 14442 并行部署,旧入口 14440 暂保留。
4. 浏览器贯通上传、新版本、运行、日志、结果和历史;在模型服务仍正常的条件下执行一次有界 smoke。
5. 验收后切换 14440 的项目入口,保留旧容器/数据和明确回退路径。未通过则保留新预览并如实报告。
## 前后端接口契约 v1
JSON 错误 `{detail: string}`。修改请求必须含 `X-XAS-Console: 1`。所有时间为 UTC ISO。
- GET `/api/summary`: `{scripts, ready, runs, active, worker:{online,last_seen}, storage:{run_bytes}, limits:{...}}`
- GET `/api/scripts`: `{items:[Script]}`;GET `/api/scripts/{id}`: Script(含 versions)
- Script: `{id,name,description,kind:'managed'|'external',language:'python'|'shell',source_path,source_group,status:'ready'|'needs_configuration'|'missing',enabled,reason,version,sha256,updated_at,config:{args:[],cwd:'',output_paths:[],timeout_seconds:300,profile:'standard'|'legacy_smoke'},versions:[{version,sha256,created_at,filename}]}`
- GET `/api/scripts/{id}/code?version=`: `{code,filename,sha256,truncated,redacted}`;GET `/api/scripts/{id}/download?version=` 返回只读源文件(含秘密的文件拒绝下载)
- POST `/api/scripts/upload`: multipart `file`, `name`, `description`(新建);POST `/api/scripts/{id}/versions`: multipart `file`(仅 managed);返回 Script。
- PATCH `/api/scripts/{id}`: `{name?,description?,enabled?,config?:{args?,cwd?,output_paths?,timeout_seconds?}}`;不允许更新代码、profile、路径来源或版本。
- POST `/api/discover`: 返回 `{registered,missing,total}`,仅扫描预设来源。
- POST `/api/scripts/{id}/runs`: `{request_id:UUID}`,返回 Run;重复请求返回同一记录。运行采用当前登记配置和版本。
- GET `/api/runs?script_id=&limit=100`: `{items:[Run]}`;GET `/api/runs/{id}`: Run。
- Run: `{id,script_id,script_name,version,sha256,state:'queued'|'running'|'succeeded'|'failed'|'cancelled'|'timed_out'|'interrupted',created_at,started_at,finished_at,exit_code,message,config,artifacts:[{id,name,size,kind:'text'|'json'|'file'}],synthetic,source_ip}`。
- POST `/api/runs/{id}/cancel`: 返回 Run;GET `/api/runs/{id}/log?offset=0`: `{text,next_offset,done,truncated}`。
- GET `/api/runs/{id}/log/download`;GET `/api/runs/{id}/artifacts/{artifact_id}`(下载);GET 同路径加 `/preview`: `{text,truncated}`。
网页无需外部 CDN。中文、清晰加载/空/错误状态,脚本列表筛选,详情页源码只读、配置编辑、版本上传、运行记录。运行页轮询日志与状态,取消只对进行中的任务显示。结果区展示文件列表、文本预览/下载。默认突出真实状态,不把模拟验收算作模型测评。