Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/vm-repair/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Release History
===============

2.2.3
++++++
Fixing a crash ("version: null") when running any ``vm repair`` command on Azure CLI 2.87. Newer ``setuptools`` no longer generates the ``metadata.json`` that CLI 2.87 relied on to read the installed extension version, so the version resolved to ``None`` and the extension's version check raised a ``TypeError`` before the command could run. The version check now handles a missing version gracefully instead of failing. Azure CLI 2.88 also fixes the underlying metadata issue, so upgrading the CLI remains the recommended long-term resolution.

2.2.1
++++++
Fixing a command injection vulnerability (MSRC 115198 / VULN-185362). Source VM tag values copied via ``--copy-tags`` could contain shell metacharacters that, on Windows, were interpreted by ``cmd.exe`` and executed as arbitrary commands on the operator's workstation. Tag keys and values are now validated and quoted before being interpolated into the ``az`` command, and ``_call_az_command`` quotes every argument so ``cmd.exe`` treats shell metacharacters as literal text. Minimum fixed version: 2.2.1.
Expand Down
10 changes: 9 additions & 1 deletion src/vm-repair/azext_vm_repair/repair_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,16 @@ def check_extension_version(extension_name):

extension_to_check = extension_to_check[0]

# On some Azure CLI versions (e.g. 2.87) the installed extension metadata is missing because
# newer setuptools no longer generates 'metadata.json', so the version resolves to None. Skip
# the up-to-date check instead of crashing the command on a None comparison (fixed in CLI 2.88).
installed_version = extension_to_check.get('version')
if not installed_version:
logger.debug('Could not determine the installed version of the %s extension; skipping version check.', extension_name)
return

for ext in available_extensions:
if ext['name'] == extension_name and ext['version'] > extension_to_check['version']:
if ext['name'] == extension_name and ext.get('version') and ext['version'] > installed_version:
logger.warning('The %s extension is not up to date, please update with az extension update -n %s', extension_name, extension_name)
return

Expand Down
54 changes: 54 additions & 0 deletions src/vm-repair/azext_vm_repair/tests/latest/test_repair_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
# pylint: disable=line-too-long
import unittest
from unittest import mock

from azext_vm_repair.repair_utils import check_extension_version


class CheckExtensionVersionTest(unittest.TestCase):

def _run(self, installed, available):
with mock.patch('azure.cli.core.extension.operations.list_extensions', return_value=installed), \
mock.patch('azure.cli.core.extension.operations.list_available_extensions', return_value=available):
check_extension_version('vm-repair')

def test_none_installed_version_does_not_raise(self):
# Regression for the "version: null" crash on Azure CLI 2.87, where the installed
# extension metadata is missing and the version resolves to None. Comparing a version
# string against None used to raise TypeError and abort every vm-repair command.
installed = [{'name': 'vm-repair', 'version': None}]
available = [{'name': 'vm-repair', 'version': '2.2.2'}]
try:
self._run(installed, available)
except TypeError:
self.fail('check_extension_version raised TypeError on a None installed version')
Comment on lines +25 to +28

def test_none_available_version_does_not_raise(self):
installed = [{'name': 'vm-repair', 'version': '2.2.2'}]
available = [{'name': 'vm-repair', 'version': None}]
try:
self._run(installed, available)
except TypeError:
self.fail('check_extension_version raised TypeError on a None available version')
Comment on lines +33 to +36

def test_newer_available_version_warns(self):
installed = [{'name': 'vm-repair', 'version': '2.2.1'}]
available = [{'name': 'vm-repair', 'version': '2.2.2'}]
with mock.patch('azext_vm_repair.repair_utils.logger') as mock_logger:
self._run(installed, available)
mock_logger.warning.assert_called_once()

def test_up_to_date_does_not_warn(self):
installed = [{'name': 'vm-repair', 'version': '2.2.2'}]
available = [{'name': 'vm-repair', 'version': '2.2.2'}]
with mock.patch('azext_vm_repair.repair_utils.logger') as mock_logger:
self._run(installed, available)
mock_logger.warning.assert_not_called()


if __name__ == '__main__':
unittest.main()
2 changes: 1 addition & 1 deletion src/vm-repair/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from codecs import open
from setuptools import setup, find_packages

VERSION = "2.2.1"
VERSION = "2.2.3"

CLASSIFIERS = [
'Development Status :: 4 - Beta',
Expand Down
Loading