diff --git a/src/lib/onboard/windows-mxc/host-qualification.test.ts b/src/lib/onboard/windows-mxc/host-qualification.test.ts new file mode 100644 index 00000000000..e80fb38289d --- /dev/null +++ b/src/lib/onboard/windows-mxc/host-qualification.test.ts @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it } from "vitest"; + +import { + assessWindowsMxcProcessContainerCandidate, + parseWindowsBuild, + WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION, +} from "./host-qualification"; + +describe("native Windows/MXC process_container host qualification", () => { + it("returns a candidate at the exact inactive x64 build floor (#8178)", () => { + expect( + assessWindowsMxcProcessContainerCandidate({ + platform: "win32", + nativeArchitecture: "x64", + release: "10.0.26100", + }), + ).toEqual({ + candidate: true, + contractVersion: WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION, + platform: "win32", + nativeArchitecture: "x64", + windowsBuild: 26100, + }); + }); + + it("accepts a newer Windows revision without treating it as the build (#8178)", () => { + expect( + assessWindowsMxcProcessContainerCandidate({ + platform: "win32", + nativeArchitecture: "x64", + release: "10.0.28000.1836", + }), + ).toMatchObject({ candidate: true, windowsBuild: 28000 }); + }); + + it("rejects WSL and every other non-Windows host (#8178)", () => { + expect( + assessWindowsMxcProcessContainerCandidate({ + platform: "linux", + nativeArchitecture: "x64", + release: "6.6.87.2-microsoft-standard-WSL2", + }), + ).toMatchObject({ candidate: false, reason: "non-windows-host" }); + }); + + it("rejects an emulated x64 process on a native ARM64 host (#8178)", () => { + expect( + assessWindowsMxcProcessContainerCandidate({ + platform: "win32", + nativeArchitecture: "arm64", + release: "10.0.28000", + }), + ).toMatchObject({ candidate: false, reason: "unqualified-architecture" }); + }); + + it("fails closed below the process_container candidate build floor (#8178)", () => { + expect( + assessWindowsMxcProcessContainerCandidate({ + platform: "win32", + nativeArchitecture: "x64", + release: "10.0.26099", + }), + ).toMatchObject({ + candidate: false, + reason: "windows-build-below-candidate-floor", + }); + }); + + it.each([ + "", + "10", + "10.0", + "10.0.build", + "6.6.87.2-microsoft-standard-WSL2", + ])("fails closed when release %j is not a Windows build form (#8178)", (release) => { + expect( + assessWindowsMxcProcessContainerCandidate({ + platform: "win32", + nativeArchitecture: "x64", + release, + }), + ).toMatchObject({ candidate: false, reason: "unknown-windows-build" }); + }); +}); + +describe("Windows build parsing", () => { + it.each([ + ["10.0.26100", 26100], + ["10.0.26300.8553", 26300], + [" 10.0.28000.1836 ", 28000], + ])("extracts the build from %s (#8178)", (release, expected) => { + expect(parseWindowsBuild(release)).toBe(expected); + }); +}); diff --git a/src/lib/onboard/windows-mxc/host-qualification.ts b/src/lib/onboard/windows-mxc/host-qualification.ts new file mode 100644 index 00000000000..7642b4f4aed --- /dev/null +++ b/src/lib/onboard/windows-mxc/host-qualification.ts @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +export const WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION = 1 as const; +export const WINDOWS_MXC_PROCESS_CONTAINER_MINIMUM_BUILD = 26100 as const; + +export interface WindowsMxcHostFacts { + readonly platform: NodeJS.Platform; + readonly nativeArchitecture: string; + readonly release: string; +} + +export type WindowsMxcProcessContainerCandidateResult = + | { + readonly candidate: true; + readonly contractVersion: typeof WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION; + readonly platform: "win32"; + readonly nativeArchitecture: "x64"; + readonly windowsBuild: number; + } + | { + readonly candidate: false; + readonly contractVersion: typeof WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION; + readonly reason: + | "non-windows-host" + | "unqualified-architecture" + | "unknown-windows-build" + | "windows-build-below-candidate-floor"; + readonly detail: string; + }; + +/** + * Extract the Windows build from the Node.js `os.release()` form + * `..[.]`. + */ +export function parseWindowsBuild(release: string): number | null { + const match = /^\d+\.\d+\.(\d+)(?:\.\d+)?$/.exec(release.trim()); + if (!match) return null; + + const build = Number(match[1]); + return Number.isSafeInteger(build) ? build : null; +} + +/** + * Evaluate the inactive native Windows/MXC `process_container` candidate. + * + * This is a host-facts contract only. A positive result does not select a + * runtime provider or establish a supported Windows compatibility matrix. + */ +export function assessWindowsMxcProcessContainerCandidate( + facts: WindowsMxcHostFacts, +): WindowsMxcProcessContainerCandidateResult { + if (facts.platform !== "win32") { + return { + candidate: false, + contractVersion: WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION, + reason: "non-windows-host", + detail: "Native Windows/MXC requires a Windows host; WSL is not a native Windows host.", + }; + } + + // `process.arch` identifies the Node.js binary and can report x64 under + // Windows ARM64 emulation. The caller must supply the native host value. + if (facts.nativeArchitecture !== "x64") { + return { + candidate: false, + contractVersion: WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION, + reason: "unqualified-architecture", + detail: "The inactive Windows/MXC process_container candidate currently qualifies x64 only.", + }; + } + + const windowsBuild = parseWindowsBuild(facts.release); + if (windowsBuild === null) { + return { + candidate: false, + contractVersion: WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION, + reason: "unknown-windows-build", + detail: "The Windows build could not be determined from the host release.", + }; + } + + if (windowsBuild < WINDOWS_MXC_PROCESS_CONTAINER_MINIMUM_BUILD) { + return { + candidate: false, + contractVersion: WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION, + reason: "windows-build-below-candidate-floor", + detail: `The Windows/MXC process_container candidate requires Windows build ${WINDOWS_MXC_PROCESS_CONTAINER_MINIMUM_BUILD} or newer.`, + }; + } + + return { + candidate: true, + contractVersion: WINDOWS_MXC_PROCESS_CONTAINER_HOST_CONTRACT_VERSION, + platform: "win32", + nativeArchitecture: "x64", + windowsBuild, + }; +}