From 10a08e31136fb309932725fa0a7ba429fe485f65 Mon Sep 17 00:00:00 2001 From: Tomas Kopecek Date: Feb 01 2021 14:36:30 +0000 Subject: PR#2651: make policy test thread safe Merges #2651 https://pagure.io/koji/pull-request/2651 Fixes: #2650 https://pagure.io/koji/issue/2650 policy test is not thread safe --- diff --git a/hub/kojihub.py b/hub/kojihub.py index bb9907d..a7efcd5 100644 --- a/hub/kojihub.py +++ b/hub/kojihub.py @@ -9745,22 +9745,25 @@ class PolicyTest(koji.policy.BaseSimpleTest): def __init__(self, str): super(PolicyTest, self).__init__(str) - self.depth = 0 - # this is used to detect loops. Note that each test in a ruleset is - # a distinct instance of its test class. So this value is particular - # to a given appearance of a policy check in a ruleset. def run(self, data): args = self.str.split()[1:] - if self.depth != 0: + # we store some instance-specific state in context for loop detection + # note that context is thread local and cleared after each call + # note that this instance represents a specific test in the policy + # i.e. each occurrence of 'policy foo' is a separate instance + key = 'policy_test_state_%s_running' % id(self) + if hasattr(context, key): # LOOP! raise koji.GenericError("encountered policy loop at %s" % self.str) ruleset = context.policy.get(args[0]) if not ruleset: raise koji.GenericError("no such policy: %s" % args[0]) - self.depth += 1 - result = ruleset.apply(data) - self.depth -= 1 + setattr(context, key, True) + try: + result = ruleset.apply(data) + finally: + delattr(context, key) if result is None: return False else: