Merge pull request #2262 from pikasTech/fix/2261-trans-sh-option-error
Pipelines as Code CI / hwlab-web-probe-sentinel-nc01- Success
Pipelines as Code CI / platform-infra-gitea-nc01- Success
Pipelines as Code CI / unidesk-host- Success

修复 trans shell 参数错误的 stack 泄露
This commit is contained in:
Lyon
2026-07-16 10:19:14 +08:00
committed by GitHub
3 changed files with 31 additions and 1 deletions
+2
View File
@@ -57,6 +57,8 @@ trans gh:/owner/repo/issue/<number> cat
- 诊断不披露文件正文,也不回退 `apply-patch-v1`
- 当前 HWLAB node/lane source workspace 的正式预检/同步入口是 `bun scripts/cli.ts hwlab nodes control-plane source-workspace sync --node <node> --lane <lane> --confirm``source-workspace status`;不要把裸 `trans <node>:<workspace> git fetch ...` 当成当前 HWLAB node/lane workspace 预检/修复入口。
- `sh`/`bash` 必须显式声明 shell;单进程命令优先 direct argv 或已知 operation。
- `sh`/`bash` 不接受 `-c` 等 shell 选项;错误返回 `ssh-sh-option-unsupported`,并在连接前退出。
- shell 逻辑使用 `trans <route> sh <<'SH' ... SH`;单进程直接使用 `trans <route> <command> [args...]`
- 普通 trans/ssh 短连接硬预算 60s;长 CI/CD、trace、logs、build、硬件流程必须 submit-and-poll。
- 一次性远程实验不得临时发明第二套状态协议:
- 使用 [远程临时实验 smoke](references/remote-experiment-smoke.md) 的参数合同;
+18
View File
@@ -181,6 +181,24 @@ describe("ssh bounded progressive help", () => {
expect(result.stdout).not.toContain(" at ");
});
test("rejects unsupported shell options locally with compact correction paths", () => {
for (const outputArgs of [[], ["--json"]]) {
const result = spawnSync("bun", ["scripts/ssh-cli.ts", "NC01:/root/unidesk", "sh", "-c", "git status --short", ...outputArgs], {
cwd: repoRoot,
env: { ...process.env, UNIDESK_SSH_ENTRYPOINT: "trans", UNIDESK_TRANS_REPO_ROOT: repoRoot },
encoding: "utf8",
});
expect(result.status).toBe(1);
expect(result.stderr).toBe("");
expect(result.stdout).toContain("ssh-sh-option-unsupported");
expect(result.stdout).toContain("trans <route> sh <<'SH' ... SH");
expect(result.stdout).toContain("trans <route> <command> [args...]");
expect(result.stdout).not.toContain("scripts/src/ssh.ts");
expect(result.stdout).not.toContain("ssh-runtime.ts");
expect(result.stdout).not.toContain("\"stack\"");
}
});
test("rejects the moved root entrypoint locally with one exact replacement", () => {
const result = spawnSync("bun", ["scripts/cli.ts", "trans", "NC01:/root/unidesk", "git", "status", "--short"], {
cwd: repoRoot,
+11 -1
View File
@@ -2024,7 +2024,17 @@ function buildShellCommand(args: string[], shell: "sh" | "bash", commandName: st
scriptArgs.push(...args.slice(index + 1));
break;
}
if (arg.startsWith("-")) throw new Error(`unsupported ${commandName} option: ${arg}`);
if (arg.startsWith("-")) {
throw new CliInputError(`unsupported ${commandName} option: ${arg}`, {
code: "ssh-sh-option-unsupported",
argument: arg,
usage: [
`trans <route> ${shell} <<'SH' ... SH`,
"trans <route> <command> [args...]",
],
hint: `Use a quoted ${shell} heredoc for shell logic, or pass a single process as direct argv. ${shell} options such as ${arg} are not accepted.`,
});
}
scriptArgs.push(arg);
}
return { remoteCommand: shellArgv([shell, "-s", "--", ...scriptArgs]), requiresStdin: true, invocationKind: "helper", stdinPrefix: shellScriptStdinPrefix() };