fix: harden d601 k3s guards

This commit is contained in:
Codex
2026-05-23 16:21:45 +00:00
parent 026a718a24
commit c93fb275c5
14 changed files with 353 additions and 57 deletions
+25 -22
View File
@@ -4,6 +4,11 @@ import { createWriteStream, existsSync, mkdirSync, openSync, readSync, statSync,
import { mkdir, writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { repoRoot, rootPath } from "./config";
import {
classifyD601DefaultKubectlDiagnostic,
classifyD601K3sTarget,
d601NativeKubeconfig,
} from "./d601-k3s-guard";
type HwlabCdAction = "status" | "apply";
type HwlabCdEnvironment = "dev";
@@ -59,7 +64,7 @@ interface CommandView {
const namespace = "hwlab-dev";
const lockName = "hwlab-dev-cd-lock";
const nativeKubeconfig = "/etc/rancher/k3s/k3s.yaml";
const nativeKubeconfig = d601NativeKubeconfig;
const defaultFrontendLiveUrl = "http://74.48.78.17:16666/health/live";
const defaultApiLiveUrl = "http://74.48.78.17:16667/health/live";
const parseCaptureLimitBytes = 4 * 1024 * 1024;
@@ -347,38 +352,36 @@ async function gitSummary(repoPath: string, dumpDir: string, timeoutMs: number):
async function nativeK3sGuard(kubeconfig: string, dumpDir: string, timeoutMs: number): Promise<Record<string, unknown>> {
const env = { ...process.env, KUBECONFIG: kubeconfig };
const [context, server, nodes] = await Promise.all([
const [context, server, nodes, defaultContext, defaultServer, defaultNodes] = await Promise.all([
runCaptured(["kubectl", "config", "current-context"], repoRoot, dumpDir, "k3s-current-context", { env, timeoutMs }),
runCaptured(["kubectl", "config", "view", "--minify", "-o", "jsonpath={.clusters[0].cluster.server}"], repoRoot, dumpDir, "k3s-server", { env, timeoutMs }),
runCaptured(["kubectl", "get", "nodes", "-o", "jsonpath={range .items[*]}{.metadata.name}{\"\\n\"}{end}"], repoRoot, dumpDir, "k3s-nodes", { env, timeoutMs }),
runCaptured(["kubectl", "config", "current-context"], repoRoot, dumpDir, "default-kubectl-current-context", { timeoutMs }),
runCaptured(["kubectl", "config", "view", "--minify", "-o", "jsonpath={.clusters[0].cluster.server}"], repoRoot, dumpDir, "default-kubectl-server", { timeoutMs }),
runCaptured(["kubectl", "get", "nodes", "-o", "jsonpath={range .items[*]}{.metadata.name}{\"\\n\"}{end}"], repoRoot, dumpDir, "default-kubectl-nodes", { timeoutMs }),
]);
const contextText = context.stdoutText.trim();
const serverText = server.stdoutText.trim();
const nodeNames = nodes.stdoutText.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
const combined = `${context.stdoutText}\n${context.stderrText}\n${server.stdoutText}\n${server.stderrText}\n${nodes.stdoutText}\n${nodes.stderrText}`;
const refusalSignals = [
/docker-desktop/iu.test(combined) ? "docker-desktop" : null,
/desktop-control-plane/iu.test(combined) ? "desktop-control-plane" : null,
/127\.0\.0\.1:11700/u.test(combined) ? "127.0.0.1:11700" : null,
].filter((signal): signal is string => signal !== null);
const refusal = refusalSignals.length > 0;
const readable = context.ok && server.ok && nodes.ok;
return {
status: refusal ? "refused" : readable ? "pass" : "blocked",
refusal,
refusalSignals,
const defaultDiagnostic = classifyD601DefaultKubectlDiagnostic({
currentContext: defaultContext.stdoutText.trim() || null,
apiServer: defaultServer.stdoutText.trim() || null,
combinedText: `${defaultContext.stdoutText}\n${defaultContext.stderrText}\n${defaultServer.stdoutText}\n${defaultServer.stderrText}\n${defaultNodes.stdoutText}\n${defaultNodes.stderrText}`,
commandsOk: defaultContext.ok && defaultServer.ok && defaultNodes.ok,
});
const guard = classifyD601K3sTarget({
kubeconfig,
injectedEnv: { KUBECONFIG: kubeconfig },
expectedKubeconfig: nativeKubeconfig,
currentContext: contextText || null,
apiServer: serverText || null,
nodeNames,
nodeCount: nodeNames.length,
summary: refusal
? "Refusing HWLAB CD because kubectl resolved to a Docker Desktop control plane signal."
: readable
? "D601 native k3s guard passed with explicit KUBECONFIG."
: "D601 native k3s guard could not fully read context, server, and nodes.",
commands: [context, server, nodes].map(commandView),
commandsOk: context.ok && server.ok && nodes.ok,
combinedText: `${context.stdoutText}\n${context.stderrText}\n${server.stdoutText}\n${server.stderrText}\n${nodes.stdoutText}\n${nodes.stderrText}`,
}, defaultDiagnostic);
return {
...guard,
injectedEnv: { KUBECONFIG: kubeconfig },
commands: [context, server, nodes, defaultContext, defaultServer, defaultNodes].map(commandView),
};
}