diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index c2fc27e46..0954585f2 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -1,18 +1,3 @@ -# Copyright 2021 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - docker: image: gcr.io/repo-automation-bots/owlbot-python:latest - digest: sha256:c66ba3c8d7bc8566f47df841f98cd0097b28fff0b1864c86f5817f4c8c3e8600 - + digest: sha256:df50e8d462f86d6bcb42f27ecad55bb12c404f1c65de9c6fe4c4d25120080bd6 diff --git a/.kokoro/samples/python3.9/common.cfg b/.kokoro/samples/python3.9/common.cfg new file mode 100644 index 000000000..b1eacb8f6 --- /dev/null +++ b/.kokoro/samples/python3.9/common.cfg @@ -0,0 +1,40 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Build logs will be here +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} + +# Specify which tests to run +env_vars: { + key: "RUN_TESTS_SESSION" + value: "py-3.9" +} + +# Declare build specific Cloud project. +env_vars: { + key: "BUILD_SPECIFIC_GCLOUD_PROJECT" + value: "python-docs-samples-tests-py39" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/google-auth-library-python/.kokoro/test-samples.sh" +} + +# Configure the docker image for kokoro-trampoline. +env_vars: { + key: "TRAMPOLINE_IMAGE" + value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker" +} + +# Download secrets for samples +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples" + +# Download trampoline resources. +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" + +# Use the trampoline script to run in docker. +build_file: "google-auth-library-python/.kokoro/trampoline.sh" \ No newline at end of file diff --git a/.kokoro/samples/python3.9/continuous.cfg b/.kokoro/samples/python3.9/continuous.cfg new file mode 100644 index 000000000..a1c8d9759 --- /dev/null +++ b/.kokoro/samples/python3.9/continuous.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} \ No newline at end of file diff --git a/.kokoro/samples/python3.9/periodic-head.cfg b/.kokoro/samples/python3.9/periodic-head.cfg new file mode 100644 index 000000000..f9cfcd33e --- /dev/null +++ b/.kokoro/samples/python3.9/periodic-head.cfg @@ -0,0 +1,11 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} + +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/python-pubsub/.kokoro/test-samples-against-head.sh" +} diff --git a/.kokoro/samples/python3.9/periodic.cfg b/.kokoro/samples/python3.9/periodic.cfg new file mode 100644 index 000000000..50fec9649 --- /dev/null +++ b/.kokoro/samples/python3.9/periodic.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "False" +} \ No newline at end of file diff --git a/.kokoro/samples/python3.9/presubmit.cfg b/.kokoro/samples/python3.9/presubmit.cfg new file mode 100644 index 000000000..a1c8d9759 --- /dev/null +++ b/.kokoro/samples/python3.9/presubmit.cfg @@ -0,0 +1,6 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +env_vars: { + key: "INSTALL_LIBRARY_FROM_SOURCE" + value: "True" +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index aae65ed59..d04dad5b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://pypi.org/project/google-auth/#history +### [1.32.1](https://www.github.com/googleapis/google-auth-library-python/compare/v1.32.0...v1.32.1) (2021-06-30) + + +### Bug Fixes + +* avoid leaking sub-session created for '_auth_request' ([#789](https://www.github.com/googleapis/google-auth-library-python/issues/789)) ([2079ab5](https://www.github.com/googleapis/google-auth-library-python/commit/2079ab5e1db464f502248ae4f9e424deeef87fb2)) + ## [1.32.0](https://www.github.com/googleapis/google-auth-library-python/compare/v1.31.0...v1.32.0) (2021-06-16) diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py index a4784b386..817176bef 100644 --- a/google/auth/transport/requests.py +++ b/google/auth/transport/requests.py @@ -340,17 +340,19 @@ def __init__( self._default_host = default_host if auth_request is None: - auth_request_session = requests.Session() + self._auth_request_session = requests.Session() # Using an adapter to make HTTP requests robust to network errors. # This adapter retrys HTTP requests when network errors occur # and the requests seems safely retryable. retry_adapter = requests.adapters.HTTPAdapter(max_retries=3) - auth_request_session.mount("https://", retry_adapter) + self._auth_request_session.mount("https://", retry_adapter) # Do not pass `self` as the session here, as it can lead to # infinite recursion. - auth_request = Request(auth_request_session) + auth_request = Request(self._auth_request_session) + else: + self._auth_request_session = None # Request instance used by internal methods (for example, # credentials.refresh). @@ -533,3 +535,8 @@ def request( def is_mtls(self): """Indicates if the created SSL channel is mutual TLS.""" return self._is_mtls + + def close(self): + if self._auth_request_session is not None: + self._auth_request_session.close() + super(AuthorizedSession, self).close() diff --git a/google/auth/version.py b/google/auth/version.py index d675c0bff..2ffa8a43a 100644 --- a/google/auth/version.py +++ b/google/auth/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.32.0" +__version__ = "1.32.1" diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index 2e9cacd05..24d89b1bf 100644 Binary files a/system_tests/secrets.tar.enc and b/system_tests/secrets.tar.enc differ diff --git a/system_tests/system_tests_sync/test_requests.py b/system_tests/system_tests_sync/test_requests.py index 3ac9179b5..28004848b 100644 --- a/system_tests/system_tests_sync/test_requests.py +++ b/system_tests/system_tests_sync/test_requests.py @@ -32,8 +32,10 @@ def test_authorized_session_with_service_account_and_self_signed_jwt(): # List Pub/Sub Topics through the REST API # https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/list - response = session.get("https://pubsub.googleapis.com/v1/projects/{}/topics".format(project_id)) - response.raise_for_status() + url = "https://pubsub.googleapis.com/v1/projects/{}/topics".format(project_id) + with session: + response = session.get(url) + response.raise_for_status() # Check that self-signed JWT was created and is being used assert credentials._jwt_credentials is not None diff --git a/tests/transport/test_requests.py b/tests/transport/test_requests.py index f494c1443..ed9300d76 100644 --- a/tests/transport/test_requests.py +++ b/tests/transport/test_requests.py @@ -213,7 +213,7 @@ def test_constructor_with_auth_request(self): mock.sentinel.credentials, auth_request=auth_request ) - assert authed_session._auth_request == auth_request + assert authed_session._auth_request is auth_request def test_request_default_timeout(self): credentials = mock.Mock(wraps=CredentialsStub()) @@ -504,3 +504,22 @@ def test_configure_mtls_channel_without_client_cert_env( auth_session.configure_mtls_channel(mock_callback) assert not auth_session.is_mtls mock_callback.assert_not_called() + + def test_close_wo_passed_in_auth_request(self): + authed_session = google.auth.transport.requests.AuthorizedSession( + mock.sentinel.credentials + ) + authed_session._auth_request_session = mock.Mock(spec=["close"]) + + authed_session.close() + + authed_session._auth_request_session.close.assert_called_once_with() + + def test_close_w_passed_in_auth_request(self): + http = mock.create_autospec(requests.Session) + auth_request = google.auth.transport.requests.Request(http) + authed_session = google.auth.transport.requests.AuthorizedSession( + mock.sentinel.credentials, auth_request=auth_request + ) + + authed_session.close() # no raise