fix(cloud): stop googleapiclient pulling in the system oauth2client (#10110) (#10112)

On packaged Linux installs the bundled venv is created with
--system-site-packages (issue #7173) so it can reach system packages such
as dbus-python. That also exposes the deprecated system oauth2client and
whatever pyOpenSSL ships alongside it. googleapiclient imports oauth2client
optionally, and on Ubuntu 24.04 that drags in a pyOpenSSL too old for our
bundled cryptography, aborting startup at blueprint registration with
"AttributeError: module 'lib' has no attribute 'GEN_EMAIL'".

pgAdmin only ever authenticates to Google via google-auth and
google-auth-oauthlib, so park a None sentinel under
sys.modules['oauth2client'] before importing googleapiclient in both the
web module and the standalone pgacloud provider. The optional import then
fails cleanly and googleapiclient falls back to google-auth.

Closes #10110
This commit is contained in:
Dave Page
2026-07-24 19:02:29 +05:30
committed by GitHub
parent 67755809a6
commit 75dd304d25
3 changed files with 82 additions and 0 deletions
+11
View File
@@ -8,12 +8,23 @@
# ##########################################################################
import json
import os
import sys
import time
from utils.io import debug, error, output
from utils.misc import get_my_ip, get_random_id
from providers._abstract import AbsProvider
# pgAdmin only authenticates to Google via google-auth, never the
# long-deprecated oauth2client. googleapiclient still tries to import
# oauth2client optionally, and on packaged installs the venv inherits the
# system site-packages (--system-site-packages, see issue #7173) where a
# stale oauth2client and an incompatible pyOpenSSL may be present. That
# optional import drags in the broken pyOpenSSL and crashes with "module
# 'lib' has no attribute 'GEN_EMAIL'". Blocking the module here makes
# googleapiclient fall back to google-auth cleanly. See issue #10110.
sys.modules.setdefault('oauth2client', None)
from googleapiclient import discovery
from googleapiclient.errors import HttpError
from google.auth.transport.requests import Request
+13
View File
@@ -10,6 +10,7 @@
# Google Cloud Deployment Implementation
import json
import os
import sys
from urllib.parse import unquote
from config import root
@@ -25,6 +26,18 @@ from flask import session, current_app, request
from flask_babel import gettext as _
from oauthlib.oauth2 import AccessDeniedError
# pgAdmin only authenticates to Google via google-auth and
# google-auth-oauthlib, never the long-deprecated oauth2client.
# googleapiclient still tries to import oauth2client optionally, and on
# packaged installs the venv inherits the system site-packages
# (--system-site-packages, see issue #7173) where a stale oauth2client and
# an incompatible pyOpenSSL may be present. That optional import drags in
# the broken pyOpenSSL and aborts startup with "module 'lib' has no
# attribute 'GEN_EMAIL'". Blocking the module here makes googleapiclient
# fall back to google-auth cleanly. See issue #10110.
sys.modules.setdefault('oauth2client', None)
from googleapiclient import discovery
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
@@ -0,0 +1,58 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""
Regression test for issue #10110.
On packaged installs the venv inherits the system site-packages
(--system-site-packages, see issue #7173). When a stale ``oauth2client``
and an incompatible ``pyOpenSSL`` live there, googleapiclient's optional
``import oauth2client`` drags in the broken pyOpenSSL and aborts pgAdmin
startup with "module 'lib' has no attribute 'GEN_EMAIL'".
The cloud.google module guards against this by parking a ``None`` sentinel
under ``sys.modules['oauth2client']`` before importing googleapiclient, so
the optional import fails cleanly and google-auth is used instead.
"""
import sys
import unittest
from pgadmin.utils.route import BaseTestGenerator
class _SkipServerSetUpMixin:
"""Skip BaseTestGenerator's Postgres connection — pure logic tests."""
def setUp(self):
unittest.TestCase.setUp(self)
class TestOauth2ClientBlockedOnGoogleImport(
_SkipServerSetUpMixin, BaseTestGenerator):
"""Importing cloud.google must keep googleapiclient off oauth2client."""
scenarios = (('default', {}),)
def runTest(self):
# Importing the module installs the sentinel as a side effect.
import pgadmin.misc.cloud.google # noqa: F401
# The sentinel must be in place so googleapiclient never imports
# the deprecated oauth2client (and the pyOpenSSL it would pull in).
self.assertIsNone(
sys.modules.get('oauth2client', 'missing'),
"cloud.google must park a None sentinel under "
"sys.modules['oauth2client'] to block the optional import")
# googleapiclient must consequently report no oauth2client support.
import googleapiclient._auth as _auth
self.assertFalse(
_auth.HAS_OAUTH2CLIENT,
"googleapiclient must fall back to google-auth, not oauth2client")