Files
pikasTech-unidesk/scripts/ci-install-visibility-contract-test.ts
T

97 lines
4.4 KiB
TypeScript

import { readFileSync } from "node:fs";
import { ciHelp } from "./src/ci";
function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}
const source = readFileSync("scripts/src/ci.ts", "utf8");
const jobsSource = readFileSync("scripts/src/jobs.ts", "utf8");
const help = JSON.stringify(ciHelp());
assertCondition(
source.includes("interface CiInstallOptions")
&& source.includes("skipPrewarm: boolFlag(args, \"--skip-prewarm\")")
&& source.includes("skipTektonInstall: boolFlag(args, \"--skip-tekton-install\")")
&& source.includes("wait: boolFlag(args, \"--wait\")")
&& source.includes("prewarm: options.skipPrewarm ? \"skipped\" : \"completed\"")
&& source.includes("tektonInstall: options.skipTektonInstall ? \"skipped\" : \"completed\""),
"ci install must expose controlled manifest refresh skip modes",
);
assertCondition(
source.includes("function installAsync(options: CiInstallOptions)")
&& source.includes("\"ci_install\"")
&& source.includes("ciInstallCommand(options)")
&& source.includes("options.wait ? install(config, options) : installAsync(options)")
&& source.includes("if (action === \"install-status\") return installStatus(nameArg ?? \"latest\")"),
"ci install must default to async job mode with status follow-up",
);
assertCondition(
source.includes("event: \"ci.install.progress\"")
&& source.includes("emitCiInstallProgress(\"apply-manifest\", \"started\"")
&& source.includes("emitCiInstallProgress(\"upload-manifest\", \"started\"")
&& source.includes("emitCiInstallProgress(\"kubectl-apply\", \"started\"")
&& source.includes("emitCiInstallProgress(\"install\", \"failed\"")
&& jobsSource.includes("summarizeCiInstallJobProgress")
&& jobsSource.includes("parseJsonLineEvents(stderrTail, \"ci.install.progress\")"),
"ci install job status must expose stage progress events",
);
assertCondition(
source.includes("timeoutMs: Math.min(Math.max(waitMs, 15_000), 45_000)")
&& source.includes("maxResponseBytes: 3_000_000, timeoutMs: 15_000")
&& source.includes("backend-core-dispatch-timeout"),
"ci dispatch submit must use bounded backend-core fetch timeout",
);
assertCondition(
source.includes("const hostSshBase64UploadChunkChars = 3000")
&& source.includes("chunks(encoded, hostSshBase64UploadChunkChars)")
&& source.includes("provider-gateway rejects long host.ssh commands"),
"ci host.ssh base64 upload must stay below provider command length limits",
);
assertCondition(
source.includes("runSshCommandCapture(config, `${target.providerId}:k3s`, [\"script\"], script)")
&& source.includes("base64 -d > \\\"$tmp\\\" <<'UNIDESK_CI_MANIFEST_B64'")
&& source.includes("test -s \\\"$tmp\\\"")
&& source.includes("manifest_bytes="),
"ci manifest apply must embed YAML through k3s route script with byte visibility",
);
assertCondition(
source.includes("ci_runtime_image_containerd_root_required=true")
&& source.includes("failureLines")
&& source.includes("rerun with: bun scripts/cli.ts ci install --skip-prewarm"),
"ci prewarm failure must expose concise root/containerd visibility and recovery",
);
assertCondition(
help.includes("ci install --skip-prewarm")
&& help.includes("ci install --skip-prewarm --skip-tekton-install")
&& help.includes("ci install-status latest")
&& help.includes("ci install --wait --skip-prewarm --skip-tekton-install")
&& help.includes("async-job")
&& help.includes("Use --wait only for explicit synchronous debugging")
&& help.includes("Use --skip-prewarm only to refresh Tekton/CI manifests")
&& help.includes("Use --skip-tekton-install with --skip-prewarm only when Tekton is already installed"),
"ci help must document manifest refresh boundaries",
ciHelp(),
);
console.log(JSON.stringify({
ok: true,
checks: [
"ci install exposes controlled manifest refresh skip modes",
"ci install defaults to async job mode with status follow-up",
"ci install job status exposes stage progress events",
"ci dispatch submit uses bounded backend-core fetch timeout",
"ci host.ssh base64 upload stays below provider command length limits",
"ci manifest apply embeds YAML through k3s route script with byte visibility",
"ci prewarm failure exposes concise root/containerd recovery",
"ci help documents manifest refresh boundaries",
],
}));