We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bulk query API
A bulk query API would allow developers to more easily query the API without hitting rate limits. It would also help with scenarios like #257, where an SBOM will contain many dependencies.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `docs/build.py`
Content:
```
1 # Copyright 2021 Google LLC
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 """Documentation builder."""
15 
16 import json
17 import os
18 import shutil
19 import subprocess
20 
21 _ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
22 _GENERATED_FILENAME = 'v1/osv_service_v1.swagger.json'
23 
24 
25 def property_description_workaround(definition):
26   """Work around an OpenAPI limitation with a field descriptions getting
27   replaced by the object descriptions."""
28   # Workaround described in https://github.com/Redocly/redoc/issues/835.
29   for value in definition['properties'].values():
30     if '$ref' in value:
31       value['allOf'] = [{'$ref': value['$ref']}]
32       del value['$ref']
33 
34 
35 def replace_property_name(definition, key, replacement):
36   """Replace property name."""
37   definition['properties'][replacement] = definition['properties'][key]
38   del definition['properties'][key]
39 
40 
41 def main():
42   api_dir = os.path.join(_ROOT_DIR, 'gcp', 'api')
43   v1_api_dir = os.path.join(api_dir, 'v1')
44   googleapis_dir = os.path.join(api_dir, 'googleapis')
45   service_proto_path = os.path.join(v1_api_dir, 'osv_service_v1.proto')
46 
47   # Add OSV dependencies.
48   osv_path = os.path.join(api_dir, 'osv')
49   if os.path.exists(osv_path):
50     shutil.rmtree(osv_path)
51 
52   shutil.copytree(os.path.join(_ROOT_DIR, 'lib', 'osv'), osv_path)
53 
54   subprocess.run([
55       'protoc',
56       '-I',
57       api_dir,
58       '-I',
59       v1_api_dir,
60       '-I',
61       googleapis_dir,
62       '--openapiv2_out',
63       '.',
64       '--openapiv2_opt',
65       'logtostderr=true',
66       service_proto_path,
67   ],
68                  check=True)
69 
70   with open(_GENERATED_FILENAME) as f:
71     spec = json.load(f)
72 
73   spec['host'] = 'api.osv.dev'
74   spec['info']['title'] = 'OSV'
75   spec['info']['version'] = '1.0'
76   spec['tags'] = [{
77       'name': 'api',
78       'x-displayName': 'API',
79       'description': 'The API has 2 methods:'
80   }, {
81       'name': 'vulnerability_schema',
82       'x-displayName': 'Vulnerability schema',
83       'description': 'Please see the [OpenSSF Open Source Vulnerability spec]'
84                      '(https://ossf.github.io/osv-schema/).',
85   }]
86 
87   spec['x-tagGroups'] = [{
88       'name': 'API',
89       'tags': ['api']
90   }, {
91       'name': 'Schema',
92       'tags': ['vulnerability_schema']
93   }]
94 
95   spec['paths']['/v1/query']['post']['tags'] = ['api']
96   spec['paths']['/v1/vulns/{id}']['get']['tags'] = ['api']
97 
98   spec['paths']['/v1/query']['post']['x-code-samples'] = [{
99       'lang':
100           'Curl example',
101       'source':
102           ('curl -X POST -d \\\n'
103            '  \'{"commit": "6879efc2c1596d11a6a6ad296f80063b558d5e0f"}\' \\\n'
104            '  "https://api.osv.dev/v1/query"\n\n'
105            'curl -X POST -d \\\n'
106            '  \'{"package": {"name": "mruby"}, "version": "2.1.2rc"}\' \\\n'
107            '  "https://api.osv.dev/v1/query"')
108   }]
109 
110   spec['paths']['/v1/vulns/{id}']['get']['x-code-samples'] = [{
111       'lang': 'Curl example',
112       'source': 'curl "https://api.osv.dev/v1/vulns/OSV-2020-111"'
113   }]
114 
115   property_description_workaround(spec['definitions']['v1Query'])
116   property_description_workaround(spec['definitions']['osvVulnerability'])
117 
118   replace_property_name(spec['definitions']['osvVulnerability'],
119                         'databaseSpecific', 'database_specific')
120 
121   with open('sections.md') as f:
122     spec['info']['description'] = f.read()
123 
124   with open(_GENERATED_FILENAME, 'w') as f:
125     f.write(json.dumps(spec, indent=2))
126 
127   shutil.move(_GENERATED_FILENAME, os.path.basename(_GENERATED_FILENAME))
128 
129 
130 if __name__ == '__main__':
131   main()
132
```

Path: `gcp/api/osv_service_v1_pb2_grpc.py`
Content:
```
1 # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2 """Client and server classes corresponding to protobuf-defined services."""
3 import grpc
4 
5 from osv import vulnerability_pb2 as osv_dot_vulnerability__pb2
6 import osv_service_v1_pb2 as osv__service__v1__pb2
7 
8 
9 class OSVStub(object):
10     """Open source vulnerability database.
11     """
12 
13     def __init__(self, channel):
14         """Constructor.
15 
16         Args:
17             channel: A grpc.Channel.
18         """
19         self.GetVulnById = channel.unary_unary(
20                 '/osv.v1.OSV/GetVulnById',
21                 request_serializer=osv__service__v1__pb2.GetVulnByIdParameters.SerializeToString,
22                 response_deserializer=osv_dot_vulnerability__pb2.Vulnerability.FromString,
23                 )
24         self.QueryAffected = channel.unary_unary(
25                 '/osv.v1.OSV/QueryAffected',
26                 request_serializer=osv__service__v1__pb2.QueryAffectedParameters.SerializeToString,
27                 response_deserializer=osv__service__v1__pb2.VulnerabilityList.FromString,
28                 )
29         self.QueryAffectedBatch = channel.unary_unary(
30                 '/osv.v1.OSV/QueryAffectedBatch',
31                 request_serializer=osv__service__v1__pb2.QueryAffectedBatchParameters.SerializeToString,
32                 response_deserializer=osv__service__v1__pb2.BatchVulnerabilityList.FromString,
33                 )
34 
35 
36 class OSVServicer(object):
37     """Open source vulnerability database.
38     """
39 
40     def GetVulnById(self, request, context):
41         """Return a `Vulnerability` object for a given OSV ID.
42         """
43         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
44         context.set_details('Method not implemented!')
45         raise NotImplementedError('Method not implemented!')
46 
47     def QueryAffected(self, request, context):
48         """Query vulnerabilities for a particular project at a given commit or
49         version.
50         """
51         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
52         context.set_details('Method not implemented!')
53         raise NotImplementedError('Method not implemented!')
54 
55     def QueryAffectedBatch(self, request, context):
56         """Query vulnerabilities for a particular project at given commits and
57         versions.
58         """
59         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
60         context.set_details('Method not implemented!')
61         raise NotImplementedError('Method not implemented!')
62 
63 
64 def add_OSVServicer_to_server(servicer, server):
65     rpc_method_handlers = {
66             'GetVulnById': grpc.unary_unary_rpc_method_handler(
67                     servicer.GetVulnById,
68                     request_deserializer=osv__service__v1__pb2.GetVulnByIdParameters.FromString,
69                     response_serializer=osv_dot_vulnerability__pb2.Vulnerability.SerializeToString,
70             ),
71             'QueryAffected': grpc.unary_unary_rpc_method_handler(
72                     servicer.QueryAffected,
73                     request_deserializer=osv__service__v1__pb2.QueryAffectedParameters.FromString,
74                     response_serializer=osv__service__v1__pb2.VulnerabilityList.SerializeToString,
75             ),
76             'QueryAffectedBatch': grpc.unary_unary_rpc_method_handler(
77                     servicer.QueryAffectedBatch,
78                     request_deserializer=osv__service__v1__pb2.QueryAffectedBatchParameters.FromString,
79                     response_serializer=osv__service__v1__pb2.BatchVulnerabilityList.SerializeToString,
80             ),
81     }
82     generic_handler = grpc.method_handlers_generic_handler(
83             'osv.v1.OSV', rpc_method_handlers)
84     server.add_generic_rpc_handlers((generic_handler,))
85 
86 
87  # This class is part of an EXPERIMENTAL API.
88 class OSV(object):
89     """Open source vulnerability database.
90     """
91 
92     @staticmethod
93     def GetVulnById(request,
94             target,
95             options=(),
96             channel_credentials=None,
97             call_credentials=None,
98             insecure=False,
99             compression=None,
100             wait_for_ready=None,
101             timeout=None,
102             metadata=None):
103         return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/GetVulnById',
104             osv__service__v1__pb2.GetVulnByIdParameters.SerializeToString,
105             osv_dot_vulnerability__pb2.Vulnerability.FromString,
106             options, channel_credentials,
107             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
108 
109     @staticmethod
110     def QueryAffected(request,
111             target,
112             options=(),
113             channel_credentials=None,
114             call_credentials=None,
115             insecure=False,
116             compression=None,
117             wait_for_ready=None,
118             timeout=None,
119             metadata=None):
120         return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/QueryAffected',
121             osv__service__v1__pb2.QueryAffectedParameters.SerializeToString,
122             osv__service__v1__pb2.VulnerabilityList.FromString,
123             options, channel_credentials,
124             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
125 
126     @staticmethod
127     def QueryAffectedBatch(request,
128             target,
129             options=(),
130             channel_credentials=None,
131             call_credentials=None,
132             insecure=False,
133             compression=None,
134             wait_for_ready=None,
135             timeout=None,
136             metadata=None):
137         return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/QueryAffectedBatch',
138             osv__service__v1__pb2.QueryAffectedBatchParameters.SerializeToString,
139             osv__service__v1__pb2.BatchVulnerabilityList.FromString,
140             options, channel_credentials,
141             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
142
```
--- 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/docs/build.py b/docs/build.py
--- a/docs/build.py
+++ b/docs/build.py
@@ -76,7 +76,7 @@
   spec['tags'] = [{
       'name': 'api',
       'x-displayName': 'API',
-      'description': 'The API has 2 methods:'
+      'description': 'The API has 3 methods:'
   }, {
       'name': 'vulnerability_schema',
       'x-displayName': 'Vulnerability schema',
@@ -93,6 +93,7 @@
   }]
 
   spec['paths']['/v1/query']['post']['tags'] = ['api']
+  spec['paths']['/v1/querybatch']['post']['tags'] = ['api']
   spec['paths']['/v1/vulns/{id}']['get']['tags'] = ['api']
 
   spec['paths']['/v1/query']['post']['x-code-samples'] = [{
@@ -107,6 +108,33 @@
            '  "https://api.osv.dev/v1/query"')
   }]
 
+  spec['paths']['/v1/querybatch']['post']['x-code-samples'] = [{
+      'lang':
+          'Curl example',
+      'source':
+          ("""cat <<EOF | curl -X POST -d @- "https://api.osv.dev/v1/querybatch"
+{
+  "queries": [
+    {
+      "package": {
+        "purl": "pkg:pypi/antlr4-python3-runtime@4.7.2"
+      }
+    },
+    {
+      "commit": "6879efc2c1596d11a6a6ad296f80063b558d5e0f"
+    },
+    {
+      "package": {
+        "ecosystem": "PyPI",
+        "name": "jinja2"
+      },
+      "version": "2.4.1"
+    }
+  ]
+}
+EOF""")
+  }]
+
   spec['paths']['/v1/vulns/{id}']['get']['x-code-samples'] = [{
       'lang': 'Curl example',
       'source': 'curl "https://api.osv.dev/v1/vulns/OSV-2020-111"'
diff --git a/gcp/api/osv_service_v1_pb2_grpc.py b/gcp/api/osv_service_v1_pb2_grpc.py
--- a/gcp/api/osv_service_v1_pb2_grpc.py
+++ b/gcp/api/osv_service_v1_pb2_grpc.py
@@ -53,8 +53,7 @@
         raise NotImplementedError('Method not implemented!')
 
     def QueryAffectedBatch(self, request, context):
-        """Query vulnerabilities for a particular project at given commits and
-        versions.
+        """Query vulnerabilities (batched) for given package versions and commits.
         """
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')

{"golden_diff": "diff --git a/docs/build.py b/docs/build.py\n--- a/docs/build.py\n+++ b/docs/build.py\n@@ -76,7 +76,7 @@\n   spec['tags'] = [{\n       'name': 'api',\n       'x-displayName': 'API',\n-      'description': 'The API has 2 methods:'\n+      'description': 'The API has 3 methods:'\n   }, {\n       'name': 'vulnerability_schema',\n       'x-displayName': 'Vulnerability schema',\n@@ -93,6 +93,7 @@\n   }]\n \n   spec['paths']['/v1/query']['post']['tags'] = ['api']\n+  spec['paths']['/v1/querybatch']['post']['tags'] = ['api']\n   spec['paths']['/v1/vulns/{id}']['get']['tags'] = ['api']\n \n   spec['paths']['/v1/query']['post']['x-code-samples'] = [{\n@@ -107,6 +108,33 @@\n            '  \"https://api.osv.dev/v1/query\"')\n   }]\n \n+  spec['paths']['/v1/querybatch']['post']['x-code-samples'] = [{\n+      'lang':\n+          'Curl example',\n+      'source':\n+          (\"\"\"cat <<EOF | curl -X POST -d @- \"https://api.osv.dev/v1/querybatch\"\n+{\n+  \"queries\": [\n+    {\n+      \"package\": {\n+        \"purl\": \"pkg:pypi/antlr4-python3-runtime@4.7.2\"\n+      }\n+    },\n+    {\n+      \"commit\": \"6879efc2c1596d11a6a6ad296f80063b558d5e0f\"\n+    },\n+    {\n+      \"package\": {\n+        \"ecosystem\": \"PyPI\",\n+        \"name\": \"jinja2\"\n+      },\n+      \"version\": \"2.4.1\"\n+    }\n+  ]\n+}\n+EOF\"\"\")\n+  }]\n+\n   spec['paths']['/v1/vulns/{id}']['get']['x-code-samples'] = [{\n       'lang': 'Curl example',\n       'source': 'curl \"https://api.osv.dev/v1/vulns/OSV-2020-111\"'\ndiff --git a/gcp/api/osv_service_v1_pb2_grpc.py b/gcp/api/osv_service_v1_pb2_grpc.py\n--- a/gcp/api/osv_service_v1_pb2_grpc.py\n+++ b/gcp/api/osv_service_v1_pb2_grpc.py\n@@ -53,8 +53,7 @@\n         raise NotImplementedError('Method not implemented!')\n \n     def QueryAffectedBatch(self, request, context):\n-        \"\"\"Query vulnerabilities for a particular project at given commits and\n-        versions.\n+        \"\"\"Query vulnerabilities (batched) for given package versions and commits.\n         \"\"\"\n         context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n         context.set_details('Method not implemented!')\n", "issue": "Bulk query API\nA bulk query API would allow developers to more easily query the API without hitting rate limits. It would also help with scenarios like #257, where an SBOM will contain many dependencies.\n", "before_files": [{"content": "# Copyright 2021 Google LLC\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\"\"\"Documentation builder.\"\"\"\n\nimport json\nimport os\nimport shutil\nimport subprocess\n\n_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n_GENERATED_FILENAME = 'v1/osv_service_v1.swagger.json'\n\n\ndef property_description_workaround(definition):\n  \"\"\"Work around an OpenAPI limitation with a field descriptions getting\n  replaced by the object descriptions.\"\"\"\n  # Workaround described in https://github.com/Redocly/redoc/issues/835.\n  for value in definition['properties'].values():\n    if '$ref' in value:\n      value['allOf'] = [{'$ref': value['$ref']}]\n      del value['$ref']\n\n\ndef replace_property_name(definition, key, replacement):\n  \"\"\"Replace property name.\"\"\"\n  definition['properties'][replacement] = definition['properties'][key]\n  del definition['properties'][key]\n\n\ndef main():\n  api_dir = os.path.join(_ROOT_DIR, 'gcp', 'api')\n  v1_api_dir = os.path.join(api_dir, 'v1')\n  googleapis_dir = os.path.join(api_dir, 'googleapis')\n  service_proto_path = os.path.join(v1_api_dir, 'osv_service_v1.proto')\n\n  # Add OSV dependencies.\n  osv_path = os.path.join(api_dir, 'osv')\n  if os.path.exists(osv_path):\n    shutil.rmtree(osv_path)\n\n  shutil.copytree(os.path.join(_ROOT_DIR, 'lib', 'osv'), osv_path)\n\n  subprocess.run([\n      'protoc',\n      '-I',\n      api_dir,\n      '-I',\n      v1_api_dir,\n      '-I',\n      googleapis_dir,\n      '--openapiv2_out',\n      '.',\n      '--openapiv2_opt',\n      'logtostderr=true',\n      service_proto_path,\n  ],\n                 check=True)\n\n  with open(_GENERATED_FILENAME) as f:\n    spec = json.load(f)\n\n  spec['host'] = 'api.osv.dev'\n  spec['info']['title'] = 'OSV'\n  spec['info']['version'] = '1.0'\n  spec['tags'] = [{\n      'name': 'api',\n      'x-displayName': 'API',\n      'description': 'The API has 2 methods:'\n  }, {\n      'name': 'vulnerability_schema',\n      'x-displayName': 'Vulnerability schema',\n      'description': 'Please see the [OpenSSF Open Source Vulnerability spec]'\n                     '(https://ossf.github.io/osv-schema/).',\n  }]\n\n  spec['x-tagGroups'] = [{\n      'name': 'API',\n      'tags': ['api']\n  }, {\n      'name': 'Schema',\n      'tags': ['vulnerability_schema']\n  }]\n\n  spec['paths']['/v1/query']['post']['tags'] = ['api']\n  spec['paths']['/v1/vulns/{id}']['get']['tags'] = ['api']\n\n  spec['paths']['/v1/query']['post']['x-code-samples'] = [{\n      'lang':\n          'Curl example',\n      'source':\n          ('curl -X POST -d \\\\\\n'\n           '  \\'{\"commit\": \"6879efc2c1596d11a6a6ad296f80063b558d5e0f\"}\\' \\\\\\n'\n           '  \"https://api.osv.dev/v1/query\"\\n\\n'\n           'curl -X POST -d \\\\\\n'\n           '  \\'{\"package\": {\"name\": \"mruby\"}, \"version\": \"2.1.2rc\"}\\' \\\\\\n'\n           '  \"https://api.osv.dev/v1/query\"')\n  }]\n\n  spec['paths']['/v1/vulns/{id}']['get']['x-code-samples'] = [{\n      'lang': 'Curl example',\n      'source': 'curl \"https://api.osv.dev/v1/vulns/OSV-2020-111\"'\n  }]\n\n  property_description_workaround(spec['definitions']['v1Query'])\n  property_description_workaround(spec['definitions']['osvVulnerability'])\n\n  replace_property_name(spec['definitions']['osvVulnerability'],\n                        'databaseSpecific', 'database_specific')\n\n  with open('sections.md') as f:\n    spec['info']['description'] = f.read()\n\n  with open(_GENERATED_FILENAME, 'w') as f:\n    f.write(json.dumps(spec, indent=2))\n\n  shutil.move(_GENERATED_FILENAME, os.path.basename(_GENERATED_FILENAME))\n\n\nif __name__ == '__main__':\n  main()\n", "path": "docs/build.py"}, {"content": "# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!\n\"\"\"Client and server classes corresponding to protobuf-defined services.\"\"\"\nimport grpc\n\nfrom osv import vulnerability_pb2 as osv_dot_vulnerability__pb2\nimport osv_service_v1_pb2 as osv__service__v1__pb2\n\n\nclass OSVStub(object):\n    \"\"\"Open source vulnerability database.\n    \"\"\"\n\n    def __init__(self, channel):\n        \"\"\"Constructor.\n\n        Args:\n            channel: A grpc.Channel.\n        \"\"\"\n        self.GetVulnById = channel.unary_unary(\n                '/osv.v1.OSV/GetVulnById',\n                request_serializer=osv__service__v1__pb2.GetVulnByIdParameters.SerializeToString,\n                response_deserializer=osv_dot_vulnerability__pb2.Vulnerability.FromString,\n                )\n        self.QueryAffected = channel.unary_unary(\n                '/osv.v1.OSV/QueryAffected',\n                request_serializer=osv__service__v1__pb2.QueryAffectedParameters.SerializeToString,\n                response_deserializer=osv__service__v1__pb2.VulnerabilityList.FromString,\n                )\n        self.QueryAffectedBatch = channel.unary_unary(\n                '/osv.v1.OSV/QueryAffectedBatch',\n                request_serializer=osv__service__v1__pb2.QueryAffectedBatchParameters.SerializeToString,\n                response_deserializer=osv__service__v1__pb2.BatchVulnerabilityList.FromString,\n                )\n\n\nclass OSVServicer(object):\n    \"\"\"Open source vulnerability database.\n    \"\"\"\n\n    def GetVulnById(self, request, context):\n        \"\"\"Return a `Vulnerability` object for a given OSV ID.\n        \"\"\"\n        context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n        context.set_details('Method not implemented!')\n        raise NotImplementedError('Method not implemented!')\n\n    def QueryAffected(self, request, context):\n        \"\"\"Query vulnerabilities for a particular project at a given commit or\n        version.\n        \"\"\"\n        context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n        context.set_details('Method not implemented!')\n        raise NotImplementedError('Method not implemented!')\n\n    def QueryAffectedBatch(self, request, context):\n        \"\"\"Query vulnerabilities for a particular project at given commits and\n        versions.\n        \"\"\"\n        context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n        context.set_details('Method not implemented!')\n        raise NotImplementedError('Method not implemented!')\n\n\ndef add_OSVServicer_to_server(servicer, server):\n    rpc_method_handlers = {\n            'GetVulnById': grpc.unary_unary_rpc_method_handler(\n                    servicer.GetVulnById,\n                    request_deserializer=osv__service__v1__pb2.GetVulnByIdParameters.FromString,\n                    response_serializer=osv_dot_vulnerability__pb2.Vulnerability.SerializeToString,\n            ),\n            'QueryAffected': grpc.unary_unary_rpc_method_handler(\n                    servicer.QueryAffected,\n                    request_deserializer=osv__service__v1__pb2.QueryAffectedParameters.FromString,\n                    response_serializer=osv__service__v1__pb2.VulnerabilityList.SerializeToString,\n            ),\n            'QueryAffectedBatch': grpc.unary_unary_rpc_method_handler(\n                    servicer.QueryAffectedBatch,\n                    request_deserializer=osv__service__v1__pb2.QueryAffectedBatchParameters.FromString,\n                    response_serializer=osv__service__v1__pb2.BatchVulnerabilityList.SerializeToString,\n            ),\n    }\n    generic_handler = grpc.method_handlers_generic_handler(\n            'osv.v1.OSV', rpc_method_handlers)\n    server.add_generic_rpc_handlers((generic_handler,))\n\n\n # This class is part of an EXPERIMENTAL API.\nclass OSV(object):\n    \"\"\"Open source vulnerability database.\n    \"\"\"\n\n    @staticmethod\n    def GetVulnById(request,\n            target,\n            options=(),\n            channel_credentials=None,\n            call_credentials=None,\n            insecure=False,\n            compression=None,\n            wait_for_ready=None,\n            timeout=None,\n            metadata=None):\n        return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/GetVulnById',\n            osv__service__v1__pb2.GetVulnByIdParameters.SerializeToString,\n            osv_dot_vulnerability__pb2.Vulnerability.FromString,\n            options, channel_credentials,\n            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)\n\n    @staticmethod\n    def QueryAffected(request,\n            target,\n            options=(),\n            channel_credentials=None,\n            call_credentials=None,\n            insecure=False,\n            compression=None,\n            wait_for_ready=None,\n            timeout=None,\n            metadata=None):\n        return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/QueryAffected',\n            osv__service__v1__pb2.QueryAffectedParameters.SerializeToString,\n            osv__service__v1__pb2.VulnerabilityList.FromString,\n            options, channel_credentials,\n            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)\n\n    @staticmethod\n    def QueryAffectedBatch(request,\n            target,\n            options=(),\n            channel_credentials=None,\n            call_credentials=None,\n            insecure=False,\n            compression=None,\n            wait_for_ready=None,\n            timeout=None,\n            metadata=None):\n        return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/QueryAffectedBatch',\n            osv__service__v1__pb2.QueryAffectedBatchParameters.SerializeToString,\n            osv__service__v1__pb2.BatchVulnerabilityList.FromString,\n            options, channel_credentials,\n            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)\n", "path": "gcp/api/osv_service_v1_pb2_grpc.py"}], "after_files": [{"content": "# Copyright 2021 Google LLC\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\"\"\"Documentation builder.\"\"\"\n\nimport json\nimport os\nimport shutil\nimport subprocess\n\n_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n_GENERATED_FILENAME = 'v1/osv_service_v1.swagger.json'\n\n\ndef property_description_workaround(definition):\n  \"\"\"Work around an OpenAPI limitation with a field descriptions getting\n  replaced by the object descriptions.\"\"\"\n  # Workaround described in https://github.com/Redocly/redoc/issues/835.\n  for value in definition['properties'].values():\n    if '$ref' in value:\n      value['allOf'] = [{'$ref': value['$ref']}]\n      del value['$ref']\n\n\ndef replace_property_name(definition, key, replacement):\n  \"\"\"Replace property name.\"\"\"\n  definition['properties'][replacement] = definition['properties'][key]\n  del definition['properties'][key]\n\n\ndef main():\n  api_dir = os.path.join(_ROOT_DIR, 'gcp', 'api')\n  v1_api_dir = os.path.join(api_dir, 'v1')\n  googleapis_dir = os.path.join(api_dir, 'googleapis')\n  service_proto_path = os.path.join(v1_api_dir, 'osv_service_v1.proto')\n\n  # Add OSV dependencies.\n  osv_path = os.path.join(api_dir, 'osv')\n  if os.path.exists(osv_path):\n    shutil.rmtree(osv_path)\n\n  shutil.copytree(os.path.join(_ROOT_DIR, 'lib', 'osv'), osv_path)\n\n  subprocess.run([\n      'protoc',\n      '-I',\n      api_dir,\n      '-I',\n      v1_api_dir,\n      '-I',\n      googleapis_dir,\n      '--openapiv2_out',\n      '.',\n      '--openapiv2_opt',\n      'logtostderr=true',\n      service_proto_path,\n  ],\n                 check=True)\n\n  with open(_GENERATED_FILENAME) as f:\n    spec = json.load(f)\n\n  spec['host'] = 'api.osv.dev'\n  spec['info']['title'] = 'OSV'\n  spec['info']['version'] = '1.0'\n  spec['tags'] = [{\n      'name': 'api',\n      'x-displayName': 'API',\n      'description': 'The API has 3 methods:'\n  }, {\n      'name': 'vulnerability_schema',\n      'x-displayName': 'Vulnerability schema',\n      'description': 'Please see the [OpenSSF Open Source Vulnerability spec]'\n                     '(https://ossf.github.io/osv-schema/).',\n  }]\n\n  spec['x-tagGroups'] = [{\n      'name': 'API',\n      'tags': ['api']\n  }, {\n      'name': 'Schema',\n      'tags': ['vulnerability_schema']\n  }]\n\n  spec['paths']['/v1/query']['post']['tags'] = ['api']\n  spec['paths']['/v1/querybatch']['post']['tags'] = ['api']\n  spec['paths']['/v1/vulns/{id}']['get']['tags'] = ['api']\n\n  spec['paths']['/v1/query']['post']['x-code-samples'] = [{\n      'lang':\n          'Curl example',\n      'source':\n          ('curl -X POST -d \\\\\\n'\n           '  \\'{\"commit\": \"6879efc2c1596d11a6a6ad296f80063b558d5e0f\"}\\' \\\\\\n'\n           '  \"https://api.osv.dev/v1/query\"\\n\\n'\n           'curl -X POST -d \\\\\\n'\n           '  \\'{\"package\": {\"name\": \"mruby\"}, \"version\": \"2.1.2rc\"}\\' \\\\\\n'\n           '  \"https://api.osv.dev/v1/query\"')\n  }]\n\n  spec['paths']['/v1/querybatch']['post']['x-code-samples'] = [{\n      'lang':\n          'Curl example',\n      'source':\n          (\"\"\"cat <<EOF | curl -X POST -d @- \"https://api.osv.dev/v1/querybatch\"\n{\n  \"queries\": [\n    {\n      \"package\": {\n        \"purl\": \"pkg:pypi/antlr4-python3-runtime@4.7.2\"\n      }\n    },\n    {\n      \"commit\": \"6879efc2c1596d11a6a6ad296f80063b558d5e0f\"\n    },\n    {\n      \"package\": {\n        \"ecosystem\": \"PyPI\",\n        \"name\": \"jinja2\"\n      },\n      \"version\": \"2.4.1\"\n    }\n  ]\n}\nEOF\"\"\")\n  }]\n\n  spec['paths']['/v1/vulns/{id}']['get']['x-code-samples'] = [{\n      'lang': 'Curl example',\n      'source': 'curl \"https://api.osv.dev/v1/vulns/OSV-2020-111\"'\n  }]\n\n  property_description_workaround(spec['definitions']['v1Query'])\n  property_description_workaround(spec['definitions']['osvVulnerability'])\n\n  replace_property_name(spec['definitions']['osvVulnerability'],\n                        'databaseSpecific', 'database_specific')\n\n  with open('sections.md') as f:\n    spec['info']['description'] = f.read()\n\n  with open(_GENERATED_FILENAME, 'w') as f:\n    f.write(json.dumps(spec, indent=2))\n\n  shutil.move(_GENERATED_FILENAME, os.path.basename(_GENERATED_FILENAME))\n\n\nif __name__ == '__main__':\n  main()\n", "path": "docs/build.py"}, {"content": "# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!\n\"\"\"Client and server classes corresponding to protobuf-defined services.\"\"\"\nimport grpc\n\nfrom osv import vulnerability_pb2 as osv_dot_vulnerability__pb2\nimport osv_service_v1_pb2 as osv__service__v1__pb2\n\n\nclass OSVStub(object):\n    \"\"\"Open source vulnerability database.\n    \"\"\"\n\n    def __init__(self, channel):\n        \"\"\"Constructor.\n\n        Args:\n            channel: A grpc.Channel.\n        \"\"\"\n        self.GetVulnById = channel.unary_unary(\n                '/osv.v1.OSV/GetVulnById',\n                request_serializer=osv__service__v1__pb2.GetVulnByIdParameters.SerializeToString,\n                response_deserializer=osv_dot_vulnerability__pb2.Vulnerability.FromString,\n                )\n        self.QueryAffected = channel.unary_unary(\n                '/osv.v1.OSV/QueryAffected',\n                request_serializer=osv__service__v1__pb2.QueryAffectedParameters.SerializeToString,\n                response_deserializer=osv__service__v1__pb2.VulnerabilityList.FromString,\n                )\n        self.QueryAffectedBatch = channel.unary_unary(\n                '/osv.v1.OSV/QueryAffectedBatch',\n                request_serializer=osv__service__v1__pb2.QueryAffectedBatchParameters.SerializeToString,\n                response_deserializer=osv__service__v1__pb2.BatchVulnerabilityList.FromString,\n                )\n\n\nclass OSVServicer(object):\n    \"\"\"Open source vulnerability database.\n    \"\"\"\n\n    def GetVulnById(self, request, context):\n        \"\"\"Return a `Vulnerability` object for a given OSV ID.\n        \"\"\"\n        context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n        context.set_details('Method not implemented!')\n        raise NotImplementedError('Method not implemented!')\n\n    def QueryAffected(self, request, context):\n        \"\"\"Query vulnerabilities for a particular project at a given commit or\n        version.\n        \"\"\"\n        context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n        context.set_details('Method not implemented!')\n        raise NotImplementedError('Method not implemented!')\n\n    def QueryAffectedBatch(self, request, context):\n        \"\"\"Query vulnerabilities (batched) for given package versions and commits.\n        \"\"\"\n        context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n        context.set_details('Method not implemented!')\n        raise NotImplementedError('Method not implemented!')\n\n\ndef add_OSVServicer_to_server(servicer, server):\n    rpc_method_handlers = {\n            'GetVulnById': grpc.unary_unary_rpc_method_handler(\n                    servicer.GetVulnById,\n                    request_deserializer=osv__service__v1__pb2.GetVulnByIdParameters.FromString,\n                    response_serializer=osv_dot_vulnerability__pb2.Vulnerability.SerializeToString,\n            ),\n            'QueryAffected': grpc.unary_unary_rpc_method_handler(\n                    servicer.QueryAffected,\n                    request_deserializer=osv__service__v1__pb2.QueryAffectedParameters.FromString,\n                    response_serializer=osv__service__v1__pb2.VulnerabilityList.SerializeToString,\n            ),\n            'QueryAffectedBatch': grpc.unary_unary_rpc_method_handler(\n                    servicer.QueryAffectedBatch,\n                    request_deserializer=osv__service__v1__pb2.QueryAffectedBatchParameters.FromString,\n                    response_serializer=osv__service__v1__pb2.BatchVulnerabilityList.SerializeToString,\n            ),\n    }\n    generic_handler = grpc.method_handlers_generic_handler(\n            'osv.v1.OSV', rpc_method_handlers)\n    server.add_generic_rpc_handlers((generic_handler,))\n\n\n # This class is part of an EXPERIMENTAL API.\nclass OSV(object):\n    \"\"\"Open source vulnerability database.\n    \"\"\"\n\n    @staticmethod\n    def GetVulnById(request,\n            target,\n            options=(),\n            channel_credentials=None,\n            call_credentials=None,\n            insecure=False,\n            compression=None,\n            wait_for_ready=None,\n            timeout=None,\n            metadata=None):\n        return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/GetVulnById',\n            osv__service__v1__pb2.GetVulnByIdParameters.SerializeToString,\n            osv_dot_vulnerability__pb2.Vulnerability.FromString,\n            options, channel_credentials,\n            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)\n\n    @staticmethod\n    def QueryAffected(request,\n            target,\n            options=(),\n            channel_credentials=None,\n            call_credentials=None,\n            insecure=False,\n            compression=None,\n            wait_for_ready=None,\n            timeout=None,\n            metadata=None):\n        return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/QueryAffected',\n            osv__service__v1__pb2.QueryAffectedParameters.SerializeToString,\n            osv__service__v1__pb2.VulnerabilityList.FromString,\n            options, channel_credentials,\n            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)\n\n    @staticmethod\n    def QueryAffectedBatch(request,\n            target,\n            options=(),\n            channel_credentials=None,\n            call_credentials=None,\n            insecure=False,\n            compression=None,\n            wait_for_ready=None,\n            timeout=None,\n            metadata=None):\n        return grpc.experimental.unary_unary(request, target, '/osv.v1.OSV/QueryAffectedBatch',\n            osv__service__v1__pb2.QueryAffectedBatchParameters.SerializeToString,\n            osv__service__v1__pb2.BatchVulnerabilityList.FromString,\n            options, channel_credentials,\n            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)\n", "path": "gcp/api/osv_service_v1_pb2_grpc.py"}]}