We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Certifi python module missing when deploying cloudtrail lambda functions
The following error happens when the lambda function is triggered

`[ERROR] Runtime.ImportModuleError: Unable to import module 'custodian_policy': No module named 'certifi'`

As a workaround, I had to add the *certifi* package to the policy files.

```
policies:
  - name: my-policy
    description: my description
    resource: my-resource
    mode:
      type: cloudtrail
      packages:
        - botocore
        - boto3
        - urllib3
        - certifi
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `c7n/actions/webhook.py`
Content:
```
1 # Copyright 2019 Microsoft Corporation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import json
16 
17 import certifi
18 import jmespath
19 import urllib3
20 from six.moves.urllib import parse
21 
22 from c7n import utils
23 from .core import EventAction
24 
25 
26 class Webhook(EventAction):
27     """Calls a webhook with optional parameters and body
28        populated from JMESPath queries.
29 
30         .. code-block:: yaml
31 
32           policies:
33             - name: call-webhook
34               resource: ec2
35               description: |
36                 Call webhook with list of resource groups
37               actions:
38                - type: webhook
39                  url: http://foo.com
40                  query-params:
41                     resource_name: resource.name
42                     policy_name: policy.name
43     """
44 
45     schema_alias = True
46     schema = utils.type_schema(
47         'webhook',
48         required=['url'],
49         **{
50             'url': {'type': 'string'},
51             'body': {'type': 'string'},
52             'batch': {'type': 'boolean'},
53             'batch-size': {'type': 'number'},
54             'method': {'type': 'string', 'enum': ['PUT', 'POST', 'GET', 'PATCH', 'DELETE']},
55             'query-params': {
56                 "type": "object",
57                 "additionalProperties": {
58                     "type": "string",
59                     "description": "query string values"
60                 }
61             },
62             'headers': {
63                 "type": "object",
64                 "additionalProperties": {
65                     "type": "string",
66                     "description": "header values"
67                 }
68             }
69         }
70     )
71 
72     def __init__(self, data=None, manager=None, log_dir=None):
73         super(Webhook, self).__init__(data, manager, log_dir)
74         self.http = None
75         self.url = self.data.get('url')
76         self.body = self.data.get('body')
77         self.batch = self.data.get('batch', False)
78         self.batch_size = self.data.get('batch-size', 500)
79         self.query_params = self.data.get('query-params', {})
80         self.headers = self.data.get('headers', {})
81         self.method = self.data.get('method', 'POST')
82         self.lookup_data = {
83             'account_id': self.manager.config.account_id,
84             'region': self.manager.config.region,
85             'execution_id': self.manager.ctx.execution_id,
86             'execution_start': self.manager.ctx.start_time,
87             'policy': self.manager.data
88         }
89 
90     def process(self, resources, event=None):
91         self.http = urllib3.PoolManager(
92             cert_reqs='CERT_REQUIRED',
93             ca_certs=certifi.where())
94 
95         if self.batch:
96             for chunk in utils.chunks(resources, self.batch_size):
97                 resource_data = self.lookup_data
98                 resource_data['resources'] = chunk
99                 self._process_call(resource_data)
100         else:
101             for r in resources:
102                 resource_data = self.lookup_data
103                 resource_data['resource'] = r
104                 self._process_call(resource_data)
105 
106     def _process_call(self, resource):
107         prepared_url = self._build_url(resource)
108         prepared_body = self._build_body(resource)
109         prepared_headers = self._build_headers(resource)
110 
111         if prepared_body:
112             prepared_headers['Content-Type'] = 'application/json'
113 
114         try:
115             res = self.http.request(
116                 method=self.method,
117                 url=prepared_url,
118                 body=prepared_body,
119                 headers=prepared_headers)
120 
121             self.log.info("%s got response %s with URL %s" %
122                           (self.method, res.status, prepared_url))
123         except urllib3.exceptions.HTTPError as e:
124             self.log.error("Error calling %s. Code: %s" % (prepared_url, e.reason))
125 
126     def _build_headers(self, resource):
127         return {k: jmespath.search(v, resource) for k, v in self.headers.items()}
128 
129     def _build_url(self, resource):
130         """
131         Compose URL with query string parameters.
132 
133         Will not lose existing static parameters in the URL string
134         but does not support 'duplicate' parameter entries
135         """
136 
137         if not self.query_params:
138             return self.url
139 
140         evaluated_params = {k: jmespath.search(v, resource) for k, v in self.query_params.items()}
141 
142         url_parts = list(parse.urlparse(self.url))
143         query = dict(parse.parse_qsl(url_parts[4]))
144         query.update(evaluated_params)
145         url_parts[4] = parse.urlencode(query)
146 
147         return parse.urlunparse(url_parts)
148 
149     def _build_body(self, resource):
150         """Create a JSON body and dump it to encoded bytes."""
151 
152         if not self.body:
153             return None
154 
155         return json.dumps(jmespath.search(self.body, resource)).encode('utf-8')
156
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/c7n/actions/webhook.py b/c7n/actions/webhook.py
--- a/c7n/actions/webhook.py
+++ b/c7n/actions/webhook.py
@@ -14,7 +14,11 @@
 
 import json
 
-import certifi
+try:
+    import certifi
+except ImportError:
+    certifi = None
+
 import jmespath
 import urllib3
 from six.moves.urllib import parse
@@ -90,7 +94,7 @@
     def process(self, resources, event=None):
         self.http = urllib3.PoolManager(
             cert_reqs='CERT_REQUIRED',
-            ca_certs=certifi.where())
+            ca_certs=certifi and certifi.where() or None)
 
         if self.batch:
             for chunk in utils.chunks(resources, self.batch_size):

{"golden_diff": "diff --git a/c7n/actions/webhook.py b/c7n/actions/webhook.py\n--- a/c7n/actions/webhook.py\n+++ b/c7n/actions/webhook.py\n@@ -14,7 +14,11 @@\n \n import json\n \n-import certifi\n+try:\n+    import certifi\n+except ImportError:\n+    certifi = None\n+\n import jmespath\n import urllib3\n from six.moves.urllib import parse\n@@ -90,7 +94,7 @@\n     def process(self, resources, event=None):\n         self.http = urllib3.PoolManager(\n             cert_reqs='CERT_REQUIRED',\n-            ca_certs=certifi.where())\n+            ca_certs=certifi and certifi.where() or None)\n \n         if self.batch:\n             for chunk in utils.chunks(resources, self.batch_size):\n", "issue": "Certifi python module missing when deploying cloudtrail lambda functions\nThe following error happens when the lambda function is triggered\r\n\r\n`[ERROR] Runtime.ImportModuleError: Unable to import module 'custodian_policy': No module named 'certifi'`\r\n\r\nAs a workaround, I had to add the *certifi* package to the policy files.\r\n\r\n```\r\npolicies:\r\n  - name: my-policy\r\n    description: my description\r\n    resource: my-resource\r\n    mode:\r\n      type: cloudtrail\r\n      packages:\r\n        - botocore\r\n        - boto3\r\n        - urllib3\r\n        - certifi\r\n```\n", "before_files": [{"content": "# Copyright 2019 Microsoft Corporation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\n\nimport certifi\nimport jmespath\nimport urllib3\nfrom six.moves.urllib import parse\n\nfrom c7n import utils\nfrom .core import EventAction\n\n\nclass Webhook(EventAction):\n    \"\"\"Calls a webhook with optional parameters and body\n       populated from JMESPath queries.\n\n        .. code-block:: yaml\n\n          policies:\n            - name: call-webhook\n              resource: ec2\n              description: |\n                Call webhook with list of resource groups\n              actions:\n               - type: webhook\n                 url: http://foo.com\n                 query-params:\n                    resource_name: resource.name\n                    policy_name: policy.name\n    \"\"\"\n\n    schema_alias = True\n    schema = utils.type_schema(\n        'webhook',\n        required=['url'],\n        **{\n            'url': {'type': 'string'},\n            'body': {'type': 'string'},\n            'batch': {'type': 'boolean'},\n            'batch-size': {'type': 'number'},\n            'method': {'type': 'string', 'enum': ['PUT', 'POST', 'GET', 'PATCH', 'DELETE']},\n            'query-params': {\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                    \"type\": \"string\",\n                    \"description\": \"query string values\"\n                }\n            },\n            'headers': {\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                    \"type\": \"string\",\n                    \"description\": \"header values\"\n                }\n            }\n        }\n    )\n\n    def __init__(self, data=None, manager=None, log_dir=None):\n        super(Webhook, self).__init__(data, manager, log_dir)\n        self.http = None\n        self.url = self.data.get('url')\n        self.body = self.data.get('body')\n        self.batch = self.data.get('batch', False)\n        self.batch_size = self.data.get('batch-size', 500)\n        self.query_params = self.data.get('query-params', {})\n        self.headers = self.data.get('headers', {})\n        self.method = self.data.get('method', 'POST')\n        self.lookup_data = {\n            'account_id': self.manager.config.account_id,\n            'region': self.manager.config.region,\n            'execution_id': self.manager.ctx.execution_id,\n            'execution_start': self.manager.ctx.start_time,\n            'policy': self.manager.data\n        }\n\n    def process(self, resources, event=None):\n        self.http = urllib3.PoolManager(\n            cert_reqs='CERT_REQUIRED',\n            ca_certs=certifi.where())\n\n        if self.batch:\n            for chunk in utils.chunks(resources, self.batch_size):\n                resource_data = self.lookup_data\n                resource_data['resources'] = chunk\n                self._process_call(resource_data)\n        else:\n            for r in resources:\n                resource_data = self.lookup_data\n                resource_data['resource'] = r\n                self._process_call(resource_data)\n\n    def _process_call(self, resource):\n        prepared_url = self._build_url(resource)\n        prepared_body = self._build_body(resource)\n        prepared_headers = self._build_headers(resource)\n\n        if prepared_body:\n            prepared_headers['Content-Type'] = 'application/json'\n\n        try:\n            res = self.http.request(\n                method=self.method,\n                url=prepared_url,\n                body=prepared_body,\n                headers=prepared_headers)\n\n            self.log.info(\"%s got response %s with URL %s\" %\n                          (self.method, res.status, prepared_url))\n        except urllib3.exceptions.HTTPError as e:\n            self.log.error(\"Error calling %s. Code: %s\" % (prepared_url, e.reason))\n\n    def _build_headers(self, resource):\n        return {k: jmespath.search(v, resource) for k, v in self.headers.items()}\n\n    def _build_url(self, resource):\n        \"\"\"\n        Compose URL with query string parameters.\n\n        Will not lose existing static parameters in the URL string\n        but does not support 'duplicate' parameter entries\n        \"\"\"\n\n        if not self.query_params:\n            return self.url\n\n        evaluated_params = {k: jmespath.search(v, resource) for k, v in self.query_params.items()}\n\n        url_parts = list(parse.urlparse(self.url))\n        query = dict(parse.parse_qsl(url_parts[4]))\n        query.update(evaluated_params)\n        url_parts[4] = parse.urlencode(query)\n\n        return parse.urlunparse(url_parts)\n\n    def _build_body(self, resource):\n        \"\"\"Create a JSON body and dump it to encoded bytes.\"\"\"\n\n        if not self.body:\n            return None\n\n        return json.dumps(jmespath.search(self.body, resource)).encode('utf-8')\n", "path": "c7n/actions/webhook.py"}], "after_files": [{"content": "# Copyright 2019 Microsoft Corporation\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport json\n\ntry:\n    import certifi\nexcept ImportError:\n    certifi = None\n\nimport jmespath\nimport urllib3\nfrom six.moves.urllib import parse\n\nfrom c7n import utils\nfrom .core import EventAction\n\n\nclass Webhook(EventAction):\n    \"\"\"Calls a webhook with optional parameters and body\n       populated from JMESPath queries.\n\n        .. code-block:: yaml\n\n          policies:\n            - name: call-webhook\n              resource: ec2\n              description: |\n                Call webhook with list of resource groups\n              actions:\n               - type: webhook\n                 url: http://foo.com\n                 query-params:\n                    resource_name: resource.name\n                    policy_name: policy.name\n    \"\"\"\n\n    schema_alias = True\n    schema = utils.type_schema(\n        'webhook',\n        required=['url'],\n        **{\n            'url': {'type': 'string'},\n            'body': {'type': 'string'},\n            'batch': {'type': 'boolean'},\n            'batch-size': {'type': 'number'},\n            'method': {'type': 'string', 'enum': ['PUT', 'POST', 'GET', 'PATCH', 'DELETE']},\n            'query-params': {\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                    \"type\": \"string\",\n                    \"description\": \"query string values\"\n                }\n            },\n            'headers': {\n                \"type\": \"object\",\n                \"additionalProperties\": {\n                    \"type\": \"string\",\n                    \"description\": \"header values\"\n                }\n            }\n        }\n    )\n\n    def __init__(self, data=None, manager=None, log_dir=None):\n        super(Webhook, self).__init__(data, manager, log_dir)\n        self.http = None\n        self.url = self.data.get('url')\n        self.body = self.data.get('body')\n        self.batch = self.data.get('batch', False)\n        self.batch_size = self.data.get('batch-size', 500)\n        self.query_params = self.data.get('query-params', {})\n        self.headers = self.data.get('headers', {})\n        self.method = self.data.get('method', 'POST')\n        self.lookup_data = {\n            'account_id': self.manager.config.account_id,\n            'region': self.manager.config.region,\n            'execution_id': self.manager.ctx.execution_id,\n            'execution_start': self.manager.ctx.start_time,\n            'policy': self.manager.data\n        }\n\n    def process(self, resources, event=None):\n        self.http = urllib3.PoolManager(\n            cert_reqs='CERT_REQUIRED',\n            ca_certs=certifi and certifi.where() or None)\n\n        if self.batch:\n            for chunk in utils.chunks(resources, self.batch_size):\n                resource_data = self.lookup_data\n                resource_data['resources'] = chunk\n                self._process_call(resource_data)\n        else:\n            for r in resources:\n                resource_data = self.lookup_data\n                resource_data['resource'] = r\n                self._process_call(resource_data)\n\n    def _process_call(self, resource):\n        prepared_url = self._build_url(resource)\n        prepared_body = self._build_body(resource)\n        prepared_headers = self._build_headers(resource)\n\n        if prepared_body:\n            prepared_headers['Content-Type'] = 'application/json'\n\n        try:\n            res = self.http.request(\n                method=self.method,\n                url=prepared_url,\n                body=prepared_body,\n                headers=prepared_headers)\n\n            self.log.info(\"%s got response %s with URL %s\" %\n                          (self.method, res.status, prepared_url))\n        except urllib3.exceptions.HTTPError as e:\n            self.log.error(\"Error calling %s. Code: %s\" % (prepared_url, e.reason))\n\n    def _build_headers(self, resource):\n        return {k: jmespath.search(v, resource) for k, v in self.headers.items()}\n\n    def _build_url(self, resource):\n        \"\"\"\n        Compose URL with query string parameters.\n\n        Will not lose existing static parameters in the URL string\n        but does not support 'duplicate' parameter entries\n        \"\"\"\n\n        if not self.query_params:\n            return self.url\n\n        evaluated_params = {k: jmespath.search(v, resource) for k, v in self.query_params.items()}\n\n        url_parts = list(parse.urlparse(self.url))\n        query = dict(parse.parse_qsl(url_parts[4]))\n        query.update(evaluated_params)\n        url_parts[4] = parse.urlencode(query)\n\n        return parse.urlunparse(url_parts)\n\n    def _build_body(self, resource):\n        \"\"\"Create a JSON body and dump it to encoded bytes.\"\"\"\n\n        if not self.body:\n            return None\n\n        return json.dumps(jmespath.search(self.body, resource)).encode('utf-8')\n", "path": "c7n/actions/webhook.py"}]}