Repository: dmwm/wmcore
Issue: Validate workflow run lists (RunWhitelist and RunBlacklist)

**Impact of the bug**
ReqMgr2

**Describe the bug**
As reported by the P&R in this GitLab ticket:
https://gitlab.cern.ch/CMSToolsIntegration/operations/-/issues/9#note_6390478

ReqMgr2 does not validate the data type for the request level parameters: `RunWhitelist` and `RunBlacklist`, which can be either at top level or at the task/step level as well.

**How to reproduce it**
Inject a workflow providing a list of runs with the format of `["123"]` instead of `[123]`

**Expected behavior**
The run list must be a list of integer values. So, we need to ensure that parameters RunWhitelist and RunBlacklist are properly validated before a workflow gets accepted by ReqMgr2.

This needs to be considered for all workflow types used in production (ReReco, TaskChain and StepChain).

**Additional context and error message**
None


Changed files:
test/python/WMCore_t/WMSpec_t/StdSpecs_t/TaskChain_t.py, src/python/WMCore/WMSpec/StdSpecs/DataProcessing.py, test/python/WMCore_t/WMSpec_t/StdSpecs_t/StepChain_t.py, test/python/WMCore_t/WMSpec_t/StdSpecs_t/StdBase_t.py, test/python/WMCore_t/ReqMgr_t/Utils_t/Validation_t.py, src/python/WMCore/WMSpec/StdSpecs/StdBase.py

diff --git a/src/python/WMCore/WMSpec/StdSpecs/DataProcessing.py b/src/python/WMCore/WMSpec/StdSpecs/DataProcessing.py
index 9ecf7e34f..e12a6fc85 100644
--- a/src/python/WMCore/WMSpec/StdSpecs/DataProcessing.py
+++ b/src/python/WMCore/WMSpec/StdSpecs/DataProcessing.py
@@ -46,9 +46,9 @@ class DataProcessing(StdBase):
                     "PrimaryDataset": {"optional": True, "validate": primdataset,
                                        "attr": "inputPrimaryDataset", "null": True},
                     "RunBlacklist": {"default": [], "type": makeList, "null": False,
-                                     "validate": lambda x: all([int(y) > 0 for y in x])},
+                                     "validate": lambda x: all([isinstance(y, int) and int(y) > 0 for y in x])},
                     "RunWhitelist": {"default": [], "type": makeList, "null": False,
-                                     "validate": lambda x: all([int(y) > 0 for y in x])},
+                                     "validate": lambda x: all([isinstance(y, int) and int(y) > 0 for y in x])},
                     "BlockBlacklist": {"default": [], "type": makeList,
                                        "validate": lambda x: all([block(y) for y in x])},
                     "BlockWhitelist": {"default": [], "type": makeList,
diff --git a/src/python/WMCore/WMSpec/StdSpecs/StdBase.py b/src/python/WMCore/WMSpec/StdSpecs/StdBase.py
index 2f8e44f53..d67557c96 100644
--- a/src/python/WMCore/WMSpec/StdSpecs/StdBase.py
+++ b/src/python/WMCore/WMSpec/StdSpecs/StdBase.py
@@ -1232,9 +1232,9 @@ class StdBase(object):
                      'RequestNumEvents': {'null': False, 'optional': not generator, 'type': int,
                                           'validate': lambda x: x > 0},
                      'RunBlacklist': {'default': [], 'null': False, 'optional': True, 'type': makeList,
-                                      'validate': lambda x: all([int(y) > 0 for y in x])},
+                                      'validate': lambda x: all([isinstance(y, int) and int(y) > 0 for y in x])},
                      'RunWhitelist': {'default': [], 'null': False, 'optional': True, 'type': makeList,
-                                      'validate': lambda x: all([int(y) > 0 for y in x])},
+                                      'validate': lambda x: all([isinstance(y, int) and int(y) > 0 for y in x])},
                      'ScramArch': {'null': True, 'optional': True, 'type': makeNonEmptyList,
                                    'validate': lambda x: all([y in architectures() for y in x])},
                      'Seeding': {'default': 'AutomaticSeeding', 'null': False, 'optional': True, 'type': str,
diff --git a/test/python/WMCore_t/ReqMgr_t/Utils_t/Validation_t.py b/test/python/WMCore_t/ReqMgr_t/Utils_t/Validation_t.py
index 32e3b8b8e..b147041a0 100644
--- a/test/python/WMCore_t/ReqMgr_t/Utils_t/Validation_t.py
+++ b/test/python/WMCore_t/ReqMgr_t/Utils_t/Validation_t.py
@@ -8,7 +8,8 @@ from __future__ import division, print_function
 import unittest
 
 from WMCore.ReqMgr.DataStructs.RequestError import InvalidSpecParameterValue
-from WMCore.ReqMgr.Utils.Validation import validateOutputDatasets, validate_request_priority
+from WMCore.ReqMgr.Utils.Validation import (validateOutputDatasets,
+                                            validate_request_priority)
 
 
 class ValidationTests(unittest.TestCase):
diff --git a/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StdBase_t.py b/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StdBase_t.py
index a1b9a9478..70d0c18c7 100644
--- a/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StdBase_t.py
+++ b/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StdBase_t.py
@@ -52,6 +52,20 @@ class StdBaseTest(unittest.TestCase):
         stdBaseInstance.factoryWorkloadConstruction("TestWorkload", arguments)
         return
 
+    def testRunlist(self):
+        """
+        _testStdBaseValidation_
+
+        Check that the properly setup run white/black lists
+        """
+        arguments = StdBase.getTestArguments()
+        for k in sorted(arguments.keys()):
+            print(k, arguments[k])
+        arguments['RunWhiteList'] = ["111111", "222222"]
+        stdBaseInstance = StdBase()
+        with self.assertRaises(WMSpecFactoryException):
+            stdBaseInstance.factoryWorkloadConstruction("TestWorkload", arguments)
+
     def testCalcEvtsPerJobLumi(self):
         """
         _testCalcEvtsPerJobLumi_
diff --git a/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StepChain_t.py b/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StepChain_t.py
index a018b92d6..aed5bd55a 100644
--- a/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StepChain_t.py
+++ b/test/python/WMCore_t/WMSpec_t/StdSpecs_t/StepChain_t.py
@@ -2408,6 +2408,16 @@ class StepChainTests(EmulatedUnitTestCase):
         testWorkload = factory.factoryWorkloadConstruction("TestWorkload", testArguments)
         self.assertEqual(testWorkload.startPolicyParameters()['policyName'], "MonteCarlo")
 
+    def testRunlist(self):
+        """
+        Check that the properly setup run white/black lists
+        """
+        arguments = StepChainWorkloadFactory.getTestArguments()
+        arguments['Step1']['RunWhiteList'] = ["111111", "222222"]
+        factory = StepChainWorkloadFactory()
+        with self.assertRaises(WMSpecFactoryException):
+            factory.factoryWorkloadConstruction("TestWorkload", arguments)
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/test/python/WMCore_t/WMSpec_t/StdSpecs_t/TaskChain_t.py b/test/python/WMCore_t/WMSpec_t/StdSpecs_t/TaskChain_t.py
index 592af160f..2c8fe7e50 100644
--- a/test/python/WMCore_t/WMSpec_t/StdSpecs_t/TaskChain_t.py
+++ b/test/python/WMCore_t/WMSpec_t/StdSpecs_t/TaskChain_t.py
@@ -2480,6 +2480,16 @@ class TaskChainTests(EmulatedUnitTestCase):
         testWorkload = factory.factoryWorkloadConstruction("PullingTheChain", arguments)
         self.assertEqual(testWorkload.startPolicyParameters()['policyName'], "MonteCarlo")
 
+    def testRunlist(self):
+        """
+        Check that the properly setup run white/black lists
+        """
+        arguments = TaskChainWorkloadFactory.getTestArguments()
+        arguments['Task1']['RunWhiteList'] = ["111111", "222222"]
+        factory = TaskChainWorkloadFactory()
+        with self.assertRaises(WMSpecFactoryException):
+            factory.factoryWorkloadConstruction("PullingTheChain", arguments)
+
 
 if __name__ == '__main__':
     unittest.main()