2525import sys
2626from pathlib import Path
2727
28+ AZURE_CLI_TIMEOUT_SECONDS = 15
29+
2830# Configure UTF-8 encoding for console output
2931if sys .stdout .encoding != 'utf-8' : # pragma: no cover
3032 sys .stdout = io .TextIOWrapper (sys .stdout .buffer , encoding = 'utf-8' )
@@ -210,10 +212,19 @@ def check_azure_cli():
210212 return False , 'Install Azure CLI: https://learn.microsoft.com/cli/azure/install-azure-cli'
211213
212214 try :
213- result = subprocess .run ([az_path , '--version' ], capture_output = True , text = True , check = True )
215+ result = subprocess .run (
216+ [az_path , '--version' ],
217+ capture_output = True ,
218+ text = True ,
219+ check = True ,
220+ timeout = AZURE_CLI_TIMEOUT_SECONDS ,
221+ stdin = subprocess .DEVNULL ,
222+ )
214223 version_line = (result .stdout .splitlines () or ['unknown version' ])[0 ].strip ()
215224 version = version_line .split ()[- 1 ] if version_line else 'unknown'
216225 return True , f'Azure CLI { version } detected'
226+ except subprocess .TimeoutExpired :
227+ return False , f'Azure CLI version check timed out after { AZURE_CLI_TIMEOUT_SECONDS } seconds. Retry verification or run: az --version'
217228 except subprocess .CalledProcessError :
218229 return False , 'Reinstall Azure CLI: https://learn.microsoft.com/cli/azure/install-azure-cli'
219230
@@ -225,7 +236,14 @@ def check_bicep_cli():
225236 return False , 'Install Azure CLI first: https://learn.microsoft.com/cli/azure/install-azure-cli'
226237
227238 try :
228- result = subprocess .run ([az_path , 'bicep' , 'version' ], capture_output = True , text = True , check = True )
239+ result = subprocess .run (
240+ [az_path , 'bicep' , 'version' ],
241+ capture_output = True ,
242+ text = True ,
243+ check = True ,
244+ timeout = AZURE_CLI_TIMEOUT_SECONDS ,
245+ stdin = subprocess .DEVNULL ,
246+ )
229247 version_line = (result .stdout .splitlines () or ['unknown version' ])[0 ].strip ()
230248 version = 'unknown'
231249 if 'version' in version_line .lower ():
@@ -235,6 +253,8 @@ def check_bicep_cli():
235253 version = parts [index + 1 ]
236254 break
237255 return True , f'Bicep { version } detected'
256+ except subprocess .TimeoutExpired :
257+ return False , f'Bicep version check timed out after { AZURE_CLI_TIMEOUT_SECONDS } seconds. Retry verification or run: az bicep version'
238258 except subprocess .CalledProcessError :
239259 return False , 'Install Bicep: az bicep install'
240260
@@ -251,12 +271,16 @@ def check_azure_login():
251271 capture_output = True ,
252272 text = True ,
253273 check = True ,
274+ timeout = AZURE_CLI_TIMEOUT_SECONDS ,
275+ stdin = subprocess .DEVNULL ,
254276 )
255277 account = json .loads (result .stdout )
256278 name = account .get ('name' , 'unknown' )
257279 tenant = account .get ('tenantId' , 'unknown' )
258280 subscription = account .get ('id' , 'unknown' )
259281 return True , f'Logged in (sub: { name } , id: { subscription } , tenant: { tenant } )'
282+ except subprocess .TimeoutExpired :
283+ return False , f'Azure login check timed out after { AZURE_CLI_TIMEOUT_SECONDS } seconds. Retry verification or run: az account show'
260284 except (subprocess .CalledProcessError , json .JSONDecodeError ):
261285 return False , (
262286 'Log in via the APIM Developer CLI or `az login --tenant <tenant-id>`,'
@@ -292,6 +316,8 @@ def check_azure_providers():
292316 capture_output = True ,
293317 text = True ,
294318 check = True ,
319+ timeout = AZURE_CLI_TIMEOUT_SECONDS ,
320+ stdin = subprocess .DEVNULL ,
295321 )
296322 registered_providers = sorted (set (json .loads (result .stdout )))
297323
@@ -302,6 +328,11 @@ def check_azure_providers():
302328
303329 fix_cmds = ', ' .join ([f'az provider register -n { provider } ' for provider in missing_providers ])
304330 return False , f'Register missing providers: { fix_cmds } '
331+ except subprocess .TimeoutExpired :
332+ return False , (
333+ f'Azure provider check timed out after { AZURE_CLI_TIMEOUT_SECONDS } seconds. '
334+ 'Retry verification after Azure CLI responds normally.'
335+ )
305336 except (subprocess .CalledProcessError , json .JSONDecodeError , FileNotFoundError ):
306337 return False , 'Log in then retry: az login --tenant <tenant> && az account set --subscription <subscription>'
307338
0 commit comments