tao.chen and Claude
573397dbb4
tools: persist spark_submit calls to SubmissionRepo
...
Co-Authored-By: Claude <noreply@anthropic.com >
2026-07-14 13:45:07 +08:00
tao.chen and Claude
876f1c9edb
uploads: dual-write uploads to DB, startup backfill, and audit log
...
Store now indexes every Save into the upload_files table via SetRepo.
DB failures are logged as warnings and do not fail the upload because
.meta.json remains the source of truth and startup backfill recovers.
Add Store.Backfill to walk Root at startup and insert index rows for
any pre-existing .meta.json sidecars, swallowing duplicate-key races.
The upload_file MCP Tool now writes an audit_log entry on success.
Tests cover dual-write args, repo-error non-failure, and backfill
skipping existing rows.
Co-Authored-By: Claude <noreply@anthropic.com >
2026-07-14 11:30:39 +08:00
tao.chen
dab4cd062e
修复 spark_submit 参数重复、上传校验绕过等 8 处缺陷
...
对应代码审查发现的问题(#1, #2 , #4-#8, #10):
#1 CRITICAL:spark_submit 在 argv 中重复拼接 binary。此前
cmd := []string{binary} 后又把 cmd 作为 Args 传给 executor.Run,
而 executor 会再拼一次 Binary,导致 OS argv 为 [binary, binary, ...],
spark-submit 会把自身当作应用 jar。现在 cmd 从 --master 开始,
executor.Run 使用 Binary + Args,argv 正确。
#2:Validate 曾接受 .meta.json 路径本身。现在显式拒绝 sidecar 路径,
要求传入数据文件路径。
#4:Sweep 对 sidecar 损坏的数据文件跳过清理。现在损坏 sidecar 会回退
到数据文件 mtime,超期即删除。
#5:upload_file 描述仍引用已移除的 args 字段,已改为引用 script_path
及结构化字段。
#6:Deps.UploadStore 改为值类型 uploads.Store,避免 nil 绕过上传校验;
移除 spark_submit/upload_file 中的 nil 检查。
#7:master/queue/executor_memory 增加空字符串校验。
#8:提取 buildSparkSubmitCommand 构建 argv,消除双写参数的结构性根因。
#10:Validate 失败时记录 slog.Warn("spark_submit.unminted_path_rejected")。
新增测试:
- TestSparkSubmit_StructuredCommand:断言 argv 首行为 --master,末行
仍为 script_path。
- TestSparkSubmit_EmptyMaster:空 master 返回错误。
- TestStore_Validate_RejectsSidecarPath:拒绝 .meta.json 路径。
- TestStore_Sweep_DeletesDataWithCorruptSidecar:损坏 sidecar 的数据文件
被清理。
未在本提交处理:
- #9 cluster.DefaultSubmitArgs 弃用留作后续批次。
Co-Authored-By: tao.chen <93983997+taochen-ct@users.noreply.github.com >
2026-07-14 10:09:48 +08:00
tao.chen and Claude
c9e54a3f27
tools: 强制 spark_submit 的 script_path 必须来自 upload_file
...
在 spark_submit handler 中增加 server-minted 校验:script_path 必须通过
本服务器 upload_file 的 UploadStore.Validate,否则立即返回清晰错误,避免
远程 agent 把自身本地路径转发给服务器侧 spark-submit 时出现难以定位的
FileNotFoundException。
校验对 nil UploadStore 是安全的:当 d.UploadStore 为 nil 时直接跳过,保留
不强制依赖 store 的测试或降级场景。当前 testDepsWithDataDir 始终会注入
UploadStore,所以测试走的是真实校验路径。
同步更新了 script_path 的工具描述,明确声明非 upload_file 铸造的路径会被
拒绝。这是对 7920dc9 中“path 永远在最后”规则的收紧——现在不仅位置固定,
而且必须是本机 uploads 目录下的有效上传文件。
测试调整:
- 新增 TestSparkSubmit_RejectsNonMintedPath:使用 t.TempDir() 下未通过
upload_file 写入的文件作为 script_path,断言返回错误并包含
"not from upload_file"。
- TestSparkSubmit_MissingRequiredField / TestSparkSubmit_BadSparkConfValue
原来使用 "/tmp/script.py" 作为占位路径,现在会先通过 UploadStore.Save
生成一个铸造路径,确保它们继续分别验证 master 缺失和 spark_conf 值类型
错误,而不是被新的路径守卫拦截。
Co-Authored-By: Claude <noreply@anthropic.com >
2026-07-13 19:49:26 +08:00
tao.chen and Claude
7920dc9597
tools: 仿照 Python build_spark_submit_command 将 spark_submit 改为结构化参数
...
将 spark_submit 的自由 args[] 替换为与 Python 服务一致的 schema:cluster_id、
master、deploy_mode、script_path、queue、executor_memory、executor_cores、
num_executors、spark_conf、extra_args。命令行顺序严格对齐 Python 实现:
binary → --master → --queue → --executor-memory → --executor-cores →
--num-executors → 按 key 排序的 --conf key=value → 按 key 排序的 --flag value →
script_path 永远在最后。
deploy_mode 是 Python 参考函数的入参,但该函数实际并不输出 --deploy-mode;
Go 端保留这个字段并校验其值,但同样不发射它,以保持行为一致。如果后续需要
--deploy-mode,再在此处添加并记录差异。
cluster.DefaultSubmitArgs 不再被拼接到 argv 中;该字段仍保留用于 admin API
向后兼容,运行时移除它的工作是后续独立的 follow-up。
删除了 translateArgs、pathLikeArg 以及 spark_submit.unminted_path 警告逻辑
(本次提交取代 2570713),因为自由参数已不存在,警告无从触发。新增
parseStringMap、sortedStringKeys 和 requireNonNegativeInt 辅助函数;
requireNonNegativeInt 同时接受 int 与 float64,以兼容测试直接构造的整数
字面量和 JSON 解码后的 float64。
测试更新:
- TestSparkSubmit_StructuredCommand:验证完整 argv 顺序,并断言 script_path
是最后一项。
- TestSparkSubmit_MissingRequiredField:校验缺少 master 时返回错误。
- TestSparkSubmit_BadSparkConfValue:校验 spark_conf 的值不是字符串时报错。
Co-Authored-By: Claude <noreply@anthropic.com >
2026-07-13 19:35:16 +08:00
tao.chen and Claude
2570713fbf
tools: 为 spark_submit 的未 mint 绝对路径增加可观测警告
...
LLM 有时会把自己本地的绝对路径直接传给 spark_submit;这个路径在 MCP
服务器上不存在,spark-submit 会失败,但当前 translateArgs 是静默透传,
问题难以定位。添加 logger.Warn("spark_submit.unminted_path"),对
服务器未 mint 的绝对路径/路径型参数发出警告,同时保持透传不变。
生产环境中这条警告是诚实的可观测信号,而不是回归指标:集群本地合法路径
(如 /opt/spark/examples/pi.py)也会触发警告,这是设计上的,因为我们
无法区分“合法集群路径”和“LLM 本地路径”。
测试锁定:
- minted_path_no_warn:上传文件返回的 path 不触发警告
- cluster_local_path_warns:未 mint 的绝对路径触发一次警告且 path 正确
- non_path_args_never_warn:--class、Main、--master 等普通参数不触发警告
translateArgs 对 logger 做 nil-safe 处理:测试中 deps.Logger 未设置时不
会 panic,也不会产生日志,保持现有测试的简洁。
Co-Authored-By: Claude <noreply@anthropic.com >
2026-07-13 19:18:35 +08:00
tao.chen and Claude
f374ebfdb4
uploads,tools,config,main: 将 upload_file 返回路径改为服务器端绝对路径并透传给 spark_submit
...
之前 upload_file 把文件写到 DataDir/uploads/<filename>,返回相对路径
uploads/hello.txt。MCP 服务器与 agent 不在同一台机器,agent 无法构造服务
器本地路径,因此 spark_submit 无法定位脚本。
改为由新的 internal/uploads 包 mint 一个 32 字符十六进制 file_id,文件落盘为
DataDir/uploads/<file_id>,元数据写入 <file_id>.meta.json(原始文件名只存在
sidecar 里)。upload_file 返回 {file_id, path, name, size, sha256},其中 path
是绝对路径。spark_submit 的 description 明确要求 LLM 直接把 upload_file 返回
的 path 放进 args,不要自己构造路径。
为什么只在描述里约束而不在代码里拒绝非 mint 的绝对路径:集群本地已有路径
(如 /opt/spark/examples/pi.py)是合法的 spark-submit 参数,代码不能替
LLM 拒绝。
测试锁定:
- internal/uploads: Save 往返、AbsPath/Validate 非法路径、Sweep 过期/未过期/
孤立 sidecar
- internal/mcp/tools: upload_file 新响应字段、spark_submit 透传 mint 路径与
集群本地路径
刻意未做:S3/HDFS 上传、给 spark_submit 新增 file_id 参数、在代码层面拒绝
集群本地绝对路径。
破坏性变更:upload_file 响应从相对 path 改为绝对 path,并新增 file_id/name/
sha256 字段。该工具尚无外部调用者。
Co-Authored-By: Claude <noreply@anthropic.com >
2026-07-13 19:13:14 +08:00