ecef028132
Co-Authored-By: Codex <noreply@openai.com>
86 lines
3.9 KiB
TypeScript
86 lines
3.9 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import { describe, expect, test } from "bun:test";
|
|
import { repoRoot } from "./config";
|
|
import { sshHelp, sshHelpScope } from "./help";
|
|
|
|
describe("ssh download scoped help", () => {
|
|
test("selects only the exact help-first download scope", () => {
|
|
expect(sshHelpScope(["ssh", "--help", "download"])).toBe("download");
|
|
expect(sshHelpScope(["ssh", "help", "download"])).toBe("download");
|
|
expect(sshHelpScope(["ssh", "--help"])).toBeUndefined();
|
|
expect(sshHelpScope(["ssh", "NC01:k3s", "--help"])).toBeUndefined();
|
|
expect(sshHelpScope(["ssh", "--help", "download", "extra"])).toBeUndefined();
|
|
});
|
|
|
|
test("keeps download help bounded and discloses the executing source root", () => {
|
|
const scoped = sshHelp("download") as {
|
|
scope: string;
|
|
runtime: { repoRoot: string; cliPath: string; cwdSelectsRepoRoot: boolean; rootSelection: { environmentVariable: string } };
|
|
usage: string[];
|
|
examples: Record<string, string>;
|
|
contract: { pathOrder: string[]; transport: string; verification: { automatic: boolean } };
|
|
};
|
|
const full = sshHelp() as { usage: string[] };
|
|
const serialized = JSON.stringify(scoped);
|
|
|
|
expect(scoped.scope).toBe("download");
|
|
expect(scoped.usage.length).toBeLessThanOrEqual(4);
|
|
expect(scoped.usage.length).toBeLessThan(full.usage.length);
|
|
expect(Buffer.byteLength(serialized, "utf8")).toBeLessThan(10_240);
|
|
expect(serialized).not.toContain("git exact-commit");
|
|
expect(scoped.runtime.repoRoot).toBe(repoRoot);
|
|
expect(scoped.runtime.cliPath).toBe(`${repoRoot}/scripts/ssh-cli.ts`);
|
|
expect(scoped.runtime.cwdSelectsRepoRoot).toBe(false);
|
|
expect(scoped.runtime.rootSelection.environmentVariable).toBe("UNIDESK_TRANS_REPO_ROOT");
|
|
expect(scoped.contract.pathOrder).toEqual(["remote-file", "local-file"]);
|
|
expect(scoped.contract.transport).toBe("host.ssh.tcp-pool");
|
|
expect(scoped.contract.verification.automatic).toBe(true);
|
|
expect(scoped.examples.host).toContain("download /tmp/trace.json ./trace.json");
|
|
expect(scoped.examples.k3sWorkload).toBe(
|
|
"trans NC01:k3s:hwlab-v03:hwlab-cloud-api:hwlab-cloud-api download /tmp/trace.json ./trace.json",
|
|
);
|
|
expect(scoped.examples.windowsDrive).toContain("D:\\tmp\\trace.json");
|
|
expect(scoped.examples.explicitWorktree).toBe(
|
|
`UNIDESK_TRANS_REPO_ROOT=${repoRoot} trans NC01:k3s:hwlab-v03:hwlab-cloud-api:hwlab-cloud-api download /tmp/trace.json ./trace.json`,
|
|
);
|
|
});
|
|
|
|
test("renders the original trans command without stdout dump fallback", () => {
|
|
const result = spawnSync("bun", ["scripts/ssh-cli.ts", "--help", "download"], {
|
|
cwd: repoRoot,
|
|
env: {
|
|
...process.env,
|
|
UNIDESK_SSH_ENTRYPOINT: "trans",
|
|
UNIDESK_TRANS_REPO_ROOT: repoRoot,
|
|
},
|
|
encoding: "utf8",
|
|
});
|
|
|
|
expect(result.status).toBe(0);
|
|
expect(result.stderr).toBe("");
|
|
expect(Buffer.byteLength(result.stdout, "utf8")).toBeLessThan(10_240);
|
|
const rendered = JSON.parse(result.stdout) as {
|
|
ok: boolean;
|
|
command: string;
|
|
data: { scope: string; runtime: { repoRoot: string }; usage: string[]; outputTruncated?: boolean };
|
|
};
|
|
expect(rendered.ok).toBe(true);
|
|
expect(rendered.command).toBe("trans --help download");
|
|
expect(rendered.data.scope).toBe("download");
|
|
expect(rendered.data.runtime.repoRoot).toBe(repoRoot);
|
|
expect(rendered.data.usage.length).toBeLessThanOrEqual(4);
|
|
expect(rendered.data.outputTruncated).toBeUndefined();
|
|
|
|
const unified = spawnSync("bun", ["scripts/cli.ts", "ssh", "--help", "download"], {
|
|
cwd: repoRoot,
|
|
env: process.env,
|
|
encoding: "utf8",
|
|
});
|
|
expect(unified.status).toBe(0);
|
|
expect(unified.stderr).toBe("");
|
|
const unifiedRendered = JSON.parse(unified.stdout) as { data: { scope: string; runtime: { repoRoot: string } } };
|
|
expect(unifiedRendered.data.scope).toBe("download");
|
|
expect(unifiedRendered.data.runtime.repoRoot).toBe(repoRoot);
|
|
});
|
|
});
|