From 36b32ddcd5b0626fc862db9a2ee5c48d62ba3bf6 Mon Sep 17 00:00:00 2001 From: Sverre Johansen Date: Thu, 2 Oct 2025 11:38:58 +0200 Subject: [PATCH 1/3] Add Linux support to ado-npm-auth and node-azureauth This change enables native Linux (x64 and arm64) support for automatic Azure DevOps authentication in both packages. Changes in packages/ado-npm-auth: - Added linux (x64, arm64) to supported platforms in is-supported-platform-and-architecture.ts Changes in packages/node-azureauth: - Added linux (x64, arm64) to supported platforms - Fixed binary name map (azureauth instead of azureauth.exe for Linux) - Added .deb download support for Linux binaries - Implemented extractDeb() function to handle .deb package extraction - Updated DOWNLOAD_MAP to include Linux .deb files for x64 and arm64 The azureauth CLI (v0.8.4+) already provides Linux binaries, this change enables the wrappers to use them. Fixes support for native Linux users who previously had to manually configure PAT tokens. --- .../is-supported-platform-and-architecture.ts | 3 +- packages/node-azureauth/src/install.ts | 88 +++++++++++++++++-- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/packages/ado-npm-auth/src/azureauth/is-supported-platform-and-architecture.ts b/packages/ado-npm-auth/src/azureauth/is-supported-platform-and-architecture.ts index 14aa74b6..a0b4cfc9 100644 --- a/packages/ado-npm-auth/src/azureauth/is-supported-platform-and-architecture.ts +++ b/packages/ado-npm-auth/src/azureauth/is-supported-platform-and-architecture.ts @@ -2,13 +2,14 @@ import { arch, platform } from "os"; import { isWsl } from "../utils/is-wsl.js"; /** - * Determines if the currently running platform is supported by azureauth. Currently, supported platforms are Windows, Mac & WSL + * Determines if the currently running platform is supported by azureauth. Currently, supported platforms are Windows, Mac, Linux & WSL * @returns { boolean } if the current platform is supported by azureauth */ export const isSupportedPlatformAndArchitecture = (): boolean => { const supportedPlatformsAndArchitectures: Record = { win32: ["x64"], darwin: ["x64", "arm64"], + linux: ["x64", "arm64"], }; return ( diff --git a/packages/node-azureauth/src/install.ts b/packages/node-azureauth/src/install.ts index 54e27843..5f2e33ee 100644 --- a/packages/node-azureauth/src/install.ts +++ b/packages/node-azureauth/src/install.ts @@ -1,5 +1,6 @@ import path from "node:path"; import fs from "node:fs"; +import { execSync } from "node:child_process"; import { DownloaderHelper } from "node-downloader-helper"; import decompress from "decompress"; @@ -22,6 +23,73 @@ async function download(url: string, saveDirectory: string): Promise { }); } +async function extractDeb(debPath: string, outputDir: string): Promise { + const tempDir = path.join(outputDir, "temp_deb_extract"); + fs.mkdirSync(tempDir, { recursive: true }); + + try { + // Copy .deb to temp directory + const debInTemp = path.join(tempDir, path.basename(debPath)); + fs.copyFileSync(debPath, debInTemp); + + // Extract the .deb file (which is an ar archive) in temp directory + execSync(`ar x ${path.basename(debPath)}`, { + cwd: tempDir, + stdio: "inherit", + }); + + // Find and extract the data.tar.* file + const files = fs.readdirSync(tempDir); + const dataTar = files.find((f) => f.startsWith("data.tar")); + + if (!dataTar) { + throw new Error("data.tar.* not found in .deb archive"); + } + + // Extract data.tar.* to a temp extract directory + const extractDir = path.join(tempDir, "extract"); + fs.mkdirSync(extractDir, { recursive: true }); + + execSync(`tar -xf ${dataTar} -C ${extractDir}`, { + cwd: tempDir, + stdio: "inherit", + }); + + // Move all files from usr/lib/azureauth to the root of outputDir + const sourceDir = path.join(extractDir, "usr", "lib", "azureauth"); + + if (fs.existsSync(sourceDir)) { + // Recursively copy all files and directories + const copyRecursive = (src: string, dest: string) => { + const stats = fs.statSync(src); + if (stats.isDirectory()) { + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest, { recursive: true }); + } + const entries = fs.readdirSync(src); + for (const entry of entries) { + copyRecursive(path.join(src, entry), path.join(dest, entry)); + } + } else { + fs.copyFileSync(src, dest); + // Make executable files executable + if (path.basename(src) === "azureauth" || stats.mode & fs.constants.S_IXUSR) { + fs.chmodSync(dest, 0o755); + } + } + }; + + const entries = fs.readdirSync(sourceDir); + for (const entry of entries) { + copyRecursive(path.join(sourceDir, entry), path.join(outputDir, entry)); + } + } + } finally { + // Clean up temp directory + fs.rmSync(tempDir, { recursive: true, force: true }); + } +} + const platform = process.platform; const arch = process.arch; @@ -37,7 +105,7 @@ const AZUREAUTH_INFO = { const AZUREAUTH_NAME_MAP: any = { def: "azureauth", win32: "azureauth.exe", - linux: "azureauth.exe", + linux: "azureauth", }; export const AZUREAUTH_NAME = @@ -73,11 +141,10 @@ export const install = async () => { x64: `azureauth-${AZUREAUTH_INFO.version}-osx-x64.tar.gz`, arm64: `azureauth-${AZUREAUTH_INFO.version}-osx-arm64.tar.gz`, }, - // TODO: support linux when the binaries are available - // linux: { - // def: "azureauth.exe", - // x64: "azureauth-${AZUREAUTH_INFO.version}-win10-x64.zip", - // }, + linux: { + x64: `azureauth-${AZUREAUTH_INFO.version}-linux-x64.deb`, + arm64: `azureauth-${AZUREAUTH_INFO.version}-linux-arm64.deb`, + }, }; if (platform in DOWNLOAD_MAP) { // download the executable @@ -106,7 +173,12 @@ export const install = async () => { const binaryPath = path.join(distPath, AZUREAUTH_NAME); - await decompress(archivePath, distPath); + // Handle .deb files differently from .zip and .tar.gz + if (filename.endsWith(".deb")) { + await extractDeb(archivePath, distPath); + } else { + await decompress(archivePath, distPath); + } if (fileExist(binaryPath)) { fs.chmodSync(binaryPath, fs.constants.S_IXUSR || 0o100); @@ -115,7 +187,7 @@ export const install = async () => { fs.chmodSync(binaryPath, 0o755); } - console.log(`Unzipped in ${archivePath}`); + console.log(`Extracted in ${archivePath}`); fs.unlinkSync(archivePath); } }; From b0070ed8541a651ad2cdff39e301c38f07cb0635 Mon Sep 17 00:00:00 2001 From: Sverre Johansen Date: Thu, 2 Oct 2025 13:03:40 +0200 Subject: [PATCH 2/3] Change files --- .../change-0f97b1a9-426e-4722-82e8-54b54ec2b0a2.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 change/change-0f97b1a9-426e-4722-82e8-54b54ec2b0a2.json diff --git a/change/change-0f97b1a9-426e-4722-82e8-54b54ec2b0a2.json b/change/change-0f97b1a9-426e-4722-82e8-54b54ec2b0a2.json new file mode 100644 index 00000000..01cd1adc --- /dev/null +++ b/change/change-0f97b1a9-426e-4722-82e8-54b54ec2b0a2.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "type": "patch", + "comment": "Add Linux x64 and arm64 platform support", + "packageName": "ado-npm-auth", + "email": "sverre.johansen@microsoft.com", + "dependentChangeType": "patch" + } + ] +} \ No newline at end of file From b3ef6f6d2775877f8997759487ec2bd71cb6e8c1 Mon Sep 17 00:00:00 2001 From: Sverre Johansen Date: Thu, 2 Oct 2025 13:03:48 +0200 Subject: [PATCH 3/3] Change files --- .../change-0dd2175c-32cf-405a-9191-dc49f581835e.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 change/change-0dd2175c-32cf-405a-9191-dc49f581835e.json diff --git a/change/change-0dd2175c-32cf-405a-9191-dc49f581835e.json b/change/change-0dd2175c-32cf-405a-9191-dc49f581835e.json new file mode 100644 index 00000000..1e694303 --- /dev/null +++ b/change/change-0dd2175c-32cf-405a-9191-dc49f581835e.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "type": "minor", + "comment": "Add Linux x64 and arm64 support with .deb binary installation", + "packageName": "azureauth", + "email": "sverre.johansen@microsoft.com", + "dependentChangeType": "patch" + } + ] +} \ No newline at end of file