diff --git a/googleapiclient/discovery_cache/__init__.py b/googleapiclient/discovery_cache/__init__.py index 6051191e73..7bb3a76771 100644 --- a/googleapiclient/discovery_cache/__init__.py +++ b/googleapiclient/discovery_cache/__init__.py @@ -68,6 +68,11 @@ def get_static_doc(serviceName, version): content = None doc_name = "{}.{}.json".format(serviceName, version) + # serviceName and version identify an API, they are not paths. Only look + # for the document directly inside of DISCOVERY_DOC_DIR. + if os.path.basename(doc_name) != doc_name: + return content + try: with open(os.path.join(DISCOVERY_DOC_DIR, doc_name), "r") as f: content = f.read() diff --git a/tests/test_discovery.py b/tests/test_discovery.py index 6912783451..6cf9a215c7 100644 --- a/tests/test_discovery.py +++ b/tests/test_discovery.py @@ -34,6 +34,7 @@ import pickle import re import sys +import tempfile import unittest from unittest import mock import urllib @@ -83,7 +84,7 @@ build_from_document, key2param, ) -from googleapiclient.discovery_cache import DISCOVERY_DOC_MAX_AGE +from googleapiclient.discovery_cache import DISCOVERY_DOC_DIR, DISCOVERY_DOC_MAX_AGE from googleapiclient.discovery_cache.base import Cache from googleapiclient.errors import ( HttpError, @@ -1499,6 +1500,23 @@ def test_unknown_api_when_static_discovery_true(self): with self.assertRaises(UnknownApiNameOrVersion): build("doesnotexist", "v3", cache_discovery=False, static_discovery=True) + def test_static_discovery_does_not_read_outside_of_documents_dir(self): + http = HttpMockSequence([({"status": "400"}, "")]) + with tempfile.TemporaryDirectory() as tmpdir: + with open(os.path.join(tmpdir, "zoo.v1.json"), "w") as f: + f.write(read_datafile("zoo.json")) + outside = os.path.join(tmpdir, "zoo") + # Both an absolute path and one relative to the bundled documents. + for name in (outside, os.path.relpath(outside, DISCOVERY_DOC_DIR)): + with self.assertRaises(UnknownApiNameOrVersion): + build( + name, + "v1", + http=http, + cache_discovery=False, + static_discovery=True, + ) + class DictCache(Cache): def __init__(self):