Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions scripts/prepare-dgx-station-host.sh
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,23 @@ dgx_station_release_profile() {
platform="$(dgx_station_release_value "$path" DGX_PLATFORM)" || return 1
[[ "$platform" == "DGX Server for GALAXY-GB300" ]] || return 1

if ota_pretty="$(dgx_station_release_value "$path" DGX_OTA_PRETTY_NAME 2>/dev/null)"; then
[[ "$ota_pretty" == "DGX OS" ]] || return 1
# DGX OS keeps its upgrade history in the DGX_OTA_* fields, so a host that has
# an OTA history is classified by the most recent OTA version it applied.
#
# A host provisioned from a full DGX OS image also carries the identity field
# DGX_OTA_PRETTY_NAME="DGX OS"; when that field is present it must read exactly
# "DGX OS". It is absent on a host that was first installed from an older base
# image (for example 7.4.1-GB300ws) and later OTA-upgraded, because an OTA
# upgrade never adds that field. In that case, fall back to the hardware
# identity and require DGX_PRETTY_NAME="NVIDIA DGX GB300WS" so that other
# release lineages that also emit DGX_OTA_* fields stay fail-closed.
if dgx_station_release_value "$path" DGX_OTA_VERSION >/dev/null 2>&1; then
if ota_pretty="$(dgx_station_release_value "$path" DGX_OTA_PRETTY_NAME 2>/dev/null)"; then
[[ "$ota_pretty" == "DGX OS" ]] || return 1
else
pretty="$(dgx_station_release_value "$path" DGX_PRETTY_NAME)" || return 1
[[ "$pretty" == "NVIDIA DGX GB300WS" ]] || return 1
fi
version="$(dgx_station_release_value "$path" DGX_OTA_VERSION)" || return 1
case "$version" in
7.2.0 | 7.4.0 | 7.5.0) printf '%s' supported-dgx-os ;;
Expand All @@ -210,7 +225,6 @@ dgx_station_release_profile() {
# No-OTA factory images are separate, exact profiles. Do not infer support
# merely from a missing OTA identity: internal BaseOS and customer images
# use different software stacks and qualification evidence.
dgx_station_release_value "$path" DGX_OTA_VERSION >/dev/null 2>&1 && return 1
dgx_station_release_value "$path" DGX_OTA_DATE >/dev/null 2>&1 && return 1
pretty="$(dgx_station_release_value "$path" DGX_PRETTY_NAME)" || return 1
version="$(dgx_station_release_value "$path" DGX_SWBUILD_VERSION)" || return 1
Expand Down
61 changes: 61 additions & 0 deletions test/install-station-dgx-os.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,36 @@ function writeNoOtaFactoryRelease(
return target;
}

function writeOtaUpgradedRelease(
overrides: Partial<{ pretty: string; otaVersion: string; swbuildVersion: string }> = {},
) {
const fields = {
pretty: "NVIDIA DGX GB300WS",
otaVersion: "7.5.0",
swbuildVersion: "7.4.1-GB300ws",
...overrides,
};
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-station-ota-upgraded-"));
const target = path.join(dir, "dgx-release");
fs.writeFileSync(
target,
[
'DGX_NAME="DGX GB300WS"',
`DGX_PRETTY_NAME="${fields.pretty}"`,
'DGX_SWBUILD_DATE="2026-02-20-05-22-42"',
`DGX_SWBUILD_VERSION="${fields.swbuildVersion}"`,
'DGX_COMMIT_ID="51c59a9"',
'DGX_PLATFORM="DGX Server for GALAXY-GB300"',
'DGX_SERIAL_NUMBER="Unknown"',
"",
`DGX_OTA_VERSION="${fields.otaVersion}"`,
'DGX_OTA_DATE="Sun Apr 12 16:25:30 PDT 2026"',
"",
].join("\n"),
);
return target;
}

describe("DGX Station stock DGX OS classification", () => {
it.each([
"7.2.0",
Expand Down Expand Up @@ -349,6 +379,37 @@ dgx_station_release_state "$DGX_RELEASE"
expect(result.stdout).toBe(expected);
});

it("classifies an OTA-upgraded GB300 workstation without the fresh-install marker as supported-dgx-os (#7103)", () => {
const release = writeOtaUpgradedRelease();
const { result, output } = runSourced(
STATION_PREPARE,
`
stat() { printf '0|0|644|256\n'; }
dgx_station_release_state "$DGX_RELEASE"
`,
{ DGX_RELEASE: release },
);

expect(result.status, output).toBe(0);
expect(result.stdout).toBe("supported-dgx-os");
});

it.each([
[
"a non-workstation DGX Server identity",
writeOtaUpgradedRelease({ pretty: "NVIDIA DGX Server" }),
],
["an unreviewed latest OTA version", writeOtaUpgradedRelease({ otaVersion: "7.6.0" })],
])("keeps a marker-less OTA host fail-closed with %s (#7103)", (_scenario, release) => {
const { result } = runSourced(
STATION_PREPARE,
`dgx_station_release_contents_are_supported "$DGX_RELEASE"`,
{ DGX_RELEASE: release },
);

expect(result.status).not.toBe(0);
});

it("keeps the classifier self-contained when the helper is transported alone", () => {
const isolated = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-station-helper-only-"));
const copiedHelper = path.join(isolated, "prepare-dgx-station-host.sh");
Expand Down
Loading