From 08c0ab8ab54ec91eca037a73e89021a4014fbac9 Mon Sep 17 00:00:00 2001 From: Daniel Holth Date: Thu, 27 Jul 2023 08:57:26 -0400 Subject: [PATCH] jlap: disable warning when not context.ssl_verify (#12923) * jlap: disable warning when not context.ssl_verify --- conda/gateways/repodata/jlap/interface.py | 5 +++ news/12731-jlap-respect-ssl-verify | 20 ++++++++++ tests/conftest.py | 6 ++- tests/fixtures_jlap.py | 20 ++++++++-- tests/gateways/test_jlap.py | 46 ++++++++++++++++++++++- 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 news/12731-jlap-respect-ssl-verify diff --git a/conda/gateways/repodata/jlap/interface.py b/conda/gateways/repodata/jlap/interface.py index dac54db3762..4bfefaa1162 100644 --- a/conda/gateways/repodata/jlap/interface.py +++ b/conda/gateways/repodata/jlap/interface.py @@ -7,6 +7,8 @@ import os from pathlib import Path +from conda.base.context import context +from conda.gateways.connection.download import disable_ssl_verify_warning from conda.gateways.connection.session import CondaSession from .. import ( @@ -70,6 +72,9 @@ def repodata_parsed(self, state: dict | RepodataState) -> dict | None: When repodata is not updated, it doesn't matter whether this function or the caller reads from a file. """ + if not context.ssl_verify: + disable_ssl_verify_warning() + session = CondaSession() repodata_url = f"{self._url}/{self._repodata_fn}" diff --git a/news/12731-jlap-respect-ssl-verify b/news/12731-jlap-respect-ssl-verify new file mode 100644 index 00000000000..9b914a57995 --- /dev/null +++ b/news/12731-jlap-respect-ssl-verify @@ -0,0 +1,20 @@ +### Enhancements + +* + +### Bug fixes + +* Hide InsecureRequestWarning for jlap when CONDA_SSL_VERIFY=false, matching + non-jlap behavior. (#12731) + +### Deprecations + +* + +### Docs + +* + +### Other + +* diff --git a/tests/conftest.py b/tests/conftest.py index 469cdc9a895..f92af61e54f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,11 @@ from conda.testing import conda_cli, path_factory, tmp_env from . import http_test_server -from .fixtures_jlap import package_repository_base, package_server # NOQA +from .fixtures_jlap import ( # NOQA + package_repository_base, + package_server, + package_server_ssl, +) pytest_plugins = ( # Add testing fixtures and internal pytest plugins here diff --git a/tests/fixtures_jlap.py b/tests/fixtures_jlap.py index 684a7e8ad91..5ab9a0c5c0e 100644 --- a/tests/fixtures_jlap.py +++ b/tests/fixtures_jlap.py @@ -18,7 +18,7 @@ import flask import pytest -from werkzeug.serving import WSGIRequestHandler, make_server +from werkzeug.serving import WSGIRequestHandler, generate_adhoc_ssl_context, make_server app = flask.Flask(__name__) @@ -58,10 +58,16 @@ def log(self, format, *args): pass -def make_server_with_socket(socket: socket.socket, base_: Path = base): +def make_server_with_socket(socket: socket.socket, base_: Path = base, ssl=False): global server, base base = base_ assert isinstance(socket.fileno(), int) + ssl_context = None + + if ssl: + # openssl may fail when mixing defaults + conda-forge + ssl_context = generate_adhoc_ssl_context() + server = make_server( "127.0.0.1", port=0, @@ -69,6 +75,7 @@ def make_server_with_socket(socket: socket.socket, base_: Path = base): fd=socket.fileno(), threaded=True, request_handler=NoLoggingWSGIRequestHandler, + ssl_context=ssl_context, ) server.serve_forever() @@ -94,11 +101,11 @@ def prepare_socket() -> socket.socket: return s -def _package_server(cleanup=True, base: Path | None = None): +def _package_server(cleanup=True, base: Path | None = None, ssl=False): socket = prepare_socket() context = multiprocessing.get_context("spawn") process = context.Process( - target=make_server_with_socket, args=(socket, base), daemon=True + target=make_server_with_socket, args=(socket, base, ssl), daemon=True ) process.start() yield socket @@ -124,6 +131,11 @@ def package_server(package_repository_base): yield from _package_server(base=package_repository_base) +@pytest.fixture(scope="session") +def package_server_ssl(package_repository_base): + yield from _package_server(base=package_repository_base, ssl=True) + + if __name__ == "__main__": print(run_on_random_port()) time.sleep(60) diff --git a/tests/gateways/test_jlap.py b/tests/gateways/test_jlap.py index ed8f1e50a90..f040a59c1fd 100644 --- a/tests/gateways/test_jlap.py +++ b/tests/gateways/test_jlap.py @@ -18,7 +18,7 @@ from conda.base.context import conda_tests_ctxt_mgmt_def_pol, context from conda.common.io import env_vars from conda.core.subdir_data import SubdirData -from conda.exceptions import CondaHTTPError +from conda.exceptions import CondaHTTPError, CondaSSLError from conda.gateways.connection.session import CondaSession from conda.gateways.repodata import ( CACHE_CONTROL_KEY, @@ -83,6 +83,50 @@ def test_jlap_fetch(package_server: socket, tmp_path: Path, mocker): assert patched.call_count == 4 +@pytest.mark.parametrize("verify_ssl", [True, False]) +def test_jlap_fetch_ssl( + package_server_ssl: socket, tmp_path: Path, mocker, verify_ssl: bool +): + """Check that JlapRepoInterface doesn't raise exceptions.""" + host, port = package_server_ssl.getsockname() + base = f"https://{host}:{port}/test" + + cache = RepodataCache(base=tmp_path / "cache", repodata_fn="repodata.json") + + url = f"{base}/osx-64" + repo = interface.JlapRepoInterface( + url, + repodata_fn="repodata.json", + cache=cache, + cache_path_json=Path(tmp_path, f"repodata_{verify_ssl}.json"), + cache_path_state=Path(tmp_path, f"repodata_{verify_ssl}{CACHE_STATE_SUFFIX}"), + ) + + expected_exception = CondaSSLError if verify_ssl else RepodataOnDisk + + # clear session cache to avoid leftover wrong-ssl-verify Session() + try: + del CondaSession._thread_local.session + except AttributeError: + pass + + state = {} + with env_vars( + {"CONDA_SSL_VERIFY": str(verify_ssl).lower()}, + stack_callback=conda_tests_ctxt_mgmt_def_pol, + ), pytest.raises(expected_exception), pytest.warns() as record: + repo.repodata(state) + + # If we didn't disable warnings, we will see two 'InsecureRequestWarning' + assert len(record) == 0, f"Unexpected warning {record[0]._category_name}" + + # clear session cache to avoid leftover wrong-ssl-verify Session() + try: + del CondaSession._thread_local.session + except AttributeError: + pass + + def test_download_and_hash( package_server: socket, tmp_path: Path,