diff --git a/docs/changes.rst b/docs/changes.rst index 57277390..7fb71c83 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -84,6 +84,9 @@ will also work with the prior version of the file (but not vice versa). * Increased versions of GitHub Actions plugins to increase node.js runtime to version 20. +* Disabled the use of Python builtins in the evaluation of 'fetch-condition' and + 'export-condition' in the metric definition file. (issue #463) + **Known issues:** * See `list of open issues`_. diff --git a/docs/usage.rst b/docs/usage.rst index 597143a0..b48c9a7f 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -929,7 +929,7 @@ Where: * ``{fetch-condition}`` is a string that is evaluated as a Python expression and that indicates whether the metric group can be fetched. For the metric group to actually be fetched, the ``fetch`` property also needs to be True. - The expression may use the following variables: + The expression may use the following variables; builtins are not available: - ``hmc_version`` - HMC version as a tuple of integers (M, N, U), e.g. (2, 16, 0). @@ -947,7 +947,7 @@ Where: * ``{export-condition}`` is a string that is evaluated as a Python expression and that controls whether the metric is exported. If it evaluates to false, the export of the metric is disabled, regardless of other such controls. - The expression may use the following variables: + The expression may use the following variables; builtins are not available: - ``hmc_version`` - HMC version as a tuple of integers (M, N, U), e.g. (2, 16, 0). diff --git a/tests/test_all.py b/tests/test_all.py index c8db503f..083c1878 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -16,6 +16,7 @@ """Unit tests for the zhmc_prometheus_exporter""" +import re import time import datetime import hashlib @@ -225,6 +226,47 @@ def test_eval_condition_resource(): assert result == 'cpc_1' +TESTCASES_EVAL_CONDITION_ERROR = [ + # (condition, warn_msg_pattern) + ('dir()', "NameError: name 'dir' is not defined"), + ('builtins.dir()', "NameError: name 'builtins' is not defined"), + ('__builtins__["dir"]', "KeyError: 'dir'"), +] + + +@pytest.mark.parametrize( + "condition, warn_msg_pattern", + TESTCASES_EVAL_CONDITION_ERROR +) +def test_eval_condition_error(condition, warn_msg_pattern): + """ + Tests eval_condition() with evaluation errors. + """ + session = setup_faked_session() + client = zhmcclient.Client(session) + cpc = client.cpcs.find(name='cpc_1') + + # Arbitrary values for these variables, since we are not testing that here: + hmc_version = '2.16.0' + hmc_api_version = (4, 10) + hmc_features = [] + se_version = '2.15.0' + se_features = [] + resource_obj = cpc + + with pytest.warns(UserWarning) as warn_records: + + # The code to be tested + zhmc_prometheus_exporter.eval_condition( + condition, hmc_version, hmc_api_version, hmc_features, se_version, + se_features, resource_obj) + + # Evaluation errors surface as one UserWarning + assert len(warn_records) == 1 + warn_record = warn_records[0] + assert re.search(warn_msg_pattern, str(warn_record.message)) + + # Fake HMC derived from # github.com/zhmcclient/python-zhmcclient/zhmcclient_mock/_hmc.py class TestCreateContext(unittest.TestCase): diff --git a/zhmc_prometheus_exporter/zhmc_prometheus_exporter.py b/zhmc_prometheus_exporter/zhmc_prometheus_exporter.py index fe46ed41..bb9ec555 100755 --- a/zhmc_prometheus_exporter/zhmc_prometheus_exporter.py +++ b/zhmc_prometheus_exporter/zhmc_prometheus_exporter.py @@ -560,6 +560,7 @@ def eval_condition( # The variables that can be used in the expression eval_vars = dict( + __builtins__={}, hmc_version=hmc_version, hmc_api_version=hmc_api_version, hmc_features=hmc_features, @@ -583,7 +584,7 @@ def eval_condition( try: # pylint: disable=eval-used - result = eval(condition, None, eval_vars) + result = eval(condition, eval_vars, None) except Exception as exc: # pylint: disable=broad-exception-caught warnings.warn("Ignoring item because its condition {!r} does not " "properly evaluate: {}: {}".