From 88a2fad16b08ec333609484967bd492ded502c3b Mon Sep 17 00:00:00 2001 From: Carlos Villela Date: Sat, 25 Jul 2026 19:34:25 -0700 Subject: [PATCH 1/3] fix(preflight): trust Docker version identity Signed-off-by: Carlos Villela --- .../onboard/preflight-podman-compat.test.ts | 3 ++- src/lib/onboard/preflight.ts | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib/onboard/preflight-podman-compat.test.ts b/src/lib/onboard/preflight-podman-compat.test.ts index ac8e48235bc..9d879ab92db 100644 --- a/src/lib/onboard/preflight-podman-compat.test.ts +++ b/src/lib/onboard/preflight-podman-compat.test.ts @@ -71,13 +71,14 @@ describe("assessHost Podman docker-compat detection (#7320)", () => { expect(result.isUnsupportedRuntime).toBe(true); }); - it("keeps real Docker classified as supported (no Podman false positive)", () => { + it("keeps Docker Engine supported when ProductLicense reports Apache-2.0", () => { const realDockerInfo = JSON.stringify({ ServerVersion: "29.6.2", OperatingSystem: "Ubuntu 24.04.3 LTS", OSType: "linux", Architecture: "x86_64", DefaultRuntime: "runc", + ProductLicense: "Apache-2.0", DockerRootDir: "/var/lib/docker", DefaultAddressPools: [{ Base: "192.168.240.0/20", Size: 24 }], ClientInfo: { Platform: { Name: "Docker Engine - Community" } }, diff --git a/src/lib/onboard/preflight.ts b/src/lib/onboard/preflight.ts index 2f0bf89380c..01f7c4e316b 100644 --- a/src/lib/onboard/preflight.ts +++ b/src/lib/onboard/preflight.ts @@ -260,11 +260,11 @@ function dockerVersionReportsPodman(versionOutput = ""): boolean { } /** - * Backstop Podman signal from `docker info --format '{{json .}}'` when the - * `docker version` probe is unavailable: Podman's docker-compat `/info` reports - * `ProductLicense: "Apache-2.0"` (Podman is Apache-2.0 licensed), whereas Docker - * Engine omits `ProductLicense` (Docker CE) or reports a Docker license string. - * Observed Apache-2.0 on the reporter-equivalent Podman machine (#7320). + * Use `ProductLicense: "Apache-2.0"` as a Podman backstop only when the + * authoritative `docker version` probe is unavailable. Podman's docker-compat + * `/info` reports this value, but Docker Engine can also report it. Without + * version evidence, preflight conservatively rejects that ambiguous runtime + * before the Docker-driver path (#7320). */ function dockerInfoReportsPodmanCompat(infoOutput = ""): boolean { const text = String(infoOutput || "").trim(); @@ -287,10 +287,10 @@ function dockerInfoReportsPodmanCompat(infoOutput = ""): boolean { * `EADDRNOTAVAIL` (#7320). */ function isDockerCompatPodman(dockerInfoOutput = "", dockerVersionOutput = ""): boolean { - return ( - dockerVersionReportsPodman(dockerVersionOutput) || - dockerInfoReportsPodmanCompat(dockerInfoOutput) - ); + if (String(dockerVersionOutput || "").trim()) { + return dockerVersionReportsPodman(dockerVersionOutput); + } + return dockerInfoReportsPodmanCompat(dockerInfoOutput); } function parseDockerCgroupVersion(info = ""): "v1" | "v2" | "unknown" { From 752b41c505d73b608e213fe3fec79d8bd10ffdd5 Mon Sep 17 00:00:00 2001 From: Apurv Kumaria Date: Sat, 25 Jul 2026 20:09:31 -0700 Subject: [PATCH 2/3] fix(preflight): fail closed on unknown runtime identity Signed-off-by: Apurv Kumaria --- .../onboard/preflight-podman-compat.test.ts | 17 ++++++ src/lib/onboard/preflight.ts | 54 +++++++++++-------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/lib/onboard/preflight-podman-compat.test.ts b/src/lib/onboard/preflight-podman-compat.test.ts index 9d879ab92db..43e78d3e591 100644 --- a/src/lib/onboard/preflight-podman-compat.test.ts +++ b/src/lib/onboard/preflight-podman-compat.test.ts @@ -71,6 +71,23 @@ describe("assessHost Podman docker-compat detection (#7320)", () => { expect(result.isUnsupportedRuntime).toBe(true); }); + it.each([ + ["an empty JSON object", "{}"], + ["unexpected plain text", "unexpected version output"], + ])("keeps the Podman info backstop for %s from the version probe", (_case, versionOutput) => { + const result = assessHost({ + platform: "darwin", + env: {}, + dockerInfoOutput: PODMAN_COMPAT_DOCKER_INFO, + dockerVersionOutput: versionOutput, + commandExistsImpl: (name: string) => name === "docker", + }); + + expect(result.dockerReachable).toBe(true); + expect(result.runtime).toBe("podman"); + expect(result.isUnsupportedRuntime).toBe(true); + }); + it("keeps Docker Engine supported when ProductLicense reports Apache-2.0", () => { const realDockerInfo = JSON.stringify({ ServerVersion: "29.6.2", diff --git a/src/lib/onboard/preflight.ts b/src/lib/onboard/preflight.ts index 01f7c4e316b..f9a7003d305 100644 --- a/src/lib/onboard/preflight.ts +++ b/src/lib/onboard/preflight.ts @@ -216,9 +216,11 @@ function inferContainerRuntime(info = ""): ContainerRuntime { return "unknown"; } +type DockerVersionIdentity = "docker" | "podman" | "unknown"; + /** - * Detect Podman fronting the Docker CLI compatibility socket from the explicit - * `docker version --format '{{json .}}'` engine banner. + * Classify the engine identity from the explicit + * `docker version --format '{{json .}}'` banner. * * Podman's docker-compat `/info` endpoint mimics Docker so closely that * `docker info` carries no "podman" marker (observed on Apple Silicon macOS: @@ -228,35 +230,43 @@ function inferContainerRuntime(info = ""): ContainerRuntime { * `Server.Components[].Name` of "Podman Engine" and a `Server.Platform.Name` * like "linux/arm64/fedora-42". Real Docker reports * `Server.Platform.Name: "Docker Engine - Community"` and components - * `Engine`/`containerd`/`runc`, so this stays false on Docker Engine, - * Docker Desktop, and Colima (#7320). + * `Engine`/`containerd`/`runc`, which provide positive Docker identity on + * Docker Engine, Docker Desktop, and Colima (#7320). */ -function dockerVersionReportsPodman(versionOutput = ""): boolean { +function classifyDockerVersionIdentity(versionOutput = ""): DockerVersionIdentity { const text = String(versionOutput || "").trim(); - if (!text) return false; + if (!text) return "unknown"; let parsed: unknown; try { parsed = JSON.parse(text); } catch { // Plain-text `docker version` still prints the "Podman Engine" server banner. - return /podman/i.test(text); + if (/podman/i.test(text)) return "podman"; + return /docker engine/i.test(text) ? "docker" : "unknown"; } const server = (parsed as Record | null)?.Server; - if (!server || typeof server !== "object") return false; + if (!server || typeof server !== "object") return "unknown"; const s = server as Record; const platformName = (s.Platform as Record | undefined)?.Name; - if (typeof platformName === "string" && /podman/i.test(platformName)) return true; + if (typeof platformName === "string" && /podman/i.test(platformName)) return "podman"; const components = s.Components; - return ( - Array.isArray(components) && - components.some((component) => { - const name = - component && typeof component === "object" - ? (component as Record).Name - : undefined; - return typeof name === "string" && /podman/i.test(name); - }) - ); + const componentNames = Array.isArray(components) + ? components.flatMap((component) => { + const name = + component && typeof component === "object" + ? (component as Record).Name + : undefined; + return typeof name === "string" ? [name] : []; + }) + : []; + if (componentNames.some((name) => /podman/i.test(name))) return "podman"; + if ( + (typeof platformName === "string" && /^docker (?:engine|desktop)\b/i.test(platformName)) || + componentNames.some((name) => name.trim().toLowerCase() === "engine") + ) { + return "docker"; + } + return "unknown"; } /** @@ -287,9 +297,9 @@ function dockerInfoReportsPodmanCompat(infoOutput = ""): boolean { * `EADDRNOTAVAIL` (#7320). */ function isDockerCompatPodman(dockerInfoOutput = "", dockerVersionOutput = ""): boolean { - if (String(dockerVersionOutput || "").trim()) { - return dockerVersionReportsPodman(dockerVersionOutput); - } + const versionIdentity = classifyDockerVersionIdentity(dockerVersionOutput); + if (versionIdentity === "podman") return true; + if (versionIdentity === "docker") return false; return dockerInfoReportsPodmanCompat(dockerInfoOutput); } From 60f8b094ad8e20fc6325630e8c00a2c435745768 Mon Sep 17 00:00:00 2001 From: Carlos Villela Date: Sat, 25 Jul 2026 20:56:14 -0700 Subject: [PATCH 3/3] test(preflight): clarify ambiguous runtime case Signed-off-by: Carlos Villela --- src/lib/onboard/preflight-podman-compat.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/onboard/preflight-podman-compat.test.ts b/src/lib/onboard/preflight-podman-compat.test.ts index 43e78d3e591..1666589b56b 100644 --- a/src/lib/onboard/preflight-podman-compat.test.ts +++ b/src/lib/onboard/preflight-podman-compat.test.ts @@ -74,7 +74,7 @@ describe("assessHost Podman docker-compat detection (#7320)", () => { it.each([ ["an empty JSON object", "{}"], ["unexpected plain text", "unexpected version output"], - ])("keeps the Podman info backstop for %s from the version probe", (_case, versionOutput) => { + ])("rejects a Podman-compatible runtime when version output is %s (#7320)", (_case, versionOutput) => { const result = assessHost({ platform: "darwin", env: {},