From 344f7c9e54ded95816dd3b54202ec1153d586351 Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Wed, 17 Jun 2026 16:18:52 +0200 Subject: [PATCH 1/2] fix(device-id): device id drift between devtools products and altas cli COMPASS-10690 --- packages/device-id/src/get-device-id.spec.ts | 45 ++++++++++++++++++-- packages/device-id/src/get-device-id.ts | 2 +- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/packages/device-id/src/get-device-id.spec.ts b/packages/device-id/src/get-device-id.spec.ts index 22e01a11..387f91f2 100644 --- a/packages/device-id/src/get-device-id.spec.ts +++ b/packages/device-id/src/get-device-id.spec.ts @@ -1,6 +1,14 @@ +import { createHmac } from 'crypto'; import { expect } from 'chai'; import { getDeviceId } from './get-device-id'; +// Replicates machineid.ProtectedID(appID) from github.com/denisbrodbeck/machineid: +// https://github.com/denisbrodbeck/machineid/blob/master/helper.go +// HMAC-SHA256(key=rawMachineId, message=appID), no case normalization. +function atlasCLIDeviceId(rawMachineId: string): string { + return createHmac('sha256', rawMachineId).update('atlascli').digest('hex'); +} + describe('getDeviceId', function () { it('returns a hashed device id when machine id is available', async function () { const mockMachineId = 'test-machine-id'; @@ -15,19 +23,18 @@ describe('getDeviceId', function () { expect(deviceId).to.not.equal('unknown'); }); - it('converts machine id to uppercase when using node-machine-id', async function () { + it('produces different hashes for lower and uppercase machine ids', async function () { const mockMachineId = 'test-machine-id'; - const getMachineId = () => Promise.resolve(mockMachineId); const resultA = await getDeviceId({ - getMachineId, + getMachineId: () => Promise.resolve(mockMachineId), }); const resultB = await getDeviceId({ getMachineId: () => Promise.resolve(mockMachineId.toUpperCase()), }); - expect(resultA).to.equal(resultB); + expect(resultA).to.not.equal(resultB); }); it('returns "unknown" when machine id is not found', async function () { @@ -149,4 +156,34 @@ describe('getDeviceId', function () { }); } }); + + describe('Atlas CLI compatibility', function () { + // Machine IDs format (case and hyphens) matter to catch case normalization bug. + const cases = [ + { + platform: 'Linux', + // /etc/machine-id is always lowercase hex without hyphens + rawMachineId: 'a8098c1af14ef2e1dc4d7f5b4e08d4c0', + }, + { + platform: 'macOS', + // IOPlatformUUID from IOKit is uppercase with hyphens + rawMachineId: 'A8098C1A-F14E-F2E1-DC4D-7F5B4E08D4C0', + }, + { + platform: 'Windows', + // MachineGuid from HKLM\SOFTWARE\Microsoft\Cryptography is lowercase with hyphens + rawMachineId: '6ba7b810-9dad-11d1-80b4-00c04fd430c8', + }, + ]; + + for (const { platform, rawMachineId } of cases) { + it(`matches Atlas CLI output for ${platform} machine id format`, async function () { + const result = await getDeviceId({ + getMachineId: () => Promise.resolve(rawMachineId), + }); + expect(result).to.equal(atlasCLIDeviceId(rawMachineId)); + }); + } + }); }); diff --git a/packages/device-id/src/get-device-id.ts b/packages/device-id/src/get-device-id.ts index dfb768ed..25008e33 100644 --- a/packages/device-id/src/get-device-id.ts +++ b/packages/device-id/src/get-device-id.ts @@ -61,7 +61,7 @@ async function resolveMachineId({ onError, }: GetDeviceIdOptions): Promise { try { - const originalId = (await getMachineId())?.toUpperCase(); + const originalId = await getMachineId(); if (!originalId) { onError?.('resolutionError', new Error('Failed to resolve machine ID')); From bdd153b5f8dc3fa6ddbe5898a2eefa54c7dfea9b Mon Sep 17 00:00:00 2001 From: Alena Khineika Date: Thu, 18 Jun 2026 14:00:00 +0200 Subject: [PATCH 2/2] docs: update a comment --- packages/device-id/src/get-device-id.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/device-id/src/get-device-id.spec.ts b/packages/device-id/src/get-device-id.spec.ts index 387f91f2..48827787 100644 --- a/packages/device-id/src/get-device-id.spec.ts +++ b/packages/device-id/src/get-device-id.spec.ts @@ -2,7 +2,7 @@ import { createHmac } from 'crypto'; import { expect } from 'chai'; import { getDeviceId } from './get-device-id'; -// Replicates machineid.ProtectedID(appID) from github.com/denisbrodbeck/machineid: +// Replicates machineid.ProtectedID(appID) from // https://github.com/denisbrodbeck/machineid/blob/master/helper.go // HMAC-SHA256(key=rawMachineId, message=appID), no case normalization. function atlasCLIDeviceId(rawMachineId: string): string {