Skip to content

Commit f1e5450

Browse files
authored
fix(amazonq): isAmazonLinux2() function incorrectly identifies regular Linux/Ubuntu in web/container env as AL2 (#8073)
## Problem PR: #7270 introduced a bug where the `isAmazonLinux2()` function incorrectly identifies regular Linux/Ubuntu systems in web/container environments as Amazon Linux 2. This happens because: 1. The function checks `os.release()` for `.amzn2.` or `.amzn2int.` patterns 2. In containerized environments (like VS Code web/remote), `os.release()` returns the __host's kernel version__, not the container's OS 3. If the host is Amazon Linux 2 but the container is Ubuntu/Linux, the function incorrectly returns `true` 4. This prevents Amazon Q LSP from starting because it thinks it's on AL2 without the required GLIBC patch ## Solution - __Skip AL2 detection for web environments__ - Returns `false` immediately since web mode runs in a browser - __Check `/etc/os-release` first__ - In containerized environments, this file contains the actual container OS, not the host OS - __Trust container OS over kernel version__ - If `/etc/os-release` shows it's not AL2 (e.g., Ubuntu), return `false` regardless of kernel version - __Fall back to kernel check only when necessary__ - Only use `os.release()` if we can't read `/etc/os-release` or if it confirms AL2 - Prioritized container OS detection over kernel version detection - Maintained backward compatibility for actual AL2 systems - Added comprehensive test coverage for the new scenarios --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent f297d64 commit f1e5450

File tree

3 files changed

+480
-30
lines changed

3 files changed

+480
-30
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Amazon Q support web/container environments running Ubuntu/Linux, even when the host machine is Amazon Linux 2."
4+
}

packages/core/src/shared/vscode/env.ts

Lines changed: 97 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
import * as semver from 'semver'
77
import * as vscode from 'vscode'
88
import * as packageJson from '../../../package.json'
9-
import * as os from 'os'
109
import { getLogger } from '../logger/logger'
1110
import { onceChanged } from '../utilities/functionUtils'
1211
import { ChildProcess } from '../utilities/processUtils'
1312
import globals, { isWeb } from '../extensionGlobals'
1413
import * as devConfig from '../../dev/config'
14+
import * as os from 'os'
1515

1616
/**
1717
* Returns true if the current build is running on CI (build server).
@@ -124,6 +124,35 @@ export function isRemoteWorkspace(): boolean {
124124
return vscode.env.remoteName === 'ssh-remote'
125125
}
126126

127+
/**
128+
* Parses an os-release file according to the freedesktop.org standard.
129+
*
130+
* @param content The content of the os-release file
131+
* @returns A record of key-value pairs from the os-release file
132+
*
133+
* @see https://www.freedesktop.org/software/systemd/man/latest/os-release.html
134+
*/
135+
function parseOsRelease(content: string): Record<string, string> {
136+
const result: Record<string, string> = {}
137+
138+
for (let line of content.split('\n')) {
139+
line = line.trim()
140+
// Skip empty lines and comments
141+
if (!line || line.startsWith('#')) {
142+
continue
143+
}
144+
145+
const eqIndex = line.indexOf('=')
146+
if (eqIndex > 0) {
147+
const key = line.slice(0, eqIndex)
148+
const value = line.slice(eqIndex + 1).replace(/^["']|["']$/g, '')
149+
result[key] = value
150+
}
151+
}
152+
153+
return result
154+
}
155+
127156
/**
128157
* Checks if the current environment has SageMaker-specific environment variables
129158
* @returns true if SageMaker environment variables are detected
@@ -146,36 +175,83 @@ export function hasSageMakerEnvVars(): boolean {
146175
/**
147176
* Checks if the current environment is running on Amazon Linux 2.
148177
*
149-
* This function attempts to detect if we're running in a container on an AL2 host
150-
* by checking both the OS release and container-specific indicators.
178+
* This function detects the container/runtime OS, not the host OS.
179+
* In containerized environments, we check the container's OS identity.
180+
*
181+
* Detection Process (in order):
182+
* 1. Returns false for web environments (browser-based)
183+
* 2. Returns false for SageMaker environments (even if container is AL2)
184+
* 3. Checks `/etc/os-release` with fallback to `/usr/lib/os-release`
185+
* - Standard Linux OS identification files per freedesktop.org spec
186+
* - Looks for `ID="amzn"` and `VERSION_ID="2"` for AL2
187+
* - This correctly identifies AL2 containers regardless of host OS
188+
*
189+
* This approach ensures correct detection in:
190+
* - Containerized environments (detects container OS, not host)
191+
* - AL2 containers on any host OS (Ubuntu, AL2023, etc.)
192+
* - Web/browser environments (returns false)
193+
* - SageMaker environments (returns false)
151194
*
152-
* Example: `5.10.220-188.869.amzn2int.x86_64` or `5.10.236-227.928.amzn2.x86_64` (Cloud Dev Machine)
195+
* Note: We intentionally do NOT check kernel version as it reflects the host OS,
196+
* not the container OS. AL2 containers should be treated as AL2 environments
197+
* regardless of whether they run on AL2, Ubuntu, or other host kernels.
198+
*
199+
* References:
200+
* - https://docs.aws.amazon.com/linux/al2/ug/ident-amazon-linux-specific.html
201+
* - https://docs.aws.amazon.com/linux/al2/ug/ident-os-release.html
202+
* - https://www.freedesktop.org/software/systemd/man/latest/os-release.html
153203
*/
154204
export function isAmazonLinux2() {
205+
// Skip AL2 detection for web environments
206+
// In web mode, we're running in a browser, not on AL2
207+
if (isWeb()) {
208+
return false
209+
}
210+
155211
// First check if we're in a SageMaker environment, which should not be treated as AL2
156-
// even if the underlying host is AL2
212+
// even if the underlying container is AL2
157213
if (hasSageMakerEnvVars()) {
158214
return false
159215
}
160216

161-
// Check if we're in a container environment that's not AL2
162-
if (process.env.container === 'docker' || process.env.DOCKER_HOST || process.env.DOCKER_BUILDKIT) {
163-
// Additional check for container OS - if we can determine it's not AL2
164-
try {
165-
const fs = require('fs')
166-
if (fs.existsSync('/etc/os-release')) {
167-
const osRelease = fs.readFileSync('/etc/os-release', 'utf8')
168-
if (!osRelease.includes('Amazon Linux 2') && !osRelease.includes('amzn2')) {
169-
return false
217+
// Only proceed with file checks on Linux platforms
218+
if (process.platform !== 'linux') {
219+
return false
220+
}
221+
222+
// Check the container/runtime OS identity via os-release files
223+
// This correctly identifies AL2 containers regardless of host OS
224+
try {
225+
const fs = require('fs')
226+
// Check /etc/os-release with fallback to /usr/lib/os-release as per freedesktop.org spec
227+
const osReleasePaths = ['/etc/os-release', '/usr/lib/os-release']
228+
229+
for (const osReleasePath of osReleasePaths) {
230+
if (fs.existsSync(osReleasePath)) {
231+
try {
232+
const osReleaseContent = fs.readFileSync(osReleasePath, 'utf8')
233+
const osRelease = parseOsRelease(osReleaseContent)
234+
235+
// Check if this is Amazon Linux 2
236+
// We trust os-release as the authoritative source for container OS identity
237+
return osRelease.VERSION_ID === '2' && osRelease.ID === 'amzn'
238+
} catch (e) {
239+
// Continue to next path if parsing fails
240+
getLogger().error(`Parsing os-release file ${osReleasePath} failed: ${e}`)
170241
}
171242
}
172-
} catch (e) {
173-
// If we can't read the file, fall back to the os.release() check
174243
}
244+
} catch (e) {
245+
// If we can't read the files, we cannot determine AL2 status
246+
getLogger().error(`Checking os-release files failed: ${e}`)
175247
}
176248

177-
// Standard check for AL2 in the OS release string
178-
return (os.release().includes('.amzn2int.') || os.release().includes('.amzn2.')) && process.platform === 'linux'
249+
// Fall back to kernel version check if os-release files are unavailable or failed
250+
// This is needed for environments where os-release might not be accessible
251+
const kernelRelease = os.release()
252+
const hasAL2Kernel = kernelRelease.includes('.amzn2int.') || kernelRelease.includes('.amzn2.')
253+
254+
return hasAL2Kernel
179255
}
180256

181257
/**
@@ -217,9 +293,9 @@ export function getExtRuntimeContext(): {
217293
extensionHost: ExtensionHostLocation
218294
} {
219295
const extensionHost =
220-
// taken from https://github.com/microsoft/vscode/blob/7c9e4bb23992c63f20cd86bbe7a52a3aa4bed89d/extensions/github-authentication/src/githubServer.ts#L121 to help determine which auth flows
221-
// should be used
222-
typeof navigator === 'undefined'
296+
// Check if we're in a Node.js environment (desktop/remote) vs web worker
297+
// Updated to be compatible with Node.js v22 which includes navigator global
298+
typeof process === 'object' && process.versions?.node
223299
? globals.context.extension.extensionKind === vscode.ExtensionKind.UI
224300
? 'local'
225301
: 'remote'

0 commit comments

Comments
 (0)