Skip to content

Commit 7e9dd7e

Browse files
dtantsurjayofdoom
authored andcommitted
Warn when the provided checksum algorithm does not match the detected
I have a case where a user provided the checksum URL with SHA256 checksums, while Metal3 defaulted os_hash_algo to "md5". We're going to change the Metal3 defaults in the next API version, but for now let us issue a clear warning in such case. Closes-Bug: #2085331 Change-Id: Ie4e62a378dc4a2089944f4302df3a8671b7c960f (cherry picked from commit d8d32d9) (cherry picked from commit aa01777)
1 parent 349c9d3 commit 7e9dd7e

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

ironic_python_agent/extensions/standby.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,25 @@ def __init__(self, image_info, time_obj=None):
581581
self._expected_hash_value,
582582
image_info)
583583

584+
# NOTE(dtantsur): verify that the user's input does not obviously
585+
# contradict the actual value. It is especially easy to make such
586+
# a mistake when providing a checksum URL.
587+
if algo:
588+
try:
589+
detected_algo = _get_algorithm_by_length(
590+
self._expected_hash_value)
591+
except ValueError:
592+
pass # an exotic algorithm?
593+
else:
594+
if detected_algo.name != algo:
595+
LOG.warning("Provided checksum algorithm %(provided)s "
596+
"does not match the detected algorithm "
597+
"%(detected)s. It may be a sign of a user "
598+
"error when providing the algorithm or the "
599+
"checksum URL.",
600+
{'provided': algo,
601+
'detected': detected_algo.name})
602+
584603
details = []
585604
for url in image_info['urls']:
586605
try:

ironic_python_agent/tests/unit/extensions/test_standby.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -795,18 +795,21 @@ def test_verify_image_success_without_md5(self, requests_mock,
795795
image_download.verify_image(image_location)
796796
hashlib_mock.assert_called_with('sha512')
797797

798+
@mock.patch.object(standby.LOG, 'warning', autospec=True)
798799
@mock.patch('hashlib.new', autospec=True)
799800
@mock.patch('builtins.open', autospec=True)
800801
@mock.patch('requests.get', autospec=True)
801802
def test_verify_image_success_with_md5_fallback(self, requests_mock,
802-
open_mock, hash_mock):
803+
open_mock, hash_mock,
804+
warn_mock):
803805
CONF.set_override('md5_enabled', True)
804806
image_info = _build_fake_image_info()
805807
image_info['os_hash_algo'] = 'algo-beyond-milky-way'
806808
image_info['os_hash_value'] = 'mysterious-alien-codes'
807809
image_info['checksum'] = 'd41d8cd98f00b204e9800998ecf8427e'
808810
response = requests_mock.return_value
809811
response.status_code = 200
812+
hash_mock.return_value.name = 'md5'
810813
hexdigest_mock = hash_mock.return_value.hexdigest
811814
hexdigest_mock.return_value = image_info['checksum']
812815
image_location = '/foo/bar'
@@ -818,7 +821,11 @@ def test_verify_image_success_with_md5_fallback(self, requests_mock,
818821
hash_mock.assert_has_calls([
819822
mock.call('md5'),
820823
mock.call().__bool__(),
824+
mock.call('md5'),
821825
mock.call().hexdigest()])
826+
warn_mock.assert_called_once_with(
827+
mock.ANY,
828+
{'provided': 'algo-beyond-milky-way', 'detected': 'md5'})
822829

823830
@mock.patch('hashlib.new', autospec=True)
824831
@mock.patch('builtins.open', autospec=True)
@@ -1760,7 +1767,39 @@ def test_download_image_retries_success(self, sleep_mock, requests_mock,
17601767
sleep_mock.assert_called_with(10)
17611768
self.assertEqual(2, sleep_mock.call_count)
17621769

1763-
def test_download_image_and_checksum(self, requests_mock, hash_mock):
1770+
@mock.patch.object(standby.LOG, 'warning', autospec=True)
1771+
def test_download_image_and_checksum(self, warn_mock, requests_mock,
1772+
hash_mock):
1773+
content = ['SpongeBob', 'SquarePants']
1774+
fake_cs = "019fe036425da1c562f2e9f5299820bf"
1775+
cs_response = mock.Mock()
1776+
cs_response.status_code = 200
1777+
cs_response.text = fake_cs + '\n'
1778+
response = mock.Mock()
1779+
response.status_code = 200
1780+
response.iter_content.return_value = content
1781+
requests_mock.side_effect = [cs_response, response]
1782+
1783+
image_info = _build_fake_image_info()
1784+
image_info['os_hash_algo'] = 'sha512'
1785+
image_info['os_hash_value'] = 'http://example.com/checksum'
1786+
hash_mock.return_value.hexdigest.return_value = fake_cs
1787+
hash_mock.return_value.name = 'sha512'
1788+
image_download = standby.ImageDownload(image_info)
1789+
1790+
self.assertEqual(content, list(image_download))
1791+
requests_mock.assert_has_calls([
1792+
mock.call('http://example.com/checksum', cert=None, verify=True,
1793+
stream=True, proxies={}, timeout=60),
1794+
mock.call(image_info['urls'][0], cert=None, verify=True,
1795+
stream=True, proxies={}, timeout=60),
1796+
])
1797+
self.assertEqual(fake_cs, image_download._hash_algo.hexdigest())
1798+
warn_mock.assert_not_called()
1799+
1800+
@mock.patch.object(standby.LOG, 'warning', autospec=True)
1801+
def test_download_image_and_checksum_warning_on_mismatch(
1802+
self, warn_mock, requests_mock, hash_mock):
17641803
content = ['SpongeBob', 'SquarePants']
17651804
fake_cs = "019fe036425da1c562f2e9f5299820bf"
17661805
cs_response = mock.Mock()
@@ -1775,6 +1814,7 @@ def test_download_image_and_checksum(self, requests_mock, hash_mock):
17751814
image_info['os_hash_algo'] = 'sha512'
17761815
image_info['os_hash_value'] = 'http://example.com/checksum'
17771816
hash_mock.return_value.hexdigest.return_value = fake_cs
1817+
hash_mock.return_value.name = 'md5'
17781818
image_download = standby.ImageDownload(image_info)
17791819

17801820
self.assertEqual(content, list(image_download))
@@ -1785,6 +1825,9 @@ def test_download_image_and_checksum(self, requests_mock, hash_mock):
17851825
stream=True, proxies={}, timeout=60),
17861826
])
17871827
self.assertEqual(fake_cs, image_download._hash_algo.hexdigest())
1828+
warn_mock.assert_called_once_with(
1829+
mock.ANY,
1830+
{'provided': 'sha512', 'detected': 'md5'})
17881831

17891832
def test_download_image_and_checksum_md5(self, requests_mock, hash_mock):
17901833

0 commit comments

Comments
 (0)