66import * as semver from 'semver'
77import * as vscode from 'vscode'
88import * as packageJson from '../../../package.json'
9- import * as os from 'os'
109import { getLogger } from '../logger/logger'
1110import { onceChanged } from '../utilities/functionUtils'
1211import { ChildProcess } from '../utilities/processUtils'
1312import globals , { isWeb } from '../extensionGlobals'
1413import * 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 */
154204export 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