diff --git a/config/scripts/ssh-relay-runtime-toolchain.mjs b/config/scripts/ssh-relay-runtime-toolchain.mjs index 72ee65e002e..04f2976a3ad 100644 --- a/config/scripts/ssh-relay-runtime-toolchain.mjs +++ b/config/scripts/ssh-relay-runtime-toolchain.mjs @@ -80,10 +80,14 @@ async function executableRecord({ versionCommand, versionArgs, versionPattern, + windowsFileVersion = false, xcrun = false }) { const path = await locateExecutable(command, { xcrun }) - const result = await capture(versionCommand ?? path, versionArgs ?? args) + const invocation = windowsFileVersion + ? sshRelayRuntimeWindowsFileVersionInvocation(path) + : { command: versionCommand ?? path, args: versionArgs ?? args } + const result = await capture(invocation.command, invocation.args) return { version: selectSshRelayRuntimeToolVersion(result, versionPattern), sha256: await sha256File(path) @@ -181,6 +185,20 @@ export function sshRelayRuntimeStripVersionProbe(platform) { : { args: ['--version'] } } +export function sshRelayRuntimeWindowsFileVersionInvocation(path) { + return { + command: 'pwsh.exe', + args: [ + '-NoLogo', + '-NoProfile', + '-NonInteractive', + '-Command', + '[System.Diagnostics.FileVersionInfo]::GetVersionInfo($args[0]).FileVersion', + path + ] + } +} + export function assertSshRelayRuntimeToolchain(toolchain, tuple) { const common = ['buildNode', 'bundledNode', 'compiler', 'buildSystem', 'python', 'archive'] const expected = tuple.startsWith('win32-') @@ -224,9 +242,10 @@ export async function collectSshRelayRuntimeToolchain(nodePath) { }), linker: await executableRecord({ command: 'link.exe', - // Why: direct no-argument invocation is silent on current hosted MSVC runners. - args: ['/?'], - versionPattern: /Linker Version/i + args: [], + // Why: hosted link.exe is silent when piped; authenticated PE metadata gives its real version. + windowsFileVersion: true, + versionPattern: /^\d+(?:\.\d+){2,3}$/ }), buildSystem: await executableRecord({ command: 'msbuild.exe', diff --git a/config/scripts/ssh-relay-runtime-toolchain.test.mjs b/config/scripts/ssh-relay-runtime-toolchain.test.mjs index 6fd6d4c3881..4b9ee2c42d6 100644 --- a/config/scripts/ssh-relay-runtime-toolchain.test.mjs +++ b/config/scripts/ssh-relay-runtime-toolchain.test.mjs @@ -6,7 +6,8 @@ import { selectSshRelayRuntimeToolVersion, sshRelayRuntimeBuilderIdentity, sshRelayRuntimeRunnerIdentity, - sshRelayRuntimeStripVersionProbe + sshRelayRuntimeStripVersionProbe, + sshRelayRuntimeWindowsFileVersionInvocation } from './ssh-relay-runtime-toolchain.mjs' const commit = 'a'.repeat(40) @@ -27,18 +28,25 @@ describe('SSH relay runtime build provenance', () => { ).toBe('Microsoft (R) C/C++ Optimizing Compiler Version 19.44.35228 for ARM64') }) - it('selects the Windows linker version from bounded help output', () => { + it('selects a bounded Windows linker file version', () => { expect( - selectSshRelayRuntimeToolVersion( - { - stdout: [ - 'Microsoft (R) Incremental Linker Version 14.44.35228.0', - 'usage: LINK [options] [files]' - ].join('\r\n') - }, - /Linker Version/i - ) - ).toBe('Microsoft (R) Incremental Linker Version 14.44.35228.0') + selectSshRelayRuntimeToolVersion({ stdout: '14.44.35228.0\r\n' }, /^\d+(?:\.\d+){2,3}$/) + ).toBe('14.44.35228.0') + }) + + it('passes the resolved linker path as a non-interpolated PowerShell argument', () => { + const path = String.raw`C:\Program Files\Microsoft Visual Studio\link.exe` + expect(sshRelayRuntimeWindowsFileVersionInvocation(path)).toEqual({ + command: 'pwsh.exe', + args: [ + '-NoLogo', + '-NoProfile', + '-NonInteractive', + '-Command', + '[System.Diagnostics.FileVersionInfo]::GetVersionInfo($args[0]).FileVersion', + path + ] + }) }) it('pins GitHub builder identity to the exact source commit', () => {