Merge remote-tracking branch 'origin/master' into fix/1726-pac-source-artifact-sync

This commit is contained in:
Codex
2026-07-11 06:10:26 +02:00
6 changed files with 179 additions and 5 deletions
+69 -1
View File
@@ -1,11 +1,13 @@
// SPEC: PJ2026-01060509 出站诊断 draft-2026-06-26-p8-egress-job-friction.
// SPEC: PJ2026-01060703 CI/CD branch follower draft-2026-07-03-p0-branch-follower.
// Static CLI help for job aliases and server lifecycle progressive disclosure.
import { join } from "node:path";
import { ghHelp, ghScopedHelp } from "./gh";
import { authBrokerHelp } from "./auth-broker";
import { platformDbHelp } from "./platform-db";
import { secretsHelp } from "./secrets";
import { healthHelp } from "./health";
import { repoRoot } from "./config";
export function rootHelp(): unknown {
return {
@@ -167,7 +169,16 @@ export function serverHelp(action: string | undefined = undefined): unknown {
};
}
export function sshHelp(): unknown {
export type SshHelpScope = "download";
export function sshHelpScope(args: string[]): SshHelpScope | undefined {
const [top, helpToken, scope] = args;
if (top !== "ssh" || args.length !== 3 || !isHelpToken(helpToken)) return undefined;
return scope === "download" ? scope : undefined;
}
export function sshHelp(scope: SshHelpScope | undefined = undefined): unknown {
if (scope === "download") return sshDownloadHelp();
return {
command: "ssh",
output: "json",
@@ -255,6 +266,63 @@ export function sshHelp(): unknown {
};
}
function sshDownloadHelp(): unknown {
const configuredRepoRoot = process.env.UNIDESK_TRANS_REPO_ROOT?.trim() || null;
const rawEntrypoint = process.env.UNIDESK_SSH_ENTRYPOINT?.trim();
const entrypoint = rawEntrypoint === "trans" || rawEntrypoint === "tran" || rawEntrypoint === "ssh"
? rawEntrypoint
: "ssh";
return {
command: `${entrypoint} download`,
output: "json",
scope: "download",
description: "Download one remote file through the selected route and verify remote/local bytes plus SHA-256 automatically.",
runtime: {
entrypoint,
repoRoot,
cliPath: join(repoRoot, "scripts", "ssh-cli.ts"),
cwdSelectsRepoRoot: false,
rootSelection: {
environmentVariable: "UNIDESK_TRANS_REPO_ROOT",
configuredValue: configuredRepoRoot,
explicitExample: `UNIDESK_TRANS_REPO_ROOT=${repoRoot} trans --help download`,
note: "The PATH wrapper selects its source root independently of cwd; set UNIDESK_TRANS_REPO_ROOT explicitly when validating a worktree implementation.",
},
},
usage: [
"trans <route> download <remote-file> <local-file>",
"trans <route> download --inactivity-timeout-ms <milliseconds> <remote-file> <local-file>",
"trans --help download",
],
options: {
"--inactivity-timeout-ms <milliseconds>": "Allow a controlled progress-emitting download to stay open while data continues flowing; ordinary trans operations retain the short runtime budget.",
},
contract: {
pathOrder: ["remote-file", "local-file"],
transport: "host.ssh.tcp-pool",
strategy: "tcp-pool-stdout-stream",
progress: "unidesk.ssh.download.progress JSON is emitted on stderr with bytes, remainingBytes and throughputBytesPerSecond.",
verification: {
automatic: true,
fields: ["bytes", "sha256"],
success: "verified=true and verification.match.{bytes,sha256}=true",
partialFilePolicy: "The local target is removed when streaming or verification fails.",
},
},
examples: {
host: "trans D601:/tmp download /tmp/trace.json ./trace.json",
k3sWorkload: "trans NC01:k3s:hwlab-v03:hwlab-cloud-api:hwlab-cloud-api download /tmp/trace.json ./trace.json",
windowsDrive: "trans D601:win download 'D:\\tmp\\trace.json' ./trace.json",
explicitWorktree: `UNIDESK_TRANS_REPO_ROOT=${repoRoot} trans NC01:k3s:hwlab-v03:hwlab-cloud-api:hwlab-cloud-api download /tmp/trace.json ./trace.json`,
},
notes: [
"A k3s download requires a workload route; the control-plane-only <provider>:k3s route cannot name a remote file inside a workload.",
"Windows drive-letter paths are mapped through the same provider's WSL /mnt/<drive> host route before verified stdout streaming.",
"The final JSON result is the integrity proof; a separate manual sha256sum comparison is not required.",
],
};
}
function configHelp(): unknown {
return {
command: "config show",
+85
View File
@@ -0,0 +1,85 @@
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);
});
});