fix: do not use the GAE APIs on gen2+ runtimes (#807)
* fix: do not use the GAE APIs on gen2+ runtimes
Currently, this library uses the App Engine API in all environments if
it can be imported successfully. This assumption made sense when the API
was only available on gen1, but this is no longer the case.
See https://github.com/GoogleCloudPlatform/appengine-python-standard
In order to comply with AIP-4115, we must treat GAE gen2+ as a "compute
engine equivalent environment" even if the GAE APIs are importable.
In other words, google.auth.default() must never return an
app_engine.Credental on GAE gen2+.Currently, this library uses the App Engine API in all environments if
it can be imported successfully. This assumption made sense when the API
was only available on gen1, but this is no longer the case.
See https://github.com/GoogleCloudPlatform/appengine-python-standard
In order to comply with AIP-4115, we must treat GAE gen2+ as a "compute
engine equivalent environment" even if the GAE APIs are importable.
In other words, google.auth.default() should not return an
app_engine.Credental on GAE gen2+.
* blacken
Co-authored-by: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com>
diff --git a/tests/test__default.py b/tests/test__default.py
index e136896..a515f38 100644
--- a/tests/test__default.py
+++ b/tests/test__default.py
@@ -447,7 +447,9 @@
yield app_identity_module
-def test__get_gae_credentials(app_identity):
+@mock.patch.dict(os.environ)
+def test__get_gae_credentials_gen1(app_identity):
+ os.environ[environment_vars.LEGACY_APPENGINE_RUNTIME] = "python27"
app_identity.get_application_id.return_value = mock.sentinel.project
credentials, project_id = _default._get_gae_credentials()
@@ -456,18 +458,65 @@
assert project_id == mock.sentinel.project
+@mock.patch.dict(os.environ)
+def test__get_gae_credentials_gen2():
+ os.environ["GAE_RUNTIME"] = "python37"
+ credentials, project_id = _default._get_gae_credentials()
+ assert credentials is None
+ assert project_id is None
+
+
+@mock.patch.dict(os.environ)
+def test__get_gae_credentials_gen2_backwards_compat():
+ # compat helpers may copy GAE_RUNTIME to APPENGINE_RUNTIME
+ # for backwards compatibility with code that relies on it
+ os.environ[environment_vars.LEGACY_APPENGINE_RUNTIME] = "python37"
+ os.environ["GAE_RUNTIME"] = "python37"
+ credentials, project_id = _default._get_gae_credentials()
+ assert credentials is None
+ assert project_id is None
+
+
+def test__get_gae_credentials_env_unset():
+ assert environment_vars.LEGACY_APPENGINE_RUNTIME not in os.environ
+ assert "GAE_RUNTIME" not in os.environ
+ credentials, project_id = _default._get_gae_credentials()
+ assert credentials is None
+ assert project_id is None
+
+
+@mock.patch.dict(os.environ)
def test__get_gae_credentials_no_app_engine():
+ # test both with and without LEGACY_APPENGINE_RUNTIME setting
+ assert environment_vars.LEGACY_APPENGINE_RUNTIME not in os.environ
+
import sys
- with mock.patch.dict("sys.modules"):
- sys.modules["google.auth.app_engine"] = None
+ with mock.patch.dict(sys.modules, {"google.auth.app_engine": None}):
+ credentials, project_id = _default._get_gae_credentials()
+ assert credentials is None
+ assert project_id is None
+
+ os.environ[environment_vars.LEGACY_APPENGINE_RUNTIME] = "python27"
credentials, project_id = _default._get_gae_credentials()
assert credentials is None
assert project_id is None
+@mock.patch.dict(os.environ)
+@mock.patch.object(app_engine, "app_identity", new=None)
def test__get_gae_credentials_no_apis():
- assert _default._get_gae_credentials() == (None, None)
+ # test both with and without LEGACY_APPENGINE_RUNTIME setting
+ assert environment_vars.LEGACY_APPENGINE_RUNTIME not in os.environ
+
+ credentials, project_id = _default._get_gae_credentials()
+ assert credentials is None
+ assert project_id is None
+
+ os.environ[environment_vars.LEGACY_APPENGINE_RUNTIME] = "python27"
+ credentials, project_id = _default._get_gae_credentials()
+ assert credentials is None
+ assert project_id is None
@mock.patch(
diff --git a/tests/test_app_engine.py b/tests/test_app_engine.py
index e335ff7..6a788b9 100644
--- a/tests/test_app_engine.py
+++ b/tests/test_app_engine.py
@@ -52,6 +52,7 @@
assert app_engine.get_project_id() == mock.sentinel.project
+@mock.patch.object(app_engine, "app_identity", new=None)
def test_get_project_id_missing_apis():
with pytest.raises(EnvironmentError) as excinfo:
assert app_engine.get_project_id()
@@ -86,6 +87,7 @@
class TestCredentials(object):
+ @mock.patch.object(app_engine, "app_identity", new=None)
def test_missing_apis(self):
with pytest.raises(EnvironmentError) as excinfo:
app_engine.Credentials()